diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index de217dbc24..937bda7a89 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -41,8 +41,7 @@ from openedx.core.lib.xblock_utils import ( request_token, wrap_fragment, wrap_xblock, - wrap_xblock_aside, - xblock_local_resource_url + wrap_xblock_aside ) from ..utils import get_visibility_partition_info @@ -94,61 +93,144 @@ def preview_handler(request, usage_key_string, handler, suffix=''): return webob_to_django_response(resp) +def handler_url(block, handler_name, suffix='', query='', thirdparty=False): + """ + Handler URL function for Preview + """ + return reverse('preview_handler', kwargs={ + 'usage_key_string': str(block.scope_ids.usage_id), + 'handler': handler_name, + 'suffix': suffix, + }) + '?' + query + + +def preview_applicable_aside_types(block, applicable_aside_types=None): + """ + Remove acid_aside and honor the config record + """ + if not StudioConfig.asides_enabled(block.scope_ids.block_type): + return [] + + # TODO: aside_type != 'acid_aside' check should be removed once AcidBlock is only installed during tests + # (see https://openedx.atlassian.net/browse/TE-811) + return [ + aside_type + for aside_type in applicable_aside_types(block) + if aside_type != 'acid_aside' + ] + + +def render_child_placeholder(block, view_name, context, wrap_xblock=None): + """ + Renders a placeholder XBlock. + """ + return wrap_xblock(block, view_name, Fragment(), context) + + +def preview_layout_asides(block, context, frag, view_name, aside_frag_fns, wrap_aside=None): + position_for_asides = '' + result = Fragment() + result.add_fragment_resources(frag) + + for aside, aside_fn in aside_frag_fns: + aside_frag = aside_fn(block, context) + if aside_frag.content != '': + aside_frag_wrapped = wrap_aside(block, aside, view_name, aside_frag, context) + aside.save() + result.add_fragment_resources(aside_frag_wrapped) + replacement = position_for_asides + aside_frag_wrapped.content + frag.content = frag.content.replace(position_for_asides, replacement) + + result.add_content(frag.content) + return result + + class PreviewModuleSystem(DescriptorSystem): # pylint: disable=abstract-method """ An XModule ModuleSystem for use in Studio previews """ # xblocks can check for this attribute during rendering to determine if # they are being rendered for preview (i.e. in Studio) - is_author_mode = True + ####################### + ####################### + ## Set directly to system below + ####################### + ####################### + # is_author_mode = True - def handler_url(self, block, handler_name, suffix='', query='', thirdparty=False): - return reverse('preview_handler', kwargs={ - 'usage_key_string': str(block.scope_ids.usage_id), - 'handler': handler_name, - 'suffix': suffix, - }) + '?' + query + ####################### + ####################### + ## Implemented as handler_url above + ####################### + ####################### + # def handler_url(self, block, handler_name, suffix='', query='', thirdparty=False): + # return reverse('preview_handler', kwargs={ + # 'usage_key_string': str(block.scope_ids.usage_id), + # 'handler': handler_name, + # 'suffix': suffix, + # }) + '?' + query - def local_resource_url(self, block, uri): - return xblock_local_resource_url(block, uri) + ####################### + ####################### + ## Being monkey patched in Descriptor system from cms.djangoapps.xblock_config.apps.py + ####################### + ####################### + # def local_resource_url(self, block, uri): + # return xblock_local_resource_url(block, uri) - def applicable_aside_types(self, block): - """ - Remove acid_aside and honor the config record - """ - if not StudioConfig.asides_enabled(block.scope_ids.block_type): - return [] + ####################### + ####################### + ## Implemented as preview_applicable_aside_types above + ####################### + ####################### + # def applicable_aside_types(self, block): + # """ + # Remove acid_aside and honor the config record + # """ + # if not StudioConfig.asides_enabled(block.scope_ids.block_type): + # return [] - # TODO: aside_type != 'acid_aside' check should be removed once AcidBlock is only installed during tests - # (see https://openedx.atlassian.net/browse/TE-811) - return [ - aside_type - for aside_type in super().applicable_aside_types(block) - if aside_type != 'acid_aside' - ] + # # TODO: aside_type != 'acid_aside' check should be removed once AcidBlock is only installed during tests + # # (see https://openedx.atlassian.net/browse/TE-811) + # return [ + # aside_type + # for aside_type in super().applicable_aside_types(block) + # if aside_type != 'acid_aside' + # ] - def render_child_placeholder(self, block, view_name, context): - """ - Renders a placeholder XBlock. - """ - return self.wrap_xblock(block, view_name, Fragment(), context) + ####################### + ####################### + ## Implemented as render_child_placeholder above + ####################### + ####################### + # def render_child_placeholder(self, block, view_name, context): + # """ + # Renders a placeholder XBlock. + # """ + # return self.wrap_xblock(block, view_name, Fragment(), context) - def layout_asides(self, block, context, frag, view_name, aside_frag_fns): - position_for_asides = '' - result = Fragment() - result.add_fragment_resources(frag) + + ####################### + ####################### + ## Implemented as preview_layout_asides above + ####################### + ####################### + # def layout_asides(self, block, context, frag, view_name, aside_frag_fns): + # position_for_asides = '' + # result = Fragment() + # result.add_fragment_resources(frag) - for aside, aside_fn in aside_frag_fns: - aside_frag = aside_fn(block, context) - if aside_frag.content != '': - aside_frag_wrapped = self.wrap_aside(block, aside, view_name, aside_frag, context) - aside.save() - result.add_fragment_resources(aside_frag_wrapped) - replacement = position_for_asides + aside_frag_wrapped.content - frag.content = frag.content.replace(position_for_asides, replacement) + # for aside, aside_fn in aside_frag_fns: + # aside_frag = aside_fn(block, context) + # if aside_frag.content != '': + # aside_frag_wrapped = self.wrap_aside(block, aside, view_name, aside_frag, context) + # aside.save() + # result.add_fragment_resources(aside_frag_wrapped) + # replacement = position_for_asides + aside_frag_wrapped.content + # frag.content = frag.content.replace(position_for_asides, replacement) - result.add_content(frag.content) - return result + # result.add_content(frag.content) + # return result def _preview_module_system(request, descriptor, field_data): @@ -206,35 +288,74 @@ def _preview_module_system(request, descriptor, field_data): else: preview_anonymous_user_id = anonymous_id_for_user(request.user, course_id) - return PreviewModuleSystem( - load_item=descriptor._runtime.load_item, - resources_fs=descriptor._runtime.resources_fs, - error_tracker=descriptor._runtime.error_tracker, - get_block=partial(_load_preview_block, request), - mixins=settings.XBLOCK_MIXINS, + services={ + "field-data": field_data, + "i18n": XBlockI18nService, + 'mako': mako_service, + "settings": SettingsService(), + "user": DjangoXBlockUserService( + request.user, + user_role=get_user_role(request.user, course_id), + anonymous_user_id=preview_anonymous_user_id, + ), + "partitions": StudioPartitionService(course_id=course_id), + "teams_configuration": TeamsConfigurationService(), + "sandbox": SandboxService(contentstore=contentstore, course_id=course_id), + "cache": CacheService(cache), + 'replace_urls': replace_url_service + } - # Set up functions to modify the fragment produced by student_view - wrappers=wrappers, - wrappers_asides=wrappers_asides, - # Get the raw DescriptorSystem, not the CombinedSystem - descriptor_runtime=descriptor._runtime, # pylint: disable=protected-access - services={ - "field-data": field_data, - "i18n": XBlockI18nService, - 'mako': mako_service, - "settings": SettingsService(), - "user": DjangoXBlockUserService( - request.user, - user_role=get_user_role(request.user, course_id), - anonymous_user_id=preview_anonymous_user_id, - ), - "partitions": StudioPartitionService(course_id=course_id), - "teams_configuration": TeamsConfigurationService(), - "sandbox": SandboxService(contentstore=contentstore, course_id=course_id), - "cache": CacheService(cache), - 'replace_urls': replace_url_service - }, + # system = PreviewModuleSystem( + # load_item=descriptor._runtime.load_item, + # resources_fs=descriptor._runtime.resources_fs, + # error_tracker=descriptor._runtime.error_tracker, + # # get_module=partial(_load_preview_module, request), + # # mixins=settings.XBLOCK_MIXINS, + + # # Set up functions to modify the fragment produced by student_view + # # wrappers=wrappers, + # # wrappers_asides=wrappers_asides, + # # Get the raw DescriptorSystem, not the CombinedSystem + # # descriptor_runtime=descriptor._runtime, # pylint: disable=protected-access + # # services={ + # # "field-data": field_data, + # # "i18n": ModuleI18nService, + # # 'mako': mako_service, + # # "settings": SettingsService(), + # # "user": DjangoXBlockUserService( + # # request.user, + # # user_role=get_user_role(request.user, course_id), + # # anonymous_user_id=preview_anonymous_user_id, + # # ), + # # "partitions": StudioPartitionService(course_id=course_id), + # # "teams_configuration": TeamsConfigurationService(), + # # "sandbox": SandboxService(contentstore=contentstore, course_id=course_id), + # # "cache": CacheService(cache), + # # 'replace_urls': replace_url_service + # # }, + # ) + + descriptor._runtime.get_block = partial(_load_preview_block, request), + descriptor._runtime.mixins = settings.XBLOCK_MIXINS + + # Set up functions to modify the fragment produced by student_view + descriptor._runtime.wrappers = wrappers + descriptor._runtime.wrappers_asides=wrappers_asides + descriptor._runtime._services.update(services) + + descriptor._runtime.is_author_mode = True + descriptor._runtime.handler_url_override = handler_url + descriptor._runtime.applicable_aside_types_override = preview_applicable_aside_types + descriptor._runtime.render_child_placeholder = partial( + render_child_placeholder, + wrap_xblock = descriptor._runtime.wrap_xblock ) + descriptor._runtime.layout_asides_override = partial( + preview_layout_asides, + wrap_aside = descriptor._runtime.wrap_aside + ) + + return descriptor._runtime class StudioPartitionService(PartitionService): diff --git a/lms/djangoapps/courseware/block_render.py b/lms/djangoapps/courseware/block_render.py index 87ea56c517..05b8fec291 100644 --- a/lms/djangoapps/courseware/block_render.py +++ b/lms/djangoapps/courseware/block_render.py @@ -67,7 +67,7 @@ from lms.djangoapps.courseware.field_overrides import OverrideFieldData from lms.djangoapps.courseware.services import UserStateService from lms.djangoapps.grades.api import GradesUtilService from lms.djangoapps.lms_xblock.field_data import LmsFieldData -from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem, UserTagsService +from lms.djangoapps.lms_xblock.runtime import UserTagsService, lms_wrappers_aside, lms_applicable_aside_types from lms.djangoapps.verify_student.services import XBlockVerificationService from openedx.core.djangoapps.bookmarks.api import BookmarksService from openedx.core.djangoapps.crawlers.models import CrawlersConfig @@ -587,50 +587,94 @@ def get_module_system_for_user( store = modulestore() - system = LmsModuleSystem( - load_item=descriptor._runtime.load_item, - resources_fs=descriptor._runtime.resources_fs, - error_tracker=descriptor._runtime.error_tracker, - get_block=inner_get_block, - # TODO: When we merge the descriptor and module systems, we can stop reaching into the mixologist (cpennington) - mixins=descriptor.runtime.mixologist._mixins, # pylint: disable=protected-access - wrappers=block_wrappers, - services={ - 'fs': FSService(), - 'field-data': field_data, - 'mako': mako_service, - 'user': user_service, - 'verification': XBlockVerificationService(), - 'proctoring': ProctoringService(), - 'milestones': milestones_helpers.get_service(), - 'credit': CreditService(), - 'bookmarks': BookmarksService(user=user), - 'gating': GatingService(), - 'grade_utils': GradesUtilService(course_id=course_id), - 'user_state': UserStateService(), - 'content_type_gating': ContentTypeGatingService(), - 'cache': CacheService(cache), - 'sandbox': SandboxService(contentstore=contentstore, course_id=course_id), - 'xqueue': xqueue_service, - 'replace_urls': replace_url_service, - 'rebind_user': rebind_user_service, - 'completion': CompletionService(user=user, context_key=course_id) - if user and user.is_authenticated - else None, - 'i18n': XBlockI18nService, - 'library_tools': LibraryToolsService(store, user_id=user.id if user else None), - 'partitions': PartitionService(course_id=course_id, cache=DEFAULT_REQUEST_CACHE.data), - 'settings': SettingsService(), - 'user_tags': UserTagsService(user=user, course_id=course_id), - 'badging': BadgingService(course_id=course_id, modulestore=store) if badges_enabled() else None, - 'teams': TeamsService(), - 'teams_configuration': TeamsConfigurationService(), - 'call_to_action': CallToActionService(), - 'publish': EventPublishingService(user, course_id, track_function), - }, - descriptor_runtime=descriptor._runtime, # pylint: disable=protected-access - request_token=request_token, - ) + services={ + 'fs': FSService(), + 'field-data': field_data, + 'mako': mako_service, + 'user': user_service, + 'verification': XBlockVerificationService(), + 'proctoring': ProctoringService(), + 'milestones': milestones_helpers.get_service(), + 'credit': CreditService(), + 'bookmarks': BookmarksService(user=user), + 'gating': GatingService(), + 'grade_utils': GradesUtilService(course_id=course_id), + 'user_state': UserStateService(), + 'content_type_gating': ContentTypeGatingService(), + 'cache': CacheService(cache), + 'sandbox': SandboxService(contentstore=contentstore, course_id=course_id), + 'xqueue': xqueue_service, + 'replace_urls': replace_url_service, + 'rebind_user': rebind_user_service, + 'completion': CompletionService(user=user, context_key=course_id) + if user and user.is_authenticated + else None, + 'i18n': XBlockI18nService, + 'library_tools': LibraryToolsService(store, user_id=user.id if user else None), + 'partitions': PartitionService(course_id=course_id, cache=DEFAULT_REQUEST_CACHE.data), + 'settings': SettingsService(), + 'user_tags': UserTagsService(user=user, course_id=course_id), + 'badging': BadgingService(course_id=course_id, modulestore=store) if badges_enabled() else None, + 'teams': TeamsService(), + 'teams_configuration': TeamsConfigurationService(), + 'call_to_action': CallToActionService(), + 'publish': EventPublishingService(user, course_id, track_function), + } + + + # system = LmsModuleSystem( + # load_item=descriptor._runtime.load_item, + # resources_fs=descriptor._runtime.resources_fs, + # error_tracker=descriptor._runtime.error_tracker, + # # get_module=inner_get_module, + # # TODO: When we merge the descriptor and module systems, we can stop reaching into the mixologist (cpennington) + # # mixins=descriptor.runtime.mixologist._mixins, # pylint: disable=protected-access + # # wrappers=block_wrappers, + # # services={ + # # 'fs': FSService(), + # # 'field-data': field_data, + # # 'mako': mako_service, + # # 'user': user_service, + # # 'verification': XBlockVerificationService(), + # # 'proctoring': ProctoringService(), + # # 'milestones': milestones_helpers.get_service(), + # # 'credit': CreditService(), + # # 'bookmarks': BookmarksService(user=user), + # # 'gating': GatingService(), + # # 'grade_utils': GradesUtilService(course_id=course_id), + # # 'user_state': UserStateService(), + # # 'content_type_gating': ContentTypeGatingService(), + # # 'cache': CacheService(cache), + # # 'sandbox': SandboxService(contentstore=contentstore, course_id=course_id), + # # 'xqueue': xqueue_service, + # # 'replace_urls': replace_url_service, + # # 'rebind_user': rebind_user_service, + # # 'completion': CompletionService(user=user, context_key=course_id) + # # if user and user.is_authenticated + # # else None, + # # 'i18n': ModuleI18nService, + # # 'library_tools': LibraryToolsService(store, user_id=user.id if user else None), + # # 'partitions': PartitionService(course_id=course_id, cache=DEFAULT_REQUEST_CACHE.data), + # # 'settings': SettingsService(), + # # 'user_tags': UserTagsService(user=user, course_id=course_id), + # # 'badging': BadgingService(course_id=course_id, modulestore=store) if badges_enabled() else None, + # # 'teams': TeamsService(), + # # 'teams_configuration': TeamsConfigurationService(), + # # 'call_to_action': CallToActionService(), + # # 'publish': EventPublishingService(user, course_id, track_function), + # # }, + # # descriptor_runtime=descriptor._runtime, # pylint: disable=protected-access + # # request_token=request_token, + # ) + + descriptor._runtime.get_block = inner_get_block + descriptor._runtime.mixins = descriptor.runtime.mixologist._mixins + descriptor._runtime.wrappers = block_wrappers + descriptor._runtime._services.update(services) + descriptor._runtime.request_token = request_token + + descriptor._runtime.wrap_asides_override = lms_wrappers_aside + descriptor._runtime.applicable_aside_types_override = lms_applicable_aside_types # pass position specified in URL to module through ModuleSystem if position is not None: @@ -640,14 +684,14 @@ def get_module_system_for_user( log.exception('Non-integer %r passed as position.', position) position = None - system.set('position', position) + descriptor._runtime.set('position', position) - system.set('user_is_staff', user_is_staff) - system.set('user_is_admin', bool(has_access(user, 'staff', 'global'))) - system.set('user_is_beta_tester', CourseBetaTesterRole(course_id).has_user(user)) - system.set('days_early_for_beta', descriptor.days_early_for_beta) + descriptor._runtime.set('user_is_staff', user_is_staff) + descriptor._runtime.set('user_is_admin', bool(has_access(user, 'staff', 'global'))) + descriptor._runtime.set('user_is_beta_tester', CourseBetaTesterRole(course_id).has_user(user)) + descriptor._runtime.set('days_early_for_beta', descriptor.days_early_for_beta) - return system, field_data + return descriptor._runtime, field_data # TODO: Find all the places that this method is called and figure out how to diff --git a/lms/djangoapps/lms_xblock/runtime.py b/lms/djangoapps/lms_xblock/runtime.py index ac7f2aa568..9b5aacd9c2 100644 --- a/lms/djangoapps/lms_xblock/runtime.py +++ b/lms/djangoapps/lms_xblock/runtime.py @@ -72,6 +72,64 @@ def local_resource_url(block, uri): return xblock_local_resource_url(block, uri) +def lms_wrappers_aside(block, aside, view, frag, context, request_token=None): + """ + Creates a div which identifies the aside, points to the original block, + and writes out the json_init_args into a script tag. + + The default implementation creates a frag to wraps frag w/ a div identifying the xblock. If you have + javascript, you'll need to override this impl + """ + if not frag.content: + return frag + + runtime_class = 'LmsRuntime' + extra_data = { + 'block-id': quote_slashes(str(block.scope_ids.usage_id)), + 'course-id': quote_slashes(str(block.scope_ids.usage_id.context_key)), + 'url-selector': 'asideBaseUrl', + 'runtime-class': runtime_class, + } + if request_token: + extra_data['request-token'] = request_token + + return wrap_xblock_aside( + runtime_class, + aside, + view, + frag, + context, + usage_id_serializer=str, + request_token=request_token, + extra_data=extra_data, + ) + + +def lms_applicable_aside_types(block, applicable_aside_types=None): + """ + Return all of the asides which might be decorating this `block`. + + Arguments: + block (:class:`.XBlock`): The block to render retrieve asides for. + """ + + config = XBlockAsidesConfig.current() + + if not config.enabled: + return [] + + if block.scope_ids.block_type in config.disabled_blocks.split(): + return [] + + # TODO: aside_type != 'acid_aside' check should be removed once AcidBlock is only installed during tests + # (see https://openedx.atlassian.net/browse/TE-811) + return [ + aside_type + for aside_type in applicable_aside_types(block) + if aside_type != 'acid_aside' + ] + + class UserTagsService: """ A runtime class that provides an interface to the user service. It handles filling in @@ -121,85 +179,114 @@ class LmsModuleSystem(DescriptorSystem): # pylint: disable=abstract-method ModuleSystem specialized to the LMS """ def __init__(self, **kwargs): - self.request_token = kwargs.pop('request_token', None) + ####################### + ####################### + ## Set Directly from module_render + ####################### + ####################### + # self.request_token = kwargs.pop('request_token', None) super().__init__(**kwargs) - def handler_url(self, *args, **kwargs): # lint-amnesty, pylint: disable=signature-differs - """ - Implement the XBlock runtime handler_url interface. + ####################### + ####################### + ## Being monkey patched in Descriptor system from lms.djangoapps.lms_xblock.apps.py + ####################### + ####################### - This is mostly just proxying to the module level `handler_url` function - defined higher up in this file. + # def handler_url(self, *args, **kwargs): # lint-amnesty, pylint: disable=signature-differs + # """ + # Implement the XBlock runtime handler_url interface. - We're doing this indirection because the module level `handler_url` - logic is also needed by the `DescriptorSystem`. The particular - `handler_url` that a `DescriptorSystem` needs will be different when - running an LMS process or a CMS/Studio process. That's accomplished by - monkey-patching a global. It's a long story, but please know that you - can't just refactor and fold that logic into here without breaking - things. + # This is mostly just proxying to the module level `handler_url` function + # defined higher up in this file. - https://openedx.atlassian.net/wiki/display/PLAT/Convert+from+Storage-centric+runtimes+to+Application-centric+runtimes + # We're doing this indirection because the module level `handler_url` + # logic is also needed by the `DescriptorSystem`. The particular + # `handler_url` that a `DescriptorSystem` needs will be different when + # running an LMS process or a CMS/Studio process. That's accomplished by + # monkey-patching a global. It's a long story, but please know that you + # can't just refactor and fold that logic into here without breaking + # things. - See :method:`xblock.runtime:Runtime.handler_url` - """ - return handler_url(*args, **kwargs) + # https://openedx.atlassian.net/wiki/display/PLAT/Convert+from+Storage-centric+runtimes+to+Application-centric+runtimes - def local_resource_url(self, *args, **kwargs): - return local_resource_url(*args, **kwargs) + # See :method:`xblock.runtime:Runtime.handler_url` + # """ + # return handler_url(*args, **kwargs) - def wrap_aside(self, block, aside, view, frag, context): - """ - Creates a div which identifies the aside, points to the original block, - and writes out the json_init_args into a script tag. + ####################### + ####################### + ## Being monkey patched in Descriptor system from lms.djangoapps.lms_xblock.apps.py + ####################### + ####################### - The default implementation creates a frag to wraps frag w/ a div identifying the xblock. If you have - javascript, you'll need to override this impl - """ - if not frag.content: - return frag + # def local_resource_url(self, *args, **kwargs): + # return local_resource_url(*args, **kwargs) - runtime_class = 'LmsRuntime' - extra_data = { - 'block-id': quote_slashes(str(block.scope_ids.usage_id)), - 'course-id': quote_slashes(str(block.course_id)), - 'url-selector': 'asideBaseUrl', - 'runtime-class': runtime_class, - } - if self.request_token: - extra_data['request-token'] = self.request_token + ####################### + ####################### + ## Implemented as lms_wrappers_aside above + ####################### + ####################### - return wrap_xblock_aside( - runtime_class, - aside, - view, - frag, - context, - usage_id_serializer=str, - request_token=self.request_token, - extra_data=extra_data, - ) + # def wrap_aside(self, block, aside, view, frag, context): + # """ + # Creates a div which identifies the aside, points to the original block, + # and writes out the json_init_args into a script tag. - def applicable_aside_types(self, block): - """ - Return all of the asides which might be decorating this `block`. + # The default implementation creates a frag to wraps frag w/ a div identifying the xblock. If you have + # javascript, you'll need to override this impl + # """ + # if not frag.content: + # return frag - Arguments: - block (:class:`.XBlock`): The block to render retrieve asides for. - """ + # runtime_class = 'LmsRuntime' + # extra_data = { + # 'block-id': quote_slashes(str(block.scope_ids.usage_id)), + # 'course-id': quote_slashes(str(block.course_id)), + # 'url-selector': 'asideBaseUrl', + # 'runtime-class': runtime_class, + # } + # if self.request_token: + # extra_data['request-token'] = self.request_token - config = XBlockAsidesConfig.current() + # return wrap_xblock_aside( + # runtime_class, + # aside, + # view, + # frag, + # context, + # usage_id_serializer=str, + # request_token=self.request_token, + # extra_data=extra_data, + # ) - if not config.enabled: - return [] + ####################### + ####################### + ## Implemented as lms_applicable_aside_types above + ####################### + ####################### - if block.scope_ids.block_type in config.disabled_blocks.split(): - return [] + # def applicable_aside_types(self, block): + # """ + # Return all of the asides which might be decorating this `block`. - # TODO: aside_type != 'acid_aside' check should be removed once AcidBlock is only installed during tests - # (see https://openedx.atlassian.net/browse/TE-811) - return [ - aside_type - for aside_type in super().applicable_aside_types(block) - if aside_type != 'acid_aside' - ] + # Arguments: + # block (:class:`.XBlock`): The block to render retrieve asides for. + # """ + + # config = XBlockAsidesConfig.current() + + # if not config.enabled: + # return [] + + # if block.scope_ids.block_type in config.disabled_blocks.split(): + # return [] + + # # TODO: aside_type != 'acid_aside' check should be removed once AcidBlock is only installed during tests + # # (see https://openedx.atlassian.net/browse/TE-811) + # return [ + # aside_type + # for aside_type in super().applicable_aside_types(block) + # if aside_type != 'acid_aside' + # ] diff --git a/xmodule/x_module.py b/xmodule/x_module.py index d99a549f3e..04d4d41970 100644 --- a/xmodule/x_module.py +++ b/xmodule/x_module.py @@ -1420,17 +1420,8 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemSh """ Base class for :class:`Runtime`s to be used with :class:`XModuleDescriptor`s """ - - def get(self, attr): - """ provide uniform access to attributes (like etree).""" - return self.__dict__.get(attr) - - def set(self, attr, val): - """provide uniform access to attributes (like etree)""" - self.__dict__[attr] = val - def __init__( - self, load_item, resources_fs, error_tracker, descriptor_runtime=None, get_policy=None, disabled_xblock_types=lambda: [], get_module=None, **kwargs + self, load_item, resources_fs, error_tracker, get_policy=None, disabled_xblock_types=lambda: [], get_module=None, **kwargs ): """ load_item: Takes a Location and returns an XModuleDescriptor @@ -1467,7 +1458,10 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemSh self.disabled_xblock_types = disabled_xblock_types self.get_module = get_module - self.descriptor_runtime = descriptor_runtime + # self.handler_url_override = None + # self.applicable_aside_types_override = None + # self.wrap_asides_override = None + # self.layout_asides_override = None def get(self, attr): """ provide uniform access to attributes (like etree).""" @@ -1479,11 +1473,10 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemSh def get_block(self, usage_id, for_parent=None): """See documentation for `xblock.runtime:Runtime.get_block`""" + block = self.load_item(usage_id, for_parent=for_parent) if self.get_module: - # return self.get_module(block) - return self.get_module(self.descriptor_runtime.get_block(usage_id, for_parent=for_parent)) - - return self.load_item(usage_id, for_parent=for_parent) + return self.get_module(block) + return block def load_block_type(self, block_type): """ @@ -1522,6 +1515,8 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemSh # This means that LMS/CMS don't have a way to define a subclass of DescriptorSystem # that implements the correct handler url. So, for now, instead, we will reference a # global function that the application can override. + if getattr(self, 'handler_url_override', None): + return self.handler_url_override(block, handler_name, suffix, query, thirdparty) return descriptor_global_handler_url(block, handler_name, suffix, query, thirdparty) def local_resource_url(self, block, uri): @@ -1538,6 +1533,9 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemSh """ See :meth:`xblock.runtime.Runtime:applicable_aside_types` for documentation. """ + if getattr(self, 'applicable_aside_types_override', None): + return self.applicable_aside_types_override(block, applicable_aside_types=super().applicable_aside_types) + potential_set = set(super().applicable_aside_types(block)) if getattr(block, 'xmodule_runtime', None) is not None: if hasattr(block.xmodule_runtime, 'applicable_aside_types'): @@ -1586,6 +1584,16 @@ class DescriptorSystem(MetricsMixin, ConfigurableFragmentWrapper, ModuleSystemSh return service(block) return service + def wrap_aside(self, block, aside, view, frag, context): + if getattr(self, 'wrap_asides_override', None): + return self.wrap_asides_override(block, aside, view, frag, context, request_token=self.request_token) + return super().wrap_aside(block, aside, view, frag, context) + + def layout_asides(self, block, context, frag, view_name, aside_frag_fns): + if getattr(self, 'layout_asides_override', None): + return self.layout_asides_override(block, context, frag, view_name, aside_frag_fns) + return super().layout_asides(block, context, frag, view_name, aside_frag_fns) + class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring def __init__(self, process_xml, **kwargs): @@ -1702,6 +1710,7 @@ class XMLParsingSystem(DescriptorSystem): # lint-amnesty, pylint: disable=abstr field_value[key] = self._make_usage_key(course_key, subvalue) setattr(xblock, field.name, field_value) + class CombinedSystem: """ This class is a shim to allow both pure XBlocks and XModuleDescriptors