You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
7.0 KiB

10 years ago
5 years ago
10 years ago
10 years ago
5 years ago
6 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
9 years ago
5 years ago
5 years ago
5 years ago
6 years ago
5 years ago
6 years ago
9 years ago
9 years ago
5 years ago
  1. from django.contrib import admin
  2. from django.core.paginator import Paginator
  3. from django.db import connection
  4. from django.db.models import F
  5. from django.urls import reverse
  6. from django.utils.html import escape
  7. from django.utils.safestring import mark_safe
  8. from hc.api.models import Channel, Check, Flip, Notification, Ping
  9. from hc.lib.date import format_duration
  10. @admin.register(Check)
  11. class ChecksAdmin(admin.ModelAdmin):
  12. class Media:
  13. css = {"all": ("css/admin/checks.css",)}
  14. search_fields = ["name", "code", "project__owner__email"]
  15. raw_id_fields = ("project",)
  16. list_display = (
  17. "id",
  18. "name_tags",
  19. "project_",
  20. "created",
  21. "n_pings",
  22. "timeout_schedule",
  23. "status",
  24. "last_start",
  25. "last_ping",
  26. )
  27. list_filter = ("status", "kind", "last_ping", "last_start")
  28. actions = ["send_alert"]
  29. def get_queryset(self, request):
  30. qs = super().get_queryset(request)
  31. qs = qs.annotate(email=F("project__owner__email"))
  32. qs = qs.annotate(project_name=F("project__name"))
  33. return qs
  34. @mark_safe
  35. def project_(self, obj):
  36. url = reverse("hc-checks", args=[obj.project.code])
  37. name = escape(obj.project_name or "Default")
  38. email = escape(obj.email)
  39. return f'{email} &rsaquo; <a href="{url}"">{name}</a>'
  40. @mark_safe
  41. def name_tags(self, obj):
  42. url = reverse("hc-details", args=[obj.code])
  43. name = escape(obj.name or "unnamed")
  44. s = f'<a href="{url}"">{name}</a>'
  45. for tag in obj.tags_list():
  46. s += " <span>%s</span>" % escape(tag)
  47. return s
  48. @admin.display(description="Schedule")
  49. def timeout_schedule(self, obj):
  50. if obj.kind == "simple":
  51. return format_duration(obj.timeout)
  52. elif obj.kind == "cron":
  53. return obj.schedule
  54. else:
  55. return "Unknown"
  56. @admin.action(description="Send Alert")
  57. def send_alert(self, request, qs):
  58. for check in qs:
  59. for channel in check.channel_set.all():
  60. channel.notify(check)
  61. self.message_user(request, "%d alert(s) sent" % qs.count())
  62. class SchemeListFilter(admin.SimpleListFilter):
  63. title = "Scheme"
  64. parameter_name = "scheme"
  65. def lookups(self, request, model_admin):
  66. return (("http", "HTTP"), ("https", "HTTPS"), ("email", "Email"))
  67. def queryset(self, request, queryset):
  68. if self.value():
  69. queryset = queryset.filter(scheme=self.value())
  70. return queryset
  71. class MethodListFilter(admin.SimpleListFilter):
  72. title = "Method"
  73. parameter_name = "method"
  74. methods = ["HEAD", "GET", "POST", "PUT", "DELETE"]
  75. def lookups(self, request, model_admin):
  76. return zip(self.methods, self.methods)
  77. def queryset(self, request, queryset):
  78. if self.value():
  79. queryset = queryset.filter(method=self.value())
  80. return queryset
  81. class KindListFilter(admin.SimpleListFilter):
  82. title = "Kind"
  83. parameter_name = "kind"
  84. kinds = ["start", "fail"]
  85. def lookups(self, request, model_admin):
  86. return zip(self.kinds, self.kinds)
  87. def queryset(self, request, queryset):
  88. if self.value():
  89. queryset = queryset.filter(kind=self.value())
  90. return queryset
  91. # Adapted from: https://djangosnippets.org/snippets/2593/
  92. class LargeTablePaginator(Paginator):
  93. """ Overrides the count method to get an estimate instead of actual count
  94. when not filtered
  95. """
  96. def _get_estimate(self):
  97. try:
  98. cursor = connection.cursor()
  99. cursor.execute(
  100. "SELECT reltuples FROM pg_class WHERE relname = %s",
  101. [self.object_list.query.model._meta.db_table],
  102. )
  103. return int(cursor.fetchone()[0])
  104. except:
  105. return 0
  106. def _get_count(self):
  107. """
  108. Changed to use an estimate if the estimate is greater than 10,000
  109. Returns the total number of objects, across all pages.
  110. """
  111. if not hasattr(self, "_count") or self._count is None:
  112. try:
  113. estimate = 0
  114. if not self.object_list.query.where:
  115. estimate = self._get_estimate()
  116. if estimate < 10000:
  117. self._count = self.object_list.count()
  118. else:
  119. self._count = estimate
  120. except (AttributeError, TypeError):
  121. # AttributeError if object_list has no count() method.
  122. # TypeError if object_list.count() requires arguments
  123. # (i.e. is of type list).
  124. self._count = len(self.object_list)
  125. return self._count
  126. count = property(_get_count)
  127. @admin.register(Ping)
  128. class PingsAdmin(admin.ModelAdmin):
  129. search_fields = ("owner__name", "owner__code")
  130. readonly_fields = ("owner",)
  131. list_select_related = ("owner",)
  132. list_display = ("id", "created", "owner", "scheme", "method", "ua")
  133. list_filter = ("created", SchemeListFilter, MethodListFilter, KindListFilter)
  134. paginator = LargeTablePaginator
  135. show_full_result_count = False
  136. @admin.register(Channel)
  137. class ChannelsAdmin(admin.ModelAdmin):
  138. class Media:
  139. css = {"all": ("css/admin/channels.css",)}
  140. search_fields = ["value", "project__owner__email"]
  141. list_display = ("id", "transport", "name", "project_", "value", "ok")
  142. list_filter = ("kind",)
  143. raw_id_fields = ("project", "checks")
  144. @mark_safe
  145. def project_(self, obj):
  146. url = reverse("hc-checks", args=[obj.project_code])
  147. name = escape(obj.project_name or "Default")
  148. email = escape(obj.email)
  149. return f"{email} &rsaquo; <a href='{url}'>{name}</a>"
  150. def get_queryset(self, request):
  151. qs = super().get_queryset(request)
  152. qs = qs.annotate(project_code=F("project__code"))
  153. qs = qs.annotate(project_name=F("project__name"))
  154. qs = qs.annotate(email=F("project__owner__email"))
  155. return qs
  156. @mark_safe
  157. def transport(self, obj):
  158. note = ""
  159. if obj.kind == "email" and not obj.email_verified:
  160. note = " (not verified)"
  161. return f'<span class="ic-{ obj.kind }"></span> &nbsp; {obj.kind}{note}'
  162. @admin.display(boolean=True)
  163. def ok(self, obj):
  164. return False if obj.last_error else True
  165. @admin.register(Notification)
  166. class NotificationsAdmin(admin.ModelAdmin):
  167. search_fields = ["owner__name", "owner__code", "channel__value", "error"]
  168. readonly_fields = ("owner",)
  169. list_select_related = ("owner", "channel")
  170. list_display = (
  171. "id",
  172. "created",
  173. "check_status",
  174. "owner",
  175. "channel_kind",
  176. "channel_value",
  177. "error",
  178. )
  179. list_filter = ("created", "check_status", "channel__kind")
  180. raw_id_fields = ("channel",)
  181. def channel_kind(self, obj):
  182. return obj.channel.kind
  183. def channel_value(self, obj):
  184. return obj.channel.value
  185. @admin.register(Flip)
  186. class FlipsAdmin(admin.ModelAdmin):
  187. list_display = ("id", "created", "processed", "owner", "old_status", "new_status")
  188. raw_id_fields = ("owner",)