initial commit
This commit is contained in:
commit
39fdd43d8e
127 files changed
+13919
No files matched your search
@@ -0,0 +1,159 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import User, Workout
|
||||
from app.routers.auth import require_auth
|
||||
from app.schemas import (
|
||||
AdjustSetRequest,
|
||||
CompleteSetRequest,
|
||||
MoveWorkoutRequest,
|
||||
PromptChoiceRequest,
|
||||
SetWeightRequest,
|
||||
WorkoutDetail,
|
||||
)
|
||||
from app.services.auth import get_or_create_profile
|
||||
from app.services.reschedule import plan_move
|
||||
from app.services.workout import (
|
||||
adjust_completed_set,
|
||||
complete_set,
|
||||
load_workout,
|
||||
pause_workout,
|
||||
resolve_prompt,
|
||||
resume_workout,
|
||||
set_exercise_weight,
|
||||
start_workout,
|
||||
workout_detail,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/api/workouts", tags=["workout-actions"])
|
||||
|
||||
|
||||
@router.post("/{workout_id}/start", response_model=WorkoutDetail)
|
||||
def api_start(workout_id: int, _: User = Depends(require_auth), db: Session = Depends(get_db)) -> WorkoutDetail:
|
||||
w = start_workout(db, load_workout(db, workout_id))
|
||||
return workout_detail(db, w)
|
||||
|
||||
|
||||
@router.post("/{workout_id}/pause", response_model=WorkoutDetail)
|
||||
def api_pause(workout_id: int, _: User = Depends(require_auth), db: Session = Depends(get_db)) -> WorkoutDetail:
|
||||
w = pause_workout(db, load_workout(db, workout_id))
|
||||
return workout_detail(db, w)
|
||||
|
||||
|
||||
@router.post("/{workout_id}/resume", response_model=WorkoutDetail)
|
||||
def api_resume(workout_id: int, _: User = Depends(require_auth), db: Session = Depends(get_db)) -> WorkoutDetail:
|
||||
w = resume_workout(db, load_workout(db, workout_id))
|
||||
return workout_detail(db, w)
|
||||
|
||||
|
||||
@router.post("/{workout_id}/complete-set", response_model=WorkoutDetail)
|
||||
def api_complete_set(
|
||||
workout_id: int,
|
||||
body: CompleteSetRequest,
|
||||
_: User = Depends(require_auth),
|
||||
db: Session = Depends(get_db),
|
||||
) -> WorkoutDetail:
|
||||
w = complete_set(
|
||||
db,
|
||||
load_workout(db, workout_id),
|
||||
actual_reps=body.actual_reps,
|
||||
actual_weight_kg=body.actual_weight_kg,
|
||||
)
|
||||
return workout_detail(db, w)
|
||||
|
||||
|
||||
@router.post("/{workout_id}/exercises/{exercise_id}/weight", response_model=WorkoutDetail)
|
||||
def api_set_weight(
|
||||
workout_id: int,
|
||||
exercise_id: int,
|
||||
body: SetWeightRequest,
|
||||
_: User = Depends(require_auth),
|
||||
db: Session = Depends(get_db),
|
||||
) -> WorkoutDetail:
|
||||
workout = load_workout(db, workout_id)
|
||||
exercise = next((e for e in workout.exercises if e.id == exercise_id), None)
|
||||
if not exercise:
|
||||
raise HTTPException(404, "Упражнение не найдено")
|
||||
w = set_exercise_weight(db, workout, exercise, body.weight_kg)
|
||||
return workout_detail(db, w)
|
||||
|
||||
|
||||
@router.post("/{workout_id}/exercises/{exercise_id}/sets/{set_id}", response_model=WorkoutDetail)
|
||||
def api_adjust_set(
|
||||
workout_id: int,
|
||||
exercise_id: int,
|
||||
set_id: int,
|
||||
body: AdjustSetRequest,
|
||||
_: User = Depends(require_auth),
|
||||
db: Session = Depends(get_db),
|
||||
) -> WorkoutDetail:
|
||||
workout = load_workout(db, workout_id)
|
||||
exercise = next((e for e in workout.exercises if e.id == exercise_id), None)
|
||||
if not exercise:
|
||||
raise HTTPException(404, "Упражнение не найдено")
|
||||
workout_set = next((s for s in exercise.sets if s.id == set_id), None)
|
||||
if not workout_set:
|
||||
raise HTTPException(404, "Подход не найден")
|
||||
w = adjust_completed_set(
|
||||
db,
|
||||
workout,
|
||||
exercise,
|
||||
workout_set,
|
||||
actual_weight_kg=body.actual_weight_kg,
|
||||
actual_reps=body.actual_reps,
|
||||
)
|
||||
return workout_detail(db, w)
|
||||
|
||||
|
||||
@router.post("/{workout_id}/move", response_model=WorkoutDetail)
|
||||
def api_move(
|
||||
workout_id: int,
|
||||
body: MoveWorkoutRequest,
|
||||
_: User = Depends(require_auth),
|
||||
db: Session = Depends(get_db),
|
||||
) -> WorkoutDetail:
|
||||
workout = load_workout(db, workout_id)
|
||||
profile = get_or_create_profile(db)
|
||||
weekdays = profile.training_weekdays or []
|
||||
if len(weekdays) != 3:
|
||||
raise HTTPException(400, "Не заданы дни тренировок")
|
||||
rows = db.query(Workout).filter(Workout.cycle_number == workout.cycle_number).all()
|
||||
assigned = plan_move(rows, workout_id, body.scheduled_date, list(weekdays))
|
||||
for row in rows:
|
||||
if row.id in assigned:
|
||||
row.scheduled_date = date(2099, 1, 1) + timedelta(days=row.id % 300)
|
||||
db.flush()
|
||||
by_id = {row.id: row for row in rows}
|
||||
for workout_row_id, scheduled in assigned.items():
|
||||
by_id[workout_row_id].scheduled_date = scheduled
|
||||
db.commit()
|
||||
return workout_detail(db, load_workout(db, workout_id))
|
||||
|
||||
|
||||
@router.post("/{workout_id}/exercises/{exercise_id}/prompt", response_model=WorkoutDetail)
|
||||
def api_prompt(
|
||||
workout_id: int,
|
||||
exercise_id: int,
|
||||
body: PromptChoiceRequest,
|
||||
_: User = Depends(require_auth),
|
||||
db: Session = Depends(get_db),
|
||||
) -> WorkoutDetail:
|
||||
workout = load_workout(db, workout_id)
|
||||
exercise = next((e for e in workout.exercises if e.id == exercise_id), None)
|
||||
if not exercise:
|
||||
raise HTTPException(404, "Упражнение не найдено")
|
||||
w = resolve_prompt(
|
||||
db,
|
||||
workout,
|
||||
exercise,
|
||||
choice=body.choice,
|
||||
weight_kg=body.weight_kg,
|
||||
increase_kg=body.increase_kg,
|
||||
decrease_kg=body.decrease_kg,
|
||||
)
|
||||
return workout_detail(db, w)
|
||||
Reference in new issue
Block a user