"""CRUD de la programmation (`Artist`) d'une édition. La coordination constitue la liste ; elle est présentée par jour et heure de passage (`performance_date`, `start_time`, `end_time`). Les bénévoles y choisissent les artistes qu'ils veulent voir (vœux stockés dans `volunteer_artist`, exposés par la fiche bénévole) — le solveur en tient compte pour éviter de les affecter pendant le passage.""" import uuid from fastapi import APIRouter, Depends, HTTPException, Response, status from sqlalchemy.exc import IntegrityError from sqlmodel import Session, select from app.api._common import owned_or_404 from app.api.deps import get_edition from app.api.schemas import ArtistCreate, ArtistRead, ArtistUpdate from app.auth.deps import current_account_in_edition, require_coordinator from app.db import get_session from app.models import Account, Artist, Edition router = APIRouter(prefix="/editions/{edition_id}/artists", tags=["artists"]) @router.get("", response_model=list[ArtistRead]) def list_artists( edition: Edition = Depends(get_edition), _account: Account = Depends(current_account_in_edition), session: Session = Depends(get_session), ) -> list[Artist]: return list( session.exec( select(Artist) .where(Artist.edition_id == edition.id) .order_by(Artist.performance_date, Artist.name) ) ) @router.post("", response_model=ArtistRead, status_code=status.HTTP_201_CREATED) def create_artist( payload: ArtistCreate, edition: Edition = Depends(get_edition), _guard: Account = Depends(require_coordinator), session: Session = Depends(get_session), ) -> Artist: name = payload.name.strip() if not name: raise HTTPException( status_code=422, detail={"code": "artist.name_required"} ) artist = Artist( edition_id=edition.id, name=name, performance_date=payload.performance_date, start_time=payload.start_time, end_time=payload.end_time, ) session.add(artist) try: session.commit() except IntegrityError as exc: session.rollback() raise HTTPException( status_code=409, detail={"code": "artist.duplicate"} ) from exc session.refresh(artist) return artist @router.patch("/{artist_id}", response_model=ArtistRead) def update_artist( artist_id: uuid.UUID, payload: ArtistUpdate, edition: Edition = Depends(get_edition), _guard: Account = Depends(require_coordinator), session: Session = Depends(get_session), ) -> Artist: artist = owned_or_404(session.get(Artist, artist_id), edition.id) changes = payload.model_dump(exclude_unset=True) if "name" in changes: name = (changes["name"] or "").strip() if not name: raise HTTPException( status_code=422, detail={"code": "artist.name_required"} ) changes["name"] = name for field, value in changes.items(): setattr(artist, field, value) try: session.commit() except IntegrityError as exc: session.rollback() raise HTTPException( status_code=409, detail={"code": "artist.duplicate"} ) from exc session.refresh(artist) return artist @router.delete("/{artist_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_artist( artist_id: uuid.UUID, edition: Edition = Depends(get_edition), _guard: Account = Depends(require_coordinator), session: Session = Depends(get_session), ) -> Response: artist = owned_or_404(session.get(Artist, artist_id), edition.id) # Cascade base : les vœux `volunteer_artist` sont supprimés. session.delete(artist) session.commit() return Response(status_code=status.HTTP_204_NO_CONTENT)