Merge pull request #23315 from edx/dcs/mfe-redirect

Redirect to learning microfrontend, except for exams
This commit is contained in:
Dave St.Germain
2020-03-09 12:18:13 -04:00
committed by GitHub
4 changed files with 129 additions and 28 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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):
"""

View File

@@ -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,