def test_skip_entrance_exame_gating(self): """ Tests gating is disabled if skip entrance exam is set for a user. """ # make sure toc is locked before allowing user to skip entrance exam locked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in self.expected_locked_toc: self.assertIn(toc_section, locked_toc) # hit skip entrance exam api in instructor app instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=instructor.username, password='******') url = reverse('mark_student_can_skip_entrance_exam', kwargs={'course_id': unicode(self.course.id)}) response = self.client.post(url, { 'unique_student_identifier': self.request.user.email, }) self.assertEqual(response.status_code, 200) unlocked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in self.expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_skip_entrance_exame_gating(self): """ Tests gating is disabled if skip entrance exam is set for a user. """ # make sure toc is locked before allowing user to skip entrance exam locked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in self.expected_locked_toc: self.assertIn(toc_section, locked_toc) # hit skip entrance exam api in instructor app instructor = InstructorFactory(course_key=self.course.id) self.client.login(username=instructor.username, password='******') url = reverse('mark_student_can_skip_entrance_exam', kwargs={'course_id': unicode(self.course.id)}) response = self.client.post( url, { 'unique_student_identifier': self.request.user.email, }) self.assertEqual(response.status_code, 200) unlocked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in self.expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_entrance_exam_gating(self): """ Unit Test: test_entrance_exam_gating """ # This user helps to cover a discovered bug in the milestone fulfillment logic chaos_user = UserFactory() locked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in self.expected_locked_toc: self.assertIn(toc_section, locked_toc) # Set up the chaos user # pylint: disable=maybe-no-member,no-member grade_dict = {'value': 1, 'max_value': 1, 'user_id': chaos_user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, chaos_user, self.course, depth=2) # pylint: disable=protected-access module = get_module( chaos_user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) # pylint: disable=maybe-no-member,no-member grade_dict = { 'value': 1, 'max_value': 1, 'user_id': self.request.user.id } field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, self.request.user, self.course, depth=2) # pylint: disable=protected-access module = get_module( self.request.user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) module = get_module( self.request.user, self.request, self.problem_2.scope_ids.usage_id, field_data_cache, )._xmodule # pylint: disable=protected-access module.system.publish(self.problem_2, 'grade', grade_dict) unlocked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in self.expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_toc_toy_from_chapter(self): chapter = 'Overview' chapter_url = '%s/%s/%s' % ('/courses', self.course_name, chapter) factory = RequestFactory() request = factory.get(chapter_url) model_data_cache = ModelDataCache.cache_for_descriptor_descendents( self.toy_course.id, self.portal_user, self.toy_course, depth=2) expected = ([{'active': True, 'sections': [{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, 'format': u'Lecture Sequence', 'due': None, 'active': False}, {'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, 'format': '', 'due': None, 'active': False}, {'url_name': 'video_123456789012', 'display_name': 'video 123456789012', 'graded': True, 'format': '', 'due': None, 'active': False}, {'url_name': 'video_4f66f493ac8f', 'display_name': 'video 4f66f493ac8f', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'Overview', 'display_name': u'Overview'}, {'active': False, 'sections': [{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'secret:magic', 'display_name': 'secret:magic'}]) actual = render.toc_for_course(self.portal_user, request, self.toy_course, chapter, None, model_data_cache) assert reduce(lambda x, y: x and (y in actual), expected, True)
def test_toc_toy_from_section(self, default_ms, setup_finds, setup_sends, toc_finds): with self.store.default_store(default_ms): self.setup_modulestore(default_ms, setup_finds, setup_sends) section = 'Welcome' expected = ([{'active': True, 'sections': [{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, 'format': u'Lecture Sequence', 'due': None, 'active': False}, {'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, 'format': '', 'due': None, 'active': True}, {'url_name': 'video_123456789012', 'display_name': 'Test Video', 'graded': True, 'format': '', 'due': None, 'active': False}, {'url_name': 'video_4f66f493ac8f', 'display_name': 'Video', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'Overview', 'display_name': u'Overview'}, {'active': False, 'sections': [{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'secret:magic', 'display_name': 'secret:magic'}]) with check_mongo_calls(toc_finds): actual = render.toc_for_course( self.request, self.toy_course, self.chapter, section, self.field_data_cache ) for toc_section in expected: self.assertIn(toc_section, actual)
def test_toc_toy_from_section(self): chapter = 'Overview' chapter_url = '%s/%s/%s' % ('/courses', self.course_name, chapter) section = 'Welcome' factory = RequestFactory() request = factory.get(chapter_url) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.toy_course.id, self.portal_user, self.toy_course, depth=2) expected = ([{'active': True, 'sections': [{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, 'format': u'Lecture Sequence', 'due': None, 'active': False}, {'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, 'format': '', 'due': None, 'active': True}, {'url_name': 'video_123456789012', 'display_name': 'Test Video', 'graded': True, 'format': '', 'due': None, 'active': False}, {'url_name': 'video_4f66f493ac8f', 'display_name': 'Video', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'Overview', 'display_name': u'Overview'}, {'active': False, 'sections': [{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'secret:magic', 'display_name': 'secret:magic'}]) actual = render.toc_for_course(self.portal_user, request, self.toy_course, chapter, section, field_data_cache) for toc_section in expected: self.assertIn(toc_section, actual)
def _return_table_of_contents(self): """ Returns table of content for the entrance exam specific to this test Returns the table of contents for course self.course, for chapter self.entrance_exam, and for section self.exam1 """ self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( # pylint: disable=attribute-defined-outside-init self.course.id, self.request.user, self.entrance_exam) return toc_for_course(self.request.user, self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache)
def _create_courseware_context(self): """ returns the chapter list base on course """ table_of_contents = toc_for_course( self.effective_user, self.request, self.course, self.chapter_url_name, self.section_url_name, self.field_data_cache, ) return table_of_contents
def _return_table_of_contents(self): """ Returns table of content for the entrance exam specific to this test Returns the table of contents for course self.course, for chapter self.entrance_exam, and for section self.exam1 """ self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( # pylint: disable=attribute-defined-outside-init self.course.id, self.request.user, self.entrance_exam ) return toc_for_course( self.request.user, self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache, )
def test_entrance_exam_gating_for_staff(self): """ Tests gating is disabled if user is member of staff. """ # Login as member of staff self.client.logout() staff_user = StaffFactory(course_key=self.course.id) staff_user.is_staff = True self.client.login(username=staff_user.username, password='******') # assert staff has access to all toc self.request.user = staff_user unlocked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in self.expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def _create_courseware_context(self): """ returns section's sequnces with its child vertical module's context. """ courseware_context = {} section_context_data = { 'section': None, 'url_name': None, 'sequences': [] } table_of_contents = toc_for_course( self.effective_user, self.request, self.course, self.chapter_url_name, self.section_url_name, self.field_data_cache, ) if self.section is not None: courseware_context[ 'section_title'] = self.section.display_name_with_default_escaped section_context = self._create_section_context( table_of_contents['previous_of_active_section'], table_of_contents['next_of_active_section'], ) """ fetch section's context data """ sequence_module = self._prefetch_sequence_context( self.section, STUDENT_VIEW, section_context) section_context_data = { 'section': self.section.display_name, 'url_name': self.section.url_name, 'sequences': sequence_module } return section_context_data
def test_entrance_exam_gating_for_staff(self): """ Tests gating is disabled if user is member of staff. """ # Login as member of staff self.client.logout() staff_user = StaffFactory(course_key=self.course.id) staff_user.is_staff = True self.client.login(username=staff_user.username, password='******') # assert staff has access to all toc self.request.user = staff_user unlocked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in self.expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_toc_toy_from_section(self, default_ms, num_finds, num_sends): with self.store.default_store(default_ms): self.setup_modulestore(default_ms, num_finds, num_sends) section = 'Welcome' expected = ([{'active': True, 'sections': [{'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, 'format': u'Lecture Sequence', 'due': None, 'active': False}, {'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, 'format': '', 'due': None, 'active': True}, {'url_name': 'video_123456789012', 'display_name': 'Test Video', 'graded': True, 'format': '', 'due': None, 'active': False}, {'url_name': 'video_4f66f493ac8f', 'display_name': 'Video', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'Overview', 'display_name': u'Overview'}, {'active': False, 'sections': [{'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, 'format': '', 'due': None, 'active': False}], 'url_name': 'secret:magic', 'display_name': 'secret:magic'}]) actual = render.toc_for_course(self.request.user, self.request, self.toy_course, self.chapter, section, self.field_data_cache) for toc_section in expected: self.assertIn(toc_section, actual)
def _create_courseware_context(self): """ return content data for particular component request of course """ table_of_contents = toc_for_course( self.effective_user, self.request, self.course, self.chapter_url_name, self.section_url_name, self.field_data_cache, ) section_context = self._create_section_context( table_of_contents['previous_of_active_section'], table_of_contents['next_of_active_section'], ) if type(self.component) is unicode or self.component is None: raise Http404 return self._prefetch_component_context(self.component, STUDENT_VIEW, section_context)
def _create_courseware_context(self, request): """ Returns and creates the rendering context for the courseware. Also returns the table of contents for the courseware. """ course_url_name = default_course_url_name(self.course.id) course_url = reverse(course_url_name, kwargs={'course_id': unicode(self.course.id)}) courseware_context = { 'csrf': csrf(self.request)['csrf_token'], 'course': self.course, 'course_url': course_url, 'chapter': self.chapter, 'section': self.section, 'init': '', 'fragment': Fragment(), 'staff_access': self.is_staff, 'masquerade': self.masquerade, 'supports_preview_menu': True, 'studio_url': get_studio_url(self.course, 'course'), 'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"), 'bookmarks_api_url': reverse('bookmarks'), 'language_preference': self._get_language_preference(), 'disable_optimizely': not WaffleSwitchNamespace('RET').is_enabled( 'enable_optimizely_in_courseware'), 'section_title': None, 'sequence_title': None, 'disable_accordion': COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id), # TODO: (Experimental Code). See https://openedx.atlassian.net/wiki/display/RET/2.+In-course+Verification+Prompts 'upgrade_link': check_and_get_upgrade_link(request, self.effective_user, self.course.id), 'upgrade_price': get_cosmetic_verified_display_price(self.course), # ENDTODO } table_of_contents = toc_for_course( self.effective_user, self.request, self.course, self.chapter_url_name, self.section_url_name, self.field_data_cache, ) courseware_context['accordion_json'] = table_of_contents courseware_context['accordion'] = render_accordion( self.request, self.course, table_of_contents['chapters'], ) courseware_context['course_sock_fragment'] = CourseSockFragmentView( ).render_to_fragment(request, course=self.course) # entrance exam data self._add_entrance_exam_to_context(courseware_context) # staff masquerading data if not is_course_open_for_learner(self.effective_user, self.course): # Disable student view button if user is staff and # course is not yet visible to students. courseware_context['disable_student_access'] = True courseware_context['supports_preview_menu'] = False if self.section: # chromeless data if self.section.chrome: chrome = [ s.strip() for s in self.section.chrome.lower().split(",") ] if 'accordion' not in chrome: courseware_context['disable_accordion'] = True if 'tabs' not in chrome: courseware_context['disable_tabs'] = True # default tab if self.section.default_tab: courseware_context['default_tab'] = self.section.default_tab # section data courseware_context[ 'section_title'] = self.section.display_name_with_default section_context = self._create_section_context( table_of_contents['previous_of_active_section'], table_of_contents['next_of_active_section'], ) courseware_context['fragment'] = self.section.render( STUDENT_VIEW, section_context) if self.section.position and self.section.has_children: display_items = self.section.get_display_items() if display_items: try: courseware_context['sequence_title'] = display_items[self.section.position - 1] \ .display_name_with_default except IndexError: log.exception( "IndexError loading courseware for user %s, course %s, section %s, position %d. Total items: %d. URL: %s", self.real_user.username, self.course.id, self.section.display_name_with_default, self.section.position, len(display_items), self.url, ) raise return courseware_context
def test_toc_toy_from_chapter(self): chapter = 'Overview' chapter_url = '%s/%s/%s' % ('/courses', self.course_name, chapter) factory = RequestFactory() request = factory.get(chapter_url) model_data_cache = ModelDataCache.cache_for_descriptor_descendents( self.toy_course.id, self.portal_user, self.toy_course, depth=2) expected = ([{ 'active': True, 'sections': [{ 'url_name': 'Toy_Videos', 'display_name': u'Toy Videos', 'graded': True, 'format': u'Lecture Sequence', 'due': None, 'active': False }, { 'url_name': 'Welcome', 'display_name': u'Welcome', 'graded': True, 'format': '', 'due': None, 'active': False }, { 'url_name': 'video_123456789012', 'display_name': 'video 123456789012', 'graded': True, 'format': '', 'due': None, 'active': False }, { 'url_name': 'video_4f66f493ac8f', 'display_name': 'video 4f66f493ac8f', 'graded': True, 'format': '', 'due': None, 'active': False }], 'url_name': 'Overview', 'display_name': u'Overview' }, { 'active': False, 'sections': [{ 'url_name': 'toyvideo', 'display_name': 'toyvideo', 'graded': True, 'format': '', 'due': None, 'active': False }], 'url_name': 'secret:magic', 'display_name': 'secret:magic' }]) actual = render.toc_for_course(self.portal_user, request, self.toy_course, chapter, None, model_data_cache) assert reduce(lambda x, y: x and (y in actual), expected, True)
def test_toc_toy_from_section(self, default_ms, setup_finds, setup_sends, toc_finds): with self.store.default_store(default_ms): self.setup_modulestore(default_ms, setup_finds, setup_sends) section = "Welcome" expected = [ { "active": True, "sections": [ { "url_name": "Toy_Videos", "display_name": u"Toy Videos", "graded": True, "format": u"Lecture Sequence", "due": None, "active": False, }, { "url_name": "Welcome", "display_name": u"Welcome", "graded": True, "format": "", "due": None, "active": True, }, { "url_name": "video_123456789012", "display_name": "Test Video", "graded": True, "format": "", "due": None, "active": False, }, { "url_name": "video_4f66f493ac8f", "display_name": "Video", "graded": True, "format": "", "due": None, "active": False, }, ], "url_name": "Overview", "display_name": u"Overview", }, { "active": False, "sections": [ { "url_name": "toyvideo", "display_name": "toyvideo", "graded": True, "format": "", "due": None, "active": False, } ], "url_name": "secret:magic", "display_name": "secret:magic", }, ] with check_mongo_calls(toc_finds): actual = render.toc_for_course( self.request.user, self.request, self.toy_course, self.chapter, section, self.field_data_cache ) for toc_section in expected: self.assertIn(toc_section, actual)
def course_courseware(request, course_id, chapter = None, section = None, position = None): if not request.user.is_authenticated(): return JsonResponse({ "status": False }) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) user = User.objects.prefetch_related("groups").get(id = request.user.id) request.user = user # keep just one instance of User course = get_course_with_access(user, 'load', course_key, depth = 2) if not registered_for_course(course, user): # TODO (vshnayder): do course instructors need to be registered to see # course? return JsonResponse({ 'status': False }) try: field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_key, user, course, depth = 2) course_module = get_module_for_descriptor(user, request, course, field_data_cache, course_key) has_content = course.has_children_at_depth(2) if not has_content: # Show empty courseware for a course with no units return JsonResponse({ 'status': False }) if position is not None: try: int(position) except ValueError: return JsonResponse({ 'status': False }) def get_units(chapter, section, position = None): chapter_descriptor = course.get_child_by(lambda m: m.location.name == chapter) section_descriptor = chapter_descriptor.get_child_by(lambda m: m.location.name == section) # cdodge: this looks silly, but let's refetch the section_descriptor with depth=None # which will prefetch the children more efficiently than doing a recursive load section_descriptor = modulestore().get_item(section_descriptor.location, depth = None) section_field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_key, user, section_descriptor, depth = None) section_module = get_module_for_descriptor(request.user, request, section_descriptor, section_field_data_cache, course_key, position) if section_module is not None: units = [] for unit in section_module.get_display_items(): verticals = [] for vertical in unit.get_display_items(): if isinstance(vertical, VideoDescriptor): subtitles = vertical.transcripts.copy() if vertical.sub != "": subtitles.update({ 'en': sub }) verticals.append({ 'name': vertical.display_name, 'video_sources': vertical.html5_sources, 'subtitles': subtitles, 'type': 'video' }) else: verticals.append({ 'name': vertical.display_name, 'type': 'other' }) units.append({ 'name': unit.display_name, 'verticals': verticals }) return units else: return None if chapter is None or section is None: context = { 'course_id': course.id.to_deprecated_string(), 'sections': toc_for_course(user, request, course, chapter, section, field_data_cache), 'course_title': course.display_name_with_default, 'status': True } for chapter in context.get('sections', []): for section in chapter.get('sections', []): section.update({ 'units': get_units(chapter['url_name'], section['url_name'])}) else: units = get_units(chapter, section, position) context = { 'units': units, 'status': True if units is not None else False } except Exception as e: # In production, don't want to let a 500 out for any reason if settings.DEBUG: raise else: log.exception(u"Error in index view: user={user}, course={course}, chapter={chapter}" u" section={section} position={position}".format(user=user, course=course, chapter=chapter, section=section, position=position)) context = { 'status': False } return JsonResponse(context)
def test_entrance_exam_gating(self): """ Unit Test: test_entrance_exam_gating """ # This user helps to cover a discovered bug in the milestone fulfillment logic chaos_user = UserFactory() locked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in self.expected_locked_toc: self.assertIn(toc_section, locked_toc) # Set up the chaos user # pylint: disable=maybe-no-member,no-member grade_dict = {'value': 1, 'max_value': 1, 'user_id': chaos_user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, chaos_user, self.course, depth=2 ) # pylint: disable=protected-access module = get_module( chaos_user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) # pylint: disable=maybe-no-member,no-member grade_dict = {'value': 1, 'max_value': 1, 'user_id': self.request.user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, self.request.user, self.course, depth=2 ) # pylint: disable=protected-access module = get_module( self.request.user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) module = get_module( self.request.user, self.request, self.problem_2.scope_ids.usage_id, field_data_cache, )._xmodule # pylint: disable=protected-access module.system.publish(self.problem_2, 'grade', grade_dict) unlocked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in self.expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_entrance_exam_gating(self): """ Unit Test: test_entrance_exam_gating """ # This user helps to cover a discovered bug in the milestone fulfillment logic chaos_user = UserFactory() 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' }]) locked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in expected_locked_toc: self.assertIn(toc_section, locked_toc) # Set up the chaos user # pylint: disable=maybe-no-member,no-member grade_dict = {'value': 1, 'max_value': 1, 'user_id': chaos_user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, chaos_user, self.course, depth=2) # pylint: disable=protected-access module = get_module( chaos_user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) # pylint: disable=maybe-no-member,no-member grade_dict = { 'value': 1, 'max_value': 1, 'user_id': self.request.user.id } field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, self.request.user, self.course, depth=2) # pylint: disable=protected-access module = get_module( self.request.user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) module = get_module( self.request.user, self.request, self.problem_2.scope_ids.usage_id, field_data_cache, )._xmodule # pylint: disable=protected-access module.system.publish(self.problem_2, 'grade', grade_dict) 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' }]) unlocked_toc = toc_for_course(self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache) for toc_section in expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_toc_toy_from_section(self): chapter = "Overview" chapter_url = "%s/%s/%s" % ("/courses", self.course_name, chapter) section = "Welcome" factory = RequestFactory() request = factory.get(chapter_url) model_data_cache = ModelDataCache.cache_for_descriptor_descendents( self.toy_course.id, self.portal_user, self.toy_course, depth=2 ) expected = [ { "active": True, "sections": [ { "url_name": "Toy_Videos", "display_name": u"Toy Videos", "graded": True, "format": u"Lecture Sequence", "due": None, "active": False, }, { "url_name": "Welcome", "display_name": u"Welcome", "graded": True, "format": "", "due": None, "active": True, }, { "url_name": "video_123456789012", "display_name": "Test Video", "graded": True, "format": "", "due": None, "active": False, }, { "url_name": "video_4f66f493ac8f", "display_name": "Video", "graded": True, "format": "", "due": None, "active": False, }, ], "url_name": "Overview", "display_name": u"Overview", }, { "active": False, "sections": [ { "url_name": "toyvideo", "display_name": "toyvideo", "graded": True, "format": "", "due": None, "active": False, } ], "url_name": "secret:magic", "display_name": "secret:magic", }, ] actual = render.toc_for_course(self.portal_user, request, self.toy_course, chapter, section, model_data_cache) for toc_section in expected: self.assertIn(toc_section, actual)
def test_entrance_exam_gating(self): """ Unit Test: test_entrance_exam_gating """ # This user helps to cover a discovered bug in the milestone fulfillment logic chaos_user = UserFactory() 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' } ] ) locked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in expected_locked_toc: self.assertIn(toc_section, locked_toc) # Set up the chaos user # pylint: disable=maybe-no-member,no-member grade_dict = {'value': 1, 'max_value': 1, 'user_id': chaos_user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, chaos_user, self.course, depth=2 ) # pylint: disable=protected-access module = get_module( chaos_user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) # pylint: disable=maybe-no-member,no-member grade_dict = {'value': 1, 'max_value': 1, 'user_id': self.request.user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, self.request.user, self.course, depth=2 ) # pylint: disable=protected-access module = get_module( self.request.user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache, )._xmodule module.system.publish(self.problem_1, 'grade', grade_dict) module = get_module( self.request.user, self.request, self.problem_2.scope_ids.usage_id, field_data_cache, )._xmodule # pylint: disable=protected-access module.system.publish(self.problem_2, 'grade', grade_dict) 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' } ] ) unlocked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def test_entrance_exam_gating(self): """ Unit Test: test_entrance_exam_gating """ # This user helps to cover a discovered bug in the milestone fulfillment logic chaos_user = UserFactory() 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", } ] locked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in expected_locked_toc: self.assertIn(toc_section, locked_toc) # Set up the chaos user # pylint: disable=maybe-no-member,no-member grade_dict = {"value": 1, "max_value": 1, "user_id": chaos_user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, chaos_user, self.course, depth=2 ) # pylint: disable=protected-access module = get_module(chaos_user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache)._xmodule module.system.publish(self.problem_1, "grade", grade_dict) # pylint: disable=maybe-no-member,no-member grade_dict = {"value": 1, "max_value": 1, "user_id": self.request.user.id} field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, self.request.user, self.course, depth=2 ) # pylint: disable=protected-access module = get_module( self.request.user, self.request, self.problem_1.scope_ids.usage_id, field_data_cache )._xmodule module.system.publish(self.problem_1, "grade", grade_dict) module = get_module( self.request.user, self.request, self.problem_2.scope_ids.usage_id, field_data_cache )._xmodule # pylint: disable=protected-access module.system.publish(self.problem_2, "grade", grade_dict) 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", }, ] unlocked_toc = toc_for_course( self.request, self.course, self.entrance_exam.url_name, self.exam_1.url_name, self.field_data_cache ) for toc_section in expected_unlocked_toc: self.assertIn(toc_section, unlocked_toc)
def _create_courseware_api_test(self, request): """ Returns and creates the rendering context for the courseware. Also returns the table of contents for the courseware. """ course_url_name = default_course_url_name(self.course.id) course_url = reverse(course_url_name, kwargs={'course_id': unicode(self.course.id)}) courseware_context = { 'course_url': course_url, 'init': '', 'content': '', 'bookmarks_api_url': reverse('bookmarks'), 'language_preference': self._get_language_preference(), 'section_title': None, 'sequence_title': None, } table_of_contents = toc_for_course( self.effective_user, self.request, self.course, self.chapter_url_name, self.section_url_name, self.field_data_cache, ) courseware_context['accordion_json'] = table_of_contents if self.section: # default tab if self.section.default_tab: courseware_context['default_tab'] = self.section.default_tab # section data courseware_context[ 'section_title'] = self.section.display_name_with_default section_context = self._create_section_context( table_of_contents['previous_of_active_section'], table_of_contents['next_of_active_section'], ) courseware_context['content'] = self.section.render( STUDENT_VIEW, section_context).to_dict()['content'] if self.section.position and self.section.has_children: display_items = self.section.get_display_items() if display_items: try: courseware_context['sequence_title'] = display_items[self.section.position - 1] \ .display_name_with_default except IndexError: log.exception( "IndexError loading courseware for user %s, course %s, section %s, position %d. Total items: %d. URL: %s", self.real_user.username, self.course.id, self.section.display_name_with_default, self.section.position, len(display_items), self.url, ) raise return json.dumps(courseware_context)