Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions cms/djangoapps/contentstore/tests/test_course_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,66 @@ def test_entrance_exam_store_default_min_score(self):
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)

Expand Down
18 changes: 14 additions & 4 deletions cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
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
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def setUp(self):
self.users = UserFactory.create_batch(5)
CourseOverview.load_from_module_store(self.course.id)

@patch('common.djangoapps.student.models.tracker')
@patch('common.djangoapps.student.models.course_enrollment.tracker')
@ddt.data(('audit', 'honor'), ('honor', 'audit'))
@ddt.unpack
def test_bulk_convert(self, from_mode, to_mode, mock_tracker):
Expand Down Expand Up @@ -55,7 +55,7 @@ def test_bulk_convert(self, from_mode, to_mode, mock_tracker):
CourseEnrollment.objects.get(mode=to_mode, course_id=self.course.id, user=user)
self._assert_mode_changed(mock_tracker, self.course, user, to_mode)

@patch('common.djangoapps.student.models.tracker')
@patch('common.djangoapps.student.models.course_enrollment.tracker')
@ddt.data(('audit', 'no-id-professional'), ('no-id-professional', 'audit'))
@ddt.unpack
def test_bulk_convert_with_org(self, from_mode, to_mode, mock_tracker):
Expand Down Expand Up @@ -108,7 +108,7 @@ def test_with_org_and_course_key(self):

assert 'Error: argument -o/--org: not allowed with argument -c/--course' == str(err.value)

@patch('common.djangoapps.student.models.tracker')
@patch('common.djangoapps.student.models.course_enrollment.tracker')
def test_with_org_and_invalid_to_mode(self, mock_tracker):
"""Verify that enrollments are changed correctly when org was given."""
from_mode = 'audit'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def setUp(self, **kwargs): # lint-amnesty, pylint: disable=unused-argument
super().setUp()

UNENROLL_DONE.connect(self.assert_unenroll_signal)
patcher = patch('common.djangoapps.student.models.tracker')
patcher = patch('common.djangoapps.student.models.course_enrollment.tracker')
self.mock_tracker = patcher.start()
self.addCleanup(patcher.stop)
self.addCleanup(UNENROLL_DONE.disconnect, self.assert_unenroll_signal)
Expand Down
5 changes: 5 additions & 0 deletions common/djangoapps/student/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'''
Student models migrated to folder to tease out the course enrollment aspects from Student
'''
from .course_enrollment import *
from .student import *
Loading