def add_entrance_exam_milestone(course_id, x_block): # Add an entrance exam milestone if one does not already exist for given xBlock # As this is a standalone method for entrance exam, We should check that given xBlock should be an entrance exam. if x_block.is_entrance_exam: namespace_choices = milestones_helpers.get_namespace_choices() milestone_namespace = milestones_helpers.generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), course_id ) milestones = milestones_helpers.get_milestones(milestone_namespace) if len(milestones): milestone = milestones[0] else: description = u'Autogenerated during {} entrance exam creation.'.format(six.text_type(course_id)) milestone = milestones_helpers.add_milestone({ 'name': _('Completed Course Entrance Exam'), 'namespace': milestone_namespace, 'description': description }) relationship_types = milestones_helpers.get_milestone_relationship_types() milestones_helpers.add_course_milestone( six.text_type(course_id), relationship_types['REQUIRES'], milestone ) milestones_helpers.add_course_content_milestone( six.text_type(course_id), six.text_type(x_block.location), relationship_types['FULFILLS'], milestone )
def add_entrance_exam_milestone(course, entrance_exam): """ Adds the milestone for given `entrance_exam` in `course` Args: course (Course): Course object in which the extrance_exam is located entrance_exam (xblock): the entrance exam to be added as a milestone """ namespace_choices = get_namespace_choices() milestone_relationship_types = get_milestone_relationship_types() milestone_namespace = generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), course.id ) milestone = add_milestone( { 'name': 'Test Milestone', 'namespace': milestone_namespace, 'description': 'Testing Courseware Entrance Exam Chapter', } ) add_course_milestone( unicode(course.id), milestone_relationship_types['REQUIRES'], milestone ) add_course_content_milestone( unicode(course.id), unicode(entrance_exam.location), milestone_relationship_types['FULFILLS'], milestone )
def add_entrance_exam_milestone(course_id, x_block): # Add an entrance exam milestone if one does not already exist for given xBlock # As this is a standalone method for entrance exam, We should check that given xBlock should be an entrance exam. if x_block.is_entrance_exam: namespace_choices = milestones_helpers.get_namespace_choices() milestone_namespace = milestones_helpers.generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), course_id ) milestones = milestones_helpers.get_milestones(milestone_namespace) if len(milestones): milestone = milestones[0] else: description = 'Autogenerated during {} entrance exam creation.'.format(unicode(course_id)) milestone = milestones_helpers.add_milestone({ 'name': _('Completed Course Entrance Exam'), 'namespace': milestone_namespace, 'description': description }) relationship_types = milestones_helpers.get_milestone_relationship_types() milestones_helpers.add_course_milestone( unicode(course_id), relationship_types['REQUIRES'], milestone ) milestones_helpers.add_course_content_milestone( unicode(course_id), unicode(x_block.location), relationship_types['FULFILLS'], milestone )
def test_get_course_tabs_list_entrance_exam_enabled(self): """ Unit Test: test_get_course_tabs_list_entrance_exam_enabled """ entrance_exam = ItemFactory.create( category="chapter", parent_location=self.course.location, data="Exam Data", display_name="Entrance Exam", is_entrance_exam=True) milestone = { 'name': 'Test Milestone', 'namespace': '{}.entrance_exams'.format(unicode(self.course.id)), 'description': 'Testing Courseware Tabs' } self.user.is_staff = False request = get_mock_request(self.user) self.course.entrance_exam_enabled = True self.course.entrance_exam_id = unicode(entrance_exam.location) milestone = add_milestone(milestone) add_course_milestone(unicode(self.course.id), self.relationship_types['REQUIRES'], milestone) add_course_content_milestone(unicode(self.course.id), unicode(entrance_exam.location), self.relationship_types['FULFILLS'], milestone) course_tab_list = get_course_tab_list(request, self.course) self.assertEqual(len(course_tab_list), 1) self.assertEqual(course_tab_list[0]['tab_id'], 'courseware') self.assertEqual(course_tab_list[0]['name'], 'Entrance Exam')
def test_get_course_tabs_list_entrance_exam_enabled(self): """ Unit Test: test_get_course_tabs_list_entrance_exam_enabled """ entrance_exam = ItemFactory.create( category="chapter", parent_location=self.course.location, data="Exam Data", display_name="Entrance Exam", is_entrance_exam=True ) milestone = { 'name': 'Test Milestone', 'namespace': '{}.entrance_exams'.format(unicode(self.course.id)), 'description': 'Testing Courseware Tabs' } self.user.is_staff = False self.course.entrance_exam_enabled = True self.course.entrance_exam_id = unicode(entrance_exam.location) milestone = milestones_helpers.add_milestone(milestone) milestones_helpers.add_course_milestone( unicode(self.course.id), self.relationship_types['REQUIRES'], milestone ) milestones_helpers.add_course_content_milestone( unicode(self.course.id), unicode(entrance_exam.location), self.relationship_types['FULFILLS'], milestone ) course_tab_list = get_course_tab_list(self.course, self.user) self.assertEqual(len(course_tab_list), 1) self.assertEqual(course_tab_list[0]['tab_id'], 'courseware') self.assertEqual(course_tab_list[0]['name'], 'Entrance Exam')
def test_get_course_tabs_list_entrance_exam_enabled(self): """ Unit Test: test_get_course_tabs_list_entrance_exam_enabled """ entrance_exam = ItemFactory.create( category="chapter", parent_location=self.course.location, data="Exam Data", display_name="Entrance Exam" ) entrance_exam.is_entrance_exam = True milestone = { "name": "Test Milestone", "namespace": "{}.entrance_exams".format(unicode(self.course.id)), "description": "Testing Courseware Tabs", } self.course.entrance_exam_enabled = True self.course.entrance_exam_id = unicode(entrance_exam.location) milestone = milestones_helpers.add_milestone(milestone) milestones_helpers.add_course_milestone( unicode(self.course.id), self.relationship_types["REQUIRES"], milestone ) milestones_helpers.add_course_content_milestone( unicode(self.course.id), unicode(entrance_exam.location), self.relationship_types["FULFILLS"], milestone ) course_tab_list = get_course_tab_list(self.course, self.user) self.assertEqual(len(course_tab_list), 2) self.assertEqual(course_tab_list[0]["tab_id"], "courseware") self.assertEqual(course_tab_list[0]["name"], "Entrance Exam") self.assertEqual(course_tab_list[1]["tab_id"], "instructor")
def test_get_required_content_with_anonymous_user(self): course = CourseFactory() required_content = milestones_helpers.get_required_content(course.id, AnonymousUser()) assert required_content == [] # NOTE (CCB): The initial version of anonymous courseware access is very simple. We avoid accidentally # exposing locked content by simply avoiding anonymous access altogether for courses runs with milestones. milestone = milestones_api.add_milestone({ 'name': 'test', 'namespace': 'test', }) milestones_helpers.add_course_milestone(str(course.id), 'requires', milestone) with pytest.raises(InvalidUserException): milestones_helpers.get_required_content(course.id, AnonymousUser())
def _create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct=None): """ Internal workflow operation to create an entrance exam """ # Provide a default value for the minimum score percent if nothing specified if entrance_exam_minimum_score_pct is None: entrance_exam_minimum_score_pct = _get_default_entrance_exam_minimum_pct( ) # Confirm the course exists course = modulestore().get_course(course_key) if course is None: return HttpResponse(status=400) # Create the entrance exam item (currently it's just a chapter) payload = { 'category': "chapter", 'display_name': _("Entrance Exam"), 'parent_locator': unicode(course.location), 'is_entrance_exam': True, 'in_entrance_exam': True, } parent_locator = unicode(course.location) created_block = create_xblock(parent_locator=parent_locator, user=request.user, category='chapter', display_name=_('Entrance Exam'), is_entrance_exam=True) # Set the entrance exam metadata flags for this course # Reload the course so we don't overwrite the new child reference course = modulestore().get_course(course_key) metadata = { 'entrance_exam_enabled': True, 'entrance_exam_minimum_score_pct': unicode(entrance_exam_minimum_score_pct), 'entrance_exam_id': unicode(created_block.location), } CourseMetadata.update_from_dict(metadata, course, request.user) # Create the entrance exam section item. create_xblock(parent_locator=unicode(created_block.location), user=request.user, category='sequential', display_name=_('Entrance Exam - Subsection')) # Add an entrance exam milestone if one does not already exist namespace_choices = milestones_helpers.get_namespace_choices() milestone_namespace = milestones_helpers.generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), course_key) milestones = milestones_helpers.get_milestones(milestone_namespace) if len(milestones): milestone = milestones[0] else: description = 'Autogenerated during {} entrance exam creation.'.format( unicode(course.id)) milestone = milestones_helpers.add_milestone({ 'name': _('Completed Course Entrance Exam'), 'namespace': milestone_namespace, 'description': description }) relationship_types = milestones_helpers.get_milestone_relationship_types() milestones_helpers.add_course_milestone(unicode(course.id), relationship_types['REQUIRES'], milestone) milestones_helpers.add_course_content_milestone( unicode(course.id), unicode(created_block.location), relationship_types['FULFILLS'], milestone) return HttpResponse(status=201)
def test_add_course_milestone_returns_none_when_app_disabled(self): response = milestones_helpers.add_course_milestone(unicode(self.course.id), 'requires', self.milestone) self.assertIsNone(response)
def setUp(self): """ Test case scaffolding """ super(EntranceExamTestCases, self).setUp() self.course = CourseFactory.create(metadata={ 'entrance_exam_enabled': True, }) self.chapter = ItemFactory.create(parent=self.course, display_name='Overview') ItemFactory.create(parent=self.chapter, display_name='Welcome') ItemFactory.create(parent=self.course, category='chapter', display_name="Week 1") self.chapter_subsection = ItemFactory.create(parent=self.chapter, category='sequential', display_name="Lesson 1") chapter_vertical = ItemFactory.create( parent=self.chapter_subsection, category='vertical', display_name='Lesson 1 Vertical - Unit 1') ItemFactory.create(parent=chapter_vertical, category="problem", display_name="Problem - Unit 1 Problem 1") ItemFactory.create(parent=chapter_vertical, category="problem", display_name="Problem - Unit 1 Problem 2") ItemFactory.create(category="instructor", parent=self.course, data="Instructor Tab", display_name="Instructor") self.entrance_exam = ItemFactory.create( parent=self.course, category="chapter", display_name="Entrance Exam Section - Chapter 1", is_entrance_exam=True, in_entrance_exam=True) self.exam_1 = ItemFactory.create( parent=self.entrance_exam, category='sequential', display_name="Exam Sequential - Subsection 1", graded=True, in_entrance_exam=True) subsection = ItemFactory.create(parent=self.exam_1, category='vertical', display_name='Exam Vertical - Unit 1') self.problem_1 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 1") self.problem_2 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 2") self.problem_3 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 3") if settings.FEATURES.get('ENTRANCE_EXAMS', False): namespace_choices = milestones_helpers.get_namespace_choices() milestone_namespace = milestones_helpers.generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), self.course.id) self.milestone = { 'name': 'Test Milestone', 'namespace': milestone_namespace, 'description': 'Testing Courseware Entrance Exam Chapter', } milestones_helpers.seed_milestone_relationship_types() self.milestone_relationship_types = milestones_helpers.get_milestone_relationship_types( ) self.milestone = milestones_helpers.add_milestone(self.milestone) milestones_helpers.add_course_milestone( unicode(self.course.id), self.milestone_relationship_types['REQUIRES'], self.milestone) milestones_helpers.add_course_content_milestone( unicode(self.course.id), unicode(self.entrance_exam.location), self.milestone_relationship_types['FULFILLS'], self.milestone) user = UserFactory() self.request = RequestFactory() self.request.user = user self.request.COOKIES = {} self.request.META = {} self.request.is_secure = lambda: True self.request.get_host = lambda: "edx.org" self.request.method = 'GET' self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, user, self.entrance_exam) self.course.entrance_exam_enabled = True self.course.entrance_exam_minimum_score_pct = 0.50 self.course.entrance_exam_id = unicode( self.entrance_exam.scope_ids.usage_id) modulestore().update_item(self.course, user.id) # pylint: disable=no-member self.client.login(username=self.request.user.username, password="******") CourseEnrollment.enroll(self.request.user, self.course.id) self.expected_locked_toc = ([{ 'active': True, 'sections': [{ 'url_name': u'Exam_Sequential_-_Subsection_1', 'display_name': u'Exam Sequential - Subsection 1', 'graded': True, 'format': '', 'due': None, 'active': True }], 'url_name': u'Entrance_Exam_Section_-_Chapter_1', 'display_name': u'Entrance Exam Section - Chapter 1' }]) self.expected_unlocked_toc = ([{ 'active': False, 'sections': [{ 'url_name': u'Welcome', 'display_name': u'Welcome', 'graded': False, 'format': '', 'due': None, 'active': False }, { 'url_name': u'Lesson_1', 'display_name': u'Lesson 1', 'graded': False, 'format': '', 'due': None, 'active': False }], 'url_name': u'Overview', 'display_name': u'Overview' }, { 'active': False, 'sections': [], 'url_name': u'Week_1', 'display_name': u'Week 1' }, { 'active': False, 'sections': [], 'url_name': u'Instructor', 'display_name': u'Instructor' }, { 'active': True, 'sections': [{ 'url_name': u'Exam_Sequential_-_Subsection_1', 'display_name': u'Exam Sequential - Subsection 1', 'graded': True, 'format': '', 'due': None, 'active': True }], 'url_name': u'Entrance_Exam_Section_-_Chapter_1', 'display_name': u'Entrance Exam Section - Chapter 1' }])
def _create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct=None): """ Internal workflow operation to create an entrance exam """ # Provide a default value for the minimum score percent if nothing specified if entrance_exam_minimum_score_pct is None: entrance_exam_minimum_score_pct = _get_default_entrance_exam_minimum_pct() # Confirm the course exists course = modulestore().get_course(course_key) if course is None: return HttpResponse(status=400) # Create the entrance exam item (currently it's just a chapter) payload = { 'category': "chapter", 'display_name': _("Entrance Exam"), 'parent_locator': unicode(course.location), 'is_entrance_exam': True, 'in_entrance_exam': True, } parent_locator = unicode(course.location) created_block = create_xblock( parent_locator=parent_locator, user=request.user, category='chapter', display_name=_('Entrance Exam'), is_entrance_exam=True ) # Set the entrance exam metadata flags for this course # Reload the course so we don't overwrite the new child reference course = modulestore().get_course(course_key) metadata = { 'entrance_exam_enabled': True, 'entrance_exam_minimum_score_pct': unicode(entrance_exam_minimum_score_pct), 'entrance_exam_id': unicode(created_block.location), } CourseMetadata.update_from_dict(metadata, course, request.user) # Create the entrance exam section item. create_xblock( parent_locator=unicode(created_block.location), user=request.user, category='sequential', display_name=_('Entrance Exam - Subsection') ) # Add an entrance exam milestone if one does not already exist namespace_choices = milestones_helpers.get_namespace_choices() milestone_namespace = milestones_helpers.generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), course_key ) milestones = milestones_helpers.get_milestones(milestone_namespace) if len(milestones): milestone = milestones[0] else: description = 'Autogenerated during {} entrance exam creation.'.format(unicode(course.id)) milestone = milestones_helpers.add_milestone({ 'name': _('Completed Course Entrance Exam'), 'namespace': milestone_namespace, 'description': description }) relationship_types = milestones_helpers.get_milestone_relationship_types() milestones_helpers.add_course_milestone( unicode(course.id), relationship_types['REQUIRES'], milestone ) milestones_helpers.add_course_content_milestone( unicode(course.id), unicode(created_block.location), relationship_types['FULFILLS'], milestone ) return HttpResponse(status=201)
def setUp(self): """ Test case scaffolding """ super(EntranceExamTestCases, self).setUp() self.course = CourseFactory.create( metadata={ 'entrance_exam_enabled': True, } ) self.chapter = ItemFactory.create( parent=self.course, display_name='Overview' ) ItemFactory.create( parent=self.chapter, display_name='Welcome' ) ItemFactory.create( parent=self.course, category='chapter', display_name="Week 1" ) self.chapter_subsection = ItemFactory.create( parent=self.chapter, category='sequential', display_name="Lesson 1" ) chapter_vertical = ItemFactory.create( parent=self.chapter_subsection, category='vertical', display_name='Lesson 1 Vertical - Unit 1' ) ItemFactory.create( parent=chapter_vertical, category="problem", display_name="Problem - Unit 1 Problem 1" ) ItemFactory.create( parent=chapter_vertical, category="problem", display_name="Problem - Unit 1 Problem 2" ) ItemFactory.create( category="instructor", parent=self.course, data="Instructor Tab", display_name="Instructor" ) self.entrance_exam = ItemFactory.create( parent=self.course, category="chapter", display_name="Entrance Exam Section - Chapter 1", is_entrance_exam=True, in_entrance_exam=True ) self.exam_1 = ItemFactory.create( parent=self.entrance_exam, category='sequential', display_name="Exam Sequential - Subsection 1", graded=True, in_entrance_exam=True ) subsection = ItemFactory.create( parent=self.exam_1, category='vertical', display_name='Exam Vertical - Unit 1' ) self.problem_1 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 1" ) self.problem_2 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 2" ) self.problem_3 = ItemFactory.create( parent=subsection, category="problem", display_name="Exam Problem - Problem 3" ) if settings.FEATURES.get('ENTRANCE_EXAMS', False): namespace_choices = milestones_helpers.get_namespace_choices() milestone_namespace = milestones_helpers.generate_milestone_namespace( namespace_choices.get('ENTRANCE_EXAM'), self.course.id ) self.milestone = { 'name': 'Test Milestone', 'namespace': milestone_namespace, 'description': 'Testing Courseware Entrance Exam Chapter', } milestones_helpers.seed_milestone_relationship_types() self.milestone_relationship_types = milestones_helpers.get_milestone_relationship_types() self.milestone = milestones_helpers.add_milestone(self.milestone) milestones_helpers.add_course_milestone( unicode(self.course.id), self.milestone_relationship_types['REQUIRES'], self.milestone ) milestones_helpers.add_course_content_milestone( unicode(self.course.id), unicode(self.entrance_exam.location), self.milestone_relationship_types['FULFILLS'], self.milestone ) user = UserFactory() self.request = RequestFactory() self.request.user = user self.request.COOKIES = {} self.request.META = {} self.request.is_secure = lambda: True self.request.get_host = lambda: "edx.org" self.request.method = 'GET' self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, user, self.entrance_exam ) self.course.entrance_exam_enabled = True self.course.entrance_exam_minimum_score_pct = 0.50 self.course.entrance_exam_id = unicode(self.entrance_exam.scope_ids.usage_id) modulestore().update_item(self.course, user.id) # pylint: disable=no-member self.client.login(username=self.request.user.username, password="******") CourseEnrollment.enroll(self.request.user, self.course.id) self.expected_locked_toc = ( [ { 'active': True, 'sections': [ { 'url_name': u'Exam_Sequential_-_Subsection_1', 'display_name': u'Exam Sequential - Subsection 1', 'graded': True, 'format': '', 'due': None, 'active': True } ], 'url_name': u'Entrance_Exam_Section_-_Chapter_1', 'display_name': u'Entrance Exam Section - Chapter 1' } ] ) self.expected_unlocked_toc = ( [ { 'active': False, 'sections': [ { 'url_name': u'Welcome', 'display_name': u'Welcome', 'graded': False, 'format': '', 'due': None, 'active': False }, { 'url_name': u'Lesson_1', 'display_name': u'Lesson 1', 'graded': False, 'format': '', 'due': None, 'active': False } ], 'url_name': u'Overview', 'display_name': u'Overview' }, { 'active': False, 'sections': [], 'url_name': u'Week_1', 'display_name': u'Week 1' }, { 'active': False, 'sections': [], 'url_name': u'Instructor', 'display_name': u'Instructor' }, { 'active': True, 'sections': [ { 'url_name': u'Exam_Sequential_-_Subsection_1', 'display_name': u'Exam Sequential - Subsection 1', 'graded': True, 'format': '', 'due': None, 'active': True } ], 'url_name': u'Entrance_Exam_Section_-_Chapter_1', 'display_name': u'Entrance Exam Section - Chapter 1' } ] )