- "Last sync: never": The old blocking sync was killed by nginx at 120s before save_token was reached. The activities made it to disk (ingestion happens per-activity as it goes), but the token's
last_sync_at timestamp was never written. After deploying, do a soft reset — it'll set last_sync_at to your most recent activity's timestamp so the next sync only fetches newer ones. - Reset 404: Added POST /api/strava/reset to serve/server.py. The soft reset now looks in _merged/index.json first (multi-user path), falling back to index.json.
This commit is contained in:
+57
-8
@@ -663,16 +663,65 @@ async def strava_status(bincio_session: Optional[str] = Cookie(default=None)) ->
|
|||||||
if not strava_client_id:
|
if not strava_client_id:
|
||||||
return JSONResponse({"configured": False, "connected": False, "last_sync": None})
|
return JSONResponse({"configured": False, "connected": False, "last_sync": None})
|
||||||
dd = _get_data_dir() / user.handle
|
dd = _get_data_dir() / user.handle
|
||||||
token_path = dd / "strava_token.json"
|
from bincio.extract.strava_api import load_token
|
||||||
connected = token_path.exists()
|
token = load_token(dd)
|
||||||
last_sync = None
|
return JSONResponse({
|
||||||
if connected:
|
"configured": True,
|
||||||
|
"connected": token is not None,
|
||||||
|
"last_sync": token.get("last_sync_at") if token else None,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/api/strava/reset")
|
||||||
|
async def strava_reset(request: Request, bincio_session: Optional[str] = Cookie(default=None)) -> JSONResponse:
|
||||||
|
"""Reset last_sync_at so the next sync re-fetches from a chosen point.
|
||||||
|
|
||||||
|
mode=soft — set to the started_at of the most recent activity on disk
|
||||||
|
(next sync only fetches activities newer than the last known one)
|
||||||
|
mode=hard — clear last_sync_at entirely
|
||||||
|
(next sync re-downloads full Strava history, skipping existing files)
|
||||||
|
"""
|
||||||
|
user = _require_user(bincio_session)
|
||||||
|
dd = _get_data_dir() / user.handle
|
||||||
|
from bincio.extract.strava_api import load_token, save_token
|
||||||
|
token = load_token(dd)
|
||||||
|
if token is None:
|
||||||
|
raise HTTPException(400, "Not connected to Strava")
|
||||||
|
|
||||||
|
body = await request.json()
|
||||||
|
mode = body.get("mode", "soft")
|
||||||
|
|
||||||
|
if mode == "hard":
|
||||||
|
token.pop("last_sync_at", None)
|
||||||
|
save_token(dd, token)
|
||||||
|
return JSONResponse({"ok": True, "mode": "hard", "last_sync_at": None})
|
||||||
|
|
||||||
|
# soft: find the most recent started_at across the user's merged index
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
last_ts: int | None = None
|
||||||
|
for index_path in [dd / "_merged" / "index.json", dd / "index.json"]:
|
||||||
|
if not index_path.exists():
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
token = json.loads(token_path.read_text())
|
index_data = json.loads(index_path.read_text(encoding="utf-8"))
|
||||||
last_sync = token.get("last_sync_at")
|
started_ats = [
|
||||||
|
a.get("started_at") for a in index_data.get("activities", [])
|
||||||
|
if a.get("started_at")
|
||||||
|
]
|
||||||
|
if started_ats:
|
||||||
|
latest = max(started_ats)
|
||||||
|
dt = datetime.fromisoformat(latest.replace("Z", "+00:00"))
|
||||||
|
last_ts = int(dt.astimezone(timezone.utc).timestamp())
|
||||||
|
break
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
continue
|
||||||
return JSONResponse({"configured": True, "connected": connected, "last_sync": last_sync})
|
|
||||||
|
if last_ts is None:
|
||||||
|
token.pop("last_sync_at", None)
|
||||||
|
else:
|
||||||
|
token["last_sync_at"] = last_ts
|
||||||
|
save_token(dd, token)
|
||||||
|
return JSONResponse({"ok": True, "mode": "soft", "last_sync_at": last_ts})
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/strava/auth-url")
|
@app.get("/api/strava/auth-url")
|
||||||
|
|||||||
Reference in New Issue
Block a user