diff --git a/lms/djangoapps/courseware/access.py b/lms/djangoapps/courseware/access.py index b03144888f83..46668f1aa864 100644 --- a/lms/djangoapps/courseware/access.py +++ b/lms/djangoapps/courseware/access.py @@ -27,6 +27,7 @@ MilestoneAccessError, MobileAvailabilityError, NoAllowedPartitionGroupsError, + OldMongoAccessError, VisibilityError ) from lms.djangoapps.courseware.access_utils import ( @@ -329,6 +330,9 @@ def can_load(): # ).or( # _has_staff_access_to_descriptor, user, courselike, courselike.id # ) + if courselike.id.deprecated: # we no longer support accessing Old Mongo courses + return OldMongoAccessError(courselike) + visible_to_nonstaff = _visible_to_nonstaff_users(courselike) if not visible_to_nonstaff: staff_access = _has_staff_access_to_descriptor(user, courselike, courselike.id) diff --git a/lms/djangoapps/courseware/access_response.py b/lms/djangoapps/courseware/access_response.py index e88b58d2051d..674003d6c85f 100644 --- a/lms/djangoapps/courseware/access_response.py +++ b/lms/djangoapps/courseware/access_response.py @@ -236,3 +236,16 @@ def __init__(self): developer_message = "User must be authenticated to view the course" user_message = _("You must be logged in to see this course") super().__init__(error_code, developer_message, user_message) + + +class OldMongoAccessError(AccessError): + """ + Access denied because the course is in Old Mongo and we no longer support them. See DEPR-58. + """ + def __init__(self, courselike): + error_code = 'old_mongo' + developer_message = 'Access to Old Mongo courses is unsupported' + user_message = _('{course_name} is no longer available.').format( + course_name=courselike.display_name_with_default, + ) + super().__init__(error_code, developer_message, user_message) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 89fa7c0596fa..cd755a8d476f 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -27,6 +27,7 @@ AuthenticationRequiredAccessError, EnrollmentRequiredAccessError, MilestoneAccessError, + OldMongoAccessError, StartDateError, ) from lms.djangoapps.courseware.date_summary import ( @@ -213,6 +214,15 @@ def check_course_access_with_redirect(course, user, action, check_if_enrolled=Fa params=params.urlencode() ), access_response) + # Redirect if trying to access an Old Mongo course + if isinstance(access_response, OldMongoAccessError): + params = QueryDict(mutable=True) + params['access_response_error'] = access_response.user_message + raise CourseAccessRedirect('{dashboard_url}?{params}'.format( + dashboard_url=reverse('dashboard'), + params=params.urlencode(), + ), access_response) + # Redirect if the user must answer a survey before entering the course. if isinstance(access_response, MilestoneAccessError): raise CourseAccessRedirect('{dashboard_url}'.format( diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index 365dc0aaf734..c81686507046 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -39,6 +39,7 @@ get_courses, get_current_child ) +from lms.djangoapps.courseware.exceptions import CourseAccessRedirect from lms.djangoapps.courseware.model_data import FieldDataCache from lms.djangoapps.courseware.module_render import get_module_for_descriptor from lms.djangoapps.courseware.courseware_access_exception import CoursewareAccessException @@ -88,6 +89,18 @@ def test_get_course_func_with_access_error(self, course_access_func_name): assert error.value.access_response.error_code == 'not_visible_to_user' assert not error.value.access_response.has_access + @ddt.data(GET_COURSE_WITH_ACCESS, GET_COURSE_OVERVIEW_WITH_ACCESS) + def test_old_mongo_access_error(self, course_access_func_name): + course_access_func = self.COURSE_ACCESS_FUNCS[course_access_func_name] + user = UserFactory.create() + with self.store.default_store(ModuleStoreEnum.Type.mongo): + course = CourseFactory.create() + + with pytest.raises(CourseAccessRedirect) as error: + course_access_func(user, 'load', course.id) + assert error.value.access_error.error_code == 'old_mongo' + assert not error.value.access_error.has_access + @ddt.data( (GET_COURSE_WITH_ACCESS, 3), (GET_COURSE_OVERVIEW_WITH_ACCESS, 0), diff --git a/openedx/features/course_experience/tests/views/test_course_home.py b/openedx/features/course_experience/tests/views/test_course_home.py index 788d150360af..4859a46de041 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -527,6 +527,25 @@ def test_expired_course(self): ) self.assertRedirects(response, expected_url) + def test_old_mongo_access_error(self): + """ + Ensure that a user accessing an Old Mongo course sees a redirect to + the student dashboard, not a 404. + """ + course = CourseFactory.create(default_store=ModuleStoreEnum.Type.mongo) + user = UserFactory(password=self.TEST_PASSWORD) + self.client.login(username=user.username, password=self.TEST_PASSWORD) + + response = self.client.get(course_home_url(course)) + + expected_params = QueryDict(mutable=True) + expected_params['access_response_error'] = f'{course.display_name_with_default} is no longer available.' + expected_url = '{url}?{params}'.format( + url=reverse('dashboard'), + params=expected_params.urlencode(), + ) + self.assertRedirects(response, expected_url) + @mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False}) def test_expiration_banner_with_expired_upgrade_deadline(self): """