added docs

This commit is contained in:
2026-06-22 06:50:13 +00:00
parent 99565ca107
commit 166b9eb4f9
30 changed files with 5912 additions and 3380 deletions
+138 -1
View File
@@ -1,4 +1,4 @@
from datetime import date
from datetime import date, datetime, timedelta, timezone
from typing import Any
from fastapi import APIRouter, Depends, HTTPException
@@ -69,6 +69,40 @@ class StepsCreate(BaseModel):
day: str | None = None
days_ago: int | None = Field(default=None, ge=0, le=90)
logged_at: str | None = None
replace: bool = False
class StepsUpdate(BaseModel):
steps: int | None = Field(default=None, ge=0)
active_calories: float | None = None
notes: str | None = None
class MealUpdate(BaseModel):
description: str | None = None
meal_type: str | None = None
calories: float | None = Field(default=None, ge=0)
protein_g: float | None = Field(default=None, ge=0)
fat_g: float | None = Field(default=None, ge=0)
carbs_g: float | None = Field(default=None, ge=0)
fiber_g: float | None = Field(default=None, ge=0)
estimated: bool | None = None
class WaterUpdate(BaseModel):
amount_ml: int | None = Field(default=None, ge=0)
class LogMerge(BaseModel):
kind: str = Field(description="meal|water|steps")
keep_id: int
merge_id: int
class DeleteLastLog(BaseModel):
kind: str = Field(description="meal|water|steps|workout")
day: str | None = None
days_ago: int | None = Field(default=None, ge=0, le=90)
class WorkoutCreate(BaseModel):
@@ -130,6 +164,24 @@ def get_charts(
return FitnessService(db, user.id).get_charts(weeks=weeks, trend=trend, end_day=end_day)
@router.get("/fitness/compare")
def compare_days(
dates: str,
db: Session = Depends(get_db),
user: User = Depends(get_current_user),
) -> dict[str, Any]:
parsed: list[date] = []
for part in dates.split(","):
part = part.strip()
if part:
parsed.append(date.fromisoformat(part))
if len(parsed) < 2:
raise HTTPException(status_code=400, detail="Provide at least two dates (YYYY-MM-DD,YYYY-MM-DD)")
if len(parsed) > 14:
raise HTTPException(status_code=400, detail="At most 14 dates")
return FitnessService(db, user.id).compare_days(parsed)
@router.get("/fitness/profile")
def get_profile(db: Session = Depends(get_db), user: User = Depends(get_current_user)) -> dict[str, Any]:
profile = FitnessService(db, user.id).get_profile()
@@ -227,9 +279,26 @@ def create_steps(
day=day,
days_ago=payload.days_ago,
logged_at=payload.logged_at,
replace=payload.replace,
)
@router.patch("/fitness/steps/{log_id}")
def update_steps(
log_id: int,
payload: StepsUpdate,
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")
result = FitnessService(db, user.id).update_step_log(log_id, updates)
if not result:
raise HTTPException(status_code=404, detail="Not found")
return result
@router.delete("/fitness/steps/{log_id}")
def delete_steps(log_id: int, db: Session = Depends(get_db), user: User = Depends(get_current_user)) -> dict[str, bool]:
if not FitnessService(db, user.id).delete_step_log(log_id):
@@ -272,6 +341,74 @@ def list_metrics(
return FitnessService(db, user.id).list_body_metrics(limit=limit)
@router.patch("/fitness/meals/{log_id}")
def update_meal(
log_id: int,
payload: MealUpdate,
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")
result = FitnessService(db, user.id).update_food_log(log_id, updates)
if not result:
raise HTTPException(status_code=404, detail="Not found")
return result
@router.patch("/fitness/water/{log_id}")
def update_water(
log_id: int,
payload: WaterUpdate,
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")
result = FitnessService(db, user.id).update_water_log(log_id, updates)
if not result:
raise HTTPException(status_code=404, detail="Not found")
return result
@router.post("/fitness/logs/merge")
def merge_logs(
payload: LogMerge,
db: Session = Depends(get_db),
user: User = Depends(get_current_user),
) -> dict[str, Any]:
service = FitnessService(db, user.id)
kind = payload.kind.lower().strip()
if kind in ("meal", "meals", "food"):
result = service.merge_food_logs(payload.keep_id, payload.merge_id)
elif kind == "water":
result = service.merge_water_logs(payload.keep_id, payload.merge_id)
elif kind in ("step", "steps"):
result = service.merge_step_logs(payload.keep_id, payload.merge_id)
else:
raise HTTPException(status_code=400, detail="Unsupported kind")
if not result:
raise HTTPException(status_code=404, detail="Not found")
return result
@router.post("/fitness/logs/delete-last")
def delete_last_log(
payload: DeleteLastLog,
db: Session = Depends(get_db),
user: User = Depends(get_current_user),
) -> dict[str, Any]:
day = date.fromisoformat(payload.day) if payload.day else None
if day is None and payload.days_ago is not None:
day = datetime.now(timezone.utc).date() - timedelta(days=int(payload.days_ago))
result = FitnessService(db, user.id).delete_last_log(payload.kind, day=day)
if not result:
raise HTTPException(status_code=404, detail="No records found")
return result
@router.delete("/fitness/meals/{log_id}")
def delete_meal(log_id: int, db: Session = Depends(get_db), user: User = Depends(get_current_user)) -> dict[str, bool]:
if not FitnessService(db, user.id).delete_food_log(log_id):