From 78b691b56a8ef126ef5ea669a5cdaf2fc9e9f571 Mon Sep 17 00:00:00 2001 From: Daniel Valenzuela Date: Thu, 25 Jul 2024 13:30:37 -0400 Subject: [PATCH] refactor: inheritable authoring mixin callbacks for editing & duplication (#33756) --- cms/djangoapps/contentstore/views/block.py | 2 +- cms/djangoapps/contentstore/views/preview.py | 2 +- .../xblock_storage_handlers/view_handlers.py | 9 ++-- cms/lib/xblock/authoring_mixin.py | 16 +++++++ xmodule/studio_editable.py | 43 +------------------ 5 files changed, 23 insertions(+), 49 deletions(-) diff --git a/cms/djangoapps/contentstore/views/block.py b/cms/djangoapps/contentstore/views/block.py index d52cc5eecfd..4d6c17838e5 100644 --- a/cms/djangoapps/contentstore/views/block.py +++ b/cms/djangoapps/contentstore/views/block.py @@ -13,6 +13,7 @@ from opaque_keys.edx.keys import CourseKey from web_fragments.fragment import Fragment +from cms.djangoapps.contentstore.utils import load_services_for_studio from cms.lib.xblock.authoring_mixin import VISIBILITY_VIEW from common.djangoapps.edxmako.shortcuts import render_to_string from common.djangoapps.student.auth import ( @@ -47,7 +48,6 @@ from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import ( handle_xblock, create_xblock_info, - load_services_for_studio, get_block_info, get_xblock, delete_orphans, diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index 9c9926a5b25..acc5fc95dfe 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -45,7 +45,7 @@ wrap_xblock_aside ) -from ..utils import get_visibility_partition_info, StudioPermissionsService +from ..utils import StudioPermissionsService, get_visibility_partition_info from .access import get_user_role from .session_kv_store import SessionKeyValueStore diff --git a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py index 6959e22b94d..4caaefccc26 100644 --- a/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py +++ b/cms/djangoapps/contentstore/xblock_storage_handlers/view_handlers.py @@ -305,13 +305,10 @@ def _update_with_callback(xblock, user, old_metadata=None, old_content=None): old_metadata = own_metadata(xblock) if old_content is None: old_content = xblock.get_explicitly_set_fields_by_scope(Scope.content) - if hasattr(xblock, "editor_saved"): - load_services_for_studio(xblock.runtime, user) - xblock.editor_saved(user, old_metadata, old_content) + load_services_for_studio(xblock.runtime, user) + xblock.editor_saved(user, old_metadata, old_content) xblock_updated = modulestore().update_item(xblock, user.id) - if hasattr(xblock_updated, "post_editor_saved"): - load_services_for_studio(xblock_updated.runtime, user) - xblock_updated.post_editor_saved(user, old_metadata, old_content) + xblock_updated.post_editor_saved(user, old_metadata, old_content) return xblock_updated diff --git a/cms/lib/xblock/authoring_mixin.py b/cms/lib/xblock/authoring_mixin.py index a3d3b3298ce..b9057391b18 100644 --- a/cms/lib/xblock/authoring_mixin.py +++ b/cms/lib/xblock/authoring_mixin.py @@ -10,6 +10,7 @@ from xblock.core import XBlock, XBlockMixin from xblock.fields import String, Scope + log = logging.getLogger(__name__) VISIBILITY_VIEW = 'visibility_view' @@ -21,6 +22,7 @@ class AuthoringMixin(XBlockMixin): """ Mixin class that provides authoring capabilities for XBlocks. """ + def _get_studio_resource_url(self, relative_url): """ Returns the Studio URL to a static resource. @@ -51,3 +53,17 @@ def visibility_view(self, _context=None): scope=Scope.settings, enforce_type=True, ) + + def editor_saved(self, user, old_metadata, old_content) -> None: # pylint: disable=unused-argument + """ + Called right *before* the block is written to the DB. Can be used, e.g., to modify fields before saving. + + By default, is a no-op. Can be overriden in subclasses. + """ + + def post_editor_saved(self, user, old_metadata, old_content) -> None: # pylint: disable=unused-argument + """ + Called right *after* the block is written to the DB. Can be used, e.g., to spin up followup tasks. + + By default, is a no-op. Can be overriden in subclasses. + """ diff --git a/xmodule/studio_editable.py b/xmodule/studio_editable.py index 29312014f96..d190c966cab 100644 --- a/xmodule/studio_editable.py +++ b/xmodule/studio_editable.py @@ -2,6 +2,7 @@ Mixin to support editing in Studio. """ from xblock.core import XBlock, XBlockMixin + from xmodule.x_module import AUTHOR_VIEW, STUDENT_VIEW @@ -12,6 +13,7 @@ class StudioEditableBlock(XBlockMixin): This class is only intended to be used with an XBlock! """ + has_author_view = True def render_children(self, context, fragment, can_reorder=False, can_add=False): @@ -49,47 +51,6 @@ def get_preview_view_name(block): """ return AUTHOR_VIEW if has_author_view(block) else STUDENT_VIEW - # Some parts of the code use getattr to dynamically check for the following methods on subclasses. - # We'd like to refactor so that we can actually declare them here as overridable methods. - # For now, we leave them here as documentation. - # See https://github.com/openedx/edx-platform/issues/33715. - # - # def editor_saved(self, old_metadata, old_content) -> None: # pylint: disable=unused-argument - # """ - # Called right *before* the block is written to the DB. Can be used, e.g., to modify fields before saving. - # - # By default, is a no-op. Can be overriden in subclasses. - # """ - # - # def post_editor_saved(self, old_metadata, old_content) -> None: # pylint: disable=unused-argument - # """ - # Called right *after* the block is written to the DB. Can be used, e.g., to spin up followup tasks. - # - # By default, is a no-op. Can be overriden in subclasses. - # """ - # - # def studio_post_duplicate(self, store, source_block) -> bool: # pylint: disable=unused-argument - # """ - # Called when a the block is duplicated. Can be used, e.g., for special handling of child duplication. - # - # Returns 'True' if children have been handled and thus shouldn't be handled by the standard - # duplication logic. - # - # By default, is a no-op. Can be overriden in subclasses. - # """ - # return False - # - # def studio_post_paste(self, store, source_node) -> bool: # pylint: disable=unused-argument - # """ - # Called after a block is copy-pasted. Can be used, e.g., for special handling of child duplication. - # - # Returns 'True' if children have been handled and thus shouldn't be handled by the standard - # duplication logic. - # - # By default, is a no-op. Can be overriden in subclasses. - # """ - # return False - def has_author_view(block): """