From d2dedf751ca2db72bfa168098eddf3ee1eb26503 Mon Sep 17 00:00:00 2001 From: Alexander J Sheehan Date: Mon, 20 May 2024 15:46:39 +0000 Subject: [PATCH] feat: allowing for group members to be specified when fetched --- .../api/serializers/subsidy_access_policy.py | 4 +++ .../tests/test_subsidy_access_policy_views.py | 30 +++++++++++++++++++ .../api/v1/views/subsidy_access_policy.py | 4 +++ .../apps/api_client/lms_client.py | 6 ++++ 4 files changed, 44 insertions(+) diff --git a/enterprise_access/apps/api/serializers/subsidy_access_policy.py b/enterprise_access/apps/api/serializers/subsidy_access_policy.py index a4e46918..e981d768 100755 --- a/enterprise_access/apps/api/serializers/subsidy_access_policy.py +++ b/enterprise_access/apps/api/serializers/subsidy_access_policy.py @@ -822,6 +822,10 @@ class GroupMemberWithAggregatesRequestSerializer(serializers.Serializer): default=False, help_text=('Set to True to traverse over and return all group members records across all pages of data.') ) + learners = serializers.ListField( + child=serializers.EmailField(required=True), + required=False, + ) def validate(self, attrs): """ diff --git a/enterprise_access/apps/api/v1/tests/test_subsidy_access_policy_views.py b/enterprise_access/apps/api/v1/tests/test_subsidy_access_policy_views.py index e1b515ae..a073f67a 100755 --- a/enterprise_access/apps/api/v1/tests/test_subsidy_access_policy_views.py +++ b/enterprise_access/apps/api/v1/tests/test_subsidy_access_policy_views.py @@ -2301,6 +2301,36 @@ def test_get_group_member_data_with_aggregates_success( assert response.headers.get('Content-Type') == 'application/json' assert response.data == expected_response + @mock.patch('enterprise_access.apps.api.v1.views.subsidy_access_policy.LmsApiClient') + @mock.patch( + 'enterprise_access.apps.api.v1.views.subsidy_access_policy.get_and_cache_subsidy_learners_aggregate_data' + ) + def test_get_group_member_data_with_aggregates_supports_specified_learners( + self, + mock_subsidy_learners_aggregate_data_cache, + mock_lms_api_client, + ): + """ + Test that the `get_group_member_data_with_aggregates` endpoint supports specifying individual learners + """ + mock_subsidy_learners_aggregate_data_cache.return_value = {1: 99} + mock_lms_api_client.return_value.fetch_group_members.return_value = self.mock_fetch_group_members + uuid = uuid4() + self.client.get( + self.subsidy_access_policy_can_redeem_endpoint, + {'group_uuid': uuid, 'learners': ["foobar@example.com"], 'page': 1} + ) + mock_lms_api_client.return_value.fetch_group_members.assert_called_with( + group_uuid=uuid, + sort_by=None, + user_query=None, + show_removed=False, + is_reversed=False, + traverse_pagination=False, + page=1, + learners=["foobar@example.com"], + ) + @mock.patch('enterprise_access.apps.api.v1.views.subsidy_access_policy.LmsApiClient') @mock.patch( 'enterprise_access.apps.api.v1.views.subsidy_access_policy.get_and_cache_subsidy_learners_aggregate_data' diff --git a/enterprise_access/apps/api/v1/views/subsidy_access_policy.py b/enterprise_access/apps/api/v1/views/subsidy_access_policy.py index d36ed050..5c901dfa 100755 --- a/enterprise_access/apps/api/v1/views/subsidy_access_policy.py +++ b/enterprise_access/apps/api/v1/views/subsidy_access_policy.py @@ -1006,6 +1006,8 @@ def get_group_member_data_with_aggregates(self, request, uuid): format_csv: (Optional) Whether or not to return data in a csv format, defaults to `False` page: (Optional) Which page of Enterprise Group Membership records to request. Leave blank to fetch all group membership records + learners: (Optional) Array of learner emails. If specified, the endpoint will only return membership + records associated with one of the provided emails. """ request_serializer = serializers.GroupMemberWithAggregatesRequestSerializer(data=request.query_params) request_serializer.is_valid(raise_exception=True) @@ -1014,6 +1016,7 @@ def get_group_member_data_with_aggregates(self, request, uuid): traverse_pagination = request_serializer.validated_data.get('traverse_pagination') sort_by = request_serializer.validated_data.get('sort_by') is_reversed = request_serializer.validated_data.get('is_reversed') + learners = request_serializer.validated_data.get('learners') try: policy = SubsidyAccessPolicy.objects.get(uuid=uuid) @@ -1051,6 +1054,7 @@ def get_group_member_data_with_aggregates(self, request, uuid): is_reversed=is_reversed, traverse_pagination=(traverse_pagination or sort_by_enrollment_count), page=page_requested_by_client, + learners=learners, ) member_results = member_response.get('results') diff --git a/enterprise_access/apps/api_client/lms_client.py b/enterprise_access/apps/api_client/lms_client.py index 32fd54ba..bbaa7db6 100755 --- a/enterprise_access/apps/api_client/lms_client.py +++ b/enterprise_access/apps/api_client/lms_client.py @@ -23,6 +23,7 @@ def all_pages_enterprise_group_members_cache_key( user_query, show_removed, is_reversed, + learners, ): """ helper method to retrieve the all enterprise group members cache key @@ -34,6 +35,7 @@ def all_pages_enterprise_group_members_cache_key( user_query, show_removed, is_reversed, + learners, ) @@ -161,6 +163,7 @@ def fetch_group_members( is_reversed=False, traverse_pagination=False, page=1, + learners=None, ): """ Fetches enterprise group member records from edx-platform. @@ -194,6 +197,8 @@ def fetch_group_members( params['show_removed'] = show_removed if is_reversed: params['is_reversed'] = is_reversed + if learners: + params['learners'] = learners if traverse_pagination: cache_key = all_pages_enterprise_group_members_cache_key( group_uuid, @@ -201,6 +206,7 @@ def fetch_group_members( user_query, show_removed, is_reversed, + learners, ) cached_response = TieredCache.get_cached_response(cache_key) if cached_response.is_found: