Files
life/backend/app/routers/workout.py

138 lines
3.5 KiB
Python

from datetime import date
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.orm import Session, selectinload
from app.auth import get_current_user
from app.database import get_db
from app.models.workout import Exercise, Workout, WorkoutSet
router = APIRouter(
prefix="/api", tags=["workouts"], dependencies=[Depends(get_current_user)]
)
# --- Schemas ---
class ExerciseCreate(BaseModel):
name: str
category: str
class ExerciseRead(ExerciseCreate):
id: int
model_config = {"from_attributes": True}
class WorkoutSetCreate(BaseModel):
exercise_id: int
set_number: int
reps: int | None = None
weight_lbs: float | None = None
duration_min: float | None = None
class WorkoutSetRead(WorkoutSetCreate):
id: int
model_config = {"from_attributes": True}
class WorkoutCreate(BaseModel):
date: date
name: str | None = None
notes: str | None = None
sets: list[WorkoutSetCreate] = []
class WorkoutRead(BaseModel):
id: int
date: date
name: str | None
notes: str | None
sets: list[WorkoutSetRead]
model_config = {"from_attributes": True}
# --- Exercise endpoints ---
@router.get("/exercises", response_model=list[ExerciseRead])
def list_exercises(db: Session = Depends(get_db)):
return db.scalars(select(Exercise).order_by(Exercise.name)).all()
@router.post("/exercises", response_model=ExerciseRead, status_code=201)
def create_exercise(body: ExerciseCreate, db: Session = Depends(get_db)):
ex = Exercise(**body.model_dump())
db.add(ex)
db.commit()
db.refresh(ex)
return ex
# --- Workout endpoints ---
@router.get("/workouts", response_model=list[WorkoutRead])
def list_workouts(
from_date: date | None = Query(None, alias="from"),
to_date: date | None = Query(None, alias="to"),
db: Session = Depends(get_db),
):
q = (
select(Workout)
.options(selectinload(Workout.sets))
.order_by(Workout.date.desc())
)
if from_date:
q = q.where(Workout.date >= from_date)
if to_date:
q = q.where(Workout.date <= to_date)
return db.scalars(q).all()
@router.post("/workouts", response_model=WorkoutRead, status_code=201)
def create_workout(body: WorkoutCreate, db: Session = Depends(get_db)):
sets_data = body.sets
workout = Workout(
date=body.date,
name=body.name,
notes=body.notes,
sets=[WorkoutSet(**s.model_dump()) for s in sets_data],
)
db.add(workout)
db.commit()
db.refresh(workout)
return workout
@router.put("/workouts/{workout_id}", response_model=WorkoutRead)
def update_workout(
workout_id: int, body: WorkoutCreate, db: Session = Depends(get_db)
):
workout = db.get(Workout, workout_id, options=[selectinload(Workout.sets)])
if not workout:
raise HTTPException(status_code=404, detail="Workout not found")
workout.date = body.date
workout.name = body.name
workout.notes = body.notes
# Replace sets
workout.sets.clear()
for s in body.sets:
workout.sets.append(WorkoutSet(**s.model_dump()))
db.commit()
db.refresh(workout)
return workout
@router.delete("/workouts/{workout_id}", status_code=204)
def delete_workout(workout_id: int, db: Session = Depends(get_db)):
workout = db.get(Workout, workout_id)
if not workout:
raise HTTPException(status_code=404, detail="Workout not found")
db.delete(workout)
db.commit()