api.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. from django.db.models import Q
  2. from django.http import Http404, HttpResponse
  3. from django.shortcuts import aget_object_or_404
  4. from ninja import Router
  5. from ninja.pagination import paginate
  6. from apps.organizations_ext.models import OrganizationUserRole
  7. from apps.projects.models import Project
  8. from glitchtip.api.authentication import AuthHttpRequest
  9. from glitchtip.api.permissions import has_permission
  10. from .models import AlertRecipient, ProjectAlert
  11. from .schema import ProjectAlertIn, ProjectAlertSchema
  12. router = Router()
  13. def get_project_alert_queryset(user_id: int, organization_slug: str, project_slug: str):
  14. return ProjectAlert.objects.filter(
  15. project__organization__users=user_id,
  16. project__organization__slug=organization_slug,
  17. project__slug=project_slug,
  18. ).prefetch_related("alertrecipient_set")
  19. @router.get(
  20. "projects/{slug:organization_slug}/{slug:project_slug}/alerts/",
  21. response=list[ProjectAlertSchema],
  22. by_alias=True,
  23. )
  24. @has_permission(["project:read"])
  25. @paginate
  26. async def list_project_alerts(
  27. request: AuthHttpRequest,
  28. response: HttpResponse,
  29. organization_slug: str,
  30. project_slug: str,
  31. ):
  32. return get_project_alert_queryset(
  33. request.auth.user_id, organization_slug, project_slug
  34. )
  35. @router.post(
  36. "projects/{slug:organization_slug}/{slug:project_slug}/alerts/",
  37. response={201: ProjectAlertSchema},
  38. by_alias=True,
  39. )
  40. @has_permission(["project:write", "project:admin"])
  41. async def create_project_alert(
  42. request: AuthHttpRequest,
  43. organization_slug: str,
  44. project_slug: str,
  45. payload: ProjectAlertIn,
  46. ):
  47. user_id = request.auth.user_id
  48. project = await aget_object_or_404(
  49. Project.objects.filter(
  50. Q(
  51. organization__users=user_id,
  52. organization__organization_users__role__gte=OrganizationUserRole.ADMIN,
  53. )
  54. | Q(teams__members__user=user_id)
  55. ).distinct(),
  56. organization__slug=organization_slug,
  57. slug=project_slug,
  58. )
  59. data = payload.dict()
  60. recipients = data.pop("alert_recipients")
  61. project_alert = await project.projectalert_set.acreate(**data)
  62. await AlertRecipient.objects.abulk_create(
  63. [AlertRecipient(alert=project_alert, **recipient) for recipient in recipients]
  64. )
  65. return await get_project_alert_queryset(
  66. user_id, organization_slug, project_slug
  67. ).aget(id=project_alert.id)
  68. @router.put(
  69. "projects/{slug:organization_slug}/{slug:project_slug}/alerts/{alert_id}/",
  70. response=ProjectAlertSchema,
  71. by_alias=True,
  72. )
  73. @has_permission(["project:write", "project:admin"])
  74. async def update_project_alert(
  75. request: AuthHttpRequest,
  76. organization_slug: str,
  77. project_slug: str,
  78. alert_id: int,
  79. payload: ProjectAlertIn,
  80. ):
  81. user_id = request.auth.user_id
  82. alert = await aget_object_or_404(
  83. get_project_alert_queryset(user_id, organization_slug, project_slug),
  84. id=alert_id,
  85. )
  86. data = payload.dict()
  87. alert_recipients = data.pop("alert_recipients")
  88. for attr, value in data.items():
  89. setattr(alert, attr, value)
  90. await alert.asave()
  91. # Create/Delete recipients as needed
  92. delete_recipient_ids = set(
  93. {id async for id in alert.alertrecipient_set.values_list("id", flat=True)}
  94. )
  95. for recipient in alert_recipients:
  96. new_recipient, created = await AlertRecipient.objects.aget_or_create(
  97. alert=alert, **recipient
  98. )
  99. if not created:
  100. delete_recipient_ids.discard(new_recipient.pk)
  101. if delete_recipient_ids:
  102. await alert.alertrecipient_set.filter(pk__in=delete_recipient_ids).adelete()
  103. return await get_project_alert_queryset(
  104. user_id, organization_slug, project_slug
  105. ).aget(id=alert.id)
  106. @router.delete(
  107. "projects/{slug:organization_slug}/{slug:project_slug}/alerts/{alert_id}/",
  108. response={204: None},
  109. )
  110. @has_permission(["project:admin"])
  111. async def delete_project_alert(
  112. request: AuthHttpRequest, organization_slug: str, project_slug: str, alert_id: int
  113. ):
  114. user_id = request.auth.user_id
  115. result, _ = (
  116. await get_project_alert_queryset(user_id, organization_slug, project_slug)
  117. .filter(id=alert_id)
  118. .filter(
  119. project__organization__users=user_id,
  120. project__organization__organization_users__role__gte=OrganizationUserRole.ADMIN,
  121. )
  122. .adelete()
  123. )
  124. if result:
  125. return 204, None
  126. raise Http404