from typing import List from fastapi import APIRouter, Depends, HTTPException, Query from sqlmodel import Session, select, func from database import get_session from models import Performance, PerformanceNickname, Tag, EntityTag, Show from schemas import PerformanceDetailRead, PerformanceNicknameCreate, PerformanceNicknameRead from auth import get_current_user router = APIRouter(prefix="/performances", tags=["performances"]) @router.get("/{performance_id_or_slug}", response_model=PerformanceDetailRead) def read_performance(performance_id_or_slug: str, session: Session = Depends(get_session)): performance = None if performance_id_or_slug.isdigit(): performance = session.get(Performance, int(performance_id_or_slug)) if not performance: # Try slug lookup performance = session.exec( select(Performance).where(Performance.slug == performance_id_or_slug) ).first() if not performance: raise HTTPException(status_code=404, detail="Performance not found") performance_id = performance.id # Use actual ID for lookups # --- Calculate Stats & Navigation --- # Get all performances of this song, ordered by date # We need to join Show to order by date all_perfs = session.exec( select(Performance, Show.date) .join(Show) .where(Performance.song_id == performance.song_id) .order_by(Show.date) ).all() # Find current index # all_perfs is a list of tuples (Performance, date) current_index = -1 for i, (p, d) in enumerate(all_perfs): if p.id == performance_id: current_index = i break prev_id = None next_id = None gap = 0 times_played = current_index + 1 # 1-based count if current_index > 0: prev_id = all_perfs[current_index - 1][0].id # Calculate Gap # Gap is number of shows between prev performance and this one prev_date = all_perfs[current_index - 1][1] current_date = all_perfs[current_index][1] gap = session.exec( select(func.count(Show.id)) .where(Show.date > prev_date) .where(Show.date < current_date) ).one() if current_index < len(all_perfs) - 1: next_id = all_perfs[current_index + 1][0].id # Construct response manually to include extra fields # We need to ensure nested models (show, song) are validated correctly perf_dict = performance.model_dump() perf_dict['show'] = performance.show perf_dict['song'] = performance.song perf_dict['nicknames'] = performance.nicknames perf_dict['previous_performance_id'] = prev_id perf_dict['next_performance_id'] = next_id perf_dict['gap'] = gap perf_dict['times_played'] = times_played return perf_dict @router.post("/{performance_id}/nicknames", response_model=PerformanceNicknameRead) def suggest_nickname( performance_id: int, nickname: PerformanceNicknameCreate, session: Session = Depends(get_session), current_user = Depends(get_current_user) ): # Check if performance exists perf = session.get(Performance, performance_id) if not perf: raise HTTPException(status_code=404, detail="Performance not found") db_nickname = PerformanceNickname.model_validate(nickname) db_nickname.performance_id = performance_id db_nickname.suggested_by = current_user.id db_nickname.status = "pending" # Default to pending session.add(db_nickname) session.commit() session.refresh(db_nickname) return db_nickname