feat: banner for staff users that displays a message for testing the new MFE experience (#29698)

Adds a new banner allowing staff users to preview and switch between the new and legacy forum experience.
This commit is contained in:
Kshitij Sobti
2022-01-18 06:18:59 +00:00
committed by GitHub
parent 5bd86ba583
commit 2bbf447ab5
17 changed files with 236 additions and 95 deletions

View File

@@ -5,10 +5,13 @@ Tests for the django comment client integration models
from django.test.testcases import TestCase
from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.tests.django_utils import (
TEST_DATA_MIXED_MODULESTORE,
ModuleStoreTestCase
)
from xmodule.modulestore.tests.factories import ToyCourseFactory
import openedx.core.djangoapps.django_comment_common.models as models
from xmodule.modulestore.tests.django_utils import TEST_DATA_MIXED_MODULESTORE, ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import ToyCourseFactory # lint-amnesty, pylint: disable=wrong-import-order
class RoleClassTestCase(ModuleStoreTestCase):

View File

@@ -1234,20 +1234,6 @@ class DiscussionTabTestCase(ModuleStoreTestCase):
with self.settings(FEATURES={'CUSTOM_COURSES_EDX': True}):
assert not self.discussion_tab_present(self.enrolled_user)
@override_settings(DISCUSSIONS_MICROFRONTEND_URL="http://test.url")
@ddt.data(
(True, 'http://test.url/{}/'),
(False, '/courses/{}/discussion/forum/'),
)
@ddt.unpack
def test_tab_with_mfe_flag(self, mfe_enabled, tab_link):
"""
Tests that the correct link is used for the MFE tab
"""
discussion_tab = CourseTabList.get_tab_by_type(self.course.tabs, 'discussion')
with override_waffle_flag(ENABLE_DISCUSSIONS_MFE, mfe_enabled):
assert discussion_tab.link_func(self.course, reverse) == tab_link.format(self.course.id)
class IsCommentableDividedTestCase(ModuleStoreTestCase):
"""

View File

@@ -5,17 +5,17 @@ Utilities for tests within the django_comment_client module.
from unittest.mock import patch
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.util.testing import UrlResetMixin
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings
from openedx.core.djangoapps.django_comment_common.models import ForumsConfig, Role
from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings, ForumsConfig, Role
from openedx.core.djangoapps.django_comment_common.utils import seed_permissions_roles
from openedx.core.lib.teams_config import TeamsConfig
from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
class ForumsEnableMixin:

View File

@@ -5,13 +5,11 @@ Views handling read (GET) requests for the Discussion tab and inline discussions
from django.conf import settings
from django.utils.translation import gettext_noop
from xmodule.tabs import TabFragmentViewMixin
import lms.djangoapps.discussion.django_comment_client.utils as utils
from lms.djangoapps.courseware.tabs import EnrolledTab
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE
from openedx.core.djangoapps.discussions.url_helpers import get_discussions_mfe_url
from openedx.features.lti_course_tab.tab import DiscussionLtiCourseTab
from xmodule.tabs import TabFragmentViewMixin # lint-amnesty, pylint: disable=wrong-import-order
class DiscussionTab(TabFragmentViewMixin, EnrolledTab):
@@ -29,20 +27,6 @@ class DiscussionTab(TabFragmentViewMixin, EnrolledTab):
body_class = 'discussion'
online_help_token = 'discussions'
@property
def link_func(self):
""" Returns a function that returns the course tab's URL. """
_link_func = super().link_func
def link_func(course, reverse_func):
""" Returns a function that returns the course tab's URL. """
mfe_url = get_discussions_mfe_url(course.id)
if ENABLE_DISCUSSIONS_MFE.is_enabled(course.id) and mfe_url:
return mfe_url
return _link_func(course, reverse_func)
return link_func
@classmethod
def is_enabled(cls, course, user=None):
if not super().is_enabled(course, user):

View File

@@ -6,6 +6,8 @@ Tests for discussion API permission logic
import itertools
import ddt
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from lms.djangoapps.discussion.rest_api.permissions import (
can_delete,
@@ -16,8 +18,6 @@ from lms.djangoapps.discussion.rest_api.permissions import (
from openedx.core.djangoapps.django_comment_common.comment_client.comment import Comment
from openedx.core.djangoapps.django_comment_common.comment_client.thread import Thread
from openedx.core.djangoapps.django_comment_common.comment_client.user import User
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
def _get_context(

View File

@@ -5,12 +5,12 @@ Tests for Discussion REST API utils.
from datetime import datetime, timedelta
from pytz import UTC
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from common.djangoapps.student.tests.factories import UserFactory, CourseEnrollmentFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from lms.djangoapps.discussion.django_comment_client.tests.factories import RoleFactory
from lms.djangoapps.discussion.rest_api.utils import discussion_open_for_user
from xmodule.modulestore.tests.factories import CourseFactory # lint-amnesty, pylint: disable=wrong-import-order
class DiscussionAPIUtilsTestCase(ModuleStoreTestCase):

View File

@@ -7,9 +7,9 @@ import logging
import uuid
import edx_api_doc_tools as apidocs
from django.shortcuts import get_object_or_404
from django.contrib.auth import get_user_model
from django.core.exceptions import BadRequest, ValidationError
from django.shortcuts import get_object_or_404
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
from opaque_keys.edx.keys import CourseKey
@@ -20,6 +20,7 @@ from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSet
from xmodule.modulestore.django import modulestore
from common.djangoapps.util.file import store_uploaded_file
from lms.djangoapps.course_goals.models import UserActivity
@@ -33,7 +34,7 @@ from openedx.core.djangoapps.user_api.models import UserRetirementStatus
from openedx.core.lib.api.authentication import BearerAuthentication, BearerAuthenticationAllowInactiveUser
from openedx.core.lib.api.parsers import MergePatchParser
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from ..rest_api.api import (
create_comment,
create_thread,
@@ -47,22 +48,18 @@ from ..rest_api.api import (
get_thread_list,
get_user_comments,
update_comment,
update_thread,
update_thread
)
from ..rest_api.forms import (
CommentGetForm,
CommentListGetForm,
UserCommentListGetForm,
CourseDiscussionRolesForm,
CourseDiscussionSettingsForm,
ThreadListGetForm,
UserCommentListGetForm
)
from ..rest_api.permissions import IsStaffOrCourseTeamOrEnrolled
from ..rest_api.serializers import (
CourseMetadataSerailizer,
DiscussionRolesListSerializer,
DiscussionRolesSerializer,
)
from ..rest_api.serializers import CourseMetadataSerailizer, DiscussionRolesListSerializer, DiscussionRolesSerializer
log = logging.getLogger(__name__)

View File

@@ -8,12 +8,12 @@ import logging
from django.conf import settings
from django.dispatch import receiver
from opaque_keys.edx.locator import LibraryLocator
from xmodule.modulestore.django import SignalHandler
from lms.djangoapps.discussion import tasks
from openedx.core.djangoapps.django_comment_common import signals
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
from openedx.core.djangoapps.theming.helpers import get_current_site
from xmodule.modulestore.django import SignalHandler # lint-amnesty, pylint: disable=wrong-import-order
log = logging.getLogger(__name__)

View File

@@ -23,6 +23,7 @@ from openedx.core.djangolib.markup import HTML
data-sort-preference="${sort_preference}"
data-flag-moderator="${json.dumps(flag_moderator)}"
data-user-group-id="${user_group_id}">
<%include file="_switch_experience_fragment.html" />
<header class="page-header has-secondary">
## Breadcrumb navigation
<div class="page-header-main">

View File

@@ -0,0 +1,16 @@
## mako
<%namespace name='static' file='../static_content.html'/>
<%page expression_filter="h"/>
<%!
import json
from django.utils.translation import ugettext as _
%>
<section class="discussion discussion-board page-content-container" id="discussion-container"
data-course-id="${course_key}" >
<%include file="_switch_experience_fragment.html" />
<iframe id='discussions-mfe-tab-embed' src='${discussions_mfe_url}'></iframe>
</section>

View File

@@ -2,14 +2,18 @@
Tests the forum notification signals.
"""
from unittest import mock
from django.test import TestCase
from edx_django_utils.cache import RequestCache
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import (
CourseFactory,
ItemFactory
)
from lms.djangoapps.discussion.signals.handlers import ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY
from openedx.core.djangoapps.django_comment_common import models, signals
from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory, SiteFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory # lint-amnesty, pylint: disable=wrong-import-order
class SendMessageHandlerTestCase(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring

View File

@@ -14,6 +14,7 @@ from edx_ace.channel import ChannelType, get_channel_for_message
from edx_ace.recipient import Recipient
from edx_ace.renderers import EmailRenderer
from edx_ace.utils import date
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
import openedx.core.djangoapps.django_comment_common.comment_client as cc
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
@@ -25,7 +26,6 @@ from openedx.core.djangoapps.django_comment_common.models import ForumsConfig
from openedx.core.djangoapps.django_comment_common.signals import comment_created
from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory
from openedx.core.lib.celery.task_utils import emulate_http_request
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order
NOW = datetime.utcnow()
ONE_HOUR_AGO = NOW - timedelta(hours=1)

View File

@@ -1,8 +1,7 @@
"""
Tests the forum notification views.
"""
import itertools
import json
import logging
from datetime import datetime
@@ -16,11 +15,24 @@ from django.test.utils import override_settings
from django.urls import reverse
from django.utils import translation
from edx_django_utils.cache import RequestCache
from edx_toggles.toggles.testutils import override_waffle_flag
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.django_utils import (
TEST_DATA_MONGO_MODULESTORE,
ModuleStoreTestCase,
SharedModuleStoreTestCase
)
from xmodule.modulestore.tests.factories import (
CourseFactory,
ItemFactory,
check_mongo_calls
)
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
from common.djangoapps.student.roles import CourseStaffRole, UserBasedRole
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
from common.djangoapps.util.testing import EventTestMixin, UrlResetMixin
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
from lms.djangoapps.discussion import views
@@ -39,6 +51,7 @@ from lms.djangoapps.discussion.django_comment_client.tests.utils import (
topic_name_to_id
)
from lms.djangoapps.discussion.django_comment_client.utils import strip_none
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE
from lms.djangoapps.discussion.views import _get_discussion_default_topic_id, course_discussions_settings_handler
from lms.djangoapps.teams.tests.factories import CourseTeamFactory, CourseTeamMembershipFactory
from openedx.core.djangoapps.course_groups.models import CourseUserGroup
@@ -56,14 +69,6 @@ from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES
from openedx.core.lib.teams_config import TeamsConfig
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired
from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
from xmodule.modulestore.tests.django_utils import ( # lint-amnesty, pylint: disable=wrong-import-order
TEST_DATA_MONGO_MODULESTORE,
ModuleStoreTestCase,
SharedModuleStoreTestCase
)
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls # lint-amnesty, pylint: disable=wrong-import-order
log = logging.getLogger(__name__)
@@ -2225,3 +2230,71 @@ class ThreadViewedEventTestCase(EventTestMixin, ForumsEnableMixin, UrlResetMixin
_, event = self.get_latest_call_args()
event_items = list(event.items())
assert ((kv_pair in event_items) for kv_pair in expected_event_items)
@ddt.ddt
@patch(
'openedx.core.djangoapps.django_comment_common.comment_client.utils.perform_request',
Mock(
return_value={
"default_sort_key": "date",
"upvoted_ids": [],
"downvoted_ids": [],
"subscribed_thread_ids": [],
}
)
)
class ForumMFETestCase(ForumsEnableMixin, SharedModuleStoreTestCase):
"""
Tests that the MFE upgrade banner and MFE is shown in the correct situation with the correct UI
"""
def setUp(self):
super().setUp()
self.course = CourseFactory.create()
self.user = UserFactory.create()
self.staff_user = AdminFactory.create()
@ddt.data(*itertools.product(("http://test.url", None), (True, False), (True, False)))
@ddt.unpack
def test_staff_user(self, mfe_url, toggle_enabled, is_staff):
"""
Verify that the banner is shown with the correct links if the user is staff and the
mfe url is configured.
"""
with override_settings(DISCUSSIONS_MICROFRONTEND_URL=mfe_url):
with override_waffle_flag(ENABLE_DISCUSSIONS_MFE, toggle_enabled):
username = self.staff_user.username if is_staff else self.user.username
self.client.login(username=username, password='test')
response = self.client.get(reverse("forum_form_discussion", args=[self.course.id]))
content = response.content.decode('utf8')
if mfe_url and is_staff:
assert "made some changes to this experience!" in content
if toggle_enabled:
assert "legacy experience" in content
assert "new experience" not in content
else:
assert "legacy experience" not in content
assert "new experience" in content
else:
assert "made some changes to this experience!" not in content
@override_settings(DISCUSSIONS_MICROFRONTEND_URL="http://test.url")
@ddt.data(*itertools.product((True, False), ("legacy", "new", None)))
@ddt.unpack
def test_correct_experience_is_shown(self, toggle_enabled, experience):
"""
Verify that the correct experience is shown based on the MFE toggle flag and the query param.
"""
with override_waffle_flag(ENABLE_DISCUSSIONS_MFE, toggle_enabled):
self.client.login(username=self.staff_user.username, password='test')
url = reverse("forum_form_discussion", args=[self.course.id])
experience_in_url = ""
if experience is not None:
experience_in_url = f"discussions_experience={experience}"
response = self.client.get(f"{url}?{experience_in_url}")
content = response.content.decode('utf8')
if (toggle_enabled and experience != "legacy") or experience == "new":
assert "discussions-mfe-tab-embed" in content
else:
assert "discussions-mfe-tab-embed" not in content

View File

@@ -2,27 +2,29 @@
Views handling read (GET) requests for the Discussion tab and inline discussions.
"""
import logging
from functools import wraps
from typing import Dict, Optional
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.contrib.staticfiles.storage import staticfiles_storage
from django.http import Http404, HttpResponseForbidden, HttpResponseServerError
from django.shortcuts import render
from django.template.context_processors import csrf
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.translation import get_language_bidi, gettext_lazy as _
from django.utils.translation import get_language_bidi
from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import cache_control
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_GET, require_http_methods
from edx_django_utils.monitoring import function_trace
from functools import wraps # lint-amnesty, pylint: disable=wrong-import-order
from opaque_keys.edx.keys import CourseKey
from rest_framework import status
from web_fragments.fragment import Fragment
from xmodule.modulestore.django import modulestore
import lms.djangoapps.discussion.django_comment_client.utils as utils
import openedx.core.djangoapps.django_comment_common.comment_client as cc
@@ -58,13 +60,11 @@ from openedx.core.djangoapps.discussions.utils import (
from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings
from openedx.core.djangoapps.django_comment_common.utils import ThreadContext
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.core.djangolib.markup import HTML
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order
User = get_user_model()
log = logging.getLogger("edx.discussions")
THREADS_PER_PAGE = 20
INLINE_THREADS_PER_PAGE = 20
PAGES_NEARBY_DELTA = 2
@@ -694,6 +694,38 @@ def followed_threads(request, course_key, user_id):
raise Http404 # lint-amnesty, pylint: disable=raise-missing-from
def _discussions_mfe_context(query_params: Dict, course_key: CourseKey, user: User) -> Optional[Dict]:
"""
Returns the context for rendering the MFE banner and MFE.
Args:
query_params (Dict): request query parameters
course_key (CourseKey): course for which to get URL
Returns:
A URL for the MFE experience if active for the current request or None
"""
experience_param = query_params.get("discussions_experience", "").lower()
mfe_url = get_discussions_mfe_url(course_key)
if not mfe_url:
return {"show_banner": False, "show_mfe": False}
show_banner = bool(has_access(user, 'staff', course_key))
forum_url = reverse("forum_form_discussion", args=[course_key])
show_mfe = False
# Show the MFE if the new experience is requested,
# or if the legacy experience is not requested and the MFE is enabled
if experience_param == "new" or (experience_param != "legacy" and ENABLE_DISCUSSIONS_MFE.is_enabled(course_key)):
show_mfe = True
return {
"show_mfe": show_mfe,
"legacy_url": f"{forum_url}?discussions_experience=legacy",
"mfe_url": f"{forum_url}?discussions_experience=new",
"course_key": course_key,
"show_banner": show_banner,
"discussions_mfe_url": mfe_url,
}
class DiscussionBoardFragmentView(EdxFragmentView):
"""
Component implementation of the discussion board.
@@ -721,13 +753,9 @@ class DiscussionBoardFragmentView(EdxFragmentView):
Fragment: The fragment representing the discussion board
"""
course_key = CourseKey.from_string(course_id)
mfe_url = get_discussions_mfe_url(course_key)
if ENABLE_DISCUSSIONS_MFE.is_enabled(course_key) and mfe_url:
fragment = Fragment(
HTML(
"<iframe id='discussions-mfe-tab-embed' src='{src}'></iframe>"
).format(src=mfe_url)
)
mfe_context = _discussions_mfe_context(request.GET, course_key, request.user)
if mfe_context["show_mfe"]:
fragment = Fragment(render_to_string('discussion/discussion_mfe_embed.html', mfe_context))
fragment.add_css(
"""
#discussions-mfe-tab-embed {
@@ -762,6 +790,7 @@ class DiscussionBoardFragmentView(EdxFragmentView):
context.update({
'course_expiration_fragment': course_expiration_fragment,
})
context.update(mfe_context)
if profile_page_context:
# EDUCATOR-2119: styles are hard to reconcile if the profile page isn't also a fragment
html = render_to_string('discussion/discussion_profile_page.html', profile_page_context)

View File

@@ -0,0 +1,29 @@
## mako
<%page expression_filter="h"/>
<%!
from django.utils.translation import ugettext as _
%>
% if show_banner:
<div class="upgrade-banner d-flex bg-primary text-white align-items-center px-4 py-3">
<div class="d-flex w-100">
${_("We've made some changes to this experience! (Preview for educators only)")}
</div>
% if show_mfe:
<a class="btn btn-outline-light mr-2" href="${legacy_url}">
${_("View legacy experience")}
</a>
% else:
<a class="btn btn-outline-light mr-2" href="${mfe_url}">
${_("View the new experience")}
</a>
% endif
<a class="btn btn-outline-light">
${_("Share feedback")}
</a>
</div>
% endif

View File

@@ -1,36 +1,56 @@
"""
Helps for building discussions URLs
"""
from typing import Optional
from django.conf import settings
from opaque_keys.edx.keys import CourseKey
def get_discussions_mfe_url(course_key: CourseKey) -> str:
def _get_url_with_view_query_params(path: str, view: Optional[str] = None) -> str:
"""
Helper function to build url if a url is configured
Args:
path (str): The path in the discussions MFE
view (str): which view to generate url for
Returns:
(str) URL link for MFE
"""
if settings.DISCUSSIONS_MICROFRONTEND_URL is None:
return ''
url = f"{settings.DISCUSSIONS_MICROFRONTEND_URL}/{path}"
if view == "in_context":
url = f"{url}?inContext"
return url
def get_discussions_mfe_url(course_key: CourseKey, view: Optional[str] = None) -> str:
"""
Returns the url for discussions for the specified course in the discussions MFE.
Args:
course_key (CourseKey): course key of course for which to get url
view (str): which view to generate url for
Returns:
(str) URL link for MFE. Empty if the base url isn't configured
"""
if settings.DISCUSSIONS_MICROFRONTEND_URL is not None:
return f"{settings.DISCUSSIONS_MICROFRONTEND_URL}/{course_key}/"
return ''
return _get_url_with_view_query_params(f"{course_key}/", view)
def get_discussions_mfe_topic_url(course_key: CourseKey, topic_id: str) -> str:
def get_discussions_mfe_topic_url(course_key: CourseKey, topic_id: str, view: Optional[str] = None) -> str:
"""
Returns the url for discussions for the specified course and topic in the discussions MFE.
Args:
course_key (CourseKey): course key of course for which to get url
topic_id (str): topic id for which to generate URL
topic_id (str): topic id for topic to get url for
view (str): which view to generate url for
Returns:
(str) URL link for MFE. Empty if the base url isn't configured
"""
if settings.DISCUSSIONS_MICROFRONTEND_URL is not None:
return f"{get_discussions_mfe_url(course_key)}topics/{topic_id}"
return ''
return _get_url_with_view_query_params(f"{course_key}/topics/{topic_id}", view)

View File

@@ -11,16 +11,15 @@ 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 xblock.fields import UNIQUE_ID, Scope, String
from xblockutils.resources import ResourceLoader
from xblockutils.studio_editable import StudioEditableXBlockMixin
from xmodule.xml_module import XmlParserMixin
from openedx.core.djangoapps.discussions.url_helpers import get_discussions_mfe_topic_url
from lms.djangoapps.discussion.toggles import ENABLE_DISCUSSIONS_MFE
from openedx.core.djangoapps.discussions.url_helpers import get_discussions_mfe_topic_url
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 # lint-amnesty, pylint: disable=wrong-import-order
log = logging.getLogger(__name__)
loader = ResourceLoader(__name__) # pylint: disable=invalid-name