feat: Implement active workout flow with status management
- Added `status`, `total_sets`, and `total_volume` fields to the Workout model. - Introduced `source_kind`, `title_snapshot`, and `image_s3_url_snapshot` fields to the WorkoutItem model. - Created endpoints for managing active workouts, including finishing and discarding workouts. - Updated workout creation to ensure only one active workout exists per user. - Implemented batch addition of workout sets and updates to workout set details. - Enhanced database schema with Alembic migrations to support new fields and constraints. - Added validation to ensure at least one field is provided for workout set updates. - Updated calorie estimation logic to reflect new workout set structure.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from typing import Annotated, Any
|
||||
|
||||
import httpx
|
||||
from fastapi import Depends, FastAPI, File, HTTPException, Query, UploadFile, status
|
||||
from fastapi import Body, Depends, FastAPI, File, HTTPException, Query, UploadFile, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
@@ -152,6 +152,11 @@ async def create_workout(payload: dict[str, Any], user: CurrentUser) -> Any:
|
||||
return await logic_request("POST", "/internal/workouts", user, json=payload)
|
||||
|
||||
|
||||
@app.get("/workouts/active")
|
||||
async def get_active_workout(user: CurrentUser) -> Any:
|
||||
return await logic_request("GET", "/internal/workouts/active", user)
|
||||
|
||||
|
||||
@app.get("/workouts/{workout_id}")
|
||||
async def get_workout(workout_id: str, user: CurrentUser) -> Any:
|
||||
return await logic_request("GET", f"/internal/workouts/{workout_id}", user)
|
||||
@@ -162,6 +167,22 @@ async def update_workout(workout_id: str, payload: dict[str, Any], user: Current
|
||||
return await logic_request("PATCH", f"/internal/workouts/{workout_id}", user, json=payload)
|
||||
|
||||
|
||||
@app.post("/workouts/{workout_id}/finish")
|
||||
async def finish_workout(
|
||||
workout_id: str,
|
||||
user: CurrentUser,
|
||||
payload: Annotated[dict[str, Any] | None, Body()] = None,
|
||||
) -> Any:
|
||||
return await logic_request(
|
||||
"POST", f"/internal/workouts/{workout_id}/finish", user, json=payload
|
||||
)
|
||||
|
||||
|
||||
@app.post("/workouts/{workout_id}/discard")
|
||||
async def discard_workout(workout_id: str, user: CurrentUser) -> Any:
|
||||
return await logic_request("POST", f"/internal/workouts/{workout_id}/discard", user)
|
||||
|
||||
|
||||
@app.post("/workouts/{workout_id}/items", status_code=status.HTTP_201_CREATED)
|
||||
async def add_workout_item(workout_id: str, payload: dict[str, Any], user: CurrentUser) -> Any:
|
||||
return await logic_request("POST", f"/internal/workouts/{workout_id}/items", user, json=payload)
|
||||
@@ -174,6 +195,18 @@ async def add_workout_set(item_id: str, payload: dict[str, Any], user: CurrentUs
|
||||
)
|
||||
|
||||
|
||||
@app.post("/workout-items/{item_id}/sets/batch", status_code=status.HTTP_201_CREATED)
|
||||
async def add_workout_sets_batch(item_id: str, payload: dict[str, Any], user: CurrentUser) -> Any:
|
||||
return await logic_request(
|
||||
"POST", f"/internal/workout-items/{item_id}/sets/batch", user, json=payload
|
||||
)
|
||||
|
||||
|
||||
@app.patch("/workout-sets/{set_id}")
|
||||
async def update_workout_set(set_id: str, payload: dict[str, Any], user: CurrentUser) -> Any:
|
||||
return await logic_request("PATCH", f"/internal/workout-sets/{set_id}", user, json=payload)
|
||||
|
||||
|
||||
@app.delete("/workout-items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def remove_workout_item(item_id: str, user: CurrentUser) -> None:
|
||||
await logic_request("DELETE", f"/internal/workout-items/{item_id}", user)
|
||||
|
||||
Reference in New Issue
Block a user