Fix backend imports and clip pinning flow

This commit is contained in:
Codex
2026-04-22 07:48:12 -05:00
parent 45c2b46304
commit ec73156966
12 changed files with 736 additions and 156 deletions

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select
from sqlalchemy import select, update
from sqlalchemy.orm import Session
from ..auth import require_session
@@ -40,6 +40,24 @@ def assignment_to_response(assignment: GameAssignment) -> GameAssignmentResponse
)
@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,
@@ -47,10 +65,10 @@ def list_assignments(
_: UserSession = Depends(require_session),
db: Session = Depends(get_db),
) -> list[GameAssignmentResponse]:
query = select(GameAssignment).where(GameAssignment.external_game_id == external_game_id)
query = select(GameAssignment).join(GameAssignment.clip).where(GameAssignment.external_game_id == external_game_id)
if external_player_id:
query = query.where(GameAssignment.external_player_id == external_player_id)
assignments = db.scalars(query.order_by(GameAssignment.batting_slot, GameAssignment.updated_at.desc())).all()
assignments = db.scalars(query.order_by(AudioClip.sort_order.asc(), GameAssignment.updated_at.desc())).all()
return [assignment_to_response(assignment) for assignment in assignments]
@@ -67,12 +85,11 @@ def create_assignment(
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 attach clips owned by that player")
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.external_player_id == payload.external_player_id,
GameAssignment.clip_id == payload.clip_id,
)
)
@@ -88,6 +105,7 @@ def create_assignment(
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
@@ -96,6 +114,25 @@ def create_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.execute(update(PlaybackSession).where(PlaybackSession.current_assignment_id == assignment.id).values(current_assignment_id=None))
db.delete(assignment)
db.commit()
@router.get("/{external_game_id}/prep", response_model=GamePrepResponse)
def prepare_game(
external_game_id: str,
@@ -104,8 +141,9 @@ def prepare_game(
) -> GamePrepResponse:
assignments = db.scalars(
select(GameAssignment)
.join(GameAssignment.clip)
.where(GameAssignment.external_game_id == external_game_id)
.order_by(GameAssignment.batting_slot, GameAssignment.updated_at.desc())
.order_by(AudioClip.sort_order.asc(), GameAssignment.updated_at.desc())
).all()
external_team_id = assignments[0].external_team_id if assignments else ""
return GamePrepResponse(
@@ -148,12 +186,12 @@ def trigger_playback(
raise HTTPException(status_code=404, detail="Playback session not found")
if payload.assignment_id is None and payload.clip_id is None:
raise HTTPException(status_code=422, detail="Provide an assignment or clip to trigger")
raise HTTPException(status_code=422, detail="Provide a pin or clip to trigger")
if payload.assignment_id is not None:
assignment = db.get(GameAssignment, payload.assignment_id)
if assignment is None or assignment.external_game_id != external_game_id:
raise HTTPException(status_code=404, detail="Assignment not found")
raise HTTPException(status_code=404, detail="Pin not found")
playback.current_assignment_id = assignment.id
else:
clip = db.get(AudioClip, payload.clip_id)