156 lines
6.2 KiB
Python
156 lines
6.2 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..auth import require_session
|
|
from ..database import get_db
|
|
from ..models import AudioClip, GameAssignment, UserSession
|
|
from ..schemas import (
|
|
GameAssignmentCreate,
|
|
GameAssignmentResponse,
|
|
GamePrepResponse,
|
|
)
|
|
|
|
router = APIRouter(prefix="/games", tags=["games"])
|
|
|
|
|
|
def assignment_to_response(assignment: GameAssignment) -> GameAssignmentResponse:
|
|
normalized_url = f"/media/files/{assignment.clip.normalized_path}" if assignment.clip.normalized_path else None
|
|
return GameAssignmentResponse(
|
|
id=assignment.id,
|
|
external_team_id=assignment.external_team_id,
|
|
external_game_id=assignment.external_game_id,
|
|
external_player_id=assignment.external_player_id,
|
|
clip_id=assignment.clip_id,
|
|
clip_label=assignment.clip.label,
|
|
asset_title=assignment.clip.asset.title,
|
|
start_ms=assignment.clip.start_ms,
|
|
end_ms=assignment.clip.end_ms,
|
|
batting_slot=assignment.batting_slot,
|
|
status=assignment.status,
|
|
normalized_url=normalized_url,
|
|
updated_at=assignment.updated_at,
|
|
)
|
|
|
|
|
|
@router.get("/pins", response_model=list[GameAssignmentResponse])
|
|
def list_pins(
|
|
external_player_id: str | None = Query(default=None),
|
|
session: UserSession = Depends(require_session),
|
|
db: Session = Depends(get_db),
|
|
) -> list[GameAssignmentResponse]:
|
|
player_id = external_player_id or session.external_player_id
|
|
if not player_id or not session.external_team_id:
|
|
raise HTTPException(status_code=422, detail="Provide a player to list pins")
|
|
|
|
query = select(GameAssignment).join(GameAssignment.clip).where(
|
|
GameAssignment.external_team_id == session.external_team_id,
|
|
GameAssignment.external_player_id == player_id,
|
|
)
|
|
pins = db.scalars(query.order_by(GameAssignment.external_game_id.asc(), AudioClip.sort_order.asc())).all()
|
|
return [assignment_to_response(assignment) for assignment in pins]
|
|
|
|
|
|
@router.get("/{external_game_id}/assignments", response_model=list[GameAssignmentResponse])
|
|
def list_assignments(
|
|
external_game_id: str,
|
|
external_player_id: str | None = Query(default=None),
|
|
_: UserSession = Depends(require_session),
|
|
db: Session = Depends(get_db),
|
|
) -> list[GameAssignmentResponse]:
|
|
query = select(GameAssignment).join(GameAssignment.clip).where(
|
|
GameAssignment.external_game_id == external_game_id,
|
|
AudioClip.hidden.is_(False),
|
|
)
|
|
if external_player_id:
|
|
query = query.where(GameAssignment.external_player_id == external_player_id)
|
|
assignments = db.scalars(query.order_by(AudioClip.sort_order.asc(), GameAssignment.updated_at.desc())).all()
|
|
return [assignment_to_response(assignment) for assignment in assignments]
|
|
|
|
|
|
@router.post("/{external_game_id}/assignments", response_model=GameAssignmentResponse)
|
|
def create_assignment(
|
|
external_game_id: str,
|
|
payload: GameAssignmentCreate,
|
|
_: UserSession = Depends(require_session),
|
|
db: Session = Depends(get_db),
|
|
) -> GameAssignmentResponse:
|
|
clip = db.get(AudioClip, payload.clip_id)
|
|
if clip is None or clip.normalization_status != "ready":
|
|
raise HTTPException(status_code=422, detail="Clip is not ready")
|
|
if clip.hidden:
|
|
raise HTTPException(status_code=404, detail="Clip not found")
|
|
if clip.asset.external_team_id != payload.external_team_id:
|
|
raise HTTPException(status_code=422, detail="Clip does not belong to this team")
|
|
if clip.asset.owner_external_player_id != payload.external_player_id:
|
|
raise HTTPException(status_code=403, detail="You can only pin clips owned by that player")
|
|
|
|
assignment = db.scalar(
|
|
select(GameAssignment).where(
|
|
GameAssignment.external_game_id == external_game_id,
|
|
GameAssignment.clip_id == payload.clip_id,
|
|
)
|
|
)
|
|
if assignment is None:
|
|
assignment = GameAssignment(
|
|
external_team_id=payload.external_team_id,
|
|
external_game_id=external_game_id,
|
|
external_player_id=payload.external_player_id,
|
|
clip_id=payload.clip_id,
|
|
batting_slot=payload.batting_slot,
|
|
status=payload.status,
|
|
)
|
|
db.add(assignment)
|
|
else:
|
|
assignment.external_team_id = payload.external_team_id
|
|
assignment.external_player_id = payload.external_player_id
|
|
assignment.clip_id = payload.clip_id
|
|
assignment.batting_slot = payload.batting_slot
|
|
assignment.status = payload.status
|
|
db.commit()
|
|
db.refresh(assignment)
|
|
return assignment_to_response(assignment)
|
|
|
|
|
|
@router.delete("/{external_game_id}/assignments/{assignment_id}", status_code=204)
|
|
def delete_assignment(
|
|
external_game_id: str,
|
|
assignment_id: int,
|
|
external_player_id: str | None = Query(default=None),
|
|
_: UserSession = Depends(require_session),
|
|
db: Session = Depends(get_db),
|
|
) -> None:
|
|
assignment = db.get(GameAssignment, assignment_id)
|
|
if assignment is None or assignment.external_game_id != external_game_id:
|
|
raise HTTPException(status_code=404, detail="Pin not found")
|
|
if external_player_id is not None and assignment.external_player_id != external_player_id:
|
|
raise HTTPException(status_code=403, detail="Pin does not belong to that player")
|
|
|
|
db.delete(assignment)
|
|
db.commit()
|
|
|
|
|
|
@router.get("/{external_game_id}/prep", response_model=GamePrepResponse)
|
|
def prepare_game(
|
|
external_game_id: str,
|
|
_: UserSession = Depends(require_session),
|
|
db: Session = Depends(get_db),
|
|
) -> GamePrepResponse:
|
|
assignments = db.scalars(
|
|
select(GameAssignment)
|
|
.join(GameAssignment.clip)
|
|
.where(GameAssignment.external_game_id == external_game_id, AudioClip.hidden.is_(False))
|
|
.order_by(AudioClip.sort_order.asc(), GameAssignment.updated_at.desc())
|
|
).all()
|
|
external_team_id = assignments[0].external_team_id if assignments else ""
|
|
return GamePrepResponse(
|
|
external_game_id=external_game_id,
|
|
external_team_id=external_team_id,
|
|
prepared_at=datetime.now(timezone.utc),
|
|
assignments=[assignment_to_response(assignment) for assignment in assignments],
|
|
)
|