refactor: centralize learning MFE URL-building logic (#26689)

In preparation for switching LMS/Studio over
from serving legacy courseware URLs in certain
places (for example, resume_course_url) to serving
learning micro-frontend URLs.

TNL-7796
This commit is contained in:
Kyle McCormick
2021-02-24 08:50:15 -05:00
committed by GitHub
parent 441bfffd9b
commit 558d2eb52c
14 changed files with 67 additions and 75 deletions

View File

@@ -1,8 +0,0 @@
"""Deprecated import support. Auto-generated by import_shims/generate_shims.sh."""
# pylint: disable=redefined-builtin,wrong-import-position,wildcard-import,useless-suppression,line-too-long
from import_shims.warn import warn_deprecated_import
warn_deprecated_import('course_home_api.utils', 'lms.djangoapps.course_home_api.utils')
from lms.djangoapps.course_home_api.utils import *

View File

@@ -1,8 +0,0 @@
"""Deprecated import support. Auto-generated by import_shims/generate_shims.sh."""
# pylint: disable=redefined-builtin,wrong-import-position,wildcard-import,useless-suppression,line-too-long
from import_shims.warn import warn_deprecated_import
warn_deprecated_import('courseware.url_helpers', 'lms.djangoapps.courseware.url_helpers')
from lms.djangoapps.courseware.url_helpers import *

View File

@@ -31,7 +31,6 @@ from lms.djangoapps.course_home_api.toggles import (
course_home_mfe_dates_tab_is_active, course_home_mfe_dates_tab_is_active,
course_home_mfe_outline_tab_is_active course_home_mfe_outline_tab_is_active
) )
from lms.djangoapps.course_home_api.utils import get_microfrontend_url
from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs from lms.djangoapps.courseware.context_processor import user_timezone_locale_prefs
from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_info_section, get_course_with_access from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_info_section, get_course_with_access
@@ -46,6 +45,7 @@ from openedx.features.course_experience.course_updates import (
dismiss_current_update_for_user, dismiss_current_update_for_user,
get_current_update_for_user get_current_update_for_user
) )
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
from openedx.features.course_experience.utils import get_course_outline_block_tree, get_start_block from openedx.features.course_experience.utils import get_course_outline_block_tree, get_start_block
from openedx.features.discounts.utils import generate_offer_data from openedx.features.discounts.utils import generate_offer_data
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE
@@ -189,7 +189,7 @@ class OutlineTabView(RetrieveAPIView):
dates_tab_link = request.build_absolute_uri(reverse('dates', args=[course.id])) dates_tab_link = request.build_absolute_uri(reverse('dates', args=[course.id]))
if course_home_mfe_dates_tab_is_active(course.id): if course_home_mfe_dates_tab_is_active(course.id):
dates_tab_link = get_microfrontend_url(course_key=course.id, view_name='dates') dates_tab_link = get_learning_mfe_home_url(course_key=course.id, view_name='dates')
# Set all of the defaults # Set all of the defaults
access_expiration = None access_expiration = None

View File

@@ -1,23 +0,0 @@
"""Utility functions for course home"""
from django.conf import settings
def get_microfrontend_url(course_key, view_name=None):
"""
Takes in a course key and view name, returns the appropriate course home mfe route
"""
mfe_link = f'{settings.LEARNING_MICROFRONTEND_URL}/course/{course_key}'
if view_name:
mfe_link += f'/{view_name}'
return mfe_link
def is_request_from_learning_mfe(request):
"""
Returns whether the given request was made by the frontend-app-learning MFE.
"""
return (settings.LEARNING_MICROFRONTEND_URL and
request.META.get('HTTP_REFERER', '').startswith(settings.LEARNING_MICROFRONTEND_URL))

View File

@@ -12,9 +12,9 @@ from django.utils.translation import ugettext_noop
from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.entrance_exams import user_can_skip_entrance_exam from lms.djangoapps.courseware.entrance_exams import user_can_skip_entrance_exam
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active, course_home_mfe_outline_tab_is_active # lint-amnesty, pylint: disable=line-too-long from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active, course_home_mfe_outline_tab_is_active # lint-amnesty, pylint: disable=line-too-long
from lms.djangoapps.course_home_api.utils import get_microfrontend_url
from openedx.core.lib.course_tabs import CourseTabPluginManager from openedx.core.lib.course_tabs import CourseTabPluginManager
from openedx.features.course_experience import RELATIVE_DATES_FLAG, DISABLE_UNIFIED_COURSE_TAB_FLAG, default_course_url_name # lint-amnesty, pylint: disable=line-too-long from openedx.features.course_experience import RELATIVE_DATES_FLAG, DISABLE_UNIFIED_COURSE_TAB_FLAG, default_course_url_name # lint-amnesty, pylint: disable=line-too-long
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.models import CourseEnrollment
from xmodule.tabs import CourseTab, CourseTabList, course_reverse_func_from_name_func, key_checker from xmodule.tabs import CourseTab, CourseTabList, course_reverse_func_from_name_func, key_checker
@@ -44,7 +44,7 @@ class CoursewareTab(EnrolledTab):
def __init__(self, tab_dict): def __init__(self, tab_dict):
def link_func(course, reverse_func): def link_func(course, reverse_func):
if course_home_mfe_outline_tab_is_active(course.id): if course_home_mfe_outline_tab_is_active(course.id):
return get_microfrontend_url(course_key=course.id, view_name='home') return get_learning_mfe_home_url(course_key=course.id, view_name='home')
else: else:
reverse_name_func = lambda course: default_course_url_name(course.id) reverse_name_func = lambda course: default_course_url_name(course.id)
url_func = course_reverse_func_from_name_func(reverse_name_func) url_func = course_reverse_func_from_name_func(reverse_name_func)
@@ -326,7 +326,7 @@ class DatesTab(EnrolledTab):
def __init__(self, tab_dict): def __init__(self, tab_dict):
def link_func(course, reverse_func): def link_func(course, reverse_func):
if course_home_mfe_dates_tab_is_active(course.id): if course_home_mfe_dates_tab_is_active(course.id):
return get_microfrontend_url(course_key=course.id, view_name=self.view_name) return get_learning_mfe_home_url(course_key=course.id, view_name=self.view_name)
else: else:
return reverse_func(self.view_name, args=[six.text_type(course.id)]) return reverse_func(self.view_name, args=[six.text_type(course.id)])

View File

@@ -61,7 +61,6 @@ from lms.djangoapps.courseware.toggles import (
REDIRECT_TO_COURSEWARE_MICROFRONTEND, REDIRECT_TO_COURSEWARE_MICROFRONTEND,
) )
from lms.djangoapps.courseware.url_helpers import get_microfrontend_url, get_redirect_url
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
from lms.djangoapps.courseware.views.index import show_courseware_mfe_link from lms.djangoapps.courseware.views.index import show_courseware_mfe_link
from lms.djangoapps.experiments.testutils import override_experiment_waffle_flag from lms.djangoapps.experiments.testutils import override_experiment_waffle_flag
@@ -88,6 +87,7 @@ from openedx.features.course_experience import (
RELATIVE_DATES_FLAG RELATIVE_DATES_FLAG
) )
from openedx.features.course_experience.tests.views.helpers import add_course_mode from openedx.features.course_experience.tests.views.helpers import add_course_mode
from openedx.features.course_experience.url_helpers import get_learning_mfe_courseware_url, get_legacy_courseware_url
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired
from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.roles import CourseStaffRole from common.djangoapps.student.roles import CourseStaffRole
@@ -258,7 +258,7 @@ class TestJumpTo(ModuleStoreTestCase):
) )
expected_url += "?{}".format(urlencode({'activate_block_id': six.text_type(staff_only_vertical.location)})) expected_url += "?{}".format(urlencode({'activate_block_id': six.text_type(staff_only_vertical.location)}))
assert expected_url == get_redirect_url(course_key, usage_key, request) assert expected_url == get_legacy_courseware_url(course_key, usage_key, request)
@ddt.ddt @ddt.ddt
@@ -548,9 +548,9 @@ class ViewsTestCase(BaseViewsTestCase):
def test_get_redirect_url(self): def test_get_redirect_url(self):
# test the course location # test the course location
assert u'/courses/{course_key}/courseware?{activate_block_id}'.format(course_key=text_type(self.course_key), activate_block_id=urlencode({'activate_block_id': text_type(self.course.location)})) == get_redirect_url(self.course_key, self.course.location) # pylint: disable=line-too-long assert u'/courses/{course_key}/courseware?{activate_block_id}'.format(course_key=text_type(self.course_key), activate_block_id=urlencode({'activate_block_id': text_type(self.course.location)})) == get_legacy_courseware_url(self.course_key, self.course.location) # pylint: disable=line-too-long
# test a section location # test a section location
assert u'/courses/{course_key}/courseware/Chapter_1/Sequential_1/?{activate_block_id}'.format(course_key=text_type(self.course_key), activate_block_id=urlencode({'activate_block_id': text_type(self.section.location)})) == get_redirect_url(self.course_key, self.section.location) # pylint: disable=line-too-long assert u'/courses/{course_key}/courseware/Chapter_1/Sequential_1/?{activate_block_id}'.format(course_key=text_type(self.course_key), activate_block_id=urlencode({'activate_block_id': text_type(self.section.location)})) == get_legacy_courseware_url(self.course_key, self.section.location) # pylint: disable=line-too-long
def test_invalid_course_id(self): def test_invalid_course_id(self):
response = self.client.get('/courses/MITx/3.091X/') response = self.client.get('/courses/MITx/3.091X/')
@@ -3349,16 +3349,16 @@ class TestShowCoursewareMFE(TestCase):
course_key = CourseKey.from_string("course-v1:OpenEdX+MFE+2020") course_key = CourseKey.from_string("course-v1:OpenEdX+MFE+2020")
section_key = UsageKey.from_string("block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction") section_key = UsageKey.from_string("block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction")
unit_id = "block-v1:OpenEdX+MFE+2020+type@vertical+block@Getting_To_Know_You" unit_id = "block-v1:OpenEdX+MFE+2020+type@vertical+block@Getting_To_Know_You"
assert get_microfrontend_url(course_key) == ( assert get_learning_mfe_courseware_url(course_key) == (
'https://learningmfe.openedx.org' 'https://learningmfe.openedx.org'
'/course/course-v1:OpenEdX+MFE+2020' '/course/course-v1:OpenEdX+MFE+2020'
) )
assert get_microfrontend_url(course_key, section_key, '') == ( assert get_learning_mfe_courseware_url(course_key, section_key, '') == (
'https://learningmfe.openedx.org' 'https://learningmfe.openedx.org'
'/course/course-v1:OpenEdX+MFE+2020' '/course/course-v1:OpenEdX+MFE+2020'
'/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction' '/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction'
) )
assert get_microfrontend_url(course_key, section_key, unit_id) == ( assert get_learning_mfe_courseware_url(course_key, section_key, unit_id) == (
'https://learningmfe.openedx.org' 'https://learningmfe.openedx.org'
'/course/course-v1:OpenEdX+MFE+2020' '/course/course-v1:OpenEdX+MFE+2020'
'/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction' '/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction'

View File

@@ -12,8 +12,8 @@ from mock import patch
from six.moves.urllib.parse import urlencode from six.moves.urllib.parse import urlencode
from lms.djangoapps.courseware.field_overrides import OverrideModulestoreFieldData from lms.djangoapps.courseware.field_overrides import OverrideModulestoreFieldData
from lms.djangoapps.courseware.url_helpers import get_redirect_url
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.features.course_experience.url_helpers import get_legacy_courseware_url
from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
@@ -175,7 +175,7 @@ class RenderXBlockTestMixin(six.with_metaclass(ABCMeta, object)):
self.setup_user(admin=True, enroll=True, login=True) self.setup_user(admin=True, enroll=True, login=True)
with check_mongo_calls(mongo_calls): with check_mongo_calls(mongo_calls):
url = get_redirect_url(self.course.id, self.block_to_be_tested.location) url = get_legacy_courseware_url(self.course.id, self.block_to_be_tested.location)
response = self.client.get(url) response = self.client.get(url)
expected_elements = self.block_specific_chrome_html_elements + self.COURSEWARE_CHROME_HTML_ELEMENTS expected_elements = self.block_specific_chrome_html_elements + self.COURSEWARE_CHROME_HTML_ELEMENTS
for chrome_element in expected_elements: for chrome_element in expected_elements:

View File

@@ -44,6 +44,7 @@ from openedx.features.course_experience import (
default_course_url_name default_course_url_name
) )
from openedx.features.course_experience.views.course_sock import CourseSockFragmentView from openedx.features.course_experience.views.course_sock import CourseSockFragmentView
from openedx.features.course_experience.url_helpers import get_learning_mfe_courseware_url
from openedx.features.enterprise_support.api import data_sharing_consent_required from openedx.features.enterprise_support.api import data_sharing_consent_required
from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.util.views import ensure_valid_course_key from common.djangoapps.util.views import ensure_valid_course_key
@@ -65,7 +66,6 @@ from ..model_data import FieldDataCache
from ..module_render import get_module_for_descriptor, toc_for_course from ..module_render import get_module_for_descriptor, toc_for_course
from ..permissions import MASQUERADE_AS_STUDENT from ..permissions import MASQUERADE_AS_STUDENT
from ..toggles import COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, REDIRECT_TO_COURSEWARE_MICROFRONTEND from ..toggles import COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, REDIRECT_TO_COURSEWARE_MICROFRONTEND
from ..url_helpers import get_microfrontend_url
from .views import CourseTabView from .views import CourseTabView
log = logging.getLogger("edx.courseware.views.index") log = logging.getLogger("edx.courseware.views.index")
@@ -203,7 +203,7 @@ class CoursewareIndex(View):
unit_key = None unit_key = None
except InvalidKeyError: except InvalidKeyError:
unit_key = None unit_key = None
url = get_microfrontend_url( url = get_learning_mfe_courseware_url(
self.course_key, self.course_key,
self.section.location if self.section else None, self.section.location if self.section else None,
unit_key unit_key

View File

@@ -56,7 +56,7 @@ from lms.djangoapps.certificates import api as certs_api
from lms.djangoapps.certificates.models import CertificateStatuses from lms.djangoapps.certificates.models import CertificateStatuses
from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.commerce.utils import EcommerceService
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active
from lms.djangoapps.course_home_api.utils import get_microfrontend_url, is_request_from_learning_mfe from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url, is_request_from_learning_mfe
from lms.djangoapps.courseware.access import has_access, has_ccx_coach_role from lms.djangoapps.courseware.access import has_access, has_ccx_coach_role
from lms.djangoapps.courseware.access_utils import check_course_open_for_learner, check_public_access from lms.djangoapps.courseware.access_utils import check_course_open_for_learner, check_public_access
from lms.djangoapps.courseware.courses import ( from lms.djangoapps.courseware.courses import (
@@ -84,7 +84,6 @@ from lms.djangoapps.courseware.permissions import ( # lint-amnesty, pylint: dis
VIEW_COURSEWARE, VIEW_COURSEWARE,
VIEW_XQA_INTERFACE VIEW_XQA_INTERFACE
) )
from lms.djangoapps.courseware.url_helpers import get_redirect_url
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context
from lms.djangoapps.grades.api import CourseGradeFactory from lms.djangoapps.grades.api import CourseGradeFactory
@@ -114,6 +113,7 @@ from openedx.features.content_type_gating.models import ContentTypeGatingConfig
from openedx.features.course_duration_limits.access import generate_course_expired_fragment from openedx.features.course_duration_limits.access import generate_course_expired_fragment
from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, course_home_url_name from openedx.features.course_experience import DISABLE_UNIFIED_COURSE_TAB_FLAG, course_home_url_name
from openedx.features.course_experience.course_tools import CourseToolsPluginManager from openedx.features.course_experience.course_tools import CourseToolsPluginManager
from openedx.features.course_experience.url_helpers import get_legacy_courseware_url
from openedx.features.course_experience.utils import dates_banner_should_display from openedx.features.course_experience.utils import dates_banner_should_display
from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView from openedx.features.course_experience.views.course_dates import CourseDatesFragmentView
from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML
@@ -396,7 +396,7 @@ def jump_to(_request, course_id, location):
except InvalidKeyError: except InvalidKeyError:
raise Http404(u"Invalid course_key or usage_key") # lint-amnesty, pylint: disable=raise-missing-from raise Http404(u"Invalid course_key or usage_key") # lint-amnesty, pylint: disable=raise-missing-from
try: try:
redirect_url = get_redirect_url(course_key, usage_key, _request) redirect_url = get_legacy_courseware_url(course_key, usage_key, _request)
except ItemNotFoundError: except ItemNotFoundError:
raise Http404(u"No data at this location: {0}".format(usage_key)) # lint-amnesty, pylint: disable=raise-missing-from raise Http404(u"No data at this location: {0}".format(usage_key)) # lint-amnesty, pylint: disable=raise-missing-from
except NoPathToItem: except NoPathToItem:
@@ -1016,7 +1016,7 @@ def dates(request, course_id):
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
if course_home_mfe_dates_tab_is_active(course_key) and not request.user.is_staff: if course_home_mfe_dates_tab_is_active(course_key) and not request.user.is_staff:
microfrontend_url = get_microfrontend_url(course_key=course_key, view_name=COURSE_DATES_NAME) microfrontend_url = get_learning_mfe_home_url(course_key=course_key, view_name=COURSE_DATES_NAME)
raise Redirect(microfrontend_url) raise Redirect(microfrontend_url)
# Enable NR tracing for this view based on course # Enable NR tracing for this view based on course

View File

@@ -21,7 +21,6 @@ from opaque_keys.edx.keys import CourseKey
from lms.djangoapps.course_api.api import course_detail from lms.djangoapps.course_api.api import course_detail
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active
from lms.djangoapps.course_home_api.utils import get_microfrontend_url
from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.courses import get_course_with_access from lms.djangoapps.courseware.courses import get_course_with_access
from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade
@@ -29,6 +28,7 @@ from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquera
from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
from openedx.features.course_experience.api.v1.serializers import CourseDeadlinesMobileSerializer from openedx.features.course_experience.api.v1.serializers import CourseDeadlinesMobileSerializer
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
from openedx.features.course_experience.utils import dates_banner_should_display from openedx.features.course_experience.utils import dates_banner_should_display
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -91,7 +91,7 @@ def reset_course_deadlines(request):
tracker.emit('edx.ui.lms.reset_deadlines.clicked', research_event_data) tracker.emit('edx.ui.lms.reset_deadlines.clicked', research_event_data)
if course_home_mfe_dates_tab_is_active(course_key): if course_home_mfe_dates_tab_is_active(course_key):
body_link = get_microfrontend_url(course_key=str(course_key), view_name='dates') body_link = get_learning_mfe_home_url(course_key=str(course_key), view_name='dates')
else: else:
body_link = '{}{}'.format(settings.LMS_ROOT_URL, reverse('dates', args=[str(course_key)])) body_link = '{}{}'.format(settings.LMS_ROOT_URL, reverse('dates', args=[str(course_key)]))

View File

@@ -1,8 +1,9 @@
""" """
Module to define url helpers functions Helper functions for logic related to learning (courseare & course home) URLs.
Centralizdd in openedx/features/course_experience instead of lms/djangoapps/courseware
because the Studio course outline may need these utilities.
""" """
import six import six
from django.conf import settings from django.conf import settings
from django.urls import reverse from django.urls import reverse
@@ -12,12 +13,13 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.search import navigation_index, path_to_location from xmodule.modulestore.search import navigation_index, path_to_location
def get_redirect_url(course_key, usage_key, request=None): def get_legacy_courseware_url(course_key, usage_key, request=None):
""" Returns the redirect url back to courseware """
Return a str with the URL for the specified legacy (LMS-rendered) coursweare content.
Args: Args:
course_id(str): Course Id string course_id(str): Course Id string
location(str): The location id of course component usage_key(str): The location id of course component
Raises: Raises:
ItemNotFoundError if no data at the location or NoPathToItem if location not in any class ItemNotFoundError if no data at the location or NoPathToItem if location not in any class
@@ -55,9 +57,9 @@ def get_redirect_url(course_key, usage_key, request=None):
return redirect_url return redirect_url
def get_microfrontend_url(course_key, sequence_key=None, unit_key=None): def get_learning_mfe_courseware_url(course_key, sequence_key=None, unit_key=None):
""" """
Return a str with the URL for the specified content in the Courseware MFE. Return a str with the URL for the specified coursweare content in the Learning MFE.
The micro-frontend determines the user's position in the vertical via The micro-frontend determines the user's position in the vertical via
a separate API call, so all we need here is the course_key, section, and a separate API call, so all we need here is the course_key, section, and
@@ -74,7 +76,7 @@ def get_microfrontend_url(course_key, sequence_key=None, unit_key=None):
We're building a URL like this: We're building a URL like this:
http://localhost:2000/course-v1:edX+DemoX+Demo_Course/block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76 http://localhost:2000/course/course-v1:edX+DemoX+Demo_Course/block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76
`course_key`, `sequence_key`, and `unit_key` can be either OpaqueKeys or `course_key`, `sequence_key`, and `unit_key` can be either OpaqueKeys or
strings. They're only ever used to concatenate a URL string. strings. They're only ever used to concatenate a URL string.
@@ -88,3 +90,32 @@ def get_microfrontend_url(course_key, sequence_key=None, unit_key=None):
mfe_link += '/{}'.format(unit_key) mfe_link += '/{}'.format(unit_key)
return mfe_link return mfe_link
def get_learning_mfe_home_url(course_key, view_name=None):
"""
Given a course run key and view name, return the appropriate course home (MFE) URL.
We're building a URL like this:
http://localhost:2000/course/course-v1:edX+DemoX+Demo_Course/dates
`course_key` can be either an OpaqueKey or a string.
`view_name` is an optional string.
"""
mfe_link = f'{settings.LEARNING_MICROFRONTEND_URL}/course/{course_key}'
if view_name:
mfe_link += f'/{view_name}'
return mfe_link
def is_request_from_learning_mfe(request):
"""
Returns whether the given request was made by the frontend-app-learning MFE.
"""
return (
settings.LEARNING_MICROFRONTEND_URL and
request.META.get('HTTP_REFERER', '').startswith(settings.LEARNING_MICROFRONTEND_URL)
)

View File

@@ -15,7 +15,7 @@ from web_fragments.fragment import Fragment
from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_with_access from lms.djangoapps.courseware.courses import get_course_date_blocks, get_course_with_access
from lms.djangoapps.courseware.tabs import DatesTab from lms.djangoapps.courseware.tabs import DatesTab
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active
from lms.djangoapps.course_home_api.utils import get_microfrontend_url from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
@@ -35,7 +35,7 @@ class CourseDatesFragmentView(EdxFragmentView):
dates_tab_enabled = DatesTab.is_enabled(course, request.user) dates_tab_enabled = DatesTab.is_enabled(course, request.user)
if course_home_mfe_dates_tab_is_active(course_key): if course_home_mfe_dates_tab_is_active(course_key):
dates_tab_link = get_microfrontend_url(course_key=course.id, view_name='dates') dates_tab_link = get_learning_mfe_home_url(course_key=course.id, view_name='dates')
else: else:
dates_tab_link = reverse('dates', args=[course.id]) dates_tab_link = reverse('dates', args=[course.id])

View File

@@ -15,7 +15,6 @@ from opaque_keys.edx.keys import CourseKey
from web_fragments.fragment import Fragment from web_fragments.fragment import Fragment
from lms.djangoapps.course_home_api.toggles import course_home_mfe_outline_tab_is_active from lms.djangoapps.course_home_api.toggles import course_home_mfe_outline_tab_is_active
from lms.djangoapps.course_home_api.utils import get_microfrontend_url
from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.courses import can_self_enroll_in_course, get_course_info_section, get_course_with_access from lms.djangoapps.courseware.courses import can_self_enroll_in_course, get_course_info_section, get_course_with_access
from lms.djangoapps.course_goals.api import ( from lms.djangoapps.course_goals.api import (
@@ -33,6 +32,7 @@ from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.core.djangoapps.util.maintenance_banner import add_maintenance_banner from openedx.core.djangoapps.util.maintenance_banner import add_maintenance_banner
from openedx.features.course_duration_limits.access import generate_course_expired_fragment from openedx.features.course_duration_limits.access import generate_course_expired_fragment
from openedx.features.course_experience.course_tools import CourseToolsPluginManager from openedx.features.course_experience.course_tools import CourseToolsPluginManager
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
from openedx.features.discounts.utils import get_first_purchase_offer_banner_fragment from openedx.features.discounts.utils import get_first_purchase_offer_banner_fragment
from openedx.features.discounts.utils import format_strikeout_price from openedx.features.discounts.utils import format_strikeout_price
from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.models import CourseEnrollment
@@ -72,7 +72,7 @@ class CourseHomeView(CourseTabView):
def render_to_fragment(self, request, course=None, tab=None, **kwargs): # lint-amnesty, pylint: disable=arguments-differ, unused-argument def render_to_fragment(self, request, course=None, tab=None, **kwargs): # lint-amnesty, pylint: disable=arguments-differ, unused-argument
course_id = six.text_type(course.id) course_id = six.text_type(course.id)
if course_home_mfe_outline_tab_is_active(course.id) and not request.user.is_staff: if course_home_mfe_outline_tab_is_active(course.id) and not request.user.is_staff:
microfrontend_url = get_microfrontend_url(course_key=course_id, view_name="home") microfrontend_url = get_learning_mfe_home_url(course_key=course_id, view_name="home")
raise Redirect(microfrontend_url) raise Redirect(microfrontend_url)
home_fragment_view = CourseHomeFragmentView() home_fragment_view = CourseHomeFragmentView()
return home_fragment_view.render_to_fragment(request, course_id=course_id, **kwargs) return home_fragment_view.render_to_fragment(request, course_id=course_id, **kwargs)

View File

@@ -11,8 +11,8 @@ from django.urls import reverse
from django.utils.translation import ngettext, gettext as _ from django.utils.translation import ngettext, gettext as _
from common.lib.xmodule.xmodule.util.misc import is_xblock_an_assignment from common.lib.xmodule.xmodule.util.misc import is_xblock_an_assignment
from lms.djangoapps.course_home_api.utils import is_request_from_learning_mfe
from openedx.core.lib.mobile_utils import is_request_from_mobile_app from openedx.core.lib.mobile_utils import is_request_from_mobile_app
from openedx.features.course_experience.url_helpers import is_request_from_learning_mfe
from openedx.features.course_experience.utils import dates_banner_should_display from openedx.features.course_experience.utils import dates_banner_should_display
log = logging.getLogger(__name__) log = logging.getLogger(__name__)