"""CRUD de la programmation (`Artist`) d'une édition. La coordination constitue la liste ; elle est présentée par jour de passage (`performance_date`). 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).""" 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, ) 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)