This is the initial push of the outline of the life dashboard

This commit is contained in:
YOUNG
2026-03-09 12:52:48 -05:00
parent bf1e4e754f
commit 7596a5f382
47 changed files with 6522 additions and 3 deletions

View File

@@ -0,0 +1,137 @@
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()