From fe1942561a3978ea1070d03afa1ae0f445fe9558 Mon Sep 17 00:00:00 2001 From: David Joy Date: Thu, 6 Feb 2020 17:35:04 -0500 Subject: [PATCH] =?UTF-8?q?Redirect=20to=20the=20courseware=20MFE=20when?= =?UTF-8?q?=20the=20=E2=80=98courseware=E2=80=99=20view=20is=20loaded?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lms/djangoapps/courseware/tests/test_views.py | 51 ++++++++++++++++- lms/djangoapps/courseware/toggles.py | 2 +- lms/djangoapps/courseware/url_helpers.py | 55 ++++++++++--------- lms/djangoapps/courseware/views/index.py | 6 ++ lms/envs/test.py | 1 + 5 files changed, 88 insertions(+), 27 deletions(-) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index aa88525002..6464ffaa26 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -4,6 +4,7 @@ Tests courseware views.py """ +import logging import itertools import json import unittest @@ -36,6 +37,7 @@ from xblock.core import XBlock from xblock.fields import Scope, String import lms.djangoapps.courseware.views.views as views +from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND import shoppingcart from capa.tests.response_xml_factory import MultipleChoiceResponseXMLFactory @@ -68,6 +70,7 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi from openedx.core.djangoapps.crawlers.models import CrawlersConfig from openedx.core.djangoapps.credit.api import set_credit_requirements from openedx.core.djangoapps.credit.models import CreditCourse, CreditProvider +from openedx.core.djangoapps.site_configuration.tests.mixins import SiteMixin from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES, override_waffle_flag from openedx.core.djangolib.testing.utils import get_mock_request from openedx.core.lib.gating import api as gating_api @@ -103,9 +106,10 @@ QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES FEATURES_WITH_DISABLE_HONOR_CERTIFICATE = settings.FEATURES.copy() FEATURES_WITH_DISABLE_HONOR_CERTIFICATE['DISABLE_HONOR_CERTIFICATES'] = True +LOGGER = logging.getLogger(__name__) @ddt.ddt -class TestJumpTo(ModuleStoreTestCase): +class TestJumpTo(ModuleStoreTestCase, SiteMixin): """ Check the jumpto link for a course. """ @@ -250,6 +254,51 @@ class TestJumpTo(ModuleStoreTestCase): self.assertEqual(expected_url, get_redirect_url(course_key, usage_key, request)) + def test_jump_to_with_microfrontend_enabled(self): + course = CourseFactory.create() + chapter = ItemFactory.create(category='chapter', parent_location=course.location) + section = ItemFactory.create(category='sequential', parent_location=chapter.location) + unit = ItemFactory.create(category='vertical', parent_location=section.location) + course_key = CourseKey.from_string(six.text_type(course.id)) + + # unit position is hard coded here for simplicity - is there a simple way to get it from here? + expected = '/courses/{course_id}/courseware/{chapter_id}/{section_id}/1?{activate_block_id}'.format( + course_id=six.text_type(course.id), + chapter_id=chapter.url_name, + section_id=section.url_name, + activate_block_id=urlencode({'activate_block_id': six.text_type(unit.location)}) + ) + jumpto_url = '{0}/{1}/jump_to/{2}'.format( + '/courses', + six.text_type(course.id), + six.text_type(unit.location), + ) + + microfrontend_expected = 'http://learning-mfe/course/{course_key}/{section_id}/{unit_id}'.format( + course_key=course_key, + section_id=section.location, + unit_id=unit.location + ) + """ + http://learning-mfe/course/org.0/course_0/Run_0/i4x://org.0/course_0/sequential/sequential_2/i4x://org.0/course_0/vertical/vertical_3', + http://learning-mfe/course/org.0/course_0/Run_0/i4x://org.0/course_0/sequential/sequential_2/vertical_3 + """ + + with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, active=True): + response = self.client.get(jumpto_url) + self.assertRedirects(response, expected, status_code=302, target_status_code=302) + + # Test with waffle flag active and site setting enabled, redirects to microfrontend + site_domain = 'othersite.example.com' + self.set_up_site(site_domain, { + 'SITE_NAME': site_domain, + 'ENABLE_COURSEWARE_MICROFRONTEND': True + }) + + response = self.client.get(jumpto_url) + LOGGER.error(response.url) # None/course/org.0/course_0/Run_0/i4x://org.0/course_0/sequential/sequential_2 + self.assertRedirects(response, microfrontend_expected, fetch_redirect_response=False, status_code=302, target_status_code=302) + @ddt.ddt class IndexQueryTestCase(ModuleStoreTestCase): diff --git a/lms/djangoapps/courseware/toggles.py b/lms/djangoapps/courseware/toggles.py index 7e7a5a52ba..0058f7631f 100644 --- a/lms/djangoapps/courseware/toggles.py +++ b/lms/djangoapps/courseware/toggles.py @@ -18,7 +18,7 @@ WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='courseware') # .. toggle_creation_date: 2020-01-29 # .. toggle_expiration_date: 2020-12-31 # .. toggle_warnings: Also set settings.LEARNING_MICROFRONTEND_URL and ENABLE_COURSEWARE_MICROFRONTEND. -# .. toggle_tickets: +# .. toggle_tickets: TNL-6982 # .. toggle_status: supported REDIRECT_TO_COURSEWARE_MICROFRONTEND = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'redirect_to_microfrontend') diff --git a/lms/djangoapps/courseware/url_helpers.py b/lms/djangoapps/courseware/url_helpers.py index e8738163e8..4fbe27ad9c 100644 --- a/lms/djangoapps/courseware/url_helpers.py +++ b/lms/djangoapps/courseware/url_helpers.py @@ -11,6 +11,7 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.search import navigation_index, path_to_location from lms.djangoapps.courseware.toggles import should_redirect_to_courseware_microfrontend + def get_redirect_url(course_key, usage_key, request=None): """ Returns the redirect url back to courseware @@ -26,8 +27,8 @@ def get_redirect_url(course_key, usage_key, request=None): """ if should_redirect_to_courseware_microfrontend(course_key): - path = path_to_location(modulestore(), usage_key, request, full_path=True) - return get_microfrontend_redirect_url(course_key, path) + path = path_to_location(modulestore(), usage_key, request, full_path=True) + return get_microfrontend_redirect_url(course_key, path) ( course_key, chapter, section, vertical_unused, @@ -57,8 +58,9 @@ def get_redirect_url(course_key, usage_key, request=None): redirect_url += "?{}".format(urlencode({'activate_block_id': six.text_type(final_target_id)})) return redirect_url -def get_microfrontend_redirect_url(course_key, path): - """ + +def get_microfrontend_redirect_url(course_key, path=None): + """ 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 vertical IDs to format it's URL. @@ -68,27 +70,30 @@ def get_microfrontend_redirect_url(course_key, path): 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 - """ + """ - redirect_url = '{base_url}/{prefix}/{course_key}'.format( - base_url=settings.LEARNING_MICROFRONTEND_URL, - prefix='course/', - course_key=course_key - ) - - # The first four elements of the path list are the ones we care about here: - # - course - # - chapter - # - sequence - # - vertical - # We skip course because we already have it from our argument above, and we skip chapter because the micro-frontend URL doesn't include it. - if len(path) > 2: - redirect_url += '/{sequence_key}'.format( - sequence_key=path[2] - ) - if len(path) > 3: - redirect_url += '/{vertical_key}'.format( - vertical_key=path[3] + redirect_url = '{base_url}/{prefix}/{course_key}'.format( + base_url=settings.LEARNING_MICROFRONTEND_URL, + prefix='course', + course_key=course_key ) - return redirect_url + if path is None: + return redirect_url + + # The first four elements of the path list are the ones we care about here: + # - course + # - chapter + # - sequence + # - vertical + # We skip course because we already have it from our argument above, and we skip chapter because the micro-frontend URL doesn't include it. + if len(path) > 2: + redirect_url += '/{sequence_key}'.format( + sequence_key=path[2] + ) + if len(path) > 3: + redirect_url += '/{vertical_key}'.format( + vertical_key=path[3] + ) + + return redirect_url diff --git a/lms/djangoapps/courseware/views/index.py b/lms/djangoapps/courseware/views/index.py index 4a0fcdd719..03968c37c0 100644 --- a/lms/djangoapps/courseware/views/index.py +++ b/lms/djangoapps/courseware/views/index.py @@ -16,6 +16,7 @@ from django.conf import settings from django.contrib.auth.models import User from django.contrib.auth.views import redirect_to_login from django.http import Http404 +from django.shortcuts import redirect from django.template.context_processors import csrf from django.urls import reverse from django.utils.decorators import method_decorator @@ -31,6 +32,8 @@ from web_fragments.fragment import Fragment from edxmako.shortcuts import render_to_response, render_to_string from lms.djangoapps.courseware.courses import allow_public_access from lms.djangoapps.courseware.exceptions import CourseAccessRedirect +from lms.djangoapps.courseware.toggles import should_redirect_to_courseware_microfrontend +from lms.djangoapps.courseware.url_helpers import get_microfrontend_redirect_url from lms.djangoapps.experiments.utils import get_experiment_user_metadata_context from lms.djangoapps.gating.api import get_entrance_exam_score_ratio, get_entrance_exam_usage_key from lms.djangoapps.grades.api import CourseGradeFactory @@ -114,6 +117,9 @@ class CoursewareIndex(View): if not (request.user.is_authenticated or self.enable_unenrolled_access): return redirect_to_login(request.get_full_path()) + if should_redirect_to_courseware_microfrontend(self.course_key): + return redirect(get_microfrontend_redirect_url(self.course_key)) + self.original_chapter_url_name = chapter self.original_section_url_name = section self.chapter_url_name = chapter diff --git a/lms/envs/test.py b/lms/envs/test.py index af51f1c4e9..ff3cd29a94 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -593,6 +593,7 @@ PDF_RECEIPT_TAX_ID_LABEL = 'Tax ID' PROFILE_MICROFRONTEND_URL = "http://profile-mfe/abc/" ORDER_HISTORY_MICROFRONTEND_URL = "http://order-history-mfe/" ACCOUNT_MICROFRONTEND_URL = "http://account-mfe/" +LEARNING_MICROFRONTEND_URL = "http://learning-mfe" ########################## limiting dashboard courses ######################