added advanced workout

This commit is contained in:
2026-07-01 11:20:13 +03:00
parent 32c211676f
commit 1c61bb4102
38 changed files with 2044 additions and 376 deletions
+61 -1
View File
@@ -2,7 +2,7 @@ from datetime import date, datetime, timedelta, timezone
from typing import Any
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, field_validator
from sqlalchemy.orm import Session
from app.auth.deps import get_current_user
@@ -124,6 +124,34 @@ class WorkoutCreate(BaseModel):
logged_at: str | None = None
class WorkoutResultsUpdate(BaseModel):
distance_m: float | None = Field(default=None, ge=0)
avg_heart_rate: int | None = Field(default=None, ge=30, le=250)
max_heart_rate: int | None = Field(default=None, ge=30, le=250)
avg_pace: float | None = Field(default=None, ge=0)
avg_cadence: int | None = Field(default=None, ge=0)
max_cadence: int | None = Field(default=None, ge=0)
avg_stride_length_cm: float | None = Field(default=None, ge=0)
training_load: float | None = Field(default=None, ge=0)
aerobic_effect: float | None = Field(default=None, ge=0)
anaerobic_effect: float | None = Field(default=None, ge=0)
vo2max: float | None = Field(default=None, ge=0)
recovery_hours: float | None = Field(default=None, ge=0)
intervals: list[dict[str, Any]] | dict[str, Any] | None = None
heart_rate_zones: list[dict[str, Any]] | dict[str, Any] | None = None
perceived_effort: int | None = Field(default=None, ge=1, le=5)
exercises: list[dict[str, Any]] | None = None
@field_validator("intervals", "heart_rate_zones")
@classmethod
def validate_json_payload(cls, value: Any) -> Any:
if value is None:
return value
if not isinstance(value, (list, dict)):
raise ValueError("must be a JSON array or object")
return value
class ReminderUpdate(BaseModel):
enabled: bool | None = None
hour: int | None = Field(default=None, ge=0, le=23)
@@ -355,6 +383,38 @@ async def create_workout(
)
@router.get("/fitness/workouts/{log_id}/results")
def get_workout_results(
log_id: int,
db: Session = Depends(get_db),
user: User = Depends(get_current_user),
) -> dict[str, Any]:
result = FitnessService(db, user.id).get_workout_results(log_id)
if not result:
raise HTTPException(status_code=404, detail="Not found")
return result
@router.post("/fitness/workouts/{log_id}/results")
def save_workout_results(
log_id: int,
payload: WorkoutResultsUpdate,
db: Session = Depends(get_db),
user: User = Depends(get_current_user),
) -> dict[str, Any]:
updates = payload.model_dump(exclude_unset=True)
if not updates:
raise HTTPException(status_code=400, detail="No fields to update")
service = FitnessService(db, user.id)
try:
result = service.save_workout_results(log_id, updates)
except ValueError as exc:
raise HTTPException(status_code=422, detail=str(exc)) from exc
if not result:
raise HTTPException(status_code=404, detail="Not found")
return result
@router.get("/fitness/body-metrics")
def list_metrics(
limit: int = 30,