"""Helpers partagés par les routers CRUD. `resolve_owned_ids`/`set_artists`/`set_wished_positions` sont utilisés à la fois par `volunteers.py` (fiche éditée par la coordination) et `forms.py` (vœux saisis depuis le formulaire public) — un seul endroit pour la validation « ces ids appartiennent bien à cette édition ».""" import uuid from fastapi import HTTPException from sqlalchemy import delete from sqlmodel import Session, select from app.models import Artist, Position, VolunteerArtist, VolunteerPositionWish def owned_or_404(instance, edition_id: uuid.UUID): """404 si l'instance est absente ou rattachée à une autre édition.""" if instance is None or instance.edition_id != edition_id: raise HTTPException(status_code=404, detail={"code": "error.not_found"}) return instance def replace_links( session: Session, link_model, *, filter_column, filter_value, pairs ) -> None: """Remplace toutes les lignes d'une table d'association pour une clé.""" session.execute( delete(link_model).where(filter_column == filter_value) ) for row in pairs: session.add(link_model(**row)) def resolve_owned_ids( session: Session, model, edition_id: uuid.UUID, ids: list[uuid.UUID], code: str ) -> list[uuid.UUID]: """Ordre d'entrée conservé, doublons retirés ; 422 si un id est étranger.""" wanted = list(dict.fromkeys(ids)) if wanted: found = set( session.exec( select(model.id).where( model.edition_id == edition_id, model.id.in_(wanted), ) ) ) if len(found) != len(wanted): raise HTTPException(status_code=422, detail={"code": code}) return wanted def set_artists(session: Session, volunteer, artist_ids: list[uuid.UUID]) -> None: ids = resolve_owned_ids( session, Artist, volunteer.edition_id, artist_ids, "artist.unknown" ) replace_links( session, VolunteerArtist, filter_column=VolunteerArtist.volunteer_id, filter_value=volunteer.id, pairs=[{"volunteer_id": volunteer.id, "artist_id": aid} for aid in ids], ) def set_wished_positions( session: Session, volunteer, position_ids: list[uuid.UUID] ) -> None: ids = resolve_owned_ids( session, Position, volunteer.edition_id, position_ids, "position.unknown" ) replace_links( session, VolunteerPositionWish, filter_column=VolunteerPositionWish.volunteer_id, filter_value=volunteer.id, pairs=[{"volunteer_id": volunteer.id, "position_id": pid} for pid in ids], )