feat(gps-tracks): GPX download from public track popup
Some checks failed
CI / lint (push) Failing after 5s
CI / test (push) Failing after 6s
CI / build (push) Has been skipped
CI / lint (pull_request) Failing after 4s
CI / test (pull_request) Failing after 5s
CI / build (pull_request) Has been skipped

Реализация ET-011: кнопка «Скачать GPX» в popup публичного GPS-трека и
новый эндпоинт GET /api/gps-tracks/{track_id}/download (GPX 1.1 +
Content-Disposition с UTF-8 именем по RFC 5987). Реэкспорт защищён
per-source флагом `download_allowed` в `config/gps_sources.yaml`
(default-deny, MVP whitelist = `osm`).

Backend:
- `src/api/gps_tracks/export.py` — чистый stdlib-builder GPX 1.1
  (`build_gpx`) + санитизация имени файла (`safe_filename`, RFC 5987).
- `src/api/gps_tracks/endpoint.py` — новый route с проверками
  400 / 403 / 404 / 413; cap 200 000 точек (REQ-NF-02).
- `src/api/gps_tracks/config.py` — `load_download_allowed_sources()`
  читает YAML, default-deny при отсутствии поля; fallback на `{"osm"}`
  при отсутствии конфига.
- `src/api/main.py` — пробрасывает `GPS_SOURCES_CONFIG_PATH` в router.

Frontend:
- `src/web/gps_tracks.js` — кнопка в `_renderTrackPopupHtml`,
  обработчик `_downloadPublicTrack` (fetch + Blob + a.download — тот же
  паттерн, что в `app.js::downloadGPX`, R-1 митигирован), парсер
  `_parseFilenameFromCD` для RFC 5987, маппинг ошибок
  `_handleDownloadError` (403/404/413/5xx → showToast).
- `src/web/app.css` — стиль кнопки, 32×32 CSS px (REQ-NF-04).

Тесты:
- 13 unit для GPX-builder (UT-01/02/03/05; XSD-валидация против
  `tests/fixtures/gpx-1.1/gpx.xsd`).
- 10 unit для `safe_filename` (UT-04).
- 11 integration для download-эндпоинта (IT-01..08 +
  ANY-rule license check + default-deny без конфига).

ADR-014 (gpx-download-endpoint), ADR-015 (source-redistribution-policy).
Refs: ET-011

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 20:59:53 +00:00
parent 6fe2ecf12b
commit eea6c846c2
12 changed files with 2284 additions and 8 deletions

View File

@@ -10,6 +10,8 @@ sources:
parser_module: "src.api.gps_tracks.sources.osm"
save_user_field: true
external_url_template: "https://www.openstreetmap.org/user/{user}/traces/{external_id_numeric}"
# ET-011 / ADR-015: ODbL разрешает реэкспорт при атрибуции.
download_allowed: true
- id: enduro_russia
name: "EnduroRussia.ru"
@@ -22,6 +24,8 @@ sources:
parser_module: "src.api.gps_tracks.sources.enduro_russia"
save_user_field: false
source_priority: 80
# ET-011 / ADR-015: ToS не содержит явного разрешения на ре-экспорт.
download_allowed: false
- id: wikiloc
name: "Wikiloc"
@@ -36,6 +40,8 @@ sources:
source_priority: 70
activity_filter: [motorcycle, enduro]
max_tracks_per_run: 50
# ET-011 / ADR-015: proprietary, ToS запрещает массовый ре-экспорт.
download_allowed: false
- id: ttrails
name: "Тропинки.ру"
@@ -47,3 +53,5 @@ sources:
attribution: "ttrails.ru"
parser_module: "src.api.gps_tracks.sources.ttrails"
save_user_field: false
# ET-011 / ADR-015: collection-ADR proposed (blocked), реэкспорт запрещён.
download_allowed: false