Skip to content

Commit 07e553c

Browse files
committed
feat: Adds Waffle flags to roll out the extracted XBlocks
1 parent 01985e0 commit 07e553c

File tree

12 files changed

+135
-33
lines changed

12 files changed

+135
-33
lines changed

cms/lib/xblock/tagging/tagging.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from xblock.fields import Dict, Scope
99

1010
from common.djangoapps.edxmako.shortcuts import render_to_string
11-
from xmodule.capa_block import ProblemBlock # lint-amnesty, pylint: disable=wrong-import-order
1211
from xmodule.x_module import AUTHOR_VIEW # lint-amnesty, pylint: disable=wrong-import-order
1312

1413
_ = lambda text: text
@@ -42,6 +41,7 @@ def student_view_aside(self, block, context): # pylint: disable=unused-argument
4241
Display the tag selector with specific categories and allowed values,
4342
depending on the context.
4443
"""
44+
from xmodule.capa_block import ProblemBlock
4545
if isinstance(block, ProblemBlock):
4646
tags = []
4747
for tag in self.get_available_tags():

lms/djangoapps/courseware/views/views.py

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
from django.views.generic import View
3434
from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key
3535
from ipware.ip import get_client_ip
36+
from xblock.core import XBlock
37+
3638
from lms.djangoapps.static_template_view.views import render_500
3739
from markupsafe import escape
3840
from opaque_keys import InvalidKeyError
@@ -1562,6 +1564,10 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True, disable_sta
15621564
set_custom_attributes_for_course_key(course_key)
15631565
set_custom_attribute('usage_key', usage_key_string)
15641566
set_custom_attribute('block_type', usage_key.block_type)
1567+
block_class = XBlock.load_class(usage_key.block_type)
1568+
if hasattr(block_class, 'is_extracted'):
1569+
is_extracted = getattr(block_class, 'is_extracted')
1570+
set_custom_attribute('block_extracted', is_extracted)
15651571

15661572
requested_view = request.GET.get('view', 'student_view')
15671573
if requested_view != 'student_view' and requested_view != 'public_view': # lint-amnesty, pylint: disable=consider-using-in

requirements/edx/bundled.in

+1
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ ora2>=4.5.0 # Open Response Assessment XBlock
4747
xblock-poll # Xblock for polling users
4848
xblock-drag-and-drop-v2 # Drag and Drop XBlock
4949
xblock-google-drive # XBlock for google docs and calendar
50+
xblocks-contrib # Package having multiple core XBlocks, https://github.com/openedx/xblocks-contrib?tab=readme-ov-file#xblocks-being-moved-here

xmodule/annotatable_block.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@
77
from web_fragments.fragment import Fragment
88
from xblock.core import XBlock
99
from xblock.fields import Scope, String
10+
from xblocks_contrib.annotatable import AnnotatableBlock as _ExtractedAnnotatableBlock
1011

1112
from openedx.core.djangolib.markup import HTML, Text
1213
from xmodule.editing_block import EditingMixin
1314
from xmodule.raw_block import RawMixin
15+
from xmodule.toggles import USE_EXTRACTED_ANNOTATABLE_BLOCK
1416
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment
15-
from xmodule.xml_block import XmlMixin
1617
from xmodule.x_module import (
1718
ResourceTemplates,
1819
shim_xmodule_js,
1920
XModuleMixin,
2021
XModuleToXBlockMixin,
2122
)
23+
from xmodule.xml_block import XmlMixin
2224

2325
log = logging.getLogger(__name__)
2426

@@ -28,7 +30,7 @@
2830

2931

3032
@XBlock.needs('mako')
31-
class AnnotatableBlock(
33+
class _BuiltInAnnotatableBlock(
3234
RawMixin,
3335
XmlMixin,
3436
EditingMixin,
@@ -40,6 +42,8 @@ class AnnotatableBlock(
4042
Annotatable XBlock.
4143
"""
4244

45+
is_extracted = False
46+
4347
data = String(
4448
help=_("XML data for the annotation"),
4549
scope=Scope.content,
@@ -197,3 +201,9 @@ def studio_view(self, _context):
197201
add_webpack_js_to_fragment(fragment, 'AnnotatableBlockEditor')
198202
shim_xmodule_js(fragment, self.studio_js_module_name)
199203
return fragment
204+
205+
206+
AnnotatableBlock = (
207+
_ExtractedAnnotatableBlock if USE_EXTRACTED_ANNOTATABLE_BLOCK.is_enabled()
208+
else _BuiltInAnnotatableBlock
209+
)

xmodule/capa_block.py

+18-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@
2525
from xblock.core import XBlock
2626
from xblock.fields import Boolean, Dict, Float, Integer, Scope, String, XMLString, List
2727
from xblock.scorable import ScorableXBlockMixin, Score
28+
from xblocks_contrib.problem import ProblemBlock as _ExtractedProblemBlock
2829

30+
from common.djangoapps.xblock_django.constants import (
31+
ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID,
32+
ATTR_KEY_USER_IS_STAFF,
33+
ATTR_KEY_USER_ID,
34+
)
35+
from openedx.core.djangolib.markup import HTML, Text
2936
from xmodule.capa import responsetypes
3037
from xmodule.capa.capa_problem import LoncapaProblem, LoncapaSystem
3138
from xmodule.capa.inputtypes import Status
@@ -36,23 +43,17 @@
3643
from xmodule.exceptions import NotFoundError, ProcessingError
3744
from xmodule.graders import ShowCorrectness
3845
from xmodule.raw_block import RawMixin
39-
from xmodule.util.sandboxing import SandboxService
46+
from xmodule.toggles import USE_EXTRACTED_PROBLEM_BLOCK
4047
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_sass_to_fragment
48+
from xmodule.util.sandboxing import SandboxService
4149
from xmodule.x_module import (
4250
ResourceTemplates,
4351
XModuleMixin,
4452
XModuleToXBlockMixin,
4553
shim_xmodule_js
4654
)
4755
from xmodule.xml_block import XmlMixin
48-
from common.djangoapps.xblock_django.constants import (
49-
ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID,
50-
ATTR_KEY_USER_IS_STAFF,
51-
ATTR_KEY_USER_ID,
52-
)
53-
from openedx.core.djangolib.markup import HTML, Text
5456
from .capa.xqueue_interface import XQueueService
55-
5657
from .fields import Date, ListScoreField, ScoreField, Timedelta
5758
from .progress import Progress
5859

@@ -134,7 +135,7 @@ def from_json(self, value):
134135
@XBlock.needs('sandbox')
135136
@XBlock.needs('replace_urls')
136137
@XBlock.wants('call_to_action')
137-
class ProblemBlock(
138+
class _BuiltInProblemBlock(
138139
ScorableXBlockMixin,
139140
RawMixin,
140141
XmlMixin,
@@ -161,6 +162,8 @@ class ProblemBlock(
161162
"""
162163
INDEX_CONTENT_TYPE = 'CAPA'
163164

165+
is_extracted = False
166+
164167
resources_dir = None
165168

166169
has_score = True
@@ -2509,3 +2512,9 @@ def randomization_bin(seed, problem_id):
25092512
r_hash.update(str(problem_id).encode())
25102513
# get the first few digits of the hash, convert to an int, then mod.
25112514
return int(r_hash.hexdigest()[:7], 16) % NUM_RANDOMIZATION_BINS
2515+
2516+
2517+
ProblemBlock = (
2518+
_ExtractedProblemBlock if USE_EXTRACTED_PROBLEM_BLOCK.is_enabled()
2519+
else _BuiltInProblemBlock
2520+
)

xmodule/discussion_block.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414
from xblock.fields import UNIQUE_ID, Scope, String
1515
from xblock.utils.resources import ResourceLoader
1616
from xblock.utils.studio_editable import StudioEditableXBlockMixin
17+
from xblocks_contrib.discussion import DiscussionXBlock as _ExtractedDiscussionXBlock
1718

1819
from lms.djangoapps.discussion.django_comment_client.permissions import has_permission
1920
from openedx.core.djangoapps.discussions.models import DiscussionsConfiguration, Provider
2021
from openedx.core.djangolib.markup import HTML, Text
2122
from openedx.core.lib.xblock_utils import get_css_dependencies, get_js_dependencies
23+
from xmodule.toggles import USE_EXTRACTED_DISCUSSION_BLOCK
2224
from xmodule.xml_block import XmlMixin
2325

24-
2526
log = logging.getLogger(__name__)
2627
loader = ResourceLoader(__name__) # pylint: disable=invalid-name
2728

@@ -36,10 +37,11 @@ def _(text):
3637
@XBlock.needs('user') # pylint: disable=abstract-method
3738
@XBlock.needs('i18n')
3839
@XBlock.needs('mako')
39-
class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlMixin): # lint-amnesty, pylint: disable=abstract-method
40+
class _BuiltInDiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlMixin): # lint-amnesty, pylint: disable=abstract-method
4041
"""
4142
Provides a discussion forum that is inline with other content in the courseware.
4243
"""
44+
is_extracted = False
4345
completion_mode = XBlockCompletionMode.EXCLUDED
4446

4547
discussion_id = String(scope=Scope.settings, default=UNIQUE_ID)
@@ -275,3 +277,10 @@ def _apply_metadata_and_policy(cls, block, node, runtime):
275277
for field_name, value in metadata.items():
276278
if field_name in block.fields:
277279
setattr(block, field_name, value)
280+
281+
282+
DiscussionXBlock = (
283+
_ExtractedDiscussionXBlock if USE_EXTRACTED_DISCUSSION_BLOCK.is_enabled()
284+
else _BuiltInDiscussionXBlock
285+
)
286+

xmodule/html_block.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@
1515
from web_fragments.fragment import Fragment
1616
from xblock.core import XBlock
1717
from xblock.fields import Boolean, List, Scope, String
18+
from xblocks_contrib.html import HtmlBlock as _ExtractedHtmlBlock
1819

1920
from common.djangoapps.xblock_django.constants import ATTR_KEY_DEPRECATED_ANONYMOUS_USER_ID
2021
from xmodule.contentstore.content import StaticContent
2122
from xmodule.editing_block import EditingMixin
2223
from xmodule.edxnotes_utils import edxnotes
2324
from xmodule.html_checker import check_html
2425
from xmodule.stringify import stringify_children
25-
from xmodule.util.misc import escape_html_characters
26+
from xmodule.toggles import USE_EXTRACTED_HTML_BLOCK
2627
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment
28+
from xmodule.util.misc import escape_html_characters
2729
from xmodule.x_module import (
2830
ResourceTemplates,
2931
shim_xmodule_js,
@@ -50,6 +52,8 @@ class HtmlBlockMixin( # lint-amnesty, pylint: disable=abstract-method
5052
The HTML XBlock mixin.
5153
This provides the base class for all Html-ish blocks (including the HTML XBlock).
5254
"""
55+
is_extracted = False
56+
5357
display_name = String(
5458
display_name=_("Display Name"),
5559
help=_("The display name for this component."),
@@ -353,7 +357,7 @@ def index_dictionary(self):
353357

354358

355359
@edxnotes
356-
class HtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstract-method
360+
class _BuiltInHtmlBlock(HtmlBlockMixin): # lint-amnesty, pylint: disable=abstract-method
357361
"""
358362
This is the actual HTML XBlock.
359363
Nothing extra is required; this is just a wrapper to include edxnotes support.
@@ -489,3 +493,9 @@ def safe_parse_date(date):
489493
return datetime.strptime(date, '%B %d, %Y')
490494
except ValueError: # occurs for ill-formatted date values
491495
return datetime.today()
496+
497+
498+
HtmlBlock = (
499+
_ExtractedHtmlBlock if USE_EXTRACTED_HTML_BLOCK.is_enabled()
500+
else _BuiltInHtmlBlock
501+
)

xmodule/lti_block.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -59,40 +59,40 @@
5959
import hashlib
6060
import logging
6161
import textwrap
62-
from xml.sax.saxutils import escape
6362
from unittest import mock
6463
from urllib import parse
64+
from xml.sax.saxutils import escape
6565

6666
import nh3
6767
import oauthlib.oauth1
6868
from django.conf import settings
6969
from lxml import etree
7070
from oauthlib.oauth1.rfc5849 import signature
7171
from pytz import UTC
72-
from webob import Response
7372
from web_fragments.fragment import Fragment
73+
from webob import Response
7474
from xblock.core import List, Scope, String, XBlock
7575
from xblock.fields import Boolean, Float
76-
from xmodule.mako_block import MakoTemplateBlockBase
77-
78-
from openedx.core.djangolib.markup import HTML, Text
79-
from xmodule.editing_block import EditingMixin
76+
from xblocks_contrib.lti import LTIBlock as _ExtractedLTIBlock
8077

8178
from common.djangoapps.xblock_django.constants import (
8279
ATTR_KEY_ANONYMOUS_USER_ID,
8380
ATTR_KEY_USER_ROLE,
8481
)
82+
from openedx.core.djangolib.markup import HTML, Text
83+
from xmodule.editing_block import EditingMixin
8584
from xmodule.lti_2_util import LTI20BlockMixin, LTIError
85+
from xmodule.mako_block import MakoTemplateBlockBase
8686
from xmodule.raw_block import EmptyDataRawMixin
87+
from xmodule.toggles import USE_EXTRACTED_LTI_BLOCK
8788
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment
88-
from xmodule.xml_block import XmlMixin
8989
from xmodule.x_module import (
9090
ResourceTemplates,
9191
shim_xmodule_js,
9292
XModuleMixin,
9393
XModuleToXBlockMixin,
9494
)
95-
95+
from xmodule.xml_block import XmlMixin
9696

9797
log = logging.getLogger(__name__)
9898

@@ -274,7 +274,7 @@ class LTIFields:
274274
@XBlock.needs("mako")
275275
@XBlock.needs("user")
276276
@XBlock.needs("rebind_user")
277-
class LTIBlock(
277+
class _BuiltInLTIBlock(
278278
LTIFields,
279279
LTI20BlockMixin,
280280
EmptyDataRawMixin,
@@ -366,6 +366,7 @@ class LTIBlock(
366366
367367
Otherwise error message from LTI provider is generated.
368368
"""
369+
is_extracted = False
369370
resources_dir = None
370371
uses_xmodule_styles_setup = True
371372

@@ -984,3 +985,9 @@ def is_past_due(self):
984985
else:
985986
close_date = due_date
986987
return close_date is not None and datetime.datetime.now(UTC) > close_date
988+
989+
990+
LTIBlock = (
991+
_ExtractedLTIBlock if USE_EXTRACTED_LTI_BLOCK.is_enabled()
992+
else _BuiltInLTIBlock
993+
)

xmodule/poll_block.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
from collections import OrderedDict
1414
from copy import deepcopy
1515

16-
from web_fragments.fragment import Fragment
17-
1816
from lxml import etree
17+
from web_fragments.fragment import Fragment
1918
from xblock.core import XBlock
2019
from xblock.fields import Boolean, Dict, List, Scope, String # lint-amnesty, pylint: disable=wrong-import-order
20+
from xblocks_contrib.poll import PollBlock as _ExtractedPollBlock
21+
2122
from openedx.core.djangolib.markup import Text, HTML
2223
from xmodule.mako_block import MakoTemplateBlockBase
2324
from xmodule.stringify import stringify_children
25+
from xmodule.toggles import USE_EXTRACTED_POLL_BLOCK
2426
from xmodule.util.builtin_assets import add_webpack_js_to_fragment, add_css_to_fragment
2527
from xmodule.x_module import (
2628
ResourceTemplates,
@@ -30,20 +32,22 @@
3032
)
3133
from xmodule.xml_block import XmlMixin
3234

33-
3435
log = logging.getLogger(__name__)
3536
_ = lambda text: text
3637

3738

3839
@XBlock.needs('mako')
39-
class PollBlock(
40+
class _BuiltInPollBlock(
4041
MakoTemplateBlockBase,
4142
XmlMixin,
4243
XModuleToXBlockMixin,
4344
ResourceTemplates,
4445
XModuleMixin,
4546
): # pylint: disable=abstract-method
4647
"""Poll Block"""
48+
49+
is_extracted = False
50+
4751
# Name of poll to use in links to this poll
4852
display_name = String(
4953
help=_("The display name for this component."),
@@ -244,3 +248,8 @@ def add_child(xml_obj, answer): # lint-amnesty, pylint: disable=unused-argument
244248
add_child(xml_object, answer)
245249

246250
return xml_object
251+
252+
PollBlock = (
253+
_ExtractedPollBlock if USE_EXTRACTED_POLL_BLOCK.is_enabled()
254+
else _BuiltInPollBlock
255+
)

0 commit comments

Comments
 (0)