Merge pull request #23315 from edx/dcs/mfe-redirect
Redirect to learning microfrontend, except for exams
This commit is contained in:
@@ -92,6 +92,7 @@ from openedx.features.course_experience import (
|
||||
from openedx.features.course_experience.tests.views.helpers import add_course_mode
|
||||
from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired
|
||||
from student.models import CourseEnrollment
|
||||
from student.roles import CourseStaffRole
|
||||
from student.tests.factories import TEST_PASSWORD, AdminFactory, CourseEnrollmentFactory, UserFactory
|
||||
from util.tests.test_date_utils import fake_pgettext, fake_ugettext
|
||||
from util.url import reload_django_url_config
|
||||
@@ -100,8 +101,10 @@ from xmodule.course_module import COURSE_VISIBILITY_PRIVATE, COURSE_VISIBILITY_P
|
||||
from xmodule.graders import ShowCorrectness
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
from xmodule.modulestore.tests.django_utils import (
|
||||
TEST_DATA_MIXED_MODULESTORE,
|
||||
TEST_DATA_SPLIT_MODULESTORE,
|
||||
CourseUserType,
|
||||
ModuleStoreTestCase,
|
||||
SharedModuleStoreTestCase
|
||||
@@ -304,19 +307,9 @@ class IndexQueryTestCase(ModuleStoreTestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ViewsTestCase(ModuleStoreTestCase):
|
||||
"""
|
||||
Tests for views.py methods.
|
||||
"""
|
||||
YESTERDAY = 'yesterday'
|
||||
DATES = {
|
||||
YESTERDAY: datetime.now(UTC) - timedelta(days=1),
|
||||
None: None,
|
||||
}
|
||||
|
||||
class BaseViewsTestCase(ModuleStoreTestCase):
|
||||
def setUp(self):
|
||||
super(ViewsTestCase, self).setUp()
|
||||
super(BaseViewsTestCase, self).setUp()
|
||||
self.course = CourseFactory.create(display_name=u'teꜱᴛ course', run="Testing_course")
|
||||
with self.store.bulk_operations(self.course.id):
|
||||
self.chapter = ItemFactory.create(
|
||||
@@ -376,6 +369,25 @@ class ViewsTestCase(ModuleStoreTestCase):
|
||||
# refresh the course from the modulestore so that it has children
|
||||
self.course = modulestore().get_course(self.course.id)
|
||||
|
||||
def _create_global_staff_user(self):
|
||||
"""
|
||||
Create global staff user and log them in
|
||||
"""
|
||||
self.global_staff = GlobalStaffFactory.create() # pylint: disable=attribute-defined-outside-init
|
||||
self.assertTrue(self.client.login(username=self.global_staff.username, password=TEST_PASSWORD))
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ViewsTestCase(BaseViewsTestCase):
|
||||
"""
|
||||
Tests for views.py methods.
|
||||
"""
|
||||
YESTERDAY = 'yesterday'
|
||||
DATES = {
|
||||
YESTERDAY: datetime.now(UTC) - timedelta(days=1),
|
||||
None: None,
|
||||
}
|
||||
|
||||
def test_index_success(self):
|
||||
response = self._verify_index_response()
|
||||
self.assertContains(response, self.problem2.location)
|
||||
@@ -443,13 +455,6 @@ class ViewsTestCase(ModuleStoreTestCase):
|
||||
self.assertNotContains(response, 'Problem 1')
|
||||
self.assertNotContains(response, 'Problem 2')
|
||||
|
||||
def _create_global_staff_user(self):
|
||||
"""
|
||||
Create global staff user and log them in
|
||||
"""
|
||||
self.global_staff = GlobalStaffFactory.create() # pylint: disable=attribute-defined-outside-init
|
||||
self.assertTrue(self.client.login(username=self.global_staff.username, password=TEST_PASSWORD))
|
||||
|
||||
def _create_url_for_enroll_staff(self):
|
||||
"""
|
||||
creates the courseware url and enroll staff url
|
||||
@@ -3348,3 +3353,61 @@ class TestShowCoursewareMFE(TestCase):
|
||||
'/block-v1:OpenEdX+MFE+2020+type@sequential+block@Introduction'
|
||||
'/block-v1:OpenEdX+MFE+2020+type@vertical+block@Getting_To_Know_You'
|
||||
)
|
||||
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_COURSEWARE_MICROFRONTEND': True})
|
||||
@ddt.ddt
|
||||
class MFERedirectTests(BaseViewsTestCase):
|
||||
MODULESTORE = TEST_DATA_SPLIT_MODULESTORE
|
||||
|
||||
def _get_urls(self):
|
||||
lms_url = reverse(
|
||||
'courseware_section',
|
||||
kwargs={
|
||||
'course_id': str(self.course_key),
|
||||
'chapter': str(self.chapter.location.block_id),
|
||||
'section': str(self.section2.location.block_id),
|
||||
}
|
||||
)
|
||||
mfe_url = '{}/course/{}/{}'.format(
|
||||
settings.LEARNING_MICROFRONTEND_URL,
|
||||
self.course_key,
|
||||
self.section2.location
|
||||
)
|
||||
return lms_url, mfe_url
|
||||
|
||||
def test_learner_redirect(self):
|
||||
# learners will be redirected when the waffle flag is set
|
||||
lms_url, mfe_url = self._get_urls()
|
||||
|
||||
with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True):
|
||||
assert self.client.get(lms_url).url == mfe_url
|
||||
|
||||
def test_staff_no_redirect(self):
|
||||
lms_url, mfe_url = self._get_urls()
|
||||
|
||||
# course staff will not redirect
|
||||
course_staff = UserFactory.create(is_staff=False)
|
||||
CourseStaffRole(self.course_key).add_users(course_staff)
|
||||
self.client.login(username=course_staff.username, password='test')
|
||||
|
||||
assert self.client.get(lms_url).status_code == 200
|
||||
with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True):
|
||||
assert self.client.get(lms_url).status_code == 200
|
||||
|
||||
# global staff will never be redirected
|
||||
self._create_global_staff_user()
|
||||
assert self.client.get(lms_url).status_code == 200
|
||||
|
||||
with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True):
|
||||
assert self.client.get(lms_url).status_code == 200
|
||||
|
||||
def test_exam_no_redirect(self):
|
||||
# exams will not redirect to the mfe, for the time being
|
||||
self.section2.is_time_limited = True
|
||||
self.store.update_item(self.section2, self.user.id)
|
||||
|
||||
lms_url, mfe_url = self._get_urls()
|
||||
|
||||
with override_waffle_flag(REDIRECT_TO_COURSEWARE_MICROFRONTEND, True):
|
||||
assert self.client.get(lms_url).status_code == 200
|
||||
|
||||
@@ -30,13 +30,7 @@ from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
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 (
|
||||
COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW,
|
||||
should_redirect_to_courseware_microfrontend,
|
||||
)
|
||||
from lms.djangoapps.courseware.url_helpers import get_microfrontend_url
|
||||
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect, Redirect
|
||||
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
|
||||
@@ -62,7 +56,13 @@ from xmodule.modulestore.django import modulestore
|
||||
from xmodule.x_module import PUBLIC_VIEW, STUDENT_VIEW
|
||||
|
||||
from ..access import has_access
|
||||
from ..courses import check_course_access, get_course_with_access, get_current_child, get_studio_url
|
||||
from ..courses import (
|
||||
allow_public_access,
|
||||
check_course_access,
|
||||
get_course_with_access,
|
||||
get_current_child,
|
||||
get_studio_url
|
||||
)
|
||||
from ..entrance_exams import (
|
||||
course_has_entrance_exam,
|
||||
get_entrance_exam_content,
|
||||
@@ -73,6 +73,8 @@ from ..masquerade import check_content_start_date_for_masquerade_user, setup_mas
|
||||
from ..model_data import FieldDataCache
|
||||
from ..module_render import get_module_for_descriptor, toc_for_course
|
||||
from ..permissions import MASQUERADE_AS_STUDENT
|
||||
from ..toggles import COURSEWARE_MICROFRONTEND_COURSE_TEAM_PREVIEW, should_redirect_to_courseware_microfrontend
|
||||
from ..url_helpers import get_microfrontend_url
|
||||
|
||||
from .views import CourseTabView
|
||||
|
||||
@@ -185,6 +187,27 @@ class CoursewareIndex(View):
|
||||
# Set the user in the request to the effective user.
|
||||
self.request.user = self.effective_user
|
||||
|
||||
def _redirect_to_learning_mfe(self, request):
|
||||
"""
|
||||
Redirect to the new courseware micro frontend,
|
||||
unless this is a time limited exam.
|
||||
"""
|
||||
# learners should redirect, if the waffle flag is set
|
||||
if should_redirect_to_courseware_microfrontend(self.course_key):
|
||||
# but exams should not redirect to the mfe until they're supported
|
||||
if getattr(self.section, 'is_time_limited', False):
|
||||
return
|
||||
|
||||
# and staff will not redirect, either
|
||||
if self.is_staff:
|
||||
return
|
||||
|
||||
url = get_microfrontend_url(
|
||||
self.course_key,
|
||||
self.section.location
|
||||
)
|
||||
raise Redirect(url)
|
||||
|
||||
def render(self, request):
|
||||
"""
|
||||
Render the index page.
|
||||
@@ -201,6 +224,7 @@ class CoursewareIndex(View):
|
||||
self._redirect_if_not_requested_section()
|
||||
self._save_positions()
|
||||
self._prefetch_and_bind_section()
|
||||
self._redirect_to_learning_mfe(request)
|
||||
|
||||
check_content_start_date_for_masquerade_user(self.course_key, self.effective_user, request,
|
||||
self.course.start, self.chapter.start, self.section.start)
|
||||
|
||||
@@ -779,6 +779,20 @@ class CourseOverview(TimeStampedModel):
|
||||
"""
|
||||
return self._original_course.textbooks
|
||||
|
||||
@property
|
||||
def pdf_textbooks(self):
|
||||
"""
|
||||
TODO: move this to the model.
|
||||
"""
|
||||
return self._original_course.pdf_textbooks
|
||||
|
||||
@property
|
||||
def html_textbooks(self):
|
||||
"""
|
||||
TODO: move this to the model.
|
||||
"""
|
||||
return self._original_course.html_textbooks
|
||||
|
||||
@property
|
||||
def hide_progress_tab(self):
|
||||
"""
|
||||
|
||||
@@ -107,7 +107,7 @@ class CourseInfoSerializer(serializers.Serializer): # pylint: disable=abstract-
|
||||
tabs = []
|
||||
for priority, tab in enumerate(get_course_tab_list(course_overview.effective_user, course_overview)):
|
||||
tabs.append({
|
||||
'title': tab.title,
|
||||
'title': tab.title or tab.get('name', ''),
|
||||
'slug': tab.tab_id,
|
||||
'priority': priority,
|
||||
'type': tab.type,
|
||||
|
||||
Reference in New Issue
Block a user