diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 9043aa411d8c19350a5843e676a7188a1140293c..e26bb36cd0cca17f62603177e9887850122ed75f 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -61,7 +61,10 @@ from lms.djangoapps.certificates.tests.factories import CertificateInvalidationF from lms.djangoapps.commerce.models import CommerceConfiguration from lms.djangoapps.commerce.utils import EcommerceService from lms.djangoapps.courseware.views.index import show_courseware_mfe_link -from lms.djangoapps.courseware.toggles import REDIRECT_TO_COURSEWARE_MICROFRONTEND +from lms.djangoapps.courseware.toggles import ( + COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, + REDIRECT_TO_COURSEWARE_MICROFRONTEND, +) from lms.djangoapps.courseware.url_helpers import get_microfrontend_url from lms.djangoapps.grades.config.waffle import ASSUME_ZERO_GRADE_IF_ABSENT from lms.djangoapps.grades.config.waffle import waffle as grades_waffle @@ -3221,36 +3224,109 @@ class DatesTabTestCase(ModuleStoreTestCase): class TestShowCoursewareMFE(TestCase): """ Make sure we're showing the Courseware MFE link when appropriate. + + There are an unfortunate number of state permutations here since we have + the product of the following binary states: + + * the ENABLE_COURSEWARE_MICROFRONTEND Django setting + * user is global staff member + * user is member of the course team + * whether the course_key is an old Mongo style of key + * the COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW CourseWaffleFlag + * the REDIRECT_TO_COURSEWARE_MICROFRONTEND CourseWaffleFlag + + Giving us theoretically 2^6 = 64 states. >_< """ - def test_when_to_show(self): - course_key = CourseKey.from_string("course-v1:OpenEdX+MFE+2020") + @patch.dict(settings.FEATURES, {'ENABLE_COURSEWARE_MICROFRONTEND': False}) + def test_disabled_at_platform_level(self): + """Test every permutation where the platform feature is disabled.""" + old_course_key = CourseKey.from_string("OpenEdX/Old/2020") + new_course_key = CourseKey.from_string("course-v1:OpenEdX+New+2020") + global_staff_user = UserFactory(username="global_staff", is_staff=True) + regular_user = UserFactory(username="normal", is_staff=False) + + # We never show when the feature is entirely disabled, no matter what + # the waffle flags are set to, who the user is, or what the course_key + # type is. + combos = itertools.product( + [regular_user, global_staff_user], # User (is global staff) + [old_course_key, new_course_key], # Course Key (old vs. new) + [True, False], # is_course_staff + [True, False], # preview_active (COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW) + [True, False], # redirect_active (REDIRECT_TO_COURSEWARE_MICROFRONTEND) + ) + for user, course_key, is_course_staff, preview_active, redirect_active in combos: + with override_waffle_flag(COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, preview_active): + with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, redirect_active): + assert show_courseware_mfe_link(user, is_course_staff, course_key) is False + + @patch.dict(settings.FEATURES, {'ENABLE_COURSEWARE_MICROFRONTEND': True}) + def test_enabled_at_platform_level(self): + """Test every permutation where the platform feature is enabled.""" + old_course_key = CourseKey.from_string("OpenEdX/Old/2020") + new_course_key = CourseKey.from_string("course-v1:OpenEdX+New+2020") global_staff_user = UserFactory(username="global_staff", is_staff=True) - user = UserFactory(username="normal", is_staff=False) - - # We never show when the feature is entirely disabled. - with patch.dict(settings.FEATURES, {'ENABLE_COURSEWARE_MICROFRONTEND': False}): - self.assertFalse(show_courseware_mfe_link(global_staff_user, True, course_key)) - self.assertFalse(show_courseware_mfe_link(user, True, course_key)) - self.assertFalse(show_courseware_mfe_link(user, False, course_key)) - - # If it's enabled at the platform level, what we do depends on the - # CourseWaffleFlag and type of user... - with patch.dict(settings.FEATURES, {'ENABLE_COURSEWARE_MICROFRONTEND': True}): - # If the feature is enabled at the platform level, we always display - # the MFE link to global staff. But course staff only see it if the - # CourseWaffleFlag is also enabled for that course. Regular users - # never see the link. + regular_user = UserFactory(username="normal", is_staff=False) + + # Old style course keys are never supported and should always return false... + old_mongo_combos = itertools.product( + [regular_user, global_staff_user], # User (is global staff) + [True, False], # is_course_staff + [True, False], # preview_active (COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW) + [True, False], # redirect_active (REDIRECT_TO_COURSEWARE_MICROFRONTEND) + ) + for user, is_course_staff, preview_active, redirect_active in old_mongo_combos: + with override_waffle_flag(COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, preview_active): + with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, redirect_active): + assert show_courseware_mfe_link(user, is_course_staff, old_course_key) is False + + # We've checked all old-style course keys now, so we can test only the + # new ones going forward. Now we check combinations of waffle flags and + # user permissions... + with override_waffle_flag(COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, True): + with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True): + # (preview=on, redirect=on) + # Global and Course Staff can see the link. + self.assertTrue(show_courseware_mfe_link(global_staff_user, True, new_course_key)) + self.assertTrue(show_courseware_mfe_link(global_staff_user, False, new_course_key)) + self.assertTrue(show_courseware_mfe_link(regular_user, True, new_course_key)) + + # Regular users don't see the link. + self.assertFalse(show_courseware_mfe_link(regular_user, False, new_course_key)) with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, False): - self.assertTrue(show_courseware_mfe_link(global_staff_user, True, course_key)) - self.assertFalse(show_courseware_mfe_link(user, True, course_key)) - self.assertFalse(show_courseware_mfe_link(user, False, course_key)) + # (preview=on, redirect=off) + # Global and Course Staff can see the link. + self.assertTrue(show_courseware_mfe_link(global_staff_user, True, new_course_key)) + self.assertTrue(show_courseware_mfe_link(global_staff_user, False, new_course_key)) + self.assertTrue(show_courseware_mfe_link(regular_user, True, new_course_key)) - # If both the feature flag and CourseWaffleFlag are enabled, we should show - # to global and course staff, but not normal users. + # Regular users don't see the link. + self.assertFalse(show_courseware_mfe_link(regular_user, False, new_course_key)) + + with override_waffle_flag(COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, False): with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True): - self.assertTrue(show_courseware_mfe_link(global_staff_user, True, course_key)) - self.assertTrue(show_courseware_mfe_link(user, True, course_key)) - self.assertFalse(show_courseware_mfe_link(user, False, course_key)) + # (preview=off, redirect=on) + # Global staff see the link anyway + self.assertTrue(show_courseware_mfe_link(global_staff_user, True, new_course_key)) + self.assertTrue(show_courseware_mfe_link(global_staff_user, False, new_course_key)) + + # If redirect is active for their students, course staff see the link even + # if preview=off. + self.assertTrue(show_courseware_mfe_link(regular_user, True, new_course_key)) + + # Regular users don't see the link. + self.assertFalse(show_courseware_mfe_link(regular_user, False, new_course_key)) + with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, False): + # (preview=off, redirect=off) + # Global staff see the link anyway + self.assertTrue(show_courseware_mfe_link(global_staff_user, True, new_course_key)) + self.assertTrue(show_courseware_mfe_link(global_staff_user, False, new_course_key)) + + # Course teams can NOT see the link because both rollout waffle flags are false. + self.assertFalse(show_courseware_mfe_link(regular_user, True, new_course_key)) + + # Regular users don't see the link. + self.assertFalse(show_courseware_mfe_link(regular_user, False, new_course_key)) @override_settings(LEARNING_MICROFRONTEND_URL='https://learningmfe.openedx.org') def test_url_generation(self): diff --git a/lms/djangoapps/courseware/toggles.py b/lms/djangoapps/courseware/toggles.py index 97ed26d0dea6981428cd6b89d75d3ec5c8e7f255..b4021873950b66283c1c00f328eac396f9a7821d 100644 --- a/lms/djangoapps/courseware/toggles.py +++ b/lms/djangoapps/courseware/toggles.py @@ -12,7 +12,7 @@ WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='courseware') # .. toggle_name: courseware.redirect_to_microfrontend # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False -# .. toggle_description: Supports staged rollout of a new micro-frontend-based implementation of the courseware page. +# .. toggle_description: Supports staged rollout to students for a new micro-frontend-based implementation of the courseware page. # .. toggle_category: micro-frontend # .. toggle_use_cases: incremental_release, open_edx # .. toggle_creation_date: 2020-01-29 @@ -22,9 +22,25 @@ WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='courseware') # .. toggle_status: supported REDIRECT_TO_COURSEWARE_MICROFRONTEND = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'redirect_to_microfrontend') +# Waffle flag to display a link for the new learner experience to course teams without redirecting students. +# +# .. toggle_name: courseware.microfrontend_course_team_preview +# .. toggle_implementation: CourseWaffleFlag +# .. toggle_default: False +# .. toggle_description: Supports staged rollout to course teams of a new micro-frontend-based implementation of the courseware page. +# .. toggle_category: micro-frontend +# .. toggle_use_cases: incremental_release, open_edx +# .. toggle_creation_date: 2020-03-09 +# .. toggle_expiration_date: 2020-12-31 +# .. toggle_warnings: Also set settings.LEARNING_MICROFRONTEND_URL and ENABLE_COURSEWARE_MICROFRONTEND. +# .. toggle_tickets: TNL-6982 +# .. toggle_status: supported +COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'microfrontend_course_team_preview') + def should_redirect_to_courseware_microfrontend(course_key): return ( settings.FEATURES.get('ENABLE_COURSEWARE_MICROFRONTEND') and + (not course_key.deprecated) and # Old Mongo courses not supported REDIRECT_TO_COURSEWARE_MICROFRONTEND.is_enabled(course_key) ) diff --git a/lms/djangoapps/courseware/views/index.py b/lms/djangoapps/courseware/views/index.py index 86a265fd229f3d6373c7864c6b102210329ca22c..f1131f6d5bb5d1452a241eca7e58f0a323fb0aa4 100644 --- a/lms/djangoapps/courseware/views/index.py +++ b/lms/djangoapps/courseware/views/index.py @@ -32,7 +32,10 @@ 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.toggles import ( + COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, + should_redirect_to_courseware_microfrontend, +) from lms.djangoapps.courseware.url_helpers import get_microfrontend_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 @@ -640,16 +643,22 @@ def show_courseware_mfe_link(user, staff_access, course_key): if not settings.FEATURES.get('ENABLE_COURSEWARE_MICROFRONTEND'): return False - # Global staff members always get to see the courseware MFE button if - # the basic feature is enabled at all, regardless of whether a course - # has enabled it via flag. + # MFE does not work for Old Mongo courses. + if course_key.deprecated: + return False + + # Global staff members always get to see the courseware MFE button if the + # platform and course are capable, regardless of rollout waffle flags. if user.is_staff: return True - # If you have course staff access, you see this link only if your - # students would be redirected to the new experience (course staff are - # never automatically redirected). - if staff_access and should_redirect_to_courseware_microfrontend(course_key): + # If you have course staff access, you see this link if we've enabled the + # course team preview CourseWaffleFlag for this course *or* if we've turned + # on the redirect for your students. + mfe_enabled_for_course_team = COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW.is_enabled(course_key) + mfe_enabled_for_students = should_redirect_to_courseware_microfrontend(course_key) + + if staff_access and (mfe_enabled_for_course_team or mfe_enabled_for_students): return True return False