From 9e4a07a970fb4eb1bbc886d8bc1f8b3307a919e7 Mon Sep 17 00:00:00 2001 From: Alexander J Sheehan Date: Wed, 6 Mar 2024 21:29:13 +0000 Subject: [PATCH] feat: admin pages for enterprise groups and enterprise group memberships --- enterprise/admin/__init__.py | 64 +++++++++++++++++++++++++++++++++++- enterprise/models.py | 21 ++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/enterprise/admin/__init__.py b/enterprise/admin/__init__.py index 2d88a33dd1..5e01a876e5 100644 --- a/enterprise/admin/__init__.py +++ b/enterprise/admin/__init__.py @@ -456,7 +456,7 @@ class Meta: ) list_display = ('username', 'user_email', 'get_enterprise_customer') - search_fields = ('user_id',) + search_fields = ('user_id', 'user_email',) @admin.display( description='Enterprise Customer' @@ -583,6 +583,11 @@ class Meta: 'created' ) + search_fields = ( + 'user_email', + 'id' + ) + readonly_fields = ( 'user_email', 'enterprise_customer', @@ -1155,3 +1160,60 @@ def mark_configured(self, request, obj): obj.save() mark_configured.label = "Mark as Configured" + + +@admin.register(models.EnterpriseGroup) +class EnterpriseGroupAdmin(admin.ModelAdmin): + """ + Django admin for EnterpriseGroup model. + """ + model = models.EnterpriseGroup + list_display = ('uuid', 'enterprise_customer', 'applies_to_all_contexts', ) + list_filter = ('applies_to_all_contexts',) + search_fields = ( + 'uuid', + 'name', + 'enterprise_customer__name', + 'enterprise_customer__uuid', + ) + readonly_fields = ('count', 'members',) + + def members(self, obj): + """ + Return the non-deleted members of a group + """ + return obj.members.filter(is_removed=False) + + @admin.display(description="Number of members in group") + def count(self, obj): + """ + Return the number of members in a group + """ + return len(obj.members.filter(is_removed=False)) + + +@admin.register(models.EnterpriseGroupMembership) +class EnterpriseGroupMembershipAdmin(admin.ModelAdmin): + """ + Django admin for EnterpriseGroupMembership model. + """ + model = models.EnterpriseGroupMembership + list_display = ('group', 'membership_user',) + search_fields = ( + 'uuid', + 'group__enterprise_customer_user', + 'enterprise_customer_user', + 'pending_enterprise_customer_user', + ) + autocomplete_fields = ( + 'group', + 'enterprise_customer_user', + 'pending_enterprise_customer_user', + ) + + def membership_user(self, obj): + """ + Return the user record associated with the membership, defaulting to ``enterprise_customer_user`` + and falling back on ``obj.pending_enterprise_customer_user`` + """ + return obj.enterprise_customer_user or obj.pending_enterprise_customer_user diff --git a/enterprise/models.py b/enterprise/models.py index 79323f0119..7e4a3bc7e5 100644 --- a/enterprise/models.py +++ b/enterprise/models.py @@ -4287,3 +4287,24 @@ class Meta: # ie no issue if multiple fields have: group = A and pending_enterprise_customer_user = NULL unique_together = (("group", "enterprise_customer_user"), ("group", "pending_enterprise_customer_user")) ordering = ['-modified'] + + def clean(self, *args, **kwargs): + """ + Ensure that records added via Django Admin have matching customer records between learner and group. + """ + user = self.enterprise_customer_user or self.pending_enterprise_customer_user + if user: + user_customer = user.enterprise_customer + if user_customer != self.group.enterprise_customer: + raise ValidationError( + 'Enterprise Customer associated with membership group must match the Enterprise Customer associated' + ' with the memberships user' + ) + super().clean(*args, **kwargs) + + def __str__(self): + """ + Return human-readable string representation. + """ + user = self.enterprise_customer_user or self.pending_enterprise_customer_user + return f"member: {user} in group: {self.uuid}"