Entrance Exam authoring and messaging updates
Multi-commit history: - hide drag functionality for entrance exam section. - hide entrance exam subsection elements e.g. delete, drag, name etc. - show unit/verticals expanded in case of entrance exam - modify code in order to allow user to update entrance exam score from UI. - write down unit tests. - write down Jasmine tests. - add bok-choy test - updated bok-choy test - internationalize string - repositioned sequential block creatori - SOL-221 (entrance exam message) - SOL-199 LMS Part (show entrance exam content) and hide the course navigation bar. - redirect the view in case of entrance exam. - update code structure as per suggestions - write down unit tests - fix pep8 - instead of hiding the exam requirement message, now also showing the exam the completion message (success state). - write down unit test to show exam completion message. - Update code as per review suggestions - update doc string - addressed review suggestions - change sequential message text - css adjustments - added new css class for entrance exam score in studio - added Jasmine test for remaning coverage - sequential message should appear under the context of entrance exam subsection. - updated text in CMS and LMS as per suggestions. - added unit text to insure sequential message should not be present in other chapters rather then entrance exam. - skip setter if empty prerequisite course list - exclude logic from xblock_info.js that is specifically related to entrance exam. - added js tests and updated code as per suggestions - added tests - addressed several PR issues - Several small fixes (style, refactoring) - Fixed score update issue - added some more unit tests. - code suggested changes. - addressed PR feedback
This commit is contained in:
@@ -21,6 +21,8 @@ from milestones.api import (
|
||||
get_user_milestones,
|
||||
)
|
||||
from milestones.models import MilestoneRelationshipType
|
||||
from milestones.exceptions import InvalidMilestoneRelationshipTypeException
|
||||
from opaque_keys.edx.keys import UsageKey
|
||||
|
||||
NAMESPACE_CHOICES = {
|
||||
'ENTRANCE_EXAM': 'entrance_exams'
|
||||
@@ -150,6 +152,42 @@ def fulfill_course_milestone(course_key, user):
|
||||
add_user_milestone({'id': user.id}, milestone)
|
||||
|
||||
|
||||
def get_required_content(course, user):
|
||||
"""
|
||||
Queries milestones subsystem to see if the specified course is gated on one or more milestones,
|
||||
and if those milestones can be fulfilled via completion of a particular course content module
|
||||
"""
|
||||
required_content = []
|
||||
if settings.FEATURES.get('MILESTONES_APP', False):
|
||||
# Get all of the outstanding milestones for this course, for this user
|
||||
try:
|
||||
milestone_paths = get_course_milestones_fulfillment_paths(
|
||||
unicode(course.id),
|
||||
serialize_user(user)
|
||||
)
|
||||
except InvalidMilestoneRelationshipTypeException:
|
||||
return required_content
|
||||
|
||||
# For each outstanding milestone, see if this content is one of its fulfillment paths
|
||||
for path_key in milestone_paths:
|
||||
milestone_path = milestone_paths[path_key]
|
||||
if milestone_path.get('content') and len(milestone_path['content']):
|
||||
for content in milestone_path['content']:
|
||||
required_content.append(content)
|
||||
|
||||
#local imports to avoid circular reference
|
||||
from student.models import EntranceExamConfiguration
|
||||
can_skip_entrance_exam = EntranceExamConfiguration.user_can_skip_entrance_exam(user, course.id)
|
||||
# check if required_content has any entrance exam and user is allowed to skip it
|
||||
# then remove it from required content
|
||||
if required_content and getattr(course, 'entrance_exam_enabled', False) and can_skip_entrance_exam:
|
||||
descriptors = [modulestore().get_item(UsageKey.from_string(content)) for content in required_content]
|
||||
entrance_exam_contents = [unicode(descriptor.location)
|
||||
for descriptor in descriptors if descriptor.is_entrance_exam]
|
||||
required_content = list(set(required_content) - set(entrance_exam_contents))
|
||||
return required_content
|
||||
|
||||
|
||||
def calculate_entrance_exam_score(user, course_descriptor, exam_modules):
|
||||
"""
|
||||
Calculates the score (percent) of the entrance exam using the provided modules
|
||||
|
||||
@@ -162,3 +162,32 @@ class SettingsMilestonesTest(StudioCourseTest):
|
||||
css_selector='span.section-title',
|
||||
text='Entrance Exam'
|
||||
))
|
||||
|
||||
def test_entrance_exam_has_unit_button(self):
|
||||
"""
|
||||
Test that entrance exam should be created after checking the 'enable entrance exam' checkbox.
|
||||
And user has option to add units only instead of any Subsection.
|
||||
"""
|
||||
self.settings_detail.require_entrance_exam(required=True)
|
||||
self.settings_detail.save_changes()
|
||||
|
||||
# getting the course outline page.
|
||||
course_outline_page = CourseOutlinePage(
|
||||
self.browser, self.course_info['org'], self.course_info['number'], self.course_info['run']
|
||||
)
|
||||
course_outline_page.visit()
|
||||
course_outline_page.wait_for_ajax()
|
||||
|
||||
# button with text 'New Unit' should be present.
|
||||
self.assertTrue(element_has_text(
|
||||
page=course_outline_page,
|
||||
css_selector='.add-item a.button-new',
|
||||
text='New Unit'
|
||||
))
|
||||
|
||||
# button with text 'New Subsection' should not be present.
|
||||
self.assertFalse(element_has_text(
|
||||
page=course_outline_page,
|
||||
css_selector='.add-item a.button-new',
|
||||
text='New Subsection'
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user