diff --git a/cms/djangoapps/contentstore/migrations/0013_componentlink_downstream_is_modified_and_more.py b/cms/djangoapps/contentstore/migrations/0013_componentlink_downstream_is_modified_and_more.py new file mode 100644 index 0000000000..c119387ce7 --- /dev/null +++ b/cms/djangoapps/contentstore/migrations/0013_componentlink_downstream_is_modified_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.24 on 2025-09-23 19:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contentstore', '0012_componentlink_top_level_parent_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='componentlink', + name='downstream_is_modified', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='containerlink', + name='downstream_is_modified', + field=models.BooleanField(default=False), + ), + ] diff --git a/cms/djangoapps/contentstore/models.py b/cms/djangoapps/contentstore/models.py index fd98ec44fe..47a450cde8 100644 --- a/cms/djangoapps/contentstore/models.py +++ b/cms/djangoapps/contentstore/models.py @@ -108,6 +108,7 @@ class EntityLinkBase(models.Model): top_level_parent = models.ForeignKey("ContainerLink", on_delete=models.SET_NULL, null=True, blank=True) version_synced = models.IntegerField() version_declined = models.IntegerField(null=True, blank=True) + downstream_is_modified = models.BooleanField(default=False) created = manual_date_time_field() updated = manual_date_time_field() @@ -257,6 +258,7 @@ class ComponentLink(EntityLinkBase): version_synced: int, top_level_parent_usage_key: UsageKey | None = None, version_declined: int | None = None, + downstream_is_modified: bool = False, created: datetime | None = None, ) -> "ComponentLink": """ @@ -281,6 +283,7 @@ class ComponentLink(EntityLinkBase): 'version_synced': version_synced, 'version_declined': version_declined, 'top_level_parent': top_level_parent, + 'downstream_is_modified': downstream_is_modified, } if upstream_block: new_values['upstream_block'] = upstream_block @@ -482,6 +485,7 @@ class ContainerLink(EntityLinkBase): version_synced: int, top_level_parent_usage_key: UsageKey | None = None, version_declined: int | None = None, + downstream_is_modified: bool = False, created: datetime | None = None, ) -> "ContainerLink": """ @@ -506,6 +510,7 @@ class ContainerLink(EntityLinkBase): 'version_synced': version_synced, 'version_declined': version_declined, 'top_level_parent': top_level_parent, + 'downstream_is_modified': downstream_is_modified, } if upstream_container_id: new_values['upstream_container_id'] = upstream_container_id diff --git a/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstream_sync_integration.py b/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstream_sync_integration.py index 8eba50c829..e5cd063e81 100644 --- a/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstream_sync_integration.py +++ b/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstream_sync_integration.py @@ -384,6 +384,7 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'updated': date_format, 'upstream_key': self.upstream_html1["id"], 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 2, @@ -400,7 +401,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_problem1["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 3, @@ -417,7 +419,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_problem2["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 1, @@ -434,7 +437,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_unit["id"], - 'upstream_type': 'container' + 'upstream_type': 'container', + 'downstream_is_modified': False, } ] data = downstreams.json() @@ -533,6 +537,7 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'updated': date_format, 'upstream_key': self.upstream_html1["id"], 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 2, @@ -549,7 +554,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_problem1["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 3, @@ -566,7 +572,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_problem2["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 1, @@ -583,7 +590,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_unit["id"], - 'upstream_type': 'container' + 'upstream_type': 'container', + 'downstream_is_modified': False, } ] data = downstreams.json() @@ -681,6 +689,7 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'updated': date_format, 'upstream_key': self.upstream_html1["id"], 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 2, @@ -697,7 +706,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_problem1["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 4, @@ -714,7 +724,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': upstream_problem3["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 1, @@ -731,7 +742,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_unit["id"], - 'upstream_type': 'container' + 'upstream_type': 'container', + 'downstream_is_modified': False, } ] data = downstreams.json() @@ -810,6 +822,7 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'updated': date_format, 'upstream_key': self.upstream_html1["id"], 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 2, @@ -826,7 +839,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_problem1["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 4, @@ -843,7 +857,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': upstream_problem3["id"], - 'upstream_type': 'component' + 'upstream_type': 'component', + 'downstream_is_modified': False, }, { 'id': 1, @@ -860,7 +875,8 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'created': date_format, 'updated': date_format, 'upstream_key': self.upstream_unit["id"], - 'upstream_type': 'container' + 'upstream_type': 'container', + 'downstream_is_modified': False, } ] data = downstreams.json() @@ -1047,6 +1063,7 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): Test that we can sync a html from a library into a course. """ # 1️⃣ First, create the html in the course, using the upstream problem as a template: + date_format = self.now.isoformat().split("+")[0] + 'Z' downstream_html1 = self._create_block_from_upstream( block_category="html", parent_usage_key=str(self.course_subsection.usage_key), @@ -1079,6 +1096,34 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): >This is the HTML. """) + # Check that: The downstream links are created as expected for the component + downstreams = self._get_downstream_links( + course_id=str(self.course.id) + ) + expected_downstreams = [ + { + 'id': 1, + 'upstream_context_title': self.library_title, + 'upstream_version': 2, + 'ready_to_sync': False, + 'ready_to_sync_from_children': False, + 'upstream_context_key': self.library_id, + 'downstream_usage_key': downstream_html1["locator"], + 'downstream_context_key': str(self.course.id), + 'top_level_parent_usage_key': None, + 'version_synced': 2, + 'version_declined': None, + 'created': date_format, + 'updated': date_format, + 'upstream_key': self.upstream_html1["id"], + 'upstream_type': 'component', + 'downstream_is_modified': False, + }, + ] + data = downstreams.json() + self.assertEqual(data["count"], 1) + self.assertListEqual(data["results"], expected_downstreams) + # 2️⃣ Now, lets modify the upstream html AND the downstream display_name: self._update_course_block_fields(downstream_html1["locator"], { "display_name": "New Text Content", @@ -1111,9 +1156,36 @@ class CourseToLibraryTestCase(ContentLibrariesRestApiTest, ModuleStoreTestCase): 'version_declined': None, 'ready_to_sync': True, # <--- updated 'error_message': None, - 'is_modified': True, + 'is_modified': True, # <--- updated }) + downstreams = self._get_downstream_links( + course_id=str(self.course.id) + ) + expected_downstreams = [ + { + 'id': 1, + 'upstream_context_title': self.library_title, + 'upstream_version': 3, # <--- updated + 'ready_to_sync': True, # <--- updated + 'ready_to_sync_from_children': False, + 'upstream_context_key': self.library_id, + 'downstream_usage_key': downstream_html1["locator"], + 'downstream_context_key': str(self.course.id), + 'top_level_parent_usage_key': None, + 'version_synced': 2, + 'version_declined': None, + 'created': date_format, + 'updated': date_format, + 'upstream_key': self.upstream_html1["id"], + 'upstream_type': 'component', + 'downstream_is_modified': True, # <--- updated + }, + ] + data = downstreams.json() + self.assertEqual(data["count"], 1) + self.assertListEqual(data["results"], expected_downstreams) + # 3️⃣ Now, sync and check the resulting OLX of the downstream self._sync_downstream(downstream_html1["locator"]) diff --git a/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstreams.py b/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstreams.py index bab601e9c0..b8f2c8f410 100644 --- a/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstreams.py +++ b/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_downstreams.py @@ -675,6 +675,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -692,6 +693,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -709,6 +711,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_unit.usage_key), + 'downstream_is_modified': False, }, { 'created': date_format, @@ -726,6 +729,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_chapter.usage_key), + 'downstream_is_modified': False, }, { 'created': date_format, @@ -743,6 +747,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -760,6 +765,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -777,6 +783,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -794,6 +801,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -811,6 +819,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -828,6 +837,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_chapter.usage_key), + 'downstream_is_modified': False, }, { 'created': date_format, @@ -845,6 +855,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_chapter.usage_key), + 'downstream_is_modified': False, }, ] self.assertListEqual(data["results"], expected) @@ -884,6 +895,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -901,6 +913,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -918,6 +931,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_unit.usage_key), + 'downstream_is_modified': False, }, { 'created': date_format, @@ -935,6 +949,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_chapter.usage_key), + 'downstream_is_modified': False, }, ] self.assertListEqual(data["results"], expected) @@ -969,6 +984,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -986,6 +1002,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1003,6 +1020,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1020,6 +1038,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1037,6 +1056,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1054,6 +1074,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_chapter.usage_key), + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1071,6 +1092,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': str(self.top_level_downstream_chapter.usage_key), + 'downstream_is_modified': False, }, ] self.assertListEqual(data["results"], expected) @@ -1170,6 +1192,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1187,6 +1210,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1204,6 +1228,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1221,6 +1246,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, ] print(data["results"]) @@ -1267,6 +1293,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1284,6 +1311,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1301,6 +1329,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, ] self.assertListEqual(data["results"], expected) @@ -1354,6 +1383,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1371,6 +1401,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, { 'created': date_format, @@ -1388,6 +1419,7 @@ class GetUpstreamViewTest( 'version_declined': None, 'version_synced': 1, 'top_level_parent_usage_key': None, + 'downstream_is_modified': False, }, ] self.assertListEqual(data["results"], expected) diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 7140e7f853..3ca1d20bf5 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -2426,6 +2426,7 @@ def _create_or_update_component_link(created: datetime | None, xblock): top_level_parent_usage_key=top_level_parent_usage_key, version_synced=xblock.upstream_version, version_declined=xblock.upstream_version_declined, + downstream_is_modified=len(getattr(xblock, "downstream_customized", [])) > 0, created=created, ) @@ -2458,6 +2459,7 @@ def _create_or_update_container_link(created: datetime | None, xblock): version_synced=xblock.upstream_version, top_level_parent_usage_key=top_level_parent_usage_key, version_declined=xblock.upstream_version_declined, + downstream_is_modified=len(getattr(xblock, "downstream_customized", [])) > 0, created=created, ) diff --git a/cms/static/js/views/pages/container.js b/cms/static/js/views/pages/container.js index 831f71747d..d50f6b4bbe 100644 --- a/cms/static/js/views/pages/container.js +++ b/cms/static/js/views/pages/container.js @@ -577,6 +577,7 @@ function($, _, Backbone, gettext, BasePage, const headerElement = xblockElement.find('.xblock-header-primary'); const upstreamBlockId = headerElement.data('upstream-ref'); const upstreamBlockVersionSynced = headerElement.data('version-synced'); + const isLocallyModified = headerElement.data('is-modified'); try { if (this.options.isIframeEmbed) { @@ -586,9 +587,11 @@ function($, _, Backbone, gettext, BasePage, payload: { downstreamBlockId: xblockInfo.get('id'), displayName: xblockInfo.get('display_name'), - isVertical: xblockInfo.isVertical(), + isContainer: false, upstreamBlockId, upstreamBlockVersionSynced, + isLocallyModified: isLocallyModified === 'True', + blockType: xblockInfo.get('category'), } }, document.referrer ); diff --git a/cms/static/sass/course-unit-mfe-iframe-bundle.scss b/cms/static/sass/course-unit-mfe-iframe-bundle.scss index b53210484a..6c9b43cf0b 100644 --- a/cms/static/sass/course-unit-mfe-iframe-bundle.scss +++ b/cms/static/sass/course-unit-mfe-iframe-bundle.scss @@ -470,6 +470,14 @@ body, &.xblock-iframe-content { height: 100%; + .xblock-title { + margin-bottom: 1.5em !important; + font-size: 1.5em; + font-weight: bold; + margin-block-start: 0.83em; + margin-block-end: 0.83em; + } + // Reset the max-height to allow the settings list to grow .wrapper-comp-settings .list-input.settings-list { max-height: unset; diff --git a/cms/templates/studio_xblock_wrapper.html b/cms/templates/studio_xblock_wrapper.html index 2c57872e10..4fb3c71803 100644 --- a/cms/templates/studio_xblock_wrapper.html +++ b/cms/templates/studio_xblock_wrapper.html @@ -93,6 +93,7 @@ can_unlink = upstream_info.upstream_ref and not upstream_info.has_top_level_pare % if upstream_info.upstream_ref: data-upstream-ref = ${upstream_info.upstream_ref} data-version-synced = ${upstream_info.version_synced} + data-is-modified = ${upstream_info.is_modified} %endif >
diff --git a/common/templates/xblock_v2/xblock_iframe.html b/common/templates/xblock_v2/xblock_iframe.html index cd3096aa46..9bf0ab2df9 100644 --- a/common/templates/xblock_v2/xblock_iframe.html +++ b/common/templates/xblock_v2/xblock_iframe.html @@ -196,6 +196,11 @@ event listeners below, in certain situations. Resetting it to the default "auto" skirts the problem.-->
+ {% if show_title %} +
+ {{ display_name | safe }} +
+ {% endif %} {{ fragment.body_html | safe }} diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 1b199df151..5b3ed4bb8d 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -47,6 +47,7 @@ from rest_framework import status from rest_framework.decorators import api_view, throttle_classes from rest_framework.response import Response from rest_framework.throttling import UserRateThrottle +from rest_framework.fields import BooleanField from web_fragments.fragment import Fragment from xmodule.course_block import ( COURSE_VISIBILITY_PUBLIC, @@ -1576,6 +1577,9 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True, disable_sta Returns an HttpResponse with HTML content for the xBlock with the given usage_key. The returned HTML is a chromeless rendering of the xBlock (excluding content of the containing courseware). """ + if not disable_staff_debug_info: + disable_staff_debug_info = BooleanField().to_internal_value(request.GET.get('disable_staff_debug_info', False)) + usage_key = UsageKey.from_string(usage_key_string) usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key)) diff --git a/openedx/core/djangoapps/xblock/rest_api/views.py b/openedx/core/djangoapps/xblock/rest_api/views.py index a71fb6cfd5..4135fcbf6c 100644 --- a/openedx/core/djangoapps/xblock/rest_api/views.py +++ b/openedx/core/djangoapps/xblock/rest_api/views.py @@ -18,6 +18,7 @@ from rest_framework import permissions, serializers from rest_framework.decorators import api_view, permission_classes # lint-amnesty, pylint: disable=unused-import from rest_framework.exceptions import PermissionDenied, AuthenticationFailed, NotFound from rest_framework.response import Response +from rest_framework.fields import BooleanField from rest_framework.views import APIView from xblock.django.request import DjangoWebobRequest, webob_to_django_response from xblock.exceptions import NoSuchUsage @@ -100,6 +101,10 @@ def embed_block_view(request, usage_key: UsageKeyV2, view_name: str): Unstable - may change after Sumac """ # Check if a specific version has been requested. TODO: move this to a URL path param like the other views? + show_title = request.GET.get('show_title', False) + if show_title is not None: + show_title = BooleanField().to_internal_value(show_title) + try: version = VersionConverter().to_python(request.GET.get("version")) except ValueError as exc: @@ -147,6 +152,8 @@ def embed_block_view(request, usage_key: UsageKeyV2, view_name: str): 'view_name': view_name, 'is_development': settings.DEBUG, 'oa_manifest': new_oa_manifest, + 'display_name': block.display_name, + 'show_title': show_title, } response = render(request, 'xblock_v2/xblock_iframe.html', context, content_type='text/html')