From 5dedba8c8e2c8cf3ece35a14742b8426ff37352a Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Mon, 17 Jan 2022 09:51:48 +1030 Subject: [PATCH 1/2] temp: adds mako templates and dirs to Studio test env The content library tests were failing to locate templates when rendering XBlocks, but since these tests are skipped in CI, the issue went undetected. This fix is marked temporary because a proper fix involves adding lms/templates to the cms.envs.test MAKO_TEMPLATE_DIRS_BASE list. This was tried, and caused unrelated tests to fail, and so we took this approach instead. See PR for full details. --- cms/envs/test.py | 6 ++ common/test/problem.html | 96 ++++++++++++++++++++++++++ common/test/problem_ajax.html | 16 +++++ common/test/video.html | 122 ++++++++++++++++++++++++++++++++++ 4 files changed, 240 insertions(+) create mode 100644 common/test/problem.html create mode 100644 common/test/problem_ajax.html create mode 100644 common/test/video.html diff --git a/cms/envs/test.py b/cms/envs/test.py index 3736e76360..cea21fce05 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -267,6 +267,12 @@ TEST_ELASTICSEARCH_USE_SSL = os.environ.get( TEST_ELASTICSEARCH_HOST = os.environ.get('EDXAPP_TEST_ELASTICSEARCH_HOST', 'edx.devstack.elasticsearch710') TEST_ELASTICSEARCH_PORT = int(os.environ.get('EDXAPP_TEST_ELASTICSEARCH_PORT', '9200')) +############################# TEMPLATE CONFIGURATION ############################# +# Adds mako template dirs for content_libraries tests +MAKO_TEMPLATE_DIRS_BASE.append( + COMMON_ROOT / 'lib' / 'capa' / 'capa' / 'templates' +) + ########################## AUTHOR PERMISSION ####################### FEATURES['ENABLE_CREATOR_GROUP'] = False diff --git a/common/test/problem.html b/common/test/problem.html new file mode 100644 index 0000000000..0c63e205e0 --- /dev/null +++ b/common/test/problem.html @@ -0,0 +1,96 @@ + +<%page expression_filter="h"/> +<%! +from django.utils.translation import ngettext, gettext as _ +from openedx.core.djangolib.markup import HTML +%> + +<%namespace name='static' file='static_content.html'/> +

+ ${ problem['name'] } +

+ +
+ +
+ ${ HTML(problem['html']) } +
+ + +
+ % if demand_hint_possible: + + + + % endif + % if save_button: + + + + % endif + % if reset_button: + + + + % endif + % if answer_available: + + + + % endif +
+
+ + + % if submit_disabled_cta: + % if submit_disabled_cta.get('event_data'): + + + + + (${submit_disabled_cta['description']}) + % else: +
+ + % for form_name, form_value in submit_disabled_cta['form_values'].items(): + + % endfor + + + + + (${submit_disabled_cta['description']}) +
+ % endif + % endif +
+ ## When attempts are not 0, the CTA above will contain a message about the number of used attempts + % if attempts_allowed and (not submit_disabled_cta or attempts_used == 0): + ${ngettext("You have used {num_used} of {num_total} attempt", "You have used {num_used} of {num_total} attempts", attempts_allowed).format(num_used=attempts_used, num_total=attempts_allowed)} + % endif + ${_("Some problems have options such as save, reset, hints, or show answer. These options follow the Submit button.")} +
+
+
+
+ + diff --git a/common/test/problem_ajax.html b/common/test/problem_ajax.html new file mode 100644 index 0000000000..bbe365bd92 --- /dev/null +++ b/common/test/problem_ajax.html @@ -0,0 +1,16 @@ + +
+

+ + Loading… +

+
diff --git a/common/test/video.html b/common/test/video.html new file mode 100644 index 0000000000..ea6a54d994 --- /dev/null +++ b/common/test/video.html @@ -0,0 +1,122 @@ + +<%page expression_filter="h"/> + +<%! +from django.utils.translation import ugettext as _ +from openedx.core.djangolib.js_utils import ( + dump_js_escaped_json, js_escaped_string +) +%> +% if display_name is not UNDEFINED and display_name is not None: +

${display_name}

+% endif + +
+
+ +
+
+ + +
+
+
+ + +
+
+
+ +
+
+ +
+ + % if download_video_link or track or handout or branding_info: +

${_('Downloads and transcripts')}

+
+ % if download_video_link: + + % endif + % if track: +
+

${_('Transcripts')}

+ % if transcript_download_format: +
    + % for item in transcript_download_formats_list: +
  • + <% dname = _("Download {file}").format(file=item['display_name']) %> + ${dname} +
  • + % endfor +
+ % else: + ${_('Download transcript')} + % endif +
+ % endif + % if handout: +
+

${_('Handouts')}

+ ${_('Download Handout')} +
+ % endif + % if branding_info: +
+ ${branding_info['logo_tag']} + +
+ % endif +
+ % endif +
+% if cdn_eval: + +% endif; From ef8f841ac276eec2609f6960a963a790dcd53f43 Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Mon, 17 Jan 2022 09:57:08 +1030 Subject: [PATCH 2/2] temp: let XBlock API users optionally use LabXchange block types when fetching block metadata and rendering blocks while maintaining the original usage IDs/OLX. This change is marked temporary because LabXchange need it during the transition to a custom runtime, but it's not really useful to anyone else. We will revert this change with a future PR. --- .../tests/test_content_libraries.py | 167 ++++++++++++++++++ openedx/core/djangoapps/xblock/api.py | 19 +- .../core/djangoapps/xblock/rest_api/views.py | 49 ++++- .../xblock/runtime/blockstore_runtime.py | 9 +- 4 files changed, 232 insertions(+), 12 deletions(-) diff --git a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py index c23679cb18..599dfd9a60 100644 --- a/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py +++ b/openedx/core/djangoapps/content_libraries/tests/test_content_libraries.py @@ -3,7 +3,9 @@ Tests for Blockstore-based Content Libraries """ from uuid import UUID from unittest.mock import patch +from urllib.parse import urlparse, parse_qsl +import json import ddt from django.conf import settings from django.contrib.auth.models import Group @@ -11,6 +13,9 @@ from django.test.client import Client from django.test.utils import override_settings from organizations.models import Organization from rest_framework.test import APITestCase +from web_fragments.fragment import Fragment +from webob import Response +from xblock.core import XBlock from openedx.core.djangoapps.content_libraries.libraries_index import LibraryBlockIndexer, ContentLibraryIndexer from openedx.core.djangoapps.content_libraries.tests.base import ( @@ -20,6 +25,7 @@ from openedx.core.djangoapps.content_libraries.tests.base import ( URL_BLOCK_RENDER_VIEW, URL_BLOCK_GET_HANDLER_URL, URL_BLOCK_XBLOCK_HANDLER, + URL_LIB_BLOCK_OLX, ) from openedx.core.djangoapps.content_libraries.constants import VIDEO, COMPLEX, PROBLEM, CC_4_BY, ALL_RIGHTS_RESERVED from openedx.core.djangolib.blockstore_cache import cache @@ -903,3 +909,164 @@ class ContentLibraryXBlockValidationTest(APITestCase): self.assertEqual(response.json(), { 'detail': f"XBlock {valid_not_found_key} does not exist, or you don't have permission to view it.", }) + + +class AltBlock(XBlock): + """Class for testing LabXchange XBlock type overrides.""" + @XBlock.handler + def student_view_user_state(self, request, suffix=""): + """ + Returns a JSON response for testing. + """ + view_state = { + "id": str(self.location), + "block_type": str(self.location.block_type), + "override_type": str(self.__class__), + } + return Response( + json.dumps(view_state), + content_type='application/json', + charset='UTF-8', + ) + + def student_view(self, context=None): + """ + Returns an HTML fragment for testing. + """ + return Fragment(f"
" + "
") + + +@ddt.ddt +@elasticsearch_test +class ContentLibrariesXBlockTypeOverrideTest(ContentLibrariesRestApiTest): + """ + Tests for Blockstore-based Content Libraries XBlock API, + where the expected XBlock type returned is overridden in the request. + """ + BLOCK_DATA = ( + ('block-wo-override', {}, 'video'), + ('block-w-override', {'lx_block_types': '1'}, 'alt-block'), + ) + + def setUp(self): + super().setUp() + if settings.ENABLE_ELASTICSEARCH_FOR_TESTS: + ContentLibraryIndexer.remove_all_items() + LibraryBlockIndexer.remove_all_items() + + self.olx = """ +