fix to strava sync
This commit is contained in:
@@ -18,6 +18,7 @@ from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
from fastapi import Cookie, FastAPI, File, Form, HTTPException, Request, Response, UploadFile
|
||||
from fastapi.responses import RedirectResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
@@ -643,6 +644,70 @@ async def submit_feedback(
|
||||
return JSONResponse({"ok": True, "id": submission_id})
|
||||
|
||||
|
||||
# ── Strava ────────────────────────────────────────────────────────────────────
|
||||
|
||||
_strava_oauth_states: set[str] = set()
|
||||
|
||||
|
||||
@app.get("/api/strava/status")
|
||||
async def strava_status(bincio_session: Optional[str] = Cookie(default=None)) -> JSONResponse:
|
||||
user = _require_user(bincio_session)
|
||||
if not strava_client_id:
|
||||
return JSONResponse({"configured": False, "connected": False, "last_sync": None})
|
||||
dd = _get_data_dir() / user.handle
|
||||
token_path = dd / "strava_token.json"
|
||||
connected = token_path.exists()
|
||||
last_sync = None
|
||||
if connected:
|
||||
try:
|
||||
token = json.loads(token_path.read_text())
|
||||
last_sync = token.get("last_sync_at")
|
||||
except Exception:
|
||||
pass
|
||||
return JSONResponse({"configured": True, "connected": connected, "last_sync": last_sync})
|
||||
|
||||
|
||||
@app.get("/api/strava/auth-url")
|
||||
async def strava_auth_url(request: Request, bincio_session: Optional[str] = Cookie(default=None)) -> JSONResponse:
|
||||
_require_user(bincio_session)
|
||||
if not strava_client_id:
|
||||
raise HTTPException(400, "Strava client ID not configured on this server")
|
||||
state = secrets.token_urlsafe(16)
|
||||
_strava_oauth_states.add(state)
|
||||
redirect_uri = str(request.url_for("strava_callback"))
|
||||
from bincio.extract.strava_api import auth_url
|
||||
return JSONResponse({"url": auth_url(strava_client_id, redirect_uri, state=state)})
|
||||
|
||||
|
||||
@app.get("/api/strava/callback", name="strava_callback")
|
||||
async def strava_callback(
|
||||
request: Request,
|
||||
code: str = "",
|
||||
error: str = "",
|
||||
state: str = "",
|
||||
bincio_session: Optional[str] = Cookie(default=None),
|
||||
) -> RedirectResponse:
|
||||
site_origin = str(request.base_url).rstrip("/")
|
||||
if error or not code:
|
||||
return RedirectResponse(f"{site_origin}/?strava=error")
|
||||
if state not in _strava_oauth_states:
|
||||
return RedirectResponse(f"{site_origin}/?strava=error")
|
||||
_strava_oauth_states.discard(state)
|
||||
user = _current_user(bincio_session)
|
||||
if not user:
|
||||
return RedirectResponse(f"{site_origin}/?strava=error")
|
||||
if not strava_client_id or not strava_client_secret:
|
||||
return RedirectResponse(f"{site_origin}/?strava=error")
|
||||
dd = _get_data_dir() / user.handle
|
||||
from bincio.extract.strava_api import StravaError, exchange_code, save_token
|
||||
try:
|
||||
token = exchange_code(strava_client_id, strava_client_secret, code)
|
||||
except StravaError:
|
||||
return RedirectResponse(f"{site_origin}/?strava=error")
|
||||
save_token(dd, token)
|
||||
return RedirectResponse(f"{site_origin}/?strava=connected")
|
||||
|
||||
|
||||
@app.post("/api/strava/sync")
|
||||
async def serve_strava_sync(bincio_session: Optional[str] = Cookie(default=None)) -> JSONResponse:
|
||||
user = _require_user(bincio_session)
|
||||
|
||||
@@ -14,6 +14,9 @@ def test_serve_app_has_routes():
|
||||
paths = {r.path for r in app.routes}
|
||||
assert "/api/me" in paths
|
||||
assert "/api/upload" in paths
|
||||
assert "/api/strava/status" in paths
|
||||
assert "/api/strava/auth-url" in paths
|
||||
assert "/api/strava/callback" in paths
|
||||
assert "/api/strava/sync" in paths
|
||||
assert "/api/register" in paths
|
||||
|
||||
|
||||
Reference in New Issue
Block a user