From f9126bfdd990dc78c97d10619bd2b08ad47a1a18 Mon Sep 17 00:00:00 2001 From: Muhammad Farhan Khan Date: Mon, 2 Dec 2024 20:38:40 +0500 Subject: [PATCH] Add Django settings flags to roll out the extracted XBlocks (#35549) chore: Add Django settings flags to roll out the extracted XBlocks --- cms/envs/common.py | 10 +++ lms/djangoapps/courseware/views/views.py | 6 ++ lms/envs/common.py | 88 ++++++++++++++++++++++++ requirements/edx/base.txt | 6 ++ requirements/edx/bundled.in | 1 + requirements/edx/development.txt | 8 +++ requirements/edx/doc.txt | 6 ++ requirements/edx/testing.txt | 6 ++ xmodule/annotatable_block.py | 15 +++- xmodule/capa_block.py | 28 +++++--- xmodule/discussion_block.py | 15 +++- xmodule/html_block.py | 14 +++- xmodule/lti_block.py | 25 ++++--- xmodule/poll_block.py | 22 ++++-- xmodule/video_block/video_block.py | 14 +++- xmodule/word_cloud_block.py | 17 ++++- 16 files changed, 244 insertions(+), 37 deletions(-) diff --git a/cms/envs/common.py b/cms/envs/common.py index 00a384a359c6..20e99974b3fb 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -122,6 +122,16 @@ # Password Validator Settings AUTH_PASSWORD_VALIDATORS ) +from lms.envs.common import ( + USE_EXTRACTED_WORD_CLOUD_BLOCK, + USE_EXTRACTED_ANNOTATABLE_BLOCK, + USE_EXTRACTED_POLL_QUESTION_BLOCK, + USE_EXTRACTED_LTI_BLOCK, + USE_EXTRACTED_HTML_BLOCK, + USE_EXTRACTED_DISCUSSION_BLOCK, + USE_EXTRACTED_PROBLEM_BLOCK, + USE_EXTRACTED_VIDEO_BLOCK, +) from path import Path as path from django.urls import reverse_lazy diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 88f0ed05ccf7..6e0804db8ca0 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -33,6 +33,8 @@ from django.views.generic import View from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key from ipware.ip import get_client_ip +from xblock.core import XBlock + from lms.djangoapps.static_template_view.views import render_500 from markupsafe import escape from opaque_keys import InvalidKeyError @@ -1562,6 +1564,10 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True, disable_sta set_custom_attributes_for_course_key(course_key) set_custom_attribute('usage_key', usage_key_string) set_custom_attribute('block_type', usage_key.block_type) + block_class = XBlock.load_class(usage_key.block_type) + if hasattr(block_class, 'is_extracted'): + is_extracted = block_class.is_extracted + set_custom_attribute('block_extracted', is_extracted) requested_view = request.GET.get('view', 'student_view') if requested_view != 'student_view' and requested_view != 'public_view': # lint-amnesty, pylint: disable=consider-using-in diff --git a/lms/envs/common.py b/lms/envs/common.py index d74c28e75687..7d32c78a47b5 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -5558,3 +5558,91 @@ def _should_send_learning_badge_events(settings): LMS_COMM_DEFAULT_FROM_EMAIL = "no-reply@example.com" + + +####################### Setting for built-in Blocks Extraction ####################### +# The following Django settings flags have been introduced temporarily to facilitate +# the rollout of the extracted built-in Blocks. Flags will use to toggle between +# the old and new block quickly without putting course content or user state at risk. +# +# Ticket: https://github.com/openedx/edx-platform/issues/35308 + +# .. toggle_name: USE_EXTRACTED_WORD_CLOUD_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Word Cloud XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34840 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_WORD_CLOUD_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_ANNOTATABLE_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted annotatable XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34841 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_ANNOTATABLE_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_POLL_QUESTION_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted poll question XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until https://github.com/openedx/edx-platform/issues/34839 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_POLL_QUESTION_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_LTI_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted LTI XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_LTI_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_HTML_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted HTML XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_HTML_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_DISCUSSION_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Discussion XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_DISCUSSION_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_PROBLEM_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Problem XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_PROBLEM_BLOCK = False + +# .. toggle_name: USE_EXTRACTED_VIDEO_BLOCK +# .. toggle_default: False +# .. toggle_implementation: DjangoSetting +# .. toggle_description: Enables the use of the extracted Video XBlock, which has been shifted to the 'openedx/xblocks-contrib' repo. +# .. toggle_use_cases: temporary +# .. toggle_warning: Not production-ready until relevant subtask https://github.com/openedx/edx-platform/issues/34827 is done. +# .. toggle_creation_date: 2024-11-10 +# .. toggle_target_removal_date: 2025-06-01 +USE_EXTRACTED_VIDEO_BLOCK = False diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index ed6de1269447..7d432e2a7b7a 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -345,6 +345,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -480,6 +481,7 @@ edx-i18n-tools==1.5.0 # -c requirements/edx/../constraints.txt # -r requirements/edx/bundled.in # ora2 + # xblocks-contrib edx-milestones==0.6.0 # via -r requirements/edx/kernel.in edx-name-affirmation==3.0.1 @@ -809,6 +811,7 @@ openedx-django-pyfs==3.7.0 # via # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via -r requirements/edx/kernel.in openedx-django-wiki==2.1.0 @@ -1277,6 +1280,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via -r requirements/edx/bundled.in xblock-google-drive==0.7.0 @@ -1287,6 +1291,8 @@ xblock-utils==4.0.0 # via # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via -r requirements/edx/bundled.in xmlsec==1.3.14 # via python3-saml xss-utils==0.6.0 diff --git a/requirements/edx/bundled.in b/requirements/edx/bundled.in index 5a46c710a6d2..a9394b809f55 100644 --- a/requirements/edx/bundled.in +++ b/requirements/edx/bundled.in @@ -47,3 +47,4 @@ ora2>=4.5.0 # Open Response Assessment XBlock xblock-poll # Xblock for polling users xblock-drag-and-drop-v2 # Drag and Drop XBlock xblock-google-drive # XBlock for google docs and calendar +xblocks-contrib # Package having multiple core XBlocks, https://github.com/openedx/xblocks-contrib?tab=readme-ov-file#xblocks-being-moved-here diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 4e5e4fc6801d..1f65f6c90138 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -568,6 +568,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -763,6 +764,7 @@ edx-i18n-tools==1.5.0 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # ora2 + # xblocks-contrib edx-lint==5.4.1 # via -r requirements/edx/testing.txt edx-milestones==0.6.0 @@ -1362,6 +1364,7 @@ openedx-django-pyfs==3.7.0 # -r requirements/edx/testing.txt # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via # -r requirements/edx/doc.txt @@ -2266,6 +2269,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via # -r requirements/edx/doc.txt @@ -2284,6 +2288,10 @@ xblock-utils==4.0.0 # -r requirements/edx/testing.txt # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via + # -r requirements/edx/doc.txt + # -r requirements/edx/testing.txt xmlsec==1.3.14 # via # -r requirements/edx/doc.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 946e31c433de..2388cb4a0e1d 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -419,6 +419,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -564,6 +565,7 @@ edx-i18n-tools==1.5.0 # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # ora2 + # xblocks-contrib edx-milestones==0.6.0 # via -r requirements/edx/base.txt edx-name-affirmation==3.0.1 @@ -979,6 +981,7 @@ openedx-django-pyfs==3.7.0 # -r requirements/edx/base.txt # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.1.0 @@ -1585,6 +1588,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via -r requirements/edx/base.txt xblock-google-drive==0.7.0 @@ -1596,6 +1600,8 @@ xblock-utils==4.0.0 # -r requirements/edx/base.txt # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via -r requirements/edx/base.txt xmlsec==1.3.14 # via # -r requirements/edx/base.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 3bdd5c6e6f2c..672e70166503 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -445,6 +445,7 @@ django-statici18n==2.5.0 # lti-consumer-xblock # xblock-drag-and-drop-v2 # xblock-poll + # xblocks-contrib django-storages==1.14.3 # via # -c requirements/edx/../constraints.txt @@ -585,6 +586,7 @@ edx-i18n-tools==1.5.0 # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt # ora2 + # xblocks-contrib edx-lint==5.4.1 # via -r requirements/edx/testing.in edx-milestones==0.6.0 @@ -1024,6 +1026,7 @@ openedx-django-pyfs==3.7.0 # -r requirements/edx/base.txt # lti-consumer-xblock # xblock + # xblocks-contrib openedx-django-require==2.1.0 # via -r requirements/edx/base.txt openedx-django-wiki==2.1.0 @@ -1672,6 +1675,7 @@ xblock[django]==5.1.0 # xblock-drag-and-drop-v2 # xblock-google-drive # xblock-utils + # xblocks-contrib xblock-drag-and-drop-v2==4.0.3 # via -r requirements/edx/base.txt xblock-google-drive==0.7.0 @@ -1683,6 +1687,8 @@ xblock-utils==4.0.0 # -r requirements/edx/base.txt # edx-sga # xblock-poll +xblocks-contrib==0.1.0 + # via -r requirements/edx/base.txt xmlsec==1.3.14 # via # -r requirements/edx/base.txt diff --git a/xmodule/annotatable_block.py b/xmodule/annotatable_block.py index cec677f6c5d5..dbcf0123c59a 100644 --- a/xmodule/annotatable_block.py +++ b/xmodule/annotatable_block.py @@ -3,22 +3,24 @@ import logging import textwrap +from django.conf import settings from lxml import etree from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Scope, String +from xblocks_contrib.annotatable import AnnotatableBlock as _ExtractedAnnotatableBlock from openedx.core.djangolib.markup import HTML, Text from xmodule.editing_block import EditingMixin from xmodule.raw_block import RawMixin from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment -from xmodule.xml_block import XmlMixin from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, XModuleMixin, XModuleToXBlockMixin, ) +from xmodule.xml_block import XmlMixin log = logging.getLogger(__name__) @@ -28,7 +30,7 @@ @XBlock.needs('mako') -class AnnotatableBlock( +class _BuiltInAnnotatableBlock( RawMixin, XmlMixin, EditingMixin, @@ -40,6 +42,8 @@ class AnnotatableBlock( Annotatable XBlock. """ + is_extracted = False + data = String( help=_("XML data for the annotation"), scope=Scope.content, @@ -197,3 +201,10 @@ def studio_view(self, _context): add_webpack_js_to_fragment(fragment, 'AnnotatableBlockEditor') shim_xmodule_js(fragment, self.studio_js_module_name) return fragment + + +AnnotatableBlock = ( + _ExtractedAnnotatableBlock if settings.USE_EXTRACTED_ANNOTATABLE_BLOCK + else _BuiltInAnnotatableBlock +) +AnnotatableBlock.__name__ = "AnnotatableBlock" diff --git a/xmodule/capa_block.py b/xmodule/capa_block.py index 24737b689845..fa0e87325bb7 100644 --- a/xmodule/capa_block.py +++ b/xmodule/capa_block.py @@ -25,7 +25,14 @@ from xblock.core import XBlock from xblock.fields import Boolean, Dict, Float, Integer, Scope, String, XMLString, List from xblock.scorable import ScorableXBlockMixin, Score +from xblocks_contrib.problem import ProblemBlock as _ExtractedProblemBlock +from common.djangoapps.xblock_django.constants import ( + ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID, + ATTR_KEY_USER_IS_STAFF, + ATTR_KEY_USER_ID, +) +from openedx.core.djangolib.markup import HTML, Text from xmodule.capa import responsetypes from xmodule.capa.capa_problem import LoncapaProblem, LoncapaSystem from xmodule.capa.inputtypes import Status @@ -36,8 +43,8 @@ from xmodule.exceptions import NotFoundError, ProcessingError from xmodule.graders import ShowCorrectness from xmodule.raw_block import RawMixin -from xmodule.util.sandboxing import SandboxService from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment +from xmodule.util.sandboxing import SandboxService from xmodule.x_module import ( ResourceTemplates, XModuleMixin, @@ -45,20 +52,12 @@ shim_xmodule_js ) from xmodule.xml_block import XmlMixin -from common.djangoapps.xblock_django.constants import ( - ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID, - ATTR_KEY_USER_IS_STAFF, - ATTR_KEY_USER_ID, -) -from openedx.core.djangolib.markup import HTML, Text from .capa.xqueue_interface import XQueueService - from .fields import Date, ListScoreField, ScoreField, Timedelta from .progress import Progress log = logging.getLogger("edx.courseware") - # Make '_' a no-op so we can scrape strings. Using lambda instead of # `django.utils.translation.gettext_noop` because Django cannot be imported in this file _ = lambda text: text @@ -134,7 +133,7 @@ def from_json(self, value): @XBlock.needs('sandbox') @XBlock.needs('replace_urls') @XBlock.wants('call_to_action') -class ProblemBlock( +class _BuiltInProblemBlock( ScorableXBlockMixin, RawMixin, XmlMixin, @@ -161,6 +160,8 @@ class ProblemBlock( """ INDEX_CONTENT_TYPE = 'CAPA' + is_extracted = False + resources_dir = None has_score = True @@ -2509,3 +2510,10 @@ def randomization_bin(seed, problem_id): r_hash.update(str(problem_id).encode()) # get the first few digits of the hash, convert to an int, then mod. return int(r_hash.hexdigest()[:7], 16) % NUM_RANDOMIZATION_BINS + + +ProblemBlock = ( + _ExtractedProblemBlock if settings.USE_EXTRACTED_PROBLEM_BLOCK + else _BuiltInProblemBlock +) +ProblemBlock.__name__ = "ProblemBlock" diff --git a/xmodule/discussion_block.py b/xmodule/discussion_block.py index 89e573c07c83..79914b63d6b2 100644 --- a/xmodule/discussion_block.py +++ b/xmodule/discussion_block.py @@ -4,7 +4,7 @@ import logging import urllib - +from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage from django.urls import reverse from django.utils.translation import get_language_bidi @@ -14,6 +14,7 @@ from xblock.fields import UNIQUE_ID, Scope, String from xblock.utils.resources import ResourceLoader from xblock.utils.studio_editable import StudioEditableXBlockMixin +from xblocks_contrib.discussion import DiscussionXBlock as _ExtractedDiscussionXBlock from lms.djangoapps.discussion.django_comment_client.permissions import has_permission from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider @@ -21,7 +22,6 @@ from openedx.core.lib.xblock_utils import get_css_dependencies, get_js_dependencies from xmodule.xml_block import XmlMixin - log = logging.getLogger(__name__) loader = ResourceLoader(__name__) # pylint: disable=invalid-name @@ -36,10 +36,12 @@ def _(text): @XBlock.needs('user') # pylint: disable=abstract-method @XBlock.needs('i18n') @XBlock.needs('mako') -class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlMixin): # lint-amnesty, pylint: disable=abstract-method +class _BuiltInDiscussionXBlock(XBlock, StudioEditableXBlockMixin, + XmlMixin): # lint-amnesty, pylint: disable=abstract-method """ Provides a discussion forum that is inline with other content in the courseware. """ + is_extracted = False completion_mode = XBlockCompletionMode.EXCLUDED discussion_id = String(scope=Scope.settings, default=UNIQUE_ID) @@ -275,3 +277,10 @@ def _apply_metadata_and_policy(cls, block, node, runtime): for field_name, value in metadata.items(): if field_name in block.fields: setattr(block, field_name, value) + + +DiscussionXBlock = ( + _ExtractedDiscussionXBlock if settings.USE_EXTRACTED_DISCUSSION_BLOCK + else _BuiltInDiscussionXBlock +) +DiscussionXBlock.__name__ = "DiscussionXBlock" diff --git a/xmodule/html_block.py b/xmodule/html_block.py index 62949647cee3..9840c3007f92 100644 --- a/xmodule/html_block.py +++ b/xmodule/html_block.py @@ -15,6 +15,7 @@ from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, List, Scope, String +from xblocks_contrib.html import HtmlBlock as _ExtractedHtmlBlock from common.djangoapps.xblock_django.constants import ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID from xmodule.contentstore.content import StaticContent @@ -22,8 +23,8 @@ from xmodule.edxnotes_utils import edxnotes from xmodule.html_checker import check_html from xmodule.stringify import stringify_children -from xmodule.util.misc import escape_html_characters from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment +from xmodule.util.misc import escape_html_characters from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, @@ -50,6 +51,7 @@ class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method The HTML XBlock mixin. This provides the base class for all Html-ish blocks (including the HTML XBlock). """ + display_name = String( display_name=_("Display Name"), help=_("The display name for this component."), @@ -353,11 +355,12 @@ def index_dictionary(self): @edxnotes -class HtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstract-method +class _BuiltInHtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstract-method """ This is the actual HTML XBlock. Nothing extra is required; this is just a wrapper to include edxnotes support. """ + is_extracted = False class AboutFields: # lint-amnesty, pylint: disable=missing-class-docstring @@ -489,3 +492,10 @@ def safe_parse_date(date): return datetime.strptime(date, '%B %d, %Y') except ValueError: # occurs for ill-formatted date values return datetime.today() + + +HtmlBlock = ( + _ExtractedHtmlBlock if settings.USE_EXTRACTED_HTML_BLOCK + else _BuiltInHtmlBlock +) +HtmlBlock.__name__ = "HtmlBlock" diff --git a/xmodule/lti_block.py b/xmodule/lti_block.py index e7c173075b4e..944a7ec88db0 100644 --- a/xmodule/lti_block.py +++ b/xmodule/lti_block.py @@ -59,9 +59,9 @@ import hashlib import logging import textwrap -from xml.sax.saxutils import escape from unittest import mock from urllib import parse +from xml.sax.saxutils import escape import nh3 import oauthlib.oauth1 @@ -69,30 +69,29 @@ from lxml import etree from oauthlib.oauth1.rfc5849 import signature from pytz import UTC -from webob import Response from web_fragments.fragment import Fragment +from webob import Response from xblock.core import List, Scope, String, XBlock from xblock.fields import Boolean, Float -from xmodule.mako_block import MakoTemplateBlockBase - -from openedx.core.djangolib.markup import HTML, Text -from xmodule.editing_block import EditingMixin +from xblocks_contrib.lti import LTIBlock as _ExtractedLTIBlock from common.djangoapps.xblock_django.constants import ( ATTR_KEY_ANONYMOUS_USER_ID, ATTR_KEY_USER_ROLE, ) +from openedx.core.djangolib.markup import HTML, Text +from xmodule.editing_block import EditingMixin from xmodule.lti_2_util import LTI20BlockMixin, LTIError +from xmodule.mako_block import MakoTemplateBlockBase from xmodule.raw_block import EmptyDataRawMixin from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment -from xmodule.xml_block import XmlMixin from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, XModuleMixin, XModuleToXBlockMixin, ) - +from xmodule.xml_block import XmlMixin log = logging.getLogger(__name__) @@ -274,7 +273,7 @@ class LTIFields: @XBlock.needs("mako") @XBlock.needs("user") @XBlock.needs("rebind_user") -class LTIBlock( +class _BuiltInLTIBlock( LTIFields, LTI20BlockMixin, EmptyDataRawMixin, @@ -366,6 +365,7 @@ class LTIBlock( Otherwise error message from LTI provider is generated. """ + is_extracted = False resources_dir = None uses_xmodule_styles_setup = True @@ -984,3 +984,10 @@ def is_past_due(self): else: close_date = due_date return close_date is not None and datetime.datetime.now(UTC) > close_date + + +LTIBlock = ( + _ExtractedLTIBlock if settings.USE_EXTRACTED_LTI_BLOCK + else _BuiltInLTIBlock +) +LTIBlock.__name__ = "LTIBlock" diff --git a/xmodule/poll_block.py b/xmodule/poll_block.py index a1c9686f42ac..b8c65f1cdba8 100644 --- a/xmodule/poll_block.py +++ b/xmodule/poll_block.py @@ -6,18 +6,19 @@ If student have answered - Question with statistics for each answers. """ - import html import json import logging -from collections import OrderedDict from copy import deepcopy -from web_fragments.fragment import Fragment - +from collections import OrderedDict +from django.conf import settings from lxml import etree +from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, Dict, List, Scope, String # lint-amnesty, pylint: disable=wrong-import-order +from xblocks_contrib.poll import PollBlock as _ExtractedPollBlock + from openedx.core.djangolib.markup import Text, HTML from xmodule.mako_block import MakoTemplateBlockBase from xmodule.stringify import stringify_children @@ -30,13 +31,12 @@ ) from xmodule.xml_block import XmlMixin - log = logging.getLogger(__name__) _ = lambda text: text @XBlock.needs('mako') -class PollBlock( +class _BuiltInPollBlock( MakoTemplateBlockBase, XmlMixin, XModuleToXBlockMixin, @@ -44,6 +44,9 @@ class PollBlock( XModuleMixin, ): # pylint: disable=abstract-method """Poll Block""" + + is_extracted = False + # Name of poll to use in links to this poll display_name = String( help=_("The display name for this component."), @@ -244,3 +247,10 @@ def add_child(xml_obj, answer): # lint-amnesty, pylint: disable=unused-argument add_child(xml_object, answer) return xml_object + + +PollBlock = ( + _ExtractedPollBlock if settings.USE_EXTRACTED_POLL_QUESTION_BLOCK + else _BuiltInPollBlock +) +PollBlock.__name__ = "PollBlock" diff --git a/xmodule/video_block/video_block.py b/xmodule/video_block/video_block.py index ea9d1a44280a..84d7edcf7263 100644 --- a/xmodule/video_block/video_block.py +++ b/xmodule/video_block/video_block.py @@ -29,6 +29,7 @@ from xblock.core import XBlock from xblock.fields import ScopeIds from xblock.runtime import KvsFieldData +from xblocks_contrib.video import VideoBlock as _ExtractedVideoBlock from common.djangoapps.xblock_django.constants import ATTR_KEY_REQUEST_COUNTRY_CODE, ATTR_KEY_USER_ID from openedx.core.djangoapps.video_config.models import HLSPlaybackEnabledFlag, CourseYoutubeBlockedFlag @@ -47,8 +48,8 @@ from xmodule.mako_block import MakoTemplateBlockBase from xmodule.modulestore.inheritance import InheritanceKeyValueStore, own_metadata from xmodule.raw_block import EmptyDataRawMixin +from xmodule.util.builtin_assets import add_css_to_fragment, add_webpack_js_to_fragment from xmodule.validation import StudioValidation, StudioValidationMessage -from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment from xmodule.video_block import manage_video_subtitles_save from xmodule.x_module import ( PUBLIC_VIEW, STUDENT_VIEW, @@ -56,7 +57,6 @@ XModuleMixin, XModuleToXBlockMixin, ) from xmodule.xml_block import XmlMixin, deserialize_field, is_pointer_tag, name_to_pathname - from .bumper_utils import bumperize from .sharing_sites import sharing_sites_info_for_video from .transcripts_utils import ( @@ -119,7 +119,7 @@ @XBlock.wants('settings', 'completion', 'i18n', 'request_cache') @XBlock.needs('mako', 'user') -class VideoBlock( +class _BuiltInVideoBlock( VideoFields, VideoTranscriptsMixin, VideoStudioViewHandlers, VideoStudentViewHandlers, EmptyDataRawMixin, XmlMixin, EditingMixin, XModuleToXBlockMixin, ResourceTemplates, XModuleMixin, LicenseMixin): @@ -134,6 +134,7 @@ class VideoBlock( """ + is_extracted = False has_custom_completion = True completion_mode = XBlockCompletionMode.COMPLETABLE @@ -1260,3 +1261,10 @@ def _poster(self): edx_video_id=self.edx_video_id.strip() ) return None + + +VideoBlock = ( + _ExtractedVideoBlock if settings.USE_EXTRACTED_VIDEO_BLOCK + else _BuiltInVideoBlock +) +VideoBlock.__name__ = "VideoBlock" diff --git a/xmodule/word_cloud_block.py b/xmodule/word_cloud_block.py index d678f2a9a9f5..37e82400df78 100644 --- a/xmodule/word_cloud_block.py +++ b/xmodule/word_cloud_block.py @@ -6,23 +6,27 @@ If student have answered - words he entered and cloud. """ +from xblocks_contrib.word_cloud import WordCloudBlock as _ExtractedWordCloudBlock import json import logging +from django.conf import settings from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Boolean, Dict, Integer, List, Scope, String + from xmodule.editing_block import EditingMixin from xmodule.raw_block import EmptyDataRawMixin from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment -from xmodule.xml_block import XmlMixin from xmodule.x_module import ( ResourceTemplates, shim_xmodule_js, XModuleMixin, XModuleToXBlockMixin, ) +from xmodule.xml_block import XmlMixin + log = logging.getLogger(__name__) # Make '_' a no-op so we can scrape strings. Using lambda instead of @@ -41,7 +45,7 @@ def pretty_bool(value): @XBlock.needs('mako') -class WordCloudBlock( # pylint: disable=abstract-method +class _BuiltInWordCloudBlock( # pylint: disable=abstract-method EmptyDataRawMixin, XmlMixin, EditingMixin, @@ -53,6 +57,8 @@ class WordCloudBlock( # pylint: disable=abstract-method Word Cloud XBlock. """ + is_extracted = False + display_name = String( display_name=_("Display Name"), help=_("The display name for this component."), @@ -308,3 +314,10 @@ def index_dictionary(self): xblock_body["content_type"] = "Word Cloud" return xblock_body + + +WordCloudBlock = ( + _ExtractedWordCloudBlock if settings.USE_EXTRACTED_WORD_CLOUD_BLOCK + else _BuiltInWordCloudBlock +) +WordCloudBlock.__name__ = "WordCloudBlock"