From c24c87499f75893fbb6b35b2573f361c84a142ab Mon Sep 17 00:00:00 2001 From: Jade Olivier Date: Tue, 30 Jul 2024 11:03:03 +0200 Subject: [PATCH] feat: Commerce Coordinator step in retirement pipeline --- .../tests/utils/test_edx_api.py | 39 +++++++++++++++++++ scripts/user_retirement/utils/edx_api.py | 14 +++++++ scripts/user_retirement/utils/helpers.py | 13 ++++++- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/scripts/user_retirement/tests/utils/test_edx_api.py b/scripts/user_retirement/tests/utils/test_edx_api.py index eb826cd1a4..037ea68628 100644 --- a/scripts/user_retirement/tests/utils/test_edx_api.py +++ b/scripts/user_retirement/tests/utils/test_edx_api.py @@ -542,3 +542,42 @@ class TestLicenseManagerApi(OAuth2Mixin, unittest.TestCase): original_username=FAKE_ORIGINAL_USERNAME ) ) + + +class TestCommerceCoordinatorApi(OAuth2Mixin, unittest.TestCase): + """ + Test the edX Commerce-Coordinator API client. + """ + + @responses.activate(registry=OrderedRegistry) + def setUp(self): + super().setUp() + self.mock_access_token_response() + self.lms_base_url = 'http://localhost:18000/' + self.commerce_coordinator_base_url = 'http://localhost:8140/' + self.commerce_coordinator_api = edx_api.CommerceCoordinatorApi( + self.lms_base_url, + self.commerce_coordinator_base_url, + 'the_client_id', + 'the_client_secret' + ) + + @patch.object(edx_api.CommerceCoordinatorApi, '_request') + def test_retire_learner(self, mock_request): + learner_data = get_fake_user_retirement() + json_data = { + 'edx_lms_user_id': learner_data['user']['id'] + } + responses.add( + POST, + urljoin(self.commerce_coordinator_base_url, 'lms/user_retirement'), + match=[matchers.json_params_matcher(json_data)] + ) + + self.commerce_coordinator_api.retire_learner(learner=learner_data) + + mock_request.assert_called_once_with( + 'POST', + urljoin(self.commerce_coordinator_base_url, 'lms/user_retirement/'), + json=json_data + ) diff --git a/scripts/user_retirement/utils/edx_api.py b/scripts/user_retirement/utils/edx_api.py index e891f04019..f77675fcbc 100644 --- a/scripts/user_retirement/utils/edx_api.py +++ b/scripts/user_retirement/utils/edx_api.py @@ -490,3 +490,17 @@ class LicenseManagerApi(BaseApiClient): except HttpDoesNotExistException: LOG.info("No license manager data found for user") return True + +class CommerceCoordinatorApi(BaseApiClient): + """ + Commerce-Coordinator API client. + """ + @_retry_lms_api() + def retire_learner(self, learner): + """ + Performs the learner retirement step for Commerce-Coordinator. + Passes the learner's LMS User Id instead of username. + """ + data = {'edx_lms_user_id': learner['user']['id']} + api_url = self.get_api_url('lms/user_retirement') + return self._request('POST', api_url, json=data) diff --git a/scripts/user_retirement/utils/helpers.py b/scripts/user_retirement/utils/helpers.py index 1bcbadb4b3..42723b0999 100644 --- a/scripts/user_retirement/utils/helpers.py +++ b/scripts/user_retirement/utils/helpers.py @@ -18,7 +18,8 @@ import yaml from six import text_type from scripts.user_retirement.utils.edx_api import LmsApi # pylint: disable=wrong-import-position -from scripts.user_retirement.utils.edx_api import CredentialsApi, EcommerceApi, LicenseManagerApi +from scripts.user_retirement.utils.edx_api import CommerceCoordinatorApi, CredentialsApi, EcommerceApi, \ + LicenseManagerApi from scripts.user_retirement.utils.thirdparty_apis.amplitude_api import \ AmplitudeApi # pylint: disable=wrong-import-position from scripts.user_retirement.utils.thirdparty_apis.braze_api import BrazeApi # pylint: disable=wrong-import-position @@ -154,6 +155,7 @@ def _setup_all_apis_or_exit(fail_func, fail_code, config): credentials_base_url = config['base_urls'].get('credentials', None) segment_base_url = config['base_urls'].get('segment', None) license_manager_base_url = config['base_urls'].get('license_manager', None) + commerce_coordinator_base_url = config['base_urls'].get('commerce_coordinator', None) client_id = config['client_id'] client_secret = config['client_secret'] braze_api_key = config.get('braze_api_key', None) @@ -180,6 +182,7 @@ def _setup_all_apis_or_exit(fail_func, fail_code, config): ('CREDENTIALS', credentials_base_url), ('SEGMENT', segment_base_url), ('HUBSPOT', hubspot_api_key), + ('COMMERCE_COORDINATOR', commerce_coordinator_base_url), ): if state[2] == service and service_url is None: fail_func(fail_code, 'Service URL is not configured, but required for state {}'.format(state)) @@ -235,5 +238,13 @@ def _setup_all_apis_or_exit(fail_func, fail_code, config): segment_auth_token, segment_workspace_slug ) + + if commerce_coordinator_base_url: + config['COMMERCE_COORDINATOR'] = CommerceCoordinatorApi( + lms_base_url, + commerce_coordinator_base_url, + client_id, + client_secret, + ) except Exception as exc: # pylint: disable=broad-except fail_func(fail_code, 'Unexpected error occurred!', exc)