Files
benchpress/backend/app/routers/actions.py
T
2026-10-11 14:12:10 +03:00

160 lines
5.2 KiB
Python

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)