views.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from django.db.models import F, Prefetch, Q, Window
  2. from django.db.models.functions import RowNumber
  3. from django.shortcuts import get_object_or_404
  4. from django.utils import timezone
  5. from django.views.generic import DetailView
  6. from rest_framework import exceptions, permissions, viewsets
  7. from rest_framework.generics import CreateAPIView
  8. from glitchtip.pagination import LinkHeaderPagination
  9. from organizations_ext.models import Organization
  10. from .models import Monitor, MonitorCheck, StatusPage
  11. from .serializers import (
  12. HeartBeatCheckSerializer,
  13. MonitorCheckSerializer,
  14. MonitorDetailSerializer,
  15. MonitorSerializer,
  16. MonitorUpdateSerializer,
  17. StatusPageSerializer,
  18. )
  19. from .tasks import send_monitor_notification
  20. class HeartBeatCheckView(CreateAPIView):
  21. permission_classes = [permissions.AllowAny]
  22. authentication_classes = []
  23. serializer_class = HeartBeatCheckSerializer
  24. def perform_create(self, serializer):
  25. monitor = get_object_or_404(
  26. Monitor.objects.with_check_annotations(),
  27. organization__slug=self.kwargs.get("organization_slug"),
  28. endpoint_id=self.kwargs.get("endpoint_id"),
  29. )
  30. monitor_check = serializer.save(
  31. monitor=monitor,
  32. is_up=True,
  33. reason=None,
  34. is_change=monitor.latest_is_up != True,
  35. )
  36. if monitor.latest_is_up is False:
  37. send_monitor_notification.delay(
  38. monitor_check.pk, False, monitor.last_change
  39. )
  40. class MonitorViewSet(viewsets.ModelViewSet):
  41. queryset = Monitor.objects.with_check_annotations()
  42. serializer_class = MonitorSerializer
  43. def get_serializer_class(self):
  44. if self.action in ["retrieve"]:
  45. return MonitorDetailSerializer
  46. elif self.action in ["update"]:
  47. return MonitorUpdateSerializer
  48. return super().get_serializer_class()
  49. def get_queryset(self):
  50. if not self.request.user.is_authenticated:
  51. return self.queryset.none()
  52. queryset = self.queryset.filter(organization__users=self.request.user)
  53. organization_slug = self.kwargs.get("organization_slug")
  54. if organization_slug:
  55. queryset = queryset.filter(organization__slug=organization_slug)
  56. # Fetch latest 60 checks for each monitor
  57. queryset = queryset.prefetch_related(
  58. Prefetch(
  59. "checks",
  60. queryset=MonitorCheck.objects.filter( # Optimization
  61. start_check__gt=timezone.now() - timezone.timedelta(hours=12)
  62. )
  63. .annotate(
  64. row_number=Window(
  65. expression=RowNumber(),
  66. order_by="-start_check",
  67. partition_by=F("monitor"),
  68. ),
  69. )
  70. .filter(row_number__lte=60)
  71. .distinct(),
  72. )
  73. ).select_related("project")
  74. return queryset
  75. def perform_create(self, serializer):
  76. try:
  77. organization = Organization.objects.get(
  78. slug=self.kwargs.get("organization_slug"), users=self.request.user
  79. )
  80. except Organization.DoesNotExist as exc:
  81. raise exceptions.ValidationError("Organization not found") from exc
  82. serializer.save(organization=organization)
  83. class MonitorCheckPagination(LinkHeaderPagination):
  84. ordering = "-start_check"
  85. class MonitorCheckViewSet(viewsets.ReadOnlyModelViewSet):
  86. queryset = MonitorCheck.objects.all()
  87. serializer_class = MonitorCheckSerializer
  88. pagination_class = MonitorCheckPagination
  89. filterset_fields = ["is_change"]
  90. def get_queryset(self):
  91. if not self.request.user.is_authenticated:
  92. return self.queryset.none()
  93. queryset = self.queryset.filter(monitor__organization__users=self.request.user)
  94. organization_slug = self.kwargs.get("organization_slug")
  95. if organization_slug:
  96. queryset = queryset.filter(monitor__organization__slug=organization_slug)
  97. monitor_pk = self.kwargs.get("monitor_pk")
  98. if monitor_pk:
  99. queryset = queryset.filter(monitor__pk=monitor_pk)
  100. return queryset.only("is_up", "start_check", "reason", "response_time")
  101. class StatusPageViewSet(viewsets.ModelViewSet):
  102. queryset = StatusPage.objects.all()
  103. serializer_class = StatusPageSerializer
  104. lookup_field = "slug"
  105. def get_queryset(self):
  106. if not self.request.user.is_authenticated:
  107. return self.queryset.none()
  108. queryset = self.queryset.filter(organization__users=self.request.user)
  109. organization_slug = self.kwargs.get("organization_slug")
  110. if organization_slug:
  111. queryset = queryset.filter(organization__slug=organization_slug)
  112. return queryset
  113. def perform_create(self, serializer):
  114. try:
  115. organization = Organization.objects.get(
  116. slug=self.kwargs.get("organization_slug"), users=self.request.user
  117. )
  118. except Organization.DoesNotExist as exc:
  119. raise exceptions.ValidationError("Organization not found") from exc
  120. serializer.save(organization=organization)
  121. class StatusPageDetailView(DetailView):
  122. model = StatusPage
  123. def get_queryset(self):
  124. queryset = super().get_queryset()
  125. if self.request.user.is_authenticated:
  126. queryset = queryset.filter(
  127. Q(is_public=True) | Q(organization__users=self.request.user)
  128. )
  129. else:
  130. queryset = queryset.filter(is_public=True)
  131. return queryset.filter(
  132. organization__slug=self.kwargs.get("organization")
  133. ).distinct()
  134. def get_context_data(self, **kwargs):
  135. context = super().get_context_data(**kwargs)
  136. context["monitors"] = Monitor.objects.with_check_annotations().filter(
  137. statuspage=self.object
  138. )
  139. return context