added docs
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user