diff --git a/lti_consumer/lti_xblock.py b/lti_consumer/lti_xblock.py index 21b3e939..e0ab9a0b 100644 --- a/lti_consumer/lti_xblock.py +++ b/lti_consumer/lti_xblock.py @@ -685,7 +685,8 @@ def role(self): """ Get system user role and convert it to LTI role. """ - return ROLE_MAP.get(self.runtime.get_user_role(), 'Student') + role = self.runtime.service(self, 'user').get_current_user().opt_attrs.get('edx-platform.user_role', 'student') + return ROLE_MAP.get(role, 'Student') @property def course(self): @@ -723,11 +724,15 @@ def lti_provider_key_secret(self): def user_id(self): """ Returns the opaque anonymous_student_id for the current user. + This defaults to 'student' when testing in studio. + It will return the proper anonymous ID in the LMS. """ - user_id = self.runtime.anonymous_student_id + user_id = self.runtime.service(self, 'user').get_current_user().opt_attrs.get( + 'edx-platform.anonymous_user_id', None) + if user_id is None: raise LtiError(self.ugettext("Could not get user id for current request")) - return str(urllib.parse.quote(user_id)) + return str(user_id) def get_icon_class(self): """ Returns the icon class """ @@ -912,22 +917,20 @@ def extract_real_user_data(self): """ Extract and return real user data from the runtime """ + user = self.runtime.service(self, 'user').get_current_user() user_data = { 'user_email': None, 'user_username': None, 'user_language': None, } - if callable(self.runtime.get_real_user): - real_user_object = self.runtime.get_real_user(self.runtime.anonymous_student_id) - user_data['user_email'] = getattr(real_user_object, "email", "") - user_data['user_username'] = getattr(real_user_object, "username", "") - user_preferences = getattr(real_user_object, "preferences", None) + try: + user_data['user_email'] = user.emails[0] + except IndexError: + user_data['user_email'] = None - if user_preferences is not None: - language_preference = user_preferences.filter(key='pref-lang') - if len(language_preference) == 1: - user_data['user_language'] = language_preference[0].value + user_data['user_username'] = user.opt_attrs.get("edx-platform.username", None) + user_data['user_language'] = user.opt_attrs.get("edx-platform.user_preferences", {}).get("pref-lang", None) return user_data diff --git a/lti_consumer/tests/unit/test_lti_xblock.py b/lti_consumer/tests/unit/test_lti_xblock.py index 9a3e6a02..390438dd 100644 --- a/lti_consumer/tests/unit/test_lti_xblock.py +++ b/lti_consumer/tests/unit/test_lti_xblock.py @@ -5,7 +5,7 @@ import json import logging from datetime import timedelta -from unittest.mock import Mock, NonCallableMock, PropertyMock, patch +from unittest.mock import Mock, PropertyMock, patch import ddt from Cryptodome.PublicKey import RSA @@ -132,16 +132,29 @@ def test_role(self): """ Test `role` returns the correct LTI role string """ - self.xblock.runtime.get_user_role.return_value = 'student' + fake_user = Mock() + fake_user.opt_attrs = { + 'edx-platform.user_role': 'student' + } + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) self.assertEqual(self.xblock.role, 'Student') - self.xblock.runtime.get_user_role.return_value = 'guest' + fake_user.opt_attrs = { + 'edx-platform.user_role': 'guest' + } + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) self.assertEqual(self.xblock.role, 'Student') - self.xblock.runtime.get_user_role.return_value = 'staff' + fake_user.opt_attrs = { + 'edx-platform.user_role': 'staff' + } + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) self.assertEqual(self.xblock.role, 'Administrator') - self.xblock.runtime.get_user_role.return_value = 'instructor' + fake_user.opt_attrs = { + 'edx-platform.user_role': 'instructor' + } + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) self.assertEqual(self.xblock.role, 'Instructor') def test_course(self): @@ -218,21 +231,25 @@ def test_user_id(self): """ Test `user_id` returns the user_id string """ - self.xblock.runtime.anonymous_student_id = FAKE_USER_ID - self.assertEqual(self.xblock.user_id, FAKE_USER_ID) + fake_user = Mock() + fake_user.opt_attrs = { + 'edx-platform.anonymous_user_id': FAKE_USER_ID + } - def test_user_id_url_encoded(self): - """ - Test `user_id` url encodes the user id - """ - self.xblock.runtime.anonymous_student_id = 'user_id?&. ' - self.assertEqual(self.xblock.user_id, 'user_id%3F%26.%20') + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) + self.assertEqual(self.xblock.user_id, FAKE_USER_ID) def test_user_id_none(self): """ Test `user_id` raises LtiError when the user id cannot be returned """ - self.xblock.runtime.anonymous_student_id = None + fake_user = Mock() + fake_user.opt_attrs = { + 'edx-platform.anonymous_user_id': None + } + + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) + with self.assertRaises(LtiError): __ = self.xblock.user_id @@ -490,48 +507,47 @@ class TestExtractRealUserData(TestLtiConsumerXBlock): Unit tests for LtiConsumerXBlock.extract_real_user_data() """ - def test_get_real_user_not_callable(self): - """ - Test user_email, user_username, and user_language not available - """ - self.xblock.runtime.get_real_user = NonCallableMock() - - real_user_data = self.xblock.extract_real_user_data() - self.assertIsNone(real_user_data['user_email']) - self.assertIsNone(real_user_data['user_username']) - self.assertIsNone(real_user_data['user_language']) - def test_get_real_user_callable(self): """ Test user_email, and user_username available, but not user_language + See also documentation of new user service: + https://github.com/openedx/XBlock/blob/master/xblock/reference/user_service.py """ fake_user = Mock() - fake_user.email = 'abc@example.com' - fake_user.username = 'fake' - fake_user.preferences = None + fake_user_email = 'abc@example.com' + fake_user.emails = [fake_user_email] + fake_username = 'fake' + fake_user.opt_attrs = { + "edx-platform.username": fake_username + } - self.xblock.runtime.get_real_user = Mock(return_value=fake_user) + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) real_user_data = self.xblock.extract_real_user_data() - self.assertEqual(real_user_data['user_email'], fake_user.email) - self.assertEqual(real_user_data['user_username'], fake_user.username) + self.assertEqual(real_user_data['user_email'], fake_user_email) + self.assertEqual(real_user_data['user_username'], fake_username) self.assertIsNone(real_user_data['user_language']) def test_get_real_user_callable_with_language_preference(self): """ Test user_language available + See also documentation of new user service: + https://github.com/openedx/XBlock/blob/master/xblock/reference/user_service.py """ fake_user = Mock() - fake_user.email = 'abc@example.com' - fake_user.username = 'fake' - mock_language_pref = Mock() - mock_language_pref.value = PropertyMock(return_value='en') - fake_user.preferences.filter = Mock(return_value=[mock_language_pref]) + fake_user.emails = ['abc@example.com'] + fake_user.full_name = 'fake' + pref_language = "en" + fake_user.opt_attrs = { + "edx-platform.user_preferences": { + "pref-lang": "en" + } + } - self.xblock.runtime.get_real_user = Mock(return_value=fake_user) + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) real_user_data = self.xblock.extract_real_user_data() - self.assertEqual(real_user_data['user_language'], mock_language_pref.value) + self.assertEqual(real_user_data['user_language'], pref_language) class TestStudentView(TestLtiConsumerXBlock): @@ -630,7 +646,16 @@ def setUp(self): self.xblock._get_lti_consumer = Mock(return_value=self.mock_lti_consumer) # pylint: disable=protected-access self.xblock.due = timezone.now() self.xblock.graceperiod = timedelta(days=1) - self.xblock.runtime.get_real_user = Mock(return_value=None) + + fake_user = Mock() + fake_user_email = 'abc@example.com' + fake_user.emails = [fake_user_email] + fake_username = 'fake' + fake_user.opt_attrs = { + "edx-platform.username": fake_username + } + + self.xblock.runtime.service(self, 'user').get_current_user = Mock(return_value=fake_user) @patch('lti_consumer.lti_xblock.LtiConsumerXBlock.course') @patch('lti_consumer.lti_xblock.LtiConsumerXBlock.user_id', PropertyMock(return_value=FAKE_USER_ID))