c465e518e5
New endpoint: GET /api/activity/{id}/download/{bas|original|gpx}
- bas: streams the BAS detail JSON as an attachment
- original: streams the original FIT or GPX file from originals/
- gpx: generates a GPX from the timeseries (always available when GPS exists)
download_disabled flag stored in sidecar (edits/{id}.md), propagated to
the merged BAS detail JSON. When set, only the owner can download.
Backend: ops.py writes flag to sidecar; merge.py propagates it to detail
JSON; download.py implements the endpoint; server.py registers the router.
Frontend: EditDrawer gets a "No download" toggle button; ActivityDetail
shows a Download section (hidden when disabled and viewer is not the owner).
72 lines
1.7 KiB
Python
72 lines
1.7 KiB
Python
"""bincio serve — multi-user FastAPI application server.
|
|
|
|
Handles auth, user management, and auth-gated write operations.
|
|
nginx serves static files; this server only handles /api/* routes.
|
|
|
|
Run via `bincio serve` CLI command.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import glob as _glob
|
|
import threading
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.middleware.gzip import GZipMiddleware
|
|
|
|
from bincio.serve import deps, tasks
|
|
from bincio.serve.routers import (
|
|
activities,
|
|
admin,
|
|
auth,
|
|
download,
|
|
feed,
|
|
garmin,
|
|
ideas,
|
|
me,
|
|
segments,
|
|
strava,
|
|
uploads,
|
|
)
|
|
|
|
app = FastAPI(title="BincioActivity Serve")
|
|
|
|
|
|
@app.on_event("startup")
|
|
async def _on_startup() -> None:
|
|
"""Startup tasks: clean orphaned tmp zips; launch site-rebuild worker if --webroot set."""
|
|
data_dir = deps._get_data_dir()
|
|
for p in _glob.glob(str(data_dir / "*" / "tmp*.zip")):
|
|
try:
|
|
Path(p).unlink()
|
|
except OSError:
|
|
pass
|
|
if deps.webroot is not None:
|
|
threading.Thread(target=tasks._site_rebuild_worker, daemon=True, name="site-rebuild").start()
|
|
|
|
|
|
app.add_middleware(GZipMiddleware, minimum_size=1024)
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origin_regex=r"https?://localhost(:\d+)?|https://[a-z0-9-]+\.bincio\.org",
|
|
allow_credentials=True,
|
|
allow_methods=["GET", "POST", "DELETE"],
|
|
allow_headers=["Content-Type"],
|
|
)
|
|
|
|
for _router in [
|
|
feed.router,
|
|
auth.router,
|
|
me.router,
|
|
admin.router,
|
|
activities.router,
|
|
download.router,
|
|
uploads.router,
|
|
segments.router,
|
|
strava.router,
|
|
garmin.router,
|
|
ideas.router,
|
|
]:
|
|
app.include_router(_router)
|