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.

227 lines
6.4 KiB

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