ronheichman's picture
Deploy workout tracker
cc34c37 verified
Raw
History Blame Contribute Delete
5.59 kB
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session
from tracker.config import load_config
from tracker.config_updates import patch_active_program_id
from tracker.db import get_session
from tracker.training_schemas import (
AddProgramExerciseInput,
CreateProgramInput,
DisplaySettingsResponse,
ExerciseResponse,
HistoryResponse,
LogRunInput,
LogWorkoutInput,
ProgramDetailResponse,
ProgramExerciseDetail,
ProgramSummary,
RunLogEntry,
SetActiveProgramInput,
TodayResponse,
UpdateProgramExerciseInput,
WeightInput,
)
from tracker.training_service import (
add_exercise_to_program,
create_program_from_input,
fetch_active_program_detail,
fetch_history,
fetch_runs,
fetch_today,
list_exercise_catalog,
list_program_summaries,
log_body_weight,
log_running_session,
log_workout_session,
remove_program_exercise,
update_program_exercise,
)
router = APIRouter(prefix="/api")
@router.get("/meta/display")
def get_display_settings() -> DisplaySettingsResponse:
cfg = load_config()
return DisplaySettingsResponse(
weight_unit=cfg.display_weight_unit,
distance_unit=cfg.display_distance_unit,
)
@router.get("/today")
def get_today(
day_label: str,
program_id: int | None = None,
session: Session = Depends(get_session),
) -> TodayResponse:
cfg = load_config()
data, err = fetch_today(session, cfg, day_label, program_id)
if err is not None:
raise HTTPException(status_code=404, detail=err)
if data is None:
raise HTTPException(status_code=404, detail="No program found")
return data
@router.post("/log")
def log_workout(
body: LogWorkoutInput,
session: Session = Depends(get_session),
) -> dict[str, int]:
logged_count = log_workout_session(session, body)
return {"logged": logged_count}
@router.post("/weight")
def log_weight(
body: WeightInput,
session: Session = Depends(get_session),
) -> dict[str, float]:
weight_kg = log_body_weight(session, body)
return {"weight_kg": weight_kg}
@router.get("/history")
def get_history(
days: int = 30,
session: Session = Depends(get_session),
) -> HistoryResponse:
return fetch_history(session, days)
@router.post("/log-run")
def log_run(
body: LogRunInput,
session: Session = Depends(get_session),
) -> dict[str, int]:
run_log_id, err = log_running_session(session, body)
if err is not None:
raise HTTPException(status_code=404, detail=err)
if run_log_id is None:
raise HTTPException(status_code=500, detail="Run log failed")
return {"run_log_id": run_log_id}
@router.get("/runs")
def get_runs(
days: int = 30,
program_id: int | None = None,
day_label: str | None = None,
session: Session = Depends(get_session),
) -> list[RunLogEntry]:
return fetch_runs(session, days, program_id, day_label)
@router.get("/programs")
def list_programs(
session: Session = Depends(get_session),
) -> list[ProgramSummary]:
return list_program_summaries(session)
@router.post("/programs")
def create_program(
body: CreateProgramInput,
session: Session = Depends(get_session),
) -> ProgramSummary:
return create_program_from_input(session, body)
@router.get("/programs/active")
def get_active_program(
session: Session = Depends(get_session),
) -> ProgramDetailResponse:
cfg = load_config()
data, err = fetch_active_program_detail(session, cfg)
if err is not None:
raise HTTPException(status_code=404, detail=err)
if data is None:
raise HTTPException(status_code=404, detail="No program found")
return data
@router.put("/programs/active")
def set_active_program(body: SetActiveProgramInput) -> dict[str, int | None]:
patch_active_program_id(body.program_id)
return {"active_program_id": body.program_id}
@router.get("/exercises")
def list_exercises(
session: Session = Depends(get_session),
) -> list[ExerciseResponse]:
return list_exercise_catalog(session)
@router.post("/programs/{program_id}/exercises")
def add_program_exercise(
program_id: int,
body: AddProgramExerciseInput,
session: Session = Depends(get_session),
) -> ProgramExerciseDetail:
data, err = add_exercise_to_program(session, program_id, body)
if err is not None:
raise HTTPException(status_code=404, detail=err)
if data is None:
raise HTTPException(status_code=404, detail="Not found")
return data
@router.delete("/programs/{program_id}/exercises/{exercise_id}")
def remove_program_exercise_route(
program_id: int,
exercise_id: int,
day_label: str,
session: Session = Depends(get_session),
) -> dict[str, str]:
err = remove_program_exercise(session, program_id, exercise_id, day_label)
if err is not None:
raise HTTPException(status_code=404, detail=err)
return {"removed": f"exercise {exercise_id} from day {day_label}"}
@router.put("/programs/{program_id}/exercises/{exercise_id}")
def update_program_exercise_route(
program_id: int,
exercise_id: int,
day_label: str,
body: UpdateProgramExerciseInput,
session: Session = Depends(get_session),
) -> ProgramExerciseDetail:
data, err = update_program_exercise(session, program_id, exercise_id, day_label, body)
if err is not None:
raise HTTPException(status_code=404, detail=err)
if data is None:
raise HTTPException(status_code=404, detail="Not found")
return data