admin.py 5.6 KB

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