Skip to content

Commit

Permalink
Merge pull request #584 from openedx/sameen/ENT-8351
Browse files Browse the repository at this point in the history
 feat: fetch LMS_USER_ID from LMS
  • Loading branch information
zamanafzal authored Feb 12, 2024
2 parents 9f8052a + 56dd2df commit 54b8202
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
15 changes: 13 additions & 2 deletions license_manager/apps/api/mixins.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from functools import cached_property

from rest_framework.exceptions import ParseError

from license_manager.apps.api import utils
from license_manager.apps.api_client.lms import LMSApiClient


class UserDetailsFromJwtMixin:
Expand All @@ -18,9 +21,17 @@ def decoded_jwt(self):

return utils.get_decoded_jwt(self.request)

@property
@cached_property
def lms_user_id(self):
return utils.get_key_from_jwt(self.decoded_jwt, 'user_id')
"""
Retrieve the LMS user ID.
"""
try:
return utils.get_key_from_jwt(self.decoded_jwt, 'user_id')
except ParseError:
lms_client = LMSApiClient()
user_id = lms_client.fetch_lms_user_id(self.request.user.email)
return user_id

@property
def user_email(self):
Expand Down
14 changes: 10 additions & 4 deletions license_manager/apps/api/v1/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3227,17 +3227,23 @@ def test_get_subsidy_missing_course_key(self):
assert response.status_code == status.HTTP_400_BAD_REQUEST

@mock.patch('license_manager.apps.api.v1.views.utils.get_decoded_jwt')
def test_get_subsidy_no_jwt(self, mock_get_decoded_jwt):
@mock.patch('license_manager.apps.api.mixins.LMSApiClient')
def test_get_subsidy_no_jwt(self, MockLMSApiClient, mock_get_decoded_jwt):
"""
Verify the view returns a 400 if the user_id could not be found in the JWT.
Verify the view makes an API call to fetch lmsUserId if user_id could not be found in the JWT.
"""
self._assign_learner_roles()
mock_get_decoded_jwt.return_value = {}
url = self._get_url_with_params()

# Mock the behavior of LMSApiClient to return a sample user ID
mock_lms_client = MockLMSApiClient.return_value
mock_lms_client.fetch_lms_user_id.return_value = 443
response = self.api_client.get(url)
assert status.HTTP_404_NOT_FOUND == response.status_code

assert status.HTTP_400_BAD_REQUEST == response.status_code
assert '`user_id` is required and could not be found in your jwt' in str(response.content)
# Assert that the LMSApiClient.fetch_lms_user_id method was called once with the correct argument
mock_lms_client.fetch_lms_user_id.assert_called_once_with(self.user.email)

def test_get_subsidy_no_subscription_for_enterprise_customer(self):
"""
Expand Down
43 changes: 43 additions & 0 deletions license_manager/apps/api_client/lms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import logging

import requests
from django.conf import settings

from license_manager.apps.api_client.base_oauth import BaseOAuthClient


logger = logging.getLogger(__name__)


class LMSApiClient(BaseOAuthClient):
"""
API client for calls to the LMS.
"""
api_base_url = settings.LMS_URL
user_details_endpoint = api_base_url + '/api/user/v1/accounts'

def fetch_lms_user_id(self, email):
"""
Fetch user details for the specified user email.
Arguments:
email (str): Email of the user for which we want to fetch details for.
Returns:
str: lms_user_id of the user.
"""
# {base_api_url}/api/user/v1/[email protected]
try:
query_params = {'email': email}
response = self.client.get(self.user_details_endpoint, params=query_params)
response.raise_for_status()
response_json = response.json()
return response_json[0].get('id')
except requests.exceptions.HTTPError as exc:
logger.error(
'Failed to fetch user details for user {email} because {reason}'.format(
email=email,
reason=str(exc),
)
)
raise exc

0 comments on commit 54b8202

Please sign in to comment.