serializers.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from urllib.parse import urlparse
  2. from django.conf import settings
  3. from django.core.validators import URLValidator
  4. from django.urls import reverse
  5. from django.utils import timezone
  6. from rest_framework import serializers
  7. from rest_framework.fields import ChoiceField
  8. from .constants import HTTP_MONITOR_TYPES
  9. from .models import Monitor, MonitorCheck, MonitorType, StatusPage
  10. class MonitorCheckRelatedSerializer(serializers.ModelSerializer):
  11. isUp = serializers.BooleanField(source="is_up")
  12. startCheck = serializers.DateTimeField(source="start_check")
  13. class Meta:
  14. model = MonitorCheck
  15. fields = ("isUp", "startCheck", "reason")
  16. class MonitorCheckSerializer(MonitorCheckRelatedSerializer):
  17. responseTime = serializers.DurationField(source="response_time")
  18. class Meta:
  19. model = MonitorCheck
  20. fields = ("isUp", "startCheck", "reason", "responseTime")
  21. class HeartBeatCheckSerializer(MonitorCheckSerializer):
  22. start_check = serializers.DateTimeField(
  23. default=timezone.now, help_text="Optional, set server check start time."
  24. )
  25. class Meta(MonitorCheckSerializer.Meta):
  26. fields = ("is_up", "start_check")
  27. read_only_fields = ("is_up",)
  28. class MonitorSerializer(serializers.ModelSerializer):
  29. isUp = serializers.SerializerMethodField()
  30. lastChange = serializers.SerializerMethodField()
  31. monitorType = ChoiceField(choices=MonitorType.choices, source="monitor_type")
  32. expectedStatus = serializers.IntegerField(source="expected_status", allow_null=True)
  33. expectedBody = serializers.CharField(
  34. source="expected_body", required=False, allow_blank=True
  35. )
  36. heartbeatEndpoint = serializers.SerializerMethodField()
  37. projectName = serializers.SerializerMethodField()
  38. envName = serializers.SerializerMethodField()
  39. checks = MonitorCheckRelatedSerializer(many=True, read_only=True)
  40. def get_isUp(self, obj):
  41. if hasattr(obj, "latest_is_up"):
  42. return obj.latest_is_up
  43. def get_lastChange(self, obj):
  44. if hasattr(obj, "last_change"):
  45. if obj.last_change:
  46. return obj.last_change.isoformat().replace("+00:00", "Z")
  47. def get_heartbeatEndpoint(self, obj):
  48. if obj.endpoint_id:
  49. return settings.GLITCHTIP_URL.geturl() + reverse(
  50. "heartbeat-check",
  51. kwargs={
  52. "organization_slug": obj.organization.slug,
  53. "endpoint_id": obj.endpoint_id,
  54. },
  55. )
  56. def get_projectName(self, obj):
  57. if obj.project:
  58. return obj.project.name
  59. def get_envName(self, obj):
  60. if obj.environment:
  61. return obj.environment.name
  62. class Meta:
  63. model = Monitor
  64. fields = (
  65. "id",
  66. "monitorType",
  67. "endpoint_id",
  68. "created",
  69. "checks",
  70. "name",
  71. "url",
  72. "expectedStatus",
  73. "expectedBody",
  74. "environment",
  75. "project",
  76. "organization",
  77. "interval",
  78. "isUp",
  79. "lastChange",
  80. "heartbeatEndpoint",
  81. "projectName",
  82. "envName",
  83. "timeout",
  84. )
  85. read_only_fields = (
  86. "organization",
  87. "isUp",
  88. "lastChange",
  89. "endpoint_id",
  90. "created",
  91. "heartbeatEndpoint",
  92. "projectName",
  93. "envName",
  94. )
  95. def validate(self, attrs):
  96. monitor_type = attrs["monitor_type"]
  97. if attrs["url"] == "" and monitor_type in HTTP_MONITOR_TYPES + (
  98. MonitorType.SSL,
  99. ):
  100. raise serializers.ValidationError("URL is required for " + monitor_type)
  101. if monitor_type in HTTP_MONITOR_TYPES:
  102. URLValidator()(attrs["url"])
  103. if attrs.get("expected_status") is None and monitor_type in [
  104. MonitorType.GET,
  105. MonitorType.POST,
  106. ]:
  107. raise serializers.ValidationError(
  108. "Expected status is required for " + attrs["monitor_type"]
  109. )
  110. if attrs["monitor_type"] == MonitorType.PORT:
  111. url = attrs["url"].replace("http://", "//", 1)
  112. if not url.startswith("//"):
  113. url = "//" + url
  114. parsed_url = urlparse(url)
  115. message = "Invalid Port URL, expected hostname and port"
  116. try:
  117. if not all([parsed_url.hostname, parsed_url.port]):
  118. raise serializers.ValidationError(message)
  119. except ValueError as err:
  120. raise serializers.ValidationError(message) from err
  121. attrs["url"] = f"{parsed_url.hostname}:{parsed_url.port}"
  122. return attrs
  123. class MonitorDetailSerializer(MonitorSerializer):
  124. checks = MonitorCheckSerializer(many=True, read_only=True)
  125. class MonitorUpdateSerializer(MonitorSerializer):
  126. """Remove checks, which otherwise would be have the limit applied"""
  127. class Meta(MonitorSerializer.Meta):
  128. fields = [field for field in MonitorSerializer.Meta.fields if field != "checks"]
  129. class StatusPageSerializer(serializers.ModelSerializer):
  130. isPublic = serializers.BooleanField(source="is_public")
  131. class Meta:
  132. model = StatusPage
  133. fields = ("name", "slug", "isPublic", "monitors")
  134. read_only_fields = ("slug",)