This commit is contained in:
xds
2026-03-16 12:12:56 +03:00
commit 9d886076d6
63 changed files with 4482 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
import uuid
from pathlib import Path
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from backend.app.core.config import settings
from backend.app.core.database import get_session
from backend.app.models.activity import Activity, DataPoint
from backend.app.schemas.activity import (
ActivityResponse,
ActivityListResponse,
DataPointResponse,
)
from backend.app.services.fit_parser import parse_fit_file
from backend.app.services.metrics import calculate_metrics
router = APIRouter()
@router.post("/upload", response_model=ActivityResponse)
async def upload_activity(
rider_id: uuid.UUID,
file: UploadFile = File(...),
session: AsyncSession = Depends(get_session),
):
if not file.filename or not file.filename.lower().endswith(".fit"):
raise HTTPException(status_code=400, detail="Only .FIT files are accepted")
upload_dir = Path(settings.UPLOAD_DIR)
upload_dir.mkdir(parents=True, exist_ok=True)
file_id = uuid.uuid4()
file_path = upload_dir / f"{file_id}.fit"
content = await file.read()
file_path.write_bytes(content)
activity, data_points = parse_fit_file(content, rider_id, str(file_path))
session.add(activity)
await session.flush()
for dp in data_points:
dp.activity_id = activity.id
session.add_all(data_points)
metrics = calculate_metrics(data_points, activity, rider_id, session)
if metrics:
session.add(metrics)
await session.commit()
await session.refresh(activity)
return activity
@router.get("", response_model=ActivityListResponse)
async def list_activities(
rider_id: uuid.UUID,
limit: int = 20,
offset: int = 0,
session: AsyncSession = Depends(get_session),
):
count_query = select(func.count(Activity.id)).where(Activity.rider_id == rider_id)
total = (await session.execute(count_query)).scalar() or 0
query = (
select(Activity)
.where(Activity.rider_id == rider_id)
.order_by(Activity.date.desc())
.limit(limit)
.offset(offset)
)
result = await session.execute(query)
activities = result.scalars().all()
return ActivityListResponse(items=activities, total=total)
@router.get("/{activity_id}", response_model=ActivityResponse)
async def get_activity(
activity_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
):
activity = await session.get(Activity, activity_id)
if not activity:
raise HTTPException(status_code=404, detail="Activity not found")
return activity
@router.get("/{activity_id}/stream", response_model=list[DataPointResponse])
async def get_activity_stream(
activity_id: uuid.UUID,
session: AsyncSession = Depends(get_session),
):
query = (
select(DataPoint)
.where(DataPoint.activity_id == activity_id)
.order_by(DataPoint.timestamp)
)
result = await session.execute(query)
return result.scalars().all()