From 7ea2da508d221897ffdf6bee7dc41710c18edfae Mon Sep 17 00:00:00 2001 From: Alexander J Sheehan Date: Wed, 27 Mar 2024 16:27:19 +0000 Subject: [PATCH] feat: adding additional info to the enterprise group membership serializer --- CHANGELOG.rst | 4 ++ enterprise/__init__.py | 2 +- enterprise/api/v1/serializers.py | 41 +++++++++++++++- enterprise/models.py | 9 ++++ tests/test_enterprise/api/test_views.py | 65 ++++++++++++++++++++++++- 5 files changed, 117 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c53f65a767..993c325a02 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,10 @@ Change Log Unreleased ---------- +[4.13.12] +--------- +* feat: adding additional info to the enterprise group membership serializer + [4.13.11] --------- * feat: pass force_enrollment when bulk enrolling learners diff --git a/enterprise/__init__.py b/enterprise/__init__.py index 2d9498e47f..e5c45313d8 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,4 +2,4 @@ Your project description goes here. """ -__version__ = "4.13.11" +__version__ = "4.13.12" diff --git a/enterprise/api/v1/serializers.py b/enterprise/api/v1/serializers.py index 5bdab56b1f..67e00d43f2 100644 --- a/enterprise/api/v1/serializers.py +++ b/enterprise/api/v1/serializers.py @@ -600,9 +600,48 @@ class EnterpriseGroupMembershipSerializer(serializers.ModelSerializer): pending_learner_id = serializers.IntegerField(source='pending_enterprise_customer_user.id', allow_null=True) enterprise_group_membership_uuid = serializers.UUIDField(source='uuid', allow_null=True, read_only=True) + member_details = serializers.SerializerMethodField() + recent_action = serializers.SerializerMethodField() + member_status = serializers.SerializerMethodField() + class Meta: model = models.EnterpriseGroupMembership - fields = ('learner_id', 'pending_learner_id', 'enterprise_group_membership_uuid') + fields = ( + 'learner_id', + 'pending_learner_id', + 'enterprise_group_membership_uuid', + 'member_details', + 'recent_action', + 'member_status', + ) + + def get_member_details(self, obj): + """ + Return either the member's name and email if it's the case that the member is realized, otherwise just email + """ + if user := obj.enterprise_customer_user: + return {"user_email": user.user_email, "user_name": user.name} + return {"user_email": obj.pending_enterprise_customer_user.user_email} + + def get_recent_action(self, obj): + """ + Return the timestamp and name of the most recent action associated with the membership. + """ + if obj.is_removed: + return f"Removed: {obj.modified.strftime('%B %d, %Y')}" + if obj.enterprise_customer_user and obj.activated_at: + return f"Accepted: {obj.activated_at.strftime('%B %d, %Y')}" + return f"Invited: {obj.created.strftime('%B %d, %Y')}" + + def get_member_status(self, obj): + """ + Return the status related to the membership. + """ + if obj.is_removed: + return "removed" + if obj.enterprise_customer_user: + return "accepted" + return "pending" class EnterpriseCustomerUserReadOnlySerializer(serializers.ModelSerializer): diff --git a/enterprise/models.py b/enterprise/models.py index 9dbb8d5b3b..8f85aec7c7 100644 --- a/enterprise/models.py +++ b/enterprise/models.py @@ -1138,6 +1138,15 @@ def username(self): return self.user.username return None + @property + def name(self): + """ + Return linked user's name. + """ + if self.user is not None: + return f"{self.user.first_name} {self.user.last_name}" + return None + @property def data_sharing_consent_records(self): """ diff --git a/tests/test_enterprise/api/test_views.py b/tests/test_enterprise/api/test_views.py index 5ae7d75132..082bf539a8 100644 --- a/tests/test_enterprise/api/test_views.py +++ b/tests/test_enterprise/api/test_views.py @@ -7317,6 +7317,7 @@ def setUp(self): group=self.group_1, pending_enterprise_customer_user=None, enterprise_customer_user__enterprise_customer=self.enterprise_customer, + activated_at=datetime.now() )) def test_group_permissions(self): @@ -7353,6 +7354,52 @@ def test_successful_retrieve_group(self): response = self.client.get(url) assert response.json().get('uuid') == str(self.group_1.uuid) + def test_list_learner_pending_learner_data(self): + """ + Test the response data of the list learners in group endpoint when the membership is pending + """ + group = EnterpriseGroupFactory(enterprise_customer=self.enterprise_customer) + url = settings.TEST_SERVER + reverse( + 'enterprise-group-learners', + kwargs={'group_uuid': group.uuid}, + ) + pending_user = PendingEnterpriseCustomerUserFactory() + EnterpriseGroupMembershipFactory( + group=group, + pending_enterprise_customer_user=PendingEnterpriseCustomerUserFactory(), + enterprise_customer_user=None, + ) + response = self.client.get(url) + assert response.json().get('results')[0].get('member_details') == {'user_email': pending_user.user_email} + assert response.json().get('results')[0].get( + 'recent_action' + ) == f'Invited: {datetime.now().strftime("%B %d, %Y")}' + + def test_list_learner_statuses(self): + """ + Test the response data of the list learners in group endpoint when the membership is pending + """ + group = EnterpriseGroupFactory(enterprise_customer=self.enterprise_customer) + url = settings.TEST_SERVER + reverse( + 'enterprise-group-learners', + kwargs={'group_uuid': group.uuid}, + ) + EnterpriseGroupMembershipFactory( + group=group, + pending_enterprise_customer_user=PendingEnterpriseCustomerUserFactory(), + enterprise_customer_user=None, + ) + EnterpriseGroupMembershipFactory( + group=group, + pending_enterprise_customer_user=None, + enterprise_customer_user__enterprise_customer=self.enterprise_customer, + activated_at=datetime.now() + ) + response = self.client.get(url) + assert response.json().get('count') == 2 + statuses = [result.get('member_status') for result in response.json().get('results')] + assert statuses.sort() == ['accepted', 'pending'].sort() + def test_successful_list_learners(self): """ Test a successful GET request to the list endpoint. @@ -7364,11 +7411,18 @@ def test_successful_list_learners(self): ) results_list = [] for i in reversed(range(1, 11)): + member_user = self.enterprise_group_memberships[i].enterprise_customer_user results_list.append( { - 'learner_id': self.enterprise_group_memberships[i].enterprise_customer_user.id, + 'learner_id': member_user.id, 'pending_learner_id': None, 'enterprise_group_membership_uuid': str(self.enterprise_group_memberships[i].uuid), + 'member_details': { + 'user_name': member_user.name, + 'user_email': member_user.user_email + }, + 'recent_action': f'Accepted: {datetime.now().strftime("%B %d, %Y")}', + 'member_status': 'accepted', }, ) expected_response = { @@ -7385,15 +7439,22 @@ def test_successful_list_learners(self): kwargs={'group_uuid': self.group_1.uuid}, ) + '?page=2' page_2_response = self.client.get(url_page_2) + user = self.enterprise_group_memberships[0].enterprise_customer_user expected_response_page_2 = { 'count': 11, 'next': None, 'previous': f'http://testserver/enterprise/api/v1/enterprise-group/{self.group_1.uuid}/learners', 'results': [ { - 'learner_id': self.enterprise_group_memberships[0].enterprise_customer_user.id, + 'learner_id': user.id, 'pending_learner_id': None, 'enterprise_group_membership_uuid': str(self.enterprise_group_memberships[0].uuid), + 'member_details': { + 'user_name': user.name, + 'user_email': user.user_email + }, + 'recent_action': f'Accepted: {datetime.now().strftime("%B %d, %Y")}', + 'member_status': 'accepted', } ], }