diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index 3b36efb4a9..12c93da3bd 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -482,6 +482,66 @@ class CourseDetailsViewTest(CourseTestCase, MilestonesTestCaseMixin): self.assertTrue(course.entrance_exam_enabled) self.assertEqual(course.entrance_exam_minimum_score_pct, .5) + @unittest.skipUnless(settings.FEATURES.get('ENTRANCE_EXAMS', False), True) + @mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True}) + def test_entrance_after_changing_other_setting(self): + """ + Test entrance exam is not deactivated when prerequisites removed. + + This test ensures that the entrance milestone is not deactivated after + course details are saves without pre-requisite courses active. + + The test was implemented after a bug fixing, correcting the behaviour + that every time course details were saved, + if there wasn't any pre-requisite course in the POST + the view just deleted all the pre-requisite courses, including entrance exam, + despite the fact that the entrance_exam_enabled was True. + """ + assert not milestones_helpers.any_unfulfilled_milestones(self.course.id, self.user.id), \ + 'The initial empty state should be: no entrance exam' + + settings_details_url = get_url(self.course.id) + data = { + 'entrance_exam_enabled': 'true', + 'entrance_exam_minimum_score_pct': '60', + 'syllabus': 'none', + 'short_description': 'empty', + 'overview': '', + 'effort': '', + 'intro_video': '', + 'start_date': '2012-01-01', + 'end_date': '2012-12-31', + } + response = self.client.post( + settings_details_url, + data=json.dumps(data), + content_type='application/json', + HTTP_ACCEPT='application/json' + ) + + assert response.status_code == 200 + course = modulestore().get_course(self.course.id) + assert course.entrance_exam_enabled + assert course.entrance_exam_minimum_score_pct == .60 + + assert milestones_helpers.any_unfulfilled_milestones(self.course.id, self.user.id), \ + 'The entrance exam should be required.' + + # Call the settings handler again then ensure it didn't delete the settings of the entrance exam + data.update({ + 'start_date': '2018-01-01', + 'end_date': '{year}-12-31'.format(year=datetime.datetime.now().year + 4), + }) + response = self.client.post( + settings_details_url, + data=json.dumps(data), + content_type='application/json', + HTTP_ACCEPT='application/json' + ) + assert response.status_code == 200 + assert milestones_helpers.any_unfulfilled_milestones(self.course.id, self.user.id), \ + 'The entrance exam should be required.' + def test_editable_short_description_fetch(self): settings_details_url = get_url(self.course.id) diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 55464820d0..92a8e7dbeb 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -56,7 +56,9 @@ from common.djangoapps.util.milestones_helpers import ( is_prerequisite_courses_enabled, is_valid_course_key, remove_prerequisite_course, - set_prerequisite_courses + set_prerequisite_courses, + get_namespace_choices, + generate_milestone_namespace ) from common.djangoapps.util.string_utils import _has_non_ascii_characters from common.djangoapps.xblock_django.api import deprecated_xblocks @@ -1233,7 +1235,7 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab ) return render_to_response('settings.html', settings_context) - elif 'application/json' in request.META.get('HTTP_ACCEPT', ''): + elif 'application/json' in request.META.get('HTTP_ACCEPT', ''): # pylint: disable=too-many-nested-blocks if request.method == 'GET': course_details = CourseDetails.fetch(course_key) return JsonResponse( @@ -1252,9 +1254,17 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab set_prerequisite_courses(course_key, prerequisite_course_keys) else: # None is chosen, so remove the course prerequisites - course_milestones = milestones_api.get_course_milestones(course_key=course_key, relationship="requires") # lint-amnesty, pylint: disable=line-too-long + course_milestones = milestones_api.get_course_milestones( + course_key=course_key, + relationship="requires", + ) for milestone in course_milestones: - remove_prerequisite_course(course_key, milestone) + entrance_exam_namespace = generate_milestone_namespace( + get_namespace_choices().get('ENTRANCE_EXAM'), + course_key + ) + if milestone["namespace"] != entrance_exam_namespace: + remove_prerequisite_course(course_key, milestone) # If the entrance exams feature has been enabled, we'll need to check for some # feature-specific settings and handle them accordingly