admin.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. from django.conf import settings
  2. from django.contrib import admin
  3. from django.db.models import F, PositiveIntegerField
  4. from django.db.models.fields.json import KeyTextTransform
  5. from django.db.models.functions import Cast
  6. from django.utils.html import format_html
  7. from import_export import resources
  8. from import_export.admin import ImportExportModelAdmin
  9. from organizations.base_admin import (
  10. BaseOrganizationAdmin,
  11. BaseOrganizationUserAdmin,
  12. BaseOwnerInline,
  13. )
  14. from .models import Organization, OrganizationOwner, OrganizationUser
  15. ORGANIZATION_LIST_FILTER = (
  16. "is_active",
  17. "is_accepting_events",
  18. )
  19. if settings.BILLING_ENABLED:
  20. ORGANIZATION_LIST_FILTER += ("djstripe_customers__subscriptions__plan__product",)
  21. class OwnerInline(BaseOwnerInline):
  22. model = OrganizationOwner
  23. class OrganizationUserInline(admin.StackedInline):
  24. raw_id_fields = ("user",)
  25. model = OrganizationUser
  26. extra = 0
  27. class OrganizationResource(resources.ModelResource):
  28. class Meta:
  29. model = Organization
  30. skip_unchanged = True
  31. fields = ("id", "slug", "name", "created", "organization")
  32. class GlitchTipBaseOrganizationAdmin(BaseOrganizationAdmin):
  33. readonly_fields = ("customers", "created")
  34. list_filter = ORGANIZATION_LIST_FILTER
  35. inlines = [OrganizationUserInline, OwnerInline]
  36. show_full_result_count = False
  37. def issue_events(self, obj):
  38. return obj.issue_event_count
  39. def customers(self, obj):
  40. return format_html(
  41. " ".join(
  42. [
  43. f'<a href="{customer.get_stripe_dashboard_url()}" target="_blank">{customer.id}</a>'
  44. for customer in obj.djstripe_customers.all()
  45. ]
  46. )
  47. )
  48. def transaction_events(self, obj):
  49. return obj.transaction_count
  50. def uptime_check_events(self, obj):
  51. return obj.uptime_check_event_count
  52. def file_size(self, obj):
  53. return obj.file_size
  54. def total_events(self, obj):
  55. return obj.total_event_count
  56. class OrganizationAdmin(GlitchTipBaseOrganizationAdmin, ImportExportModelAdmin):
  57. list_display = [
  58. "name",
  59. "is_active",
  60. "is_accepting_events",
  61. "issue_events",
  62. "transaction_events",
  63. "uptime_check_events",
  64. "file_size",
  65. "total_events",
  66. ]
  67. resource_class = OrganizationResource
  68. def get_queryset(self, request):
  69. qs = self.model.objects.with_event_counts()
  70. # From super
  71. ordering = self.ordering or ()
  72. if ordering:
  73. qs = qs.order_by(*ordering)
  74. return qs
  75. class OrganizationSubscription(Organization):
  76. class Meta:
  77. proxy = True
  78. class IsOverListFilter(admin.SimpleListFilter):
  79. title = "Is over plan limit"
  80. parameter_name = "is_over"
  81. def lookups(self, request, model_admin):
  82. return (
  83. (True, "Yes"),
  84. (False, "No"),
  85. )
  86. def queryset(self, request, queryset):
  87. if self.value() is not None:
  88. queryset = queryset.filter(max_events__isnull=False)
  89. if self.value() is False:
  90. return queryset.filter(total_event_count__lte=F("max_events"))
  91. if self.value() is True:
  92. return queryset.filter(total_event_count__gt=F("max_events"))
  93. return queryset
  94. class OrganizationSubscriptionAdmin(GlitchTipBaseOrganizationAdmin):
  95. list_display = [
  96. "name",
  97. "is_active",
  98. "is_accepting_events",
  99. "issue_events",
  100. "transaction_events",
  101. "uptime_check_events",
  102. "file_size",
  103. "total_events",
  104. "max_events",
  105. "current_period_end",
  106. ]
  107. def max_events(self, obj):
  108. return obj.max_events
  109. def current_period_end(self, obj):
  110. return obj.current_period_end
  111. def get_queryset(self, request):
  112. qs = Organization.objects.with_event_counts().annotate(
  113. max_events=Cast(
  114. KeyTextTransform(
  115. "events",
  116. "djstripe_customers__subscriptions__plan__product__metadata",
  117. ),
  118. output_field=PositiveIntegerField(),
  119. ),
  120. current_period_end=F(
  121. "djstripe_customers__subscriptions__current_period_end"
  122. ),
  123. )
  124. # From super
  125. ordering = self.ordering or ()
  126. if ordering:
  127. qs = qs.order_by(*ordering)
  128. return qs
  129. list_filter = GlitchTipBaseOrganizationAdmin.list_filter + (IsOverListFilter,)
  130. class OrganizationUserResource(resources.ModelResource):
  131. class Meta:
  132. model = OrganizationUser
  133. skip_unchanged = True
  134. fields = (
  135. "id",
  136. "user",
  137. "organization",
  138. "role",
  139. "email",
  140. )
  141. import_id_fields = ("user", "email", "organization")
  142. class OrganizationUserAdmin(BaseOrganizationUserAdmin, ImportExportModelAdmin):
  143. list_display = ["user", "organization", "role", "email"]
  144. search_fields = ("email", "user__email", "organization__name")
  145. list_filter = ("role",)
  146. resource_class = OrganizationUserResource
  147. admin.site.register(Organization, OrganizationAdmin)
  148. if settings.BILLING_ENABLED:
  149. admin.site.register(OrganizationSubscription, OrganizationSubscriptionAdmin)
  150. admin.site.register(OrganizationUser, OrganizationUserAdmin)