events.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import uuid
  2. from typing import Optional
  3. from django.db.models import OuterRef, Subquery
  4. from django.http import Http404, HttpResponse
  5. from ninja.pagination import paginate
  6. from glitchtip.api.authentication import AuthHttpRequest
  7. from glitchtip.api.permissions import has_permission
  8. from ..models import IssueEvent, UserReport
  9. from ..schema import IssueEventDetailSchema, IssueEventJsonSchema, IssueEventSchema
  10. from . import router
  11. def get_queryset(
  12. request: AuthHttpRequest,
  13. issue_id: Optional[int] = None,
  14. organization_slug: Optional[str] = None,
  15. project_slug: Optional[str] = None,
  16. ):
  17. user_id = request.auth.user_id
  18. qs = IssueEvent.objects.filter(issue__project__organization__users=user_id)
  19. if issue_id:
  20. qs = qs.filter(issue_id=issue_id)
  21. if organization_slug:
  22. qs = qs.filter(issue__project__organization__slug=organization_slug)
  23. if project_slug:
  24. qs = qs.filter(issue__project__slug=project_slug)
  25. return qs.select_related("issue")
  26. async def get_user_report(event_id: uuid.UUID) -> Optional[UserReport]:
  27. return await UserReport.objects.filter(event_id=event_id).afirst()
  28. @router.get("/issues/{int:issue_id}/events/", response=list[IssueEventSchema])
  29. @paginate
  30. @has_permission(["event:read", "event:write", "event:admin"])
  31. async def list_issue_event(
  32. request: AuthHttpRequest, response: HttpResponse, issue_id: int
  33. ):
  34. return get_queryset(request, issue_id=issue_id).order_by("-received")
  35. @router.get(
  36. "/issues/{int:issue_id}/events/latest/",
  37. response=IssueEventDetailSchema,
  38. by_alias=True,
  39. )
  40. @has_permission(["event:read", "event:write", "event:admin"])
  41. async def get_latest_issue_event(request: AuthHttpRequest, issue_id: int):
  42. qs = get_queryset(request, issue_id).order_by("-received")
  43. qs = qs.annotate(
  44. previous=Subquery(
  45. qs.filter(received__lt=OuterRef("received"))
  46. .order_by("-received")
  47. .values("id")[:1]
  48. ),
  49. )
  50. event = await qs.afirst()
  51. if not event:
  52. raise Http404()
  53. event.next = None # We know the next after "latest" must be None
  54. event.user_report = await get_user_report(event.id)
  55. return event
  56. @router.get(
  57. "/issues/{int:issue_id}/events/{event_id}/",
  58. response=IssueEventDetailSchema,
  59. by_alias=True,
  60. )
  61. @has_permission(["event:read", "event:write", "event:admin"])
  62. async def get_issue_event(request: AuthHttpRequest, issue_id: int, event_id: uuid.UUID):
  63. qs = get_queryset(request, issue_id)
  64. qs = qs.annotate(
  65. previous=Subquery(
  66. qs.filter(received__lt=OuterRef("received"))
  67. .order_by("-received")
  68. .values("id")[:1]
  69. ),
  70. next=Subquery(
  71. qs.filter(received__gt=OuterRef("received"))
  72. .order_by("received")
  73. .values("id")[:1]
  74. ),
  75. )
  76. event = await qs.filter(id=event_id).afirst()
  77. if not event:
  78. raise Http404()
  79. event.user_report = await get_user_report(event.id)
  80. return event
  81. @router.get(
  82. "/projects/{slug:organization_slug}/{slug:project_slug}/events/",
  83. response=list[IssueEventSchema],
  84. by_alias=True,
  85. )
  86. @paginate
  87. @has_permission(["event:read", "event:write", "event:admin"])
  88. async def list_project_issue_event(
  89. request: AuthHttpRequest,
  90. response: HttpResponse,
  91. organization_slug: str,
  92. project_slug: str,
  93. ):
  94. return get_queryset(
  95. request, organization_slug=organization_slug, project_slug=project_slug
  96. ).order_by("-received")
  97. @router.get(
  98. "/projects/{slug:organization_slug}/{slug:project_slug}/events/{event_id}/",
  99. response=IssueEventDetailSchema,
  100. by_alias=True,
  101. )
  102. @has_permission(["event:read", "event:write", "event:admin"])
  103. async def get_project_issue_event(
  104. request: AuthHttpRequest,
  105. organization_slug: str,
  106. project_slug: str,
  107. event_id: uuid.UUID,
  108. ):
  109. qs = get_queryset(
  110. request, organization_slug=organization_slug, project_slug=project_slug
  111. )
  112. qs = qs.annotate(
  113. previous=Subquery(
  114. qs.filter(received__lt=OuterRef("received"))
  115. .order_by("-received")
  116. .values("id")[:1]
  117. ),
  118. next=Subquery(
  119. qs.filter(received__gt=OuterRef("received"))
  120. .order_by("received")
  121. .values("id")[:1]
  122. ),
  123. )
  124. event = await qs.filter(id=event_id).afirst()
  125. if not event:
  126. raise Http404()
  127. event.user_report = await get_user_report(event.id)
  128. return event
  129. @router.get(
  130. "/organizations/{slug:organization_slug}/issues/{int:issue_id}/events/{event_id}/json/",
  131. response=IssueEventJsonSchema,
  132. by_alias=True,
  133. exclude_none=True,
  134. )
  135. @has_permission(["event:read", "event:write", "event:admin"])
  136. async def get_event_json(
  137. request: AuthHttpRequest, organization_slug: str, issue_id: int, event_id: uuid.UUID
  138. ):
  139. qs = get_queryset(request, organization_slug=organization_slug, issue_id=issue_id)
  140. obj = await qs.filter(id=event_id).aget()
  141. if not obj:
  142. return Http404()
  143. return obj