125 lines
4.8 KiB
Python
125 lines
4.8 KiB
Python
from typing import List
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
|
|
from app.api.deps import (
|
|
get_current_user,
|
|
get_training_repository,
|
|
get_user_repository,
|
|
require_superuser,
|
|
)
|
|
from app.core.database.repository import TrainingRepository
|
|
from app.core.database.user_repository import UserRepository
|
|
from app.core.dto.training import TrainingDTO
|
|
from app.core.dto.user import UserDTO, UserRole
|
|
from app.core.parsers.obsidian import parse_training_data
|
|
from app.schemas.trainings import TrainingUpdate
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
async def _check_participant(
|
|
repository: UserRepository, user_id: int, role: UserRole
|
|
) -> None:
|
|
user = await repository.get(user_id)
|
|
if user is None or user.role != role:
|
|
raise HTTPException(
|
|
status_code=422, detail=f"User {user_id} is not an existing {role.value}"
|
|
)
|
|
|
|
|
|
async def _get_editable_training(
|
|
training_id: int, user: UserDTO, repository: TrainingRepository
|
|
) -> TrainingDTO:
|
|
"""A training the user may change: their own (as the trainee), or any for a superuser.
|
|
|
|
The trainer can only see the training. A training the user can't see at all is a 404.
|
|
"""
|
|
training = await repository.get(training_id, viewer=user)
|
|
if training is None:
|
|
raise HTTPException(status_code=404, detail="Training not found")
|
|
if not (user.is_superuser or training.trainee_id == user.id):
|
|
raise HTTPException(status_code=403, detail="Only the trainee can change a training")
|
|
return training
|
|
|
|
|
|
@router.get("/obsidian/", dependencies=[Depends(require_superuser)])
|
|
async def obsidian_trainings_list():
|
|
return {"data": parse_training_data()}
|
|
|
|
|
|
@router.get("/", response_model=List[TrainingDTO])
|
|
async def get_trainings_list(
|
|
user: UserDTO = Depends(get_current_user),
|
|
repository: TrainingRepository = Depends(get_training_repository),
|
|
):
|
|
"""Trainings the user takes part in (all of them for a superuser)."""
|
|
return await repository.list(viewer=user)
|
|
|
|
|
|
@router.get("/{training_id}/", response_model=TrainingDTO)
|
|
async def get_training(
|
|
training_id: int,
|
|
user: UserDTO = Depends(get_current_user),
|
|
repository: TrainingRepository = Depends(get_training_repository),
|
|
):
|
|
training = await repository.get(training_id, viewer=user)
|
|
if training is None:
|
|
raise HTTPException(status_code=404, detail="Training not found")
|
|
return training
|
|
|
|
|
|
@router.post("/", response_model=TrainingDTO, status_code=status.HTTP_201_CREATED)
|
|
async def create_training(
|
|
payload: TrainingUpdate,
|
|
user: UserDTO = Depends(get_current_user),
|
|
repository: TrainingRepository = Depends(get_training_repository),
|
|
user_repository: UserRepository = Depends(get_user_repository),
|
|
):
|
|
"""Create a training. Only a superuser may create it for another trainee."""
|
|
if payload.trainee_id != user.id:
|
|
if not user.is_superuser:
|
|
raise HTTPException(
|
|
status_code=403, detail="Only a superuser can create a training for another user"
|
|
)
|
|
await _check_participant(user_repository, payload.trainee_id, UserRole.trainee)
|
|
if payload.trainer_id is not None:
|
|
await _check_participant(user_repository, payload.trainer_id, UserRole.trainer)
|
|
training_id = await repository.save(TrainingDTO.model_validate(payload.model_dump()))
|
|
return await repository.get(training_id)
|
|
|
|
|
|
@router.put("/{training_id}/", response_model=TrainingDTO)
|
|
async def update_training(
|
|
training_id: int,
|
|
payload: TrainingUpdate,
|
|
user: UserDTO = Depends(get_current_user),
|
|
repository: TrainingRepository = Depends(get_training_repository),
|
|
user_repository: UserRepository = Depends(get_user_repository),
|
|
):
|
|
"""Replace the training: its date, trainee, trainer, exercises and approaches."""
|
|
current = await _get_editable_training(training_id, user, repository)
|
|
if payload.trainee_id != current.trainee_id:
|
|
if not user.is_superuser:
|
|
raise HTTPException(
|
|
status_code=403, detail="Only a superuser can change the trainee"
|
|
)
|
|
await _check_participant(user_repository, payload.trainee_id, UserRole.trainee)
|
|
if payload.trainer_id is not None:
|
|
await _check_participant(user_repository, payload.trainer_id, UserRole.trainer)
|
|
training = TrainingDTO.model_validate(payload.model_dump())
|
|
if not await repository.replace(training_id, training):
|
|
raise HTTPException(status_code=404, detail="Training not found")
|
|
return await repository.get(training_id)
|
|
|
|
|
|
@router.delete("/{training_id}/")
|
|
async def delete_training(
|
|
training_id: int,
|
|
user: UserDTO = Depends(get_current_user),
|
|
repository: TrainingRepository = Depends(get_training_repository),
|
|
):
|
|
await _get_editable_training(training_id, user, repository)
|
|
await repository.delete([training_id])
|
|
return {"status": "ok"}
|