templates.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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 assert_project_exists_or_404, update_object_from_payload, verify_id_list
  7. from app.models import (
  8. OrgRole,
  9. Project,
  10. SlotTag,
  11. SlotTemplate,
  12. User,
  13. association_table_template_tags,
  14. )
  15. from app.schemas.requests import TemplateCreateRequest, TemplateUpdateRequest
  16. from app.schemas.responses import TemplateResponse
  17. router = APIRouter(
  18. prefix="/project/{project_id}",
  19. )
  20. READ_ROLES = (OrgRole.ORG_ADMIN, OrgRole.RESPO_BENEVOLE, OrgRole.RESPO_COMMISSION)
  21. WRITE_ROLES = (OrgRole.ORG_ADMIN, OrgRole.RESPO_BENEVOLE, OrgRole.RESPO_COMMISSION)
  22. @router.get("/templates", response_model=list[TemplateResponse])
  23. async def list_project_templates(
  24. project_id: UUID,
  25. current_user: User = Depends(deps.require_org_role(*READ_ROLES)),
  26. session: Session = Depends(deps.get_session),
  27. ):
  28. """List slots from project"""
  29. p = session.get(Project, project_id)
  30. if p is None:
  31. raise HTTPException(status_code=404, detail="Project not found")
  32. return p.templates
  33. @router.post("/template", response_model=TemplateResponse)
  34. async def create_template(
  35. project_id: UUID,
  36. payload: TemplateCreateRequest,
  37. current_user: User = Depends(deps.require_org_role(*WRITE_ROLES)),
  38. session: Session = Depends(deps.get_session),
  39. ):
  40. """Create a new template to the project"""
  41. assert_project_exists_or_404(session, project_id)
  42. if payload.commission_id is not None:
  43. deps.assert_commission_ownership(session, current_user, project_id, payload.commission_id)
  44. template = SlotTemplate(project_id=project_id, title=payload.title)
  45. session.add(template)
  46. session.commit()
  47. dic = payload.model_dump(exclude_unset=True)
  48. if payload.tags is not None:
  49. del dic["tags"]
  50. if len(payload.tags) > 0:
  51. await verify_id_list(
  52. session, payload.tags, project_id, SlotTag, "Invalid template list"
  53. )
  54. session.execute(
  55. association_table_template_tags.insert().values(
  56. [(template.id, t_id) for t_id in payload.tags]
  57. )
  58. )
  59. update_object_from_payload(template, dic)
  60. session.commit()
  61. return template
  62. @router.post("/template/{template_id}", response_model=TemplateResponse)
  63. async def update_template(
  64. project_id: UUID,
  65. template_id: UUID,
  66. payload: TemplateUpdateRequest,
  67. current_user: User = Depends(deps.require_org_role(*WRITE_ROLES)),
  68. session: Session = Depends(deps.get_session),
  69. ):
  70. """Update a template"""
  71. template = session.get(SlotTemplate, template_id)
  72. if (template is None) or (template.project_id != str(project_id)):
  73. raise HTTPException(status_code=404, detail="Template not found")
  74. if template.commission_id is not None:
  75. deps.assert_commission_ownership(session, current_user, project_id, template.commission_id)
  76. if payload.commission_id is not None:
  77. deps.assert_commission_ownership(session, current_user, project_id, payload.commission_id)
  78. input_dict = payload.model_dump(exclude_unset=True)
  79. if payload.tags is not None:
  80. # Remove previous keys in association table
  81. session.execute(
  82. association_table_template_tags.delete().where(
  83. association_table_template_tags.c.description_id == template.id
  84. )
  85. )
  86. if len(payload.tags) > 0:
  87. await verify_id_list(
  88. session, payload.tags, project_id, SlotTag, "Invalid template list"
  89. )
  90. session.execute(
  91. association_table_template_tags.insert().values(
  92. [(template.id, t_id) for t_id in payload.tags]
  93. )
  94. )
  95. del input_dict["tags"]
  96. update_object_from_payload(template, input_dict)
  97. session.commit()
  98. session.refresh(template)
  99. return template
  100. @router.delete("/template/{template_id}")
  101. async def delete_template(
  102. project_id: UUID,
  103. template_id: UUID,
  104. current_user: User = Depends(deps.require_org_role(*WRITE_ROLES)),
  105. session: Session = Depends(deps.get_session),
  106. ):
  107. """Delete a slot from the project"""
  108. result = session.execute(
  109. select(SlotTemplate.id, SlotTemplate.commission_id).where(
  110. SlotTemplate.id == template_id, SlotTemplate.project_id == project_id
  111. )
  112. ).first()
  113. if result is None:
  114. raise HTTPException(status_code=404, detail="Template not found")
  115. if result[1] is not None:
  116. deps.assert_commission_ownership(session, current_user, project_id, result[1])
  117. session.execute(
  118. delete(SlotTemplate).where(
  119. (SlotTemplate.id == template_id) & (SlotTemplate.project_id == project_id)
  120. )
  121. )
  122. session.commit()