project.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. from datetime import timedelta
  2. from uuid import UUID
  3. from fastapi import APIRouter, Depends, HTTPException
  4. from sqlalchemy import delete, select
  5. from sqlalchemy.exc import IntegrityError
  6. from sqlalchemy.ext.asyncio import AsyncSession
  7. from app.api import deps
  8. from app.models import Project, Slot, Sms, User
  9. from app.schemas.requests import (
  10. ProjectImportGsheetRequest,
  11. ProjectRequest,
  12. ProjectSMSBatchRequest,
  13. )
  14. from app.schemas.responses import ProjectListResponse, ProjectResponse, SMSResponse
  15. router = APIRouter()
  16. @router.get("/projects", response_model=list[ProjectListResponse])
  17. async def list_project(
  18. current_user: User = Depends(deps.get_current_user),
  19. session: AsyncSession = Depends(deps.get_session),
  20. ):
  21. """Get project_list"""
  22. results = await session.execute(select(Project))
  23. return results.scalars().all()
  24. @router.get("/public-projects", response_model=list[ProjectListResponse])
  25. async def list_public_project(
  26. session: AsyncSession = Depends(deps.get_session),
  27. ):
  28. """Get the list of public projects"""
  29. results = await session.execute(select(Project).where(Project.is_public == True))
  30. return results.scalars().all()
  31. @router.post("/project", response_model=ProjectResponse)
  32. async def create_project(
  33. new_project: ProjectRequest,
  34. current_user: User = Depends(deps.get_current_user),
  35. session: AsyncSession = Depends(deps.get_session),
  36. ):
  37. """Create a new project"""
  38. project = Project(**new_project.dict())
  39. session.add(project)
  40. try:
  41. await session.commit()
  42. except IntegrityError as e:
  43. raise HTTPException(422, "Project name already exist")
  44. await session.refresh(project)
  45. return ProjectResponse.from_orm(project)
  46. @router.get("/public-project/{id}", response_model=ProjectResponse)
  47. async def get_public_project(
  48. id: UUID,
  49. session: AsyncSession = Depends(deps.get_session),
  50. ):
  51. """Get a project that is public"""
  52. result = await session.get(Project, id)
  53. if (result is None) or not result.is_public:
  54. return HTTPException(status_code=404, detail="Project not found")
  55. return result
  56. @router.get("/project/{id}", response_model=ProjectResponse)
  57. async def get_project(
  58. id: UUID,
  59. session: AsyncSession = Depends(deps.get_session),
  60. ):
  61. """Get a project"""
  62. project = await session.get(Project, id)
  63. if project is None:
  64. return HTTPException(status_code=404, detail="Project not found")
  65. project.sms
  66. project.volunteers
  67. project.slots
  68. response = ProjectResponse.from_orm(project)
  69. return response
  70. @router.post("/project/{id}", response_model=ProjectListResponse)
  71. async def update_project(
  72. id: UUID,
  73. edit_project: ProjectRequest,
  74. current_user: User = Depends(deps.get_current_user),
  75. session: AsyncSession = Depends(deps.get_session),
  76. ):
  77. """Edit project"""
  78. p = await session.get(Project, id)
  79. if p is None:
  80. raise HTTPException(status_code=404, detail="Project not found")
  81. p.name = edit_project.name
  82. p.is_public = edit_project.is_public
  83. await session.commit()
  84. return p
  85. @router.post("/project/{id}/import-gsheet", response_model=ProjectResponse)
  86. async def update_project_from_gsheet(
  87. id: UUID,
  88. gsheet: ProjectImportGsheetRequest,
  89. current_user: User = Depends(deps.get_current_user),
  90. session: AsyncSession = Depends(deps.get_session),
  91. ):
  92. """Edit project name"""
  93. p = await session.get(Project, id)
  94. if p is None:
  95. raise HTTPException(status_code=404, detail="Project not found")
  96. url = gsheet.sheet_url
  97. # TODO implement feature to import
  98. return p
  99. @router.post("/project/{id}/create-all-sms", response_model=list[SMSResponse])
  100. async def create_sms_batch(
  101. id: UUID,
  102. sms_batch: ProjectSMSBatchRequest,
  103. current_user: User = Depends(deps.get_current_user),
  104. session: AsyncSession = Depends(deps.get_session),
  105. ):
  106. """Create SMS based on a template and the list of slots and volunteer associated to the project
  107. The placeholder that can be used in the template are
  108. - {titre} slot.title
  109. - {description} slot.description
  110. - {debut} slot.starting_time
  111. - {fin} slot.ending_ting
  112. - {prenom} volunteer.name
  113. - {name} volunteer.surname
  114. """
  115. p = await session.get(Project, id)
  116. if p is None:
  117. raise HTTPException(status_code=404, detail="Project not found")
  118. # Get all slots
  119. slots = await session.execute(select(Slot).where(Slot.project_id == id))
  120. sms_list = []
  121. for slot in slots.scalars():
  122. # Replace the slot placeholder by their value
  123. slot_content = (
  124. sms_batch.template.replace("{titre}", slot.title)
  125. .replace("{description}", slot.description)
  126. .replace("{debut}", str(slot.starting_time))
  127. .replace("{fin}", str(slot.ending_time))
  128. )
  129. sending_time = slot.starting_time - timedelta(minutes=sms_batch.delta_t)
  130. for volunteer in slot.volunteers:
  131. # Create a new SMS customized for each user attache to the slot
  132. personalized_content = slot_content.replace(
  133. "{prenom}", volunteer.name
  134. ).replace("{nom}", volunteer.surname)
  135. sms = Sms(
  136. project_id=id,
  137. volunteer_id=volunteer.id,
  138. content=personalized_content,
  139. phone_number=volunteer.phone_number,
  140. sending_time=sending_time,
  141. )
  142. sms_list.append(sms)
  143. session.add_all(sms_list)
  144. await session.commit()
  145. return sms_list
  146. @router.delete("/project/{id}")
  147. async def delete_project(
  148. id: UUID,
  149. current_user: User = Depends(deps.get_current_user),
  150. session: AsyncSession = Depends(deps.get_session),
  151. ):
  152. """Delete project"""
  153. await session.execute(delete(Project).where(Project.id == id))
  154. await session.commit()