79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
from ..models.api_token import APIToken
|
|
from ..services.sync_app import SyncApp
|
|
from ..services.garmin.client import GarminClient
|
|
from ..services.postgresql_manager import PostgreSQLManager
|
|
from sqlalchemy.orm import Session
|
|
from ..utils.config import config
|
|
import logging
|
|
import json
|
|
import garth
|
|
from garth.auth_tokens import OAuth1Token, OAuth2Token
|
|
|
|
router = APIRouter()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class SyncActivityRequest(BaseModel):
|
|
days_back: int = 30
|
|
|
|
class SyncResponse(BaseModel):
|
|
status: str
|
|
message: str
|
|
job_id: Optional[str] = None
|
|
|
|
def get_db():
|
|
db_manager = PostgreSQLManager(config.DATABASE_URL)
|
|
with db_manager.get_db_session() as session:
|
|
yield session
|
|
|
|
def _load_and_verify_garth_session(db: Session):
|
|
"""Helper to load token from DB and verify session with Garmin."""
|
|
logger.info("Loading and verifying Garmin session...")
|
|
token_record = db.query(APIToken).filter_by(token_type='garmin').first()
|
|
if not (token_record and token_record.garth_oauth1_token and token_record.garth_oauth2_token):
|
|
raise HTTPException(status_code=401, detail="Garmin token not found.")
|
|
|
|
try:
|
|
oauth1_dict = json.loads(token_record.garth_oauth1_token)
|
|
oauth2_dict = json.loads(token_record.garth_oauth2_token)
|
|
|
|
domain = oauth1_dict.get('domain')
|
|
if domain:
|
|
garth.configure(domain=domain)
|
|
|
|
garth.client.oauth1_token = OAuth1Token(**oauth1_dict)
|
|
garth.client.oauth2_token = OAuth2Token(**oauth2_dict)
|
|
|
|
garth.UserProfile.get()
|
|
logger.info("Garth session verified.")
|
|
except Exception as e:
|
|
logger.error(f"Garth session verification failed: {e}", exc_info=True)
|
|
raise HTTPException(status_code=401, detail=f"Failed to authenticate with Garmin: {e}")
|
|
|
|
@router.post("/sync/activities", response_model=SyncResponse)
|
|
def sync_activities(request: SyncActivityRequest, db: Session = Depends(get_db)):
|
|
_load_and_verify_garth_session(db)
|
|
garmin_client = GarminClient() # The client is now just a thin wrapper
|
|
sync_app = SyncApp(db_session=db, garmin_client=garmin_client)
|
|
result = sync_app.sync_activities(days_back=request.days_back)
|
|
return SyncResponse(
|
|
status=result.get("status", "completed_with_errors" if result.get("failed", 0) > 0 else "completed"),
|
|
message=f"Activity sync completed: {result.get('processed', 0)} processed, {result.get('failed', 0)} failed",
|
|
job_id=f"activity-sync-{datetime.now().strftime('%Y%m%d%H%M%S')}"
|
|
)
|
|
|
|
@router.post("/sync/metrics", response_model=SyncResponse)
|
|
def sync_metrics(db: Session = Depends(get_db)):
|
|
_load_and_verify_garth_session(db)
|
|
garmin_client = GarminClient()
|
|
sync_app = SyncApp(db_session=db, garmin_client=garmin_client)
|
|
result = sync_app.sync_health_metrics()
|
|
return SyncResponse(
|
|
status=result.get("status", "completed_with_errors" if result.get("failed", 0) > 0 else "completed"),
|
|
message=f"Health metrics sync completed: {result.get('processed', 0)} processed, {result.get('failed', 0)} failed",
|
|
job_id=f"metrics-sync-{datetime.now().strftime('%Y%m%d%H%M%S')}"
|
|
)
|