from uuid import UUID from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import delete, select from sqlalchemy.orm import Session from sqlalchemy.sql import func from app.api import deps from app.api.utils import update_object_from_payload, verify_id_list from app.models import Project, Slot, User, Volunteer, association_table_volunteer_slot from app.schemas.requests import VolunteerCreateRequest, VolunteerUpdateRequest from app.schemas.responses import VolunteerResponse router = APIRouter() @router.get("/project/{project_id}/volunteers", response_model=list[VolunteerResponse]) async def list_project_volunteers( project_id: UUID, current_user: User = Depends(deps.get_current_user), session: Session = Depends(deps.get_session), ): """List volunteers from project""" p = session.get(Project, project_id) if p is None: raise HTTPException(status_code=404, detail="Project not found") results = session.execute(select(Volunteer).where(Volunteer.project_id == project_id)) return results.scalars().all() @router.post("/project/{project_id}/volunteer", response_model=VolunteerResponse) async def create_volunteer( project_id: UUID, new_volunteer: VolunteerCreateRequest, current_user: User = Depends(deps.get_current_user), session: Session = Depends(deps.get_session), ): """Create a new volunteer to the project""" p = session.get(Project, project_id) if p is None: raise HTTPException(status_code=404, detail="Project not found") input_dict = new_volunteer.model_dump() # Extract slots list from input dict slots: list[UUID] = [] if input_dict["slots"] is not None: slots = input_dict["slots"] await verify_id_list(session, slots, project_id, Slot, "Invalid slot list") del input_dict["slots"] volunteer = Volunteer(project_id=project_id, **input_dict) session.add(volunteer) # commit to optain an id for the volunteer session.commit() if len(slots) > 0: session.execute( association_table_volunteer_slot.insert().values( [(volunteer.id, slot_id) for slot_id in slots] ) ) session.commit() return volunteer @router.post("/project/{project_id}/volunteer/{volunteer_id}", response_model=VolunteerResponse) async def update_volunteer( project_id: UUID, volunteer_id: UUID, new_volunteer: VolunteerUpdateRequest, current_user: User = Depends(deps.get_current_user), session: Session = Depends(deps.get_session), ): """Update a volunteer from the project""" volunteer = session.get(Volunteer, volunteer_id) if (volunteer is None) or (volunteer.project_id != str(project_id)): raise HTTPException(status_code=404, detail="Volunteer not found") input_dict = new_volunteer.model_dump(exclude_unset=True) # Extract slots list from input dict if "slots" in input_dict: slots: list[UUID] = input_dict["slots"] await verify_id_list(session, slots, project_id, Slot, "Invalid slot list") # Remove previous values session.execute( association_table_volunteer_slot.delete().where( association_table_volunteer_slot.c.volunteer_id == volunteer.id ) ) # Add the new slots if len(slots) > 0: session.execute( association_table_volunteer_slot.insert().values( [(volunteer.id, slot_id) for slot_id in slots] ) ) del input_dict["slots"] update_object_from_payload(volunteer, input_dict) session.commit() session.refresh(volunteer) return volunteer @router.delete("/project/{project_id}/volunteer/{volunteer_id}") async def delete_volunteer( project_id: UUID, volunteer_id: UUID, current_user: User = Depends(deps.get_current_user), session: Session = Depends(deps.get_session), ): """Delete a volunteer from the project""" session.execute( delete(Volunteer).where( (Volunteer.id == volunteer_id) & (Volunteer.project_id == project_id) ) ) session.commit()