volunteers.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. from uuid import UUID
  2. from fastapi import APIRouter, Depends, HTTPException
  3. from sqlalchemy import delete, select
  4. from sqlalchemy.orm import Session
  5. from app.api import deps
  6. from app.api.utils import update_object_from_payload, verify_id_list
  7. from app.models import OrgRole, Slot, User, Volunteer, association_table_volunteer_slot
  8. from app.schemas.requests import VolunteerCreateRequest, VolunteerUpdateRequest
  9. from app.schemas.responses import VolunteerResponse
  10. router = APIRouter(prefix="/project/{project_id}", tags=["volunteers"])
  11. READ_ROLES = (OrgRole.ORG_ADMIN, OrgRole.RESPO_BENEVOLE, OrgRole.RESPO_COMMISSION)
  12. WRITE_ROLES = (OrgRole.ORG_ADMIN, OrgRole.RESPO_BENEVOLE)
  13. @router.get("/volunteers", response_model=list[VolunteerResponse])
  14. async def list_project_volunteers(
  15. project_id: UUID,
  16. current_user: User = Depends(deps.require_org_role(*READ_ROLES)),
  17. session: Session = Depends(deps.get_session),
  18. ):
  19. """List volunteers from project.
  20. respo_commission has read-only access -- they need to see who is
  21. assigned to work with them, but do not manage volunteer records."""
  22. results = session.execute(select(Volunteer).where(Volunteer.project_id == project_id))
  23. return results.scalars().all()
  24. @router.post("/volunteer", response_model=VolunteerResponse)
  25. async def create_volunteer(
  26. project_id: UUID,
  27. new_volunteer: VolunteerCreateRequest,
  28. current_user: User = Depends(deps.require_org_role(*WRITE_ROLES)),
  29. session: Session = Depends(deps.get_session),
  30. ):
  31. """Create a new volunteer to the project"""
  32. input_dict = new_volunteer.model_dump()
  33. slots: list[UUID] = []
  34. if input_dict["slots"] is not None:
  35. slots = input_dict["slots"]
  36. await verify_id_list(session, slots, project_id, Slot, "Invalid slot list")
  37. del input_dict["slots"]
  38. volunteer = Volunteer(project_id=project_id, **input_dict)
  39. session.add(volunteer)
  40. session.commit()
  41. if len(slots) > 0:
  42. session.execute(
  43. association_table_volunteer_slot.insert().values(
  44. [(volunteer.id, slot_id) for slot_id in slots]
  45. )
  46. )
  47. session.commit()
  48. session.refresh(volunteer)
  49. return volunteer
  50. @router.post("/volunteer/{volunteer_id}", response_model=VolunteerResponse)
  51. async def update_volunteer(
  52. project_id: UUID,
  53. volunteer_id: UUID,
  54. new_volunteer: VolunteerUpdateRequest,
  55. current_user: User = Depends(deps.require_org_role(*WRITE_ROLES)),
  56. session: Session = Depends(deps.get_session),
  57. ):
  58. """Update a volunteer from the project"""
  59. volunteer = session.get(Volunteer, volunteer_id)
  60. if (volunteer is None) or (volunteer.project_id != str(project_id)):
  61. raise HTTPException(status_code=404, detail="Volunteer not found")
  62. input_dict = new_volunteer.model_dump(exclude_unset=True)
  63. if "slots" in input_dict:
  64. slots: list[UUID] = input_dict["slots"]
  65. await verify_id_list(session, slots, project_id, Slot, "Invalid slot list")
  66. session.execute(
  67. association_table_volunteer_slot.delete().where(
  68. association_table_volunteer_slot.c.volunteer_id == volunteer.id
  69. )
  70. )
  71. if len(slots) > 0:
  72. session.execute(
  73. association_table_volunteer_slot.insert().values(
  74. [(volunteer.id, slot_id) for slot_id in slots]
  75. )
  76. )
  77. del input_dict["slots"]
  78. update_object_from_payload(volunteer, input_dict)
  79. session.commit()
  80. session.refresh(volunteer)
  81. return volunteer
  82. @router.delete("/volunteer/{volunteer_id}")
  83. async def delete_volunteer(
  84. project_id: UUID,
  85. volunteer_id: UUID,
  86. current_user: User = Depends(deps.require_org_role(*WRITE_ROLES)),
  87. session: Session = Depends(deps.get_session),
  88. ):
  89. """Delete a volunteer from the project"""
  90. session.execute(
  91. delete(Volunteer).where(
  92. (Volunteer.id == volunteer_id) & (Volunteer.project_id == project_id)
  93. )
  94. )
  95. session.commit()