diff --git a/lti_consumer/models.py b/lti_consumer/models.py index ac4fb7b7..eafe48f9 100644 --- a/lti_consumer/models.py +++ b/lti_consumer/models.py @@ -11,6 +11,7 @@ from lti_consumer.lti_1p1.consumer import LtiConsumer1p1 # LTI 1.3 from lti_consumer.lti_1p3.consumer import LtiAdvantageConsumer +from lti_consumer.plugin import compat from lti_consumer.utils import get_lms_base, get_lti_ags_lineitems_url @@ -77,11 +78,7 @@ def block(self): if block is None: if self.location is None: raise ValueError("Block location not set, it's not possible to retrieve the block.") - - # Import on runtime only - # pylint: disable=import-outside-toplevel,import-error - from xmodule.modulestore.django import modulestore - block = self._block = modulestore().get_item(self.location) + block = self._block = compat.load_block_as_anonymous_user(self.location) return block @block.setter diff --git a/lti_consumer/plugin/compat.py b/lti_consumer/plugin/compat.py index 68994bf4..8d22f02c 100644 --- a/lti_consumer/plugin/compat.py +++ b/lti_consumer/plugin/compat.py @@ -19,3 +19,33 @@ def run_xblock_handler_noauth(*args, **kwargs): # pylint: disable=import-error,import-outside-toplevel from lms.djangoapps.courseware.module_render import handle_xblock_callback_noauth return handle_xblock_callback_noauth(*args, **kwargs) + + +def load_block_as_anonymous_user(location): + """ + Load a block as anonymous user. + + This uses a few internal courseware methods to retrieve the descriptor + and bind an AnonymousUser to it, in a similar fashion as a `noauth` XBlock + handler. + """ + # pylint: disable=import-error,import-outside-toplevel + from django.contrib.auth.models import AnonymousUser + from xmodule.modulestore.django import modulestore + from lms.djangoapps.courseware.module_render import get_module_for_descriptor_internal + + # Retrieve descriptor from modulestore + descriptor = modulestore().get_item(location) + + # Load block, attaching it to AnonymousUser + get_module_for_descriptor_internal( + user=AnonymousUser(), + descriptor=descriptor, + student_data=None, + course_id=location.course_key, + track_function=None, + xqueue_callback_url_prefix="", + request_token="", + ) + + return descriptor diff --git a/lti_consumer/tests/unit/test_models.py b/lti_consumer/tests/unit/test_models.py index d419eb2b..67dcfe3f 100644 --- a/lti_consumer/tests/unit/test_models.py +++ b/lti_consumer/tests/unit/test_models.py @@ -108,6 +108,24 @@ def test_lti_consumer_ags_enabled(self): } ) + @patch("lti_consumer.models.compat") + def test_block_property(self, compat_mock): + """ + Check if a block is properly loaded when calling the `block` property. + """ + compat_mock.load_block_as_anonymous_user.return_value = self.xblock + + block = self.lti_1p3_config.block + self.assertEqual(block, self.xblock) + + def test_block_property_missing_location(self): + """ + Check the `block` property raises when failing to retrieve a block. + """ + self.lti_1p3_config.location = None + with self.assertRaises(ValueError): + _ = self.lti_1p3_config.block + class TestLtiAgsLineItemModel(TestCase): """