refactor: extract/ingest facade, merge_one, deduplicate ops constants

- Add bincio/extract/ingest.py as a facade over the extract internals (ingest_parsed, strava_sync), reducing coupling from 6+ imports to one
  - Add merge_one() to merge.py — fast single-activity path for interactive edits (rewrites one file + index, skips full directory rebuild)
  - Rewrite edit/ops.py to delegate to the new facade; fix broken run_strava_sync return (was referencing undefined locals)
  - Remove duplicated SPORTS, STAT_PANELS, VALID_ACTIVITY_ID from edit/server.py — now imported from ops.py
This commit is contained in:
Davide Scaini
2026-04-09 12:03:06 +02:00
parent 0223d468c9
commit 7dcb1e6dd0
5 changed files with 229 additions and 77 deletions
+3 -8
View File
@@ -3,7 +3,6 @@
from __future__ import annotations
import json
import re
import shutil
from pathlib import Path
from typing import Any
@@ -12,6 +11,8 @@ from fastapi import FastAPI, File, HTTPException, Request, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from bincio.edit.ops import SPORTS, STAT_PANELS, VALID_ACTIVITY_ID
# Populated by the CLI before uvicorn starts
data_dir: Path | None = None
site_url: str = "http://localhost:4321"
@@ -28,18 +29,12 @@ app.add_middleware(
allow_headers=["Content-Type"],
)
_VALID_ACTIVITY_ID = re.compile(r'^[a-zA-Z0-9][a-zA-Z0-9\-]{0,250}$')
def _check_id(activity_id: str) -> str:
"""Reject activity IDs that contain path traversal sequences."""
if not _VALID_ACTIVITY_ID.match(activity_id):
if not VALID_ACTIVITY_ID.match(activity_id):
raise HTTPException(400, "Invalid activity ID")
return activity_id
SPORTS = ["cycling", "running", "hiking", "walking", "swimming", "skiing", "other"]
STAT_PANELS = ["elevation", "speed", "heart_rate", "cadence", "power"]
# ── HTML UI ───────────────────────────────────────────────────────────────────