From c8bd924e23f9352d40f840e9836c23751de46352 Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Tue, 23 Nov 2021 09:56:25 +0000 Subject: [PATCH] feat: Add support for using the discussions MFE UI instead of existing UI [BD-38] [TNL-9228] (#29285) * feat: Add support for using the discussions MFE UI instead of existing UI Adds a new course waffle flag that when set along with the discussions MFE URL shows the discussions MFE UI instead of the regular UI. * test: add tests * squash!: more consistent url name --- cms/envs/common.py | 1 + cms/envs/devstack.py | 3 ++ .../tests/test_discussion_xblock.py | 50 ++++++++++++++++--- .../django_comment_client/tests/test_utils.py | 20 +++++++- lms/djangoapps/discussion/plugins.py | 14 ++++++ lms/djangoapps/discussion/toggles.py | 15 ++++++ lms/djangoapps/discussion/views.py | 20 +++++++- lms/envs/common.py | 5 ++ lms/envs/devstack.py | 3 ++ .../xblock_discussion/__init__.py | 20 +++++++- 10 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 lms/djangoapps/discussion/toggles.py diff --git a/cms/envs/common.py b/cms/envs/common.py index aacfdeafa9..75ff2f823e 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -494,6 +494,7 @@ IDA_LOGOUT_URI_LIST = [] ############################# MICROFRONTENDS ################################### COURSE_AUTHORING_MICROFRONTEND_URL = None +DISCUSSIONS_MICROFRONTEND_URL = None LIBRARY_AUTHORING_MICROFRONTEND_URL = None ############################# SOCIAL MEDIA SHARING ############################# diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index a7c0827782..469bc20454 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -162,6 +162,9 @@ LIBRARY_AUTHORING_MICROFRONTEND_URL = 'http://localhost:3001' ################### FRONTEND APPLICATION COURSE AUTHORING ################### COURSE_AUTHORING_MICROFRONTEND_URL = 'http://localhost:2001' +################### FRONTEND APPLICATION DISCUSSIONS ################### +DISCUSSIONS_MICROFRONTEND_URL = 'http://localhost:2002' + ################################# DJANGO-REQUIRE ############################### # Whether to run django-require in debug mode. diff --git a/lms/djangoapps/courseware/tests/test_discussion_xblock.py b/lms/djangoapps/courseware/tests/test_discussion_xblock.py index e48973570a..f7482187d1 100644 --- a/lms/djangoapps/courseware/tests/test_discussion_xblock.py +++ b/lms/djangoapps/courseware/tests/test_discussion_xblock.py @@ -12,15 +12,20 @@ import uuid from unittest import mock import ddt +from django.test import override_settings from django.urls import reverse +from edx_toggles.toggles.testutils import override_waffle_flag +from opaque_keys.edx.keys import CourseKey from web_fragments.fragment import Fragment from xblock.field_data import DictFieldData from lms.djangoapps.course_api.blocks.tests.helpers import deserialize_usage_key from lms.djangoapps.courseware.module_render import get_module_for_descriptor_internal from lms.djangoapps.courseware.tests.helpers import XModuleRenderingTestBase +from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from xblock_discussion import DiscussionXBlock, loader + from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import ItemFactory, ToyCourseFactory @@ -40,7 +45,7 @@ class TestDiscussionXBlock(XModuleRenderingTestBase): """ super().setUp() self.patchers = [] - self.course_id = "test_course" + self.course_id = CourseKey.from_string("course-v1:test+test+test_course") self.runtime = self.new_module_runtime() self.runtime.modulestore = mock.Mock() @@ -220,7 +225,7 @@ class TestTemplates(TestDiscussionXBlock): ) as has_perm: actual_permission = self.block.has_permission("test_permission") assert actual_permission == permission_canary - has_perm.assert_called_once_with(self.django_user_canary, 'test_permission', 'test_course') + has_perm.assert_called_once_with(self.django_user_canary, 'test_permission', self.course_id) def test_studio_view(self): """Test for studio view.""" @@ -304,6 +309,35 @@ class TestXBlockInCourse(SharedModuleStoreTestCase): assert 'data-user-create-comment="false"' in html assert 'data-user-create-subcomment="false"' in html + @override_settings(DISCUSSIONS_MICROFRONTEND_URL="http://test.url") + @override_waffle_flag(ENABLE_DISCUSSIONS_MFE, True) + def test_embed_mfe_in_course(self): + """ + Test that the xblock embeds the MFE UI when the flag is enabled + """ + discussion_xblock = get_module_for_descriptor_internal( + user=self.user, + descriptor=self.discussion, + student_data=mock.Mock(name='student_data'), + course_id=self.course.id, + track_function=mock.Mock(name='track_function'), + xqueue_callback_url_prefix=mock.Mock(name='xqueue_callback_url_prefix'), + request_token='request_token', + ) + + fragment = discussion_xblock.render('student_view') + html = fragment.content + self.assertInHTML( + """ + " + ).format(src=f"{settings.DISCUSSIONS_MICROFRONTEND_URL}/discussions/{course_id}/") + ) + fragment.add_css( + """ + #discussions-mfe-tab-embed { + width: 100%; + min-height: 800px; + border: none; + } + """ + ) + return fragment try: - course_key = CourseKey.from_string(course_id) base_context = _create_base_discussion_view_context(request, course_key) # Note: # After the thread is rendered in this fragment, an AJAX diff --git a/lms/envs/common.py b/lms/envs/common.py index fa902bf7b2..57f2026354 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -4683,6 +4683,11 @@ PROGRAM_CONSOLE_MICROFRONTEND_URL = None # .. setting_description: Base URL of the micro-frontend-based courseware page. # .. setting_warning: Also set site's courseware.courseware_mfe waffle flag. LEARNING_MICROFRONTEND_URL = None +# .. setting_name: DISCUSSIONS_MICROFRONTEND_URL +# .. setting_default: None +# .. setting_description: Base URL of the micro-frontend-based dicussions page. +# .. setting_warning: Also set site's courseware.discussions_mfe waffle flag. +DISCUSSIONS_MICROFRONTEND_URL = None ############### Settings for the ace_common plugin ################# ACE_ENABLED_CHANNELS = ['django_email'] diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py index 608928f55b..fe422a1cef 100644 --- a/lms/envs/devstack.py +++ b/lms/envs/devstack.py @@ -338,6 +338,9 @@ ACCOUNT_MICROFRONTEND_URL = 'http://localhost:1997' AUTHN_MICROFRONTEND_URL = 'http://localhost:1999' AUTHN_MICROFRONTEND_DOMAIN = 'localhost:1999' +################### FRONTEND APPLICATION DISCUSSIONS ################### +DISCUSSIONS_MICROFRONTEND_URL = 'http://localhost:2002' + ############## Docker based devstack settings ####################### FEATURES.update({ diff --git a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py index 079b1765cb..264b88725d 100644 --- a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py +++ b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion/__init__.py @@ -4,16 +4,19 @@ Discussion XBlock 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 +from web_fragments.fragment import Fragment from xblock.completable import XBlockCompletionMode from xblock.core import XBlock from xblock.fields import Scope, String, UNIQUE_ID -from web_fragments.fragment import Fragment from xblockutils.resources import ResourceLoader from xblockutils.studio_editable import StudioEditableXBlockMixin +from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE from openedx.core.djangolib.markup import HTML, Text from openedx.core.lib.xblock_builtin import get_css_dependencies, get_js_dependencies from xmodule.xml_module import XmlParserMixin @@ -166,6 +169,21 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): # li Renders student view for LMS. """ fragment = Fragment() + if ENABLE_DISCUSSIONS_MFE.is_enabled(self.course_key) and settings.DISCUSSIONS_MICROFRONTEND_URL: + url = f"{settings.DISCUSSIONS_MICROFRONTEND_URL}/discussions/{self.course_key}/topics/{self.discussion_id}" + fragment.add_content(HTML( + "" + ).format(src=url, title=_("Discussions"))) + fragment.add_css( + """ + #discussions-mfe-tab-embed { + width: 100%; + height: 800px; + border: none; + } + """ + ) + return fragment self.add_resource_urls(fragment)