diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8ce6a65d3d..d8ae74a08d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,7 +15,9 @@ Change Log Unreleased ---------- -* Nothing +[4.16.3] +-------- +* fix: fixing the removal logic for EnterpriseGroupMemberships, adding optional flag [4.16.2] --------- diff --git a/enterprise/__init__.py b/enterprise/__init__.py index 4c65fbb01b..51f220f217 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,4 +2,4 @@ Your project description goes here. """ -__version__ = "4.16.2" +__version__ = "4.16.3" diff --git a/enterprise/api/v1/views/enterprise_group.py b/enterprise/api/v1/views/enterprise_group.py index f15b48c229..cd25b3e83d 100644 --- a/enterprise/api/v1/views/enterprise_group.py +++ b/enterprise/api/v1/views/enterprise_group.py @@ -112,6 +112,7 @@ def get_learners(self, request, *args, **kwargs): are `memberDetails`, `memberStatus`, and `recentAction`. Ordering can be reversed by supplying a `-` at the beginning of the sorting value ie `-memberStatus`. - ``page`` (int, optional): Which page of paginated data to return. + - ``show_removed`` (bool, optional): Include removed learners in the response. Returns: Paginated list of learners that are associated with the enterprise group uuid:: @@ -137,6 +138,7 @@ def get_learners(self, request, *args, **kwargs): """ query_params = self.request.query_params.copy() is_reversed = bool(query_params.get('is_reversed', False)) + show_removed = bool(query_params.get('show_removed', False)) param_serializers = serializers.EnterpriseGroupLearnersRequestQuerySerializer( data=query_params @@ -155,7 +157,8 @@ def get_learners(self, request, *args, **kwargs): members = group_object.get_all_learners(user_query, sort_by, desc_order=is_reversed, - pending_users_only=pending_users_only) + pending_users_only=pending_users_only, + fetch_removed=show_removed) page = self.paginate_queryset(members) serializer = serializers.EnterpriseGroupMembershipSerializer(page, many=True) diff --git a/enterprise/models.py b/enterprise/models.py index 3963d13115..fffff4a64b 100644 --- a/enterprise/models.py +++ b/enterprise/models.py @@ -4338,9 +4338,9 @@ def _get_explicit_group_members(self, user_query=None, fetch_removed=False, pend """ Fetch explicitly defined members of a group, indicated by an existing membership record """ - members = self.members.select_related( - 'enterprise_customer_user', 'pending_enterprise_customer_user' - ) + # note: self.members doesn't seem to surface soft deleted items + members = EnterpriseGroupMembership.all_objects.filter( + group__uuid=self.uuid).select_related('enterprise_customer_user', 'pending_enterprise_customer_user') if not fetch_removed: members = members.filter(is_removed=False) if user_query: diff --git a/tests/test_enterprise/api/test_views.py b/tests/test_enterprise/api/test_views.py index cce0931388..1e26ac2e14 100644 --- a/tests/test_enterprise/api/test_views.py +++ b/tests/test_enterprise/api/test_views.py @@ -7629,6 +7629,44 @@ def test_list_learners_filtered(self): 'pending_learner_id' ) == pending_membership.pending_enterprise_customer_user.id + def test_list_removed_learners(self): + group = EnterpriseGroupFactory( + enterprise_customer=self.enterprise_customer, + applies_to_all_contexts=False, + ) + memberships_to_delete = [] + membership = EnterpriseGroupMembershipFactory( + group=group, + pending_enterprise_customer_user=None, + enterprise_customer_user__enterprise_customer=self.enterprise_customer, + ) + memberships_to_delete.append(membership.enterprise_customer_user.user.email) + + # first we remove the membership + remove_url = settings.TEST_SERVER + reverse( + 'enterprise-group-remove-learners', + kwargs={'group_uuid': group.uuid}, + ) + request_data = {'learner_emails': memberships_to_delete} + response = self.client.post(remove_url, data=request_data) + + # then we're checking if the filter works + removed_users_query_string = '?show_removed=true' + url = settings.TEST_SERVER + reverse( + 'enterprise-group-learners', + kwargs={'group_uuid': group.uuid}, + ) + removed_users_query_string + response = self.client.get(url) + assert response.json().get('count') == 1 + + # but we're doing an extra check to make sure its not fetched normally + url = settings.TEST_SERVER + reverse( + 'enterprise-group-learners', + kwargs={'group_uuid': group.uuid}, + ) + response = self.client.get(url) + assert response.json().get('count') == 0 + def test_list_learners_sort_by(self): """ Test that the list learners endpoint can be sorted by 'recentAction', 'status', 'memberDetails' @@ -7978,7 +8016,7 @@ def test_successful_assign_learners_to_group(self, mock_send_group_membership_in def test_remove_learners_404(self): """ - Test that the remove learners endpoint properly handles no finding the provided group + Test that the remove learners endpoint properly handles not finding the provided group """ url = settings.TEST_SERVER + reverse( 'enterprise-group-remove-learners',