def test_different_groups_indexed_on_same_vertical_html_blocks(self): """ Indexing course with different content groups assigned to each of multiple html units on same vertical """ group_access_content_1 = {'group_access': {666: [1]}} group_access_content_2 = {'group_access': {666: [0]}} self.client.ajax_post( reverse_usage_url("xblock_handler", self.html_unit2.location), data={'metadata': group_access_content_1} ) self.client.ajax_post( reverse_usage_url("xblock_handler", self.html_unit3.location), data={'metadata': group_access_content_2} ) self.publish_item(self.store, self.html_unit2.location) self.publish_item(self.store, self.html_unit3.location) with patch(settings.SEARCH_ENGINE + '.index') as mock_index: self.reindex_course(self.store) self.assertTrue(mock_index.called) self.assertIn(self._html_group_result(self.html_unit2, [1]), mock_index.mock_calls) self.assertIn(self._html_group_result(self.html_unit3, [0]), mock_index.mock_calls) mock_index.reset_mock()
def test_content_group_not_indexed_on_delete(self): """ indexing course with content groups deleted test """ group_access_content = {'group_access': {666: [1]}} self.client.ajax_post( reverse_usage_url("xblock_handler", self.html_unit1.location), data={'metadata': group_access_content} ) self.publish_item(self.store, self.html_unit1.location) # Checking group indexed correctly with patch(settings.SEARCH_ENGINE + '.index') as mock_index: self.reindex_course(self.store) self.assertTrue(mock_index.called) self.assertIn(self._html_group_result(self.html_unit1, [1]), mock_index.mock_calls) mock_index.reset_mock() empty_group_access = {'group_access': {}} self.client.ajax_post( reverse_usage_url("xblock_handler", self.html_unit1.location), data={'metadata': empty_group_access} ) self.publish_item(self.store, self.html_unit1.location) # Checking group removed and not indexed any more with patch(settings.SEARCH_ENGINE + '.index') as mock_index: self.reindex_course(self.store) self.assertTrue(mock_index.called) self.assertIn(self._html_nogroup_result(self.html_unit1), mock_index.mock_calls) mock_index.reset_mock()
def setUp(self): """ Initial data setup """ super(TestSubsectionGating, self).setUp() # Enable subsection gating for the test course self.course.enable_subsection_gating = True self.save_course() # create a chapter self.chapter = ItemFactory.create(parent_location=self.course.location, category='chapter', display_name='untitled chapter') # create 2 sequentials self.seq1 = ItemFactory.create(parent_location=self.chapter.location, category='sequential', display_name='untitled sequential 1') self.seq1_url = reverse_usage_url('xblock_handler', self.seq1.location) self.seq2 = ItemFactory.create(parent_location=self.chapter.location, category='sequential', display_name='untitled sequential 2') self.seq2_url = reverse_usage_url('xblock_handler', self.seq2.location)
def setUp(self): """ Creates the test course structure and a couple problems to 'edit'. """ super(TestEditItem, self).setUp() # create a chapter display_name = 'chapter created' resp = self.create_xblock(display_name=display_name, category='chapter') chap_usage_key = self.response_usage_key(resp) resp = self.create_xblock(parent_usage_key=chap_usage_key, category='sequential') self.seq_usage_key = self.response_usage_key(resp) self.seq_update_url = reverse_usage_url("xblock_handler", self.seq_usage_key) # create problem w/ boilerplate template_id = 'multiplechoice.yaml' resp = self.create_xblock(parent_usage_key=self.seq_usage_key, category='problem', boilerplate=template_id) self.problem_usage_key = self.response_usage_key(resp) self.problem_update_url = reverse_usage_url("xblock_handler", self.problem_usage_key) self.course_update_url = reverse_usage_url("xblock_handler", self.usage_key)
def setUp(self): """ Initial data setup """ super(TestSubsectionGating, self).setUp() # Enable subsection gating for the test course self.course.enable_subsection_gating = True self.save_course() # create a chapter self.chapter = ItemFactory.create( parent_location=self.course.location, category='chapter', display_name='untitled chapter' ) # create 2 sequentials self.seq1 = ItemFactory.create( parent_location=self.chapter.location, category='sequential', display_name='untitled sequential 1' ) self.seq1_url = reverse_usage_url('xblock_handler', self.seq1.location) self.seq2 = ItemFactory.create( parent_location=self.chapter.location, category='sequential', display_name='untitled sequential 2' ) self.seq2_url = reverse_usage_url('xblock_handler', self.seq2.location)
def _get_usage_dict(course, unit, item, scheme_name=None): """ Get usage info for unit/module. """ parent_unit = get_parent_unit(item) if unit == parent_unit and not item.has_children: # Display the topmost unit page if # the item is a child of the topmost unit and doesn't have its own children. unit_for_url = unit elif (not parent_unit and unit.get_parent()) or (unit == parent_unit and item.has_children): # Display the item's page rather than the unit page if # the item is one level below the topmost unit and has children, or # the item itself *is* the topmost unit (and thus does not have a parent unit, but is not an orphan). unit_for_url = item else: # If the item is nested deeper than two levels (the topmost unit > vertical > ... > item) # display the page for the nested vertical element. parent = item.get_parent() nested_vertical = item while parent != parent_unit: nested_vertical = parent parent = parent.get_parent() unit_for_url = nested_vertical unit_url = reverse_usage_url( 'container_handler', course.location.course_key.make_usage_key(unit_for_url.location.block_type, unit_for_url.location.block_id) ) usage_dict = {'label': u"{} / {}".format(unit.display_name, item.display_name), 'url': unit_url} if scheme_name == RANDOM_SCHEME: validation_summary = item.general_validation_message() usage_dict.update({'validation': validation_summary.to_json() if validation_summary else None}) return usage_dict
def test_can_get_usage_info_when_special_characters_are_used(self): """ Test if group configurations json updated successfully when special characters are being used in content experiment """ self._add_user_partitions(count=1) __, split_test, __ = self._create_content_experiment(cid=0, name_suffix='0', special_characters=u"JOSÉ ANDRÉS") actual = GroupConfiguration.get_split_test_partitions_with_usage(self.store, self.course, ) expected = [{ 'id': 0, 'name': 'Name 0', 'scheme': 'random', 'description': 'Description 0', 'version': UserPartition.VERSION, 'groups': [ {'id': 0, 'name': 'Group A', 'version': 1}, {'id': 1, 'name': 'Group B', 'version': 1}, {'id': 2, 'name': 'Group C', 'version': 1}, ], 'usage': [{ 'url': reverse_usage_url("container_handler", split_test.location), 'label': u"Test Unit 0 / Test Content Experiment 0JOSÉ ANDRÉS", 'validation': None, }], 'parameters': {}, 'active': True, }] self.assertEqual(actual, expected)
def _update_item(self, usage_key, metadata): """ Helper method: Uses the REST API to update the fields of an XBlock. This will result in the XBlock's editor_saved() method being called. """ update_url = reverse_usage_url("xblock_handler", usage_key) return self.client.ajax_post(update_url, data={"metadata": metadata})
def xblock_studio_url(xblock): """ Returns the Studio editing URL for the specified xblock. """ if not xblock_has_own_studio_page(xblock): return None category = xblock.category parent_xblock = get_parent_xblock(xblock) parent_category = parent_xblock.category if parent_xblock else None if category == 'course': return reverse_course_url('course_handler', xblock.location.course_key) elif category == 'vertical' and parent_category == 'sequential': # only show the unit page for verticals directly beneath a subsection return reverse_usage_url('unit_handler', xblock.location) else: return reverse_usage_url('container_handler', xblock.location)
def _create_problem_with_content_group(self, cid, group_id, name_suffix='', special_characters=''): """ Create a problem Assign content group to the problem. """ vertical = ItemFactory.create( category='vertical', parent_location=self.course.location, display_name="Test Unit {}".format(name_suffix) ) problem = ItemFactory.create( category='problem', parent_location=vertical.location, display_name=u"Test Problem {}{}".format(name_suffix, special_characters) ) group_access_content = {'group_access': {cid: [group_id]}} self.client.ajax_post( reverse_usage_url("xblock_handler", problem.location), data={'metadata': group_access_content} ) self.save_course() return vertical, problem
def test_preview_conditional_module_children_context( self, mock_is_condition_satisfied): """ Testst that when empty context is pass to children of ConditionalModule it will not raise KeyError. """ mock_is_condition_satisfied.return_value = True client = Client() client.login(username=self.user.username, password=self.user_password) with self.store.default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() conditional_block = ItemFactory.create( parent_location=course.location, category="conditional") # child conditional_block ItemFactory.create(parent_location=conditional_block.location, category="conditional") url = reverse_usage_url( 'preview_handler', conditional_block.location, kwargs={'handler': 'xmodule_handler/conditional_get'}) response = client.post(url) self.assertEqual(response.status_code, 200)
def _get_usage_info(course, unit, item, usage_info, group_id, scheme_name=None): """ Get usage info for unit/module. """ unit_url = reverse_usage_url( 'container_handler', course.location.course_key.make_usage_key(unit.location.block_type, unit.location.name)) usage_dict = { 'label': u"{} / {}".format(unit.display_name, item.display_name), 'url': unit_url } if scheme_name == RANDOM_SCHEME: validation_summary = item.general_validation_message() usage_dict.update({ 'validation': validation_summary.to_json() if validation_summary else None }) usage_info[group_id].append(usage_dict) return usage_info
def test_preview_conditional_module_children_context(self, mock_is_condition_satisfied): """ Testst that when empty context is pass to children of ConditionalModule it will not raise KeyError. """ mock_is_condition_satisfied.return_value = True client = Client() client.login(username=self.user.username, password=self.user_password) with self.store.default_store(ModuleStoreEnum.Type.split): course = CourseFactory.create() conditional_block = ItemFactory.create( parent_location=course.location, category="conditional" ) # child conditional_block ItemFactory.create( parent_location=conditional_block.location, category="conditional" ) url = reverse_usage_url( 'preview_handler', conditional_block.location, kwargs={'handler': 'xmodule_handler/conditional_get'} ) response = client.post(url) self.assertEqual(response.status_code, 200)
def test_post_course_update(self, mock_push_update): """ Test that a user can successfully post on course updates and handouts of a course """ self.post_course_update() # check that push notifications are not sent self.assertFalse(mock_push_update.called) updates_location = self.course.id.make_usage_key('course_info', 'updates') self.assertTrue(isinstance(updates_location, UsageKey)) self.assertEqual(updates_location.name, u'updates') # check posting on handouts handouts_location = self.course.id.make_usage_key('course_info', 'handouts') course_handouts_url = reverse_usage_url('xblock_handler', handouts_location) content = u"Sample handout" payload = {'data': content} resp = self.client.ajax_post(course_handouts_url, payload) # check that response status is 200 not 500 self.assertEqual(resp.status_code, 200) payload = json.loads(resp.content) self.assertHTMLEqual(payload['data'], content)
def _create_problem_with_content_group(self, cid, group_id, name_suffix='', special_characters=''): """ Create a problem Assign content group to the problem. """ vertical = ItemFactory.create( category='vertical', parent_location=self.course.location, display_name="Test Unit {}".format(name_suffix)) problem = ItemFactory.create(category='problem', parent_location=vertical.location, display_name=u"Test Problem {}{}".format( name_suffix, special_characters)) group_access_content = {'group_access': {cid: [group_id]}} self.client.ajax_post(reverse_usage_url("xblock_handler", problem.location), data={'metadata': group_access_content}) self.save_course() return vertical, problem
def create_export_tarball(course_module, course_key, context, status=None): """ Generates the export tarball, or returns None if there was an error. Updates the context with any error information if applicable. """ name = course_module.url_name export_file = NamedTemporaryFile(prefix=name + '.', suffix=".tar.gz") root_dir = path(mkdtemp()) try: if isinstance(course_key, LibraryLocator): export_library_to_xml(modulestore(), contentstore(), course_key, root_dir, name) else: export_course_to_xml(modulestore(), contentstore(), course_module.id, root_dir, name) if status: status.set_state(u'Compressing') status.increment_completed_steps() LOGGER.debug(u'tar file being generated at %s', export_file.name) with tarfile.open(name=export_file.name, mode='w:gz') as tar_file: tar_file.add(root_dir / name, arcname=name) except SerializationError as exc: LOGGER.exception(u'There was an error exporting %s', course_key, exc_info=True) parent = None try: failed_item = modulestore().get_item(exc.location) parent_loc = modulestore().get_parent_location(failed_item.location) if parent_loc is not None: parent = modulestore().get_item(parent_loc) except: # pylint: disable=bare-except # if we have a nested exception, then we'll show the more generic error message pass context.update({ 'in_err': True, 'raw_err_msg': str(exc), 'edit_unit_url': reverse_usage_url("container_handler", parent.location) if parent else "", }) if status: status.fail(json.dumps({'raw_error_msg': context['raw_err_msg'], 'edit_unit_url': context['edit_unit_url']})) raise except Exception as exc: LOGGER.exception(u'There was an error exporting %s', course_key, exc_info=True) context.update({ 'in_err': True, 'edit_unit_url': None, 'raw_err_msg': str(exc)}) if status: status.fail(json.dumps({'raw_error_msg': context['raw_err_msg']})) raise finally: if os.path.exists(root_dir / name): shutil.rmtree(root_dir / name) return export_file
def create_export_tarball(course_module, course_key, context, status=None): """ Generates the export tarball, or returns None if there was an error. Updates the context with any error information if applicable. """ name = course_module.url_name export_file = NamedTemporaryFile(prefix=name + '.', suffix=".tar.gz") root_dir = path(mkdtemp()) try: if isinstance(course_key, LibraryLocator): export_library_to_xml(modulestore(), contentstore(), course_key, root_dir, name) else: export_course_to_xml(modulestore(), contentstore(), course_module.id, root_dir, name) if status: status.set_state(u'Compressing') status.increment_completed_steps() LOGGER.debug(u'tar file being generated at %s', export_file.name) with tarfile.open(name=export_file.name, mode='w:gz') as tar_file: tar_file.add(root_dir / name, arcname=name) except SerializationError as exc: LOGGER.exception(u'There was an error exporting %s', course_key, exc_info=True) parent = None try: failed_item = modulestore().get_item(exc.location) parent_loc = modulestore().get_parent_location(failed_item.location) if parent_loc is not None: parent = modulestore().get_item(parent_loc) except: # pylint: disable=bare-except # if we have a nested exception, then we'll show the more generic error message pass context.update({ 'in_err': True, 'raw_err_msg': str(exc), 'edit_unit_url': reverse_usage_url("container_handler", parent.location) if parent else "", }) if status: status.fail(json.dumps({'raw_error_msg': context['raw_err_msg'], 'edit_unit_url': context['edit_unit_url']})) raise except Exception as exc: LOGGER.exception('There was an error exporting %s', course_key, exc_info=True) context.update({ 'in_err': True, 'edit_unit_url': None, 'raw_err_msg': str(exc)}) if status: status.fail(json.dumps({'raw_error_msg': context['raw_err_msg']})) raise finally: if os.path.exists(root_dir / name): shutil.rmtree(root_dir / name) return export_file
def test_delete_static_page(self): # Add static tab resp = self.create_xblock(category='static_tab') usage_key = self.response_usage_key(resp) # Now delete it. There was a bug that the delete was failing (static tabs do not exist in draft modulestore). resp = self.client.delete(reverse_usage_url('xblock_handler', usage_key)) self.assertEqual(resp.status_code, 204)
def test_get_vertical(self): # Add a vertical resp = self.create_xblock(category='vertical') usage_key = self.response_usage_key(resp) # Retrieve it resp = self.client.get(reverse_usage_url('xblock_handler', usage_key)) self.assertEqual(resp.status_code, 200)
def _update_item(self, usage_key, metadata): """ Helper method: Uses the REST API to update the fields of an XBlock. This will result in the XBlock's editor_saved() method being called. """ update_url = reverse_usage_url("xblock_handler", usage_key) return self.client.ajax_post(update_url, data={ 'metadata': metadata, })
def i_click_on_error_dialog(step): world.click_link_by_text('Correct failed component') assert_true(world.css_html("span.inline-error").startswith("Problem i4x://MITx/999/problem")) course_key = SlashSeparatedCourseKey("MITx", "999", "Robot_Super_Course") # we don't know the actual ID of the vertical. So just check that we did go to a # vertical page in the course (there should only be one). vertical_usage_key = course_key.make_usage_key("vertical", "") vertical_url = reverse_usage_url('unit_handler', vertical_usage_key) assert_equal(1, world.browser.url.count(vertical_url))
def test_delete_item_signal_handler_called(self, mock_remove_prereq, mock_set_required): seq3 = ItemFactory.create( parent_location=self.chapter.location, category='sequential', display_name='untitled sequential 3' ) self.client.delete(reverse_usage_url('xblock_handler', seq3.location)) mock_remove_prereq.assert_called_with(seq3.location) mock_set_required.assert_called_with(seq3.location.course_key, seq3.location, None, None, None)
def test_delete_item_signal_handler_called(self, mock_remove_prereq, mock_set_required): seq3 = ItemFactory.create(parent_location=self.chapter.location, category='sequential', display_name='untitled sequential 3') self.client.delete(reverse_usage_url('xblock_handler', seq3.location)) mock_remove_prereq.assert_called_with(seq3.location) mock_set_required.assert_called_with(seq3.location.course_key, seq3.location, None, None, None)
def test_published_and_draft_contents_with_update(self): """ Create a draft and publish it then modify the draft and check that published content is not modified """ # Make problem public. resp = self.client.ajax_post(self.problem_update_url, data={'publish': 'make_public'}) self.assertIsNotNone( self.get_item_from_modulestore(self.problem_usage_key, False)) # Now make a draft resp = self.client.ajax_post(self.problem_update_url, data={ 'id': unicode(self.problem_usage_key), 'metadata': {}, 'data': "<p>Problem content draft.</p>", 'publish': 'create_draft' }) # Both published and draft content should be different published = self.get_item_from_modulestore(self.problem_usage_key, False) draft = self.get_item_from_modulestore(self.problem_usage_key, True) self.assertNotEqual(draft.data, published.data) # Get problem by 'xblock_handler' view_url = reverse_usage_url("xblock_view_handler", self.problem_usage_key, {"view_name": "student_view"}) resp = self.client.get(view_url, HTTP_ACCEPT='application/json') self.assertEqual(resp.status_code, 200) # Activate the editing view view_url = reverse_usage_url("xblock_view_handler", self.problem_usage_key, {"view_name": "studio_view"}) resp = self.client.get(view_url, HTTP_ACCEPT='application/json') self.assertEqual(resp.status_code, 200) # Both published and draft content should still be different published = self.get_item_from_modulestore(self.problem_usage_key, False) draft = self.get_item_from_modulestore(self.problem_usage_key, True) self.assertNotEqual(draft.data, published.data)
def create_export_tarball(course_module, course_key, context): """ Generates the export tarball, or returns None if there was an error. Updates the context with any error information if applicable. """ name = course_module.url_name export_file = NamedTemporaryFile(prefix=name + '.', suffix=".tar.gz") root_dir = path(mkdtemp()) try: if isinstance(course_key, LibraryLocator): export_library_to_xml(modulestore(), contentstore(), course_key, root_dir, name) else: export_course_to_xml(modulestore(), contentstore(), course_module.id, root_dir, name) logging.debug(u'tar file being generated at %s', export_file.name) with tarfile.open(name=export_file.name, mode='w:gz') as tar_file: tar_file.add(root_dir / name, arcname=name) except SerializationError as exc: log.exception(u'There was an error exporting %s', course_key) unit = None failed_item = None parent = None try: failed_item = modulestore().get_item(exc.location) parent_loc = modulestore().get_parent_location(failed_item.location) if parent_loc is not None: parent = modulestore().get_item(parent_loc) if parent.location.category == 'vertical': unit = parent except: # pylint: disable=bare-except # if we have a nested exception, then we'll show the more generic error message pass context.update({ 'in_err': True, 'raw_err_msg': str(exc), 'failed_module': failed_item, 'unit': unit, 'edit_unit_url': reverse_usage_url("container_handler", parent.location) if parent else "", }) raise except Exception as exc: log.exception('There was an error exporting %s', course_key) context.update({ 'in_err': True, 'unit': None, 'raw_err_msg': str(exc)}) raise finally: shutil.rmtree(root_dir / name) return export_file
def _create_content_experiment(self, cid=-1, name_suffix='', special_characters=''): """ Create content experiment. Assign Group Configuration to the experiment if cid is provided. """ vertical = ItemFactory.create( category='vertical', parent_location=self.course.location, display_name='Test Unit {}'.format(name_suffix)) c0_url = self.course.id.make_usage_key("vertical", "split_test_cond0") c1_url = self.course.id.make_usage_key("vertical", "split_test_cond1") c2_url = self.course.id.make_usage_key("vertical", "split_test_cond2") split_test = ItemFactory.create( category='split_test', parent_location=vertical.location, user_partition_id=cid, display_name=u"Test Content Experiment {}{}".format( name_suffix, special_characters), group_id_to_child={ "0": c0_url, "1": c1_url, "2": c2_url }) ItemFactory.create( parent_location=split_test.location, category="vertical", display_name="Condition 0 vertical", location=c0_url, ) ItemFactory.create( parent_location=split_test.location, category="vertical", display_name="Condition 1 vertical", location=c1_url, ) ItemFactory.create( parent_location=split_test.location, category="vertical", display_name="Condition 2 vertical", location=c2_url, ) partitions_json = [p.to_json() for p in self.course.user_partitions] self.client.ajax_post( reverse_usage_url("xblock_handler", split_test.location), data={'metadata': { 'user_partitions': partitions_json }}) self.save_course() return (vertical, split_test)
def setup_test_set_get_section_grader_ajax(self): """ Populate the course, grab a section, get the url for the assignment type access """ self.populate_course() sections = modulestore().get_items(self.course.id, qualifiers={'category': "sequential"}) # see if test makes sense self.assertGreater(len(sections), 0, "No sections found") section = sections[0] # just take the first one return reverse_usage_url('xblock_handler', section.location)
def test_handle_requests(self, aside_key_class): """ Checks that handler to save tags in StructuredTagsAside works properly """ handler_url = reverse_usage_url( 'preview_handler', unicode(aside_key_class(self.problem.location, self.aside_name)), kwargs={'handler': 'save_tags'} ) client = AjaxEnabledTestClient() client.login(username=self.user.username, password=self.user_password) response = client.post(handler_url, json.dumps({}), content_type="application/json") self.assertEqual(response.status_code, 400) response = client.post(handler_url, json.dumps({'undefined_tag': ['undefined1', 'undefined2']}), content_type="application/json") self.assertEqual(response.status_code, 400) response = client.post(handler_url, json.dumps({self.aside_tag_dif: ['undefined1', 'undefined2']}), content_type="application/json") self.assertEqual(response.status_code, 400) def _test_helper_func(problem_location): """ Helper function """ problem = modulestore().get_item(problem_location) asides = problem.runtime.get_asides(problem) tag_aside = None for aside in asides: if isinstance(aside, StructuredTagsAside): tag_aside = aside break return tag_aside response = client.post(handler_url, json.dumps({self.aside_tag_dif: [self.aside_tag_dif_value]}), content_type="application/json") self.assertEqual(response.status_code, 200) tag_aside = _test_helper_func(self.problem.location) self.assertIsNotNone(tag_aside, "Necessary StructuredTagsAside object isn't found") self.assertEqual(tag_aside.saved_tags[self.aside_tag_dif], [self.aside_tag_dif_value]) response = client.post(handler_url, json.dumps({self.aside_tag_dif: [self.aside_tag_dif_value, self.aside_tag_dif_value2]}), content_type="application/json") self.assertEqual(response.status_code, 200) tag_aside = _test_helper_func(self.problem.location) self.assertIsNotNone(tag_aside, "Necessary StructuredTagsAside object isn't found") self.assertEqual(tag_aside.saved_tags[self.aside_tag_dif], [self.aside_tag_dif_value, self.aside_tag_dif_value2])
def i_click_on_error_dialog(step): world.click_link_by_text('Correct failed component') assert_true( world.css_html("span.inline-error").startswith( "Problem i4x://MITx/999/problem")) course_key = SlashSeparatedCourseKey("MITx", "999", "Robot_Super_Course") # we don't know the actual ID of the vertical. So just check that we did go to a # vertical page in the course (there should only be one). vertical_usage_key = course_key.make_usage_key("vertical", "") vertical_url = reverse_usage_url('unit_handler', vertical_usage_key) assert_equal(1, world.browser.url.count(vertical_url))
def _get_settings_html(): """ Helper function to get block settings HTML Used to check the available libraries. """ edit_view_url = reverse_usage_url("xblock_view_handler", lib_block.location, {"view_name": STUDIO_VIEW}) resp = self.client.get_json(edit_view_url) self.assertEquals(resp.status_code, 200) return parse_json(resp)['html']
def test_handle_requests(self, aside_key_class): """ Checks that handler to save tags in StructuredTagsAside works properly """ handler_url = reverse_usage_url( 'component_handler', unicode(aside_key_class(self.problem.location, self.aside_name)), kwargs={'handler': 'save_tags'} ) client = AjaxEnabledTestClient() client.login(username=self.user.username, password=self.user_password) response = client.post(handler_url, json.dumps({}), content_type="application/json") self.assertEqual(response.status_code, 400) response = client.post(handler_url, json.dumps({'undefined_tag': ['undefined1', 'undefined2']}), content_type="application/json") self.assertEqual(response.status_code, 400) response = client.post(handler_url, json.dumps({self.aside_tag_dif: ['undefined1', 'undefined2']}), content_type="application/json") self.assertEqual(response.status_code, 400) def _test_helper_func(problem_location): """ Helper function """ problem = modulestore().get_item(problem_location) asides = problem.runtime.get_asides(problem) tag_aside = None for aside in asides: if isinstance(aside, StructuredTagsAside): tag_aside = aside break return tag_aside response = client.post(handler_url, json.dumps({self.aside_tag_dif: [self.aside_tag_dif_value]}), content_type="application/json") self.assertEqual(response.status_code, 200) tag_aside = _test_helper_func(self.problem.location) self.assertIsNotNone(tag_aside, "Necessary StructuredTagsAside object isn't found") self.assertEqual(tag_aside.saved_tags[self.aside_tag_dif], [self.aside_tag_dif_value]) response = client.post(handler_url, json.dumps({self.aside_tag_dif: [self.aside_tag_dif_value, self.aside_tag_dif_value2]}), content_type="application/json") self.assertEqual(response.status_code, 200) tag_aside = _test_helper_func(self.problem.location) self.assertIsNotNone(tag_aside, "Necessary StructuredTagsAside object isn't found") self.assertEqual(tag_aside.saved_tags[self.aside_tag_dif], [self.aside_tag_dif_value, self.aside_tag_dif_value2])
def test_can_get_correct_usage_info_for_unit(self): """ When group access is set on the unit level, the usage info should return a url to the unit, not the sequential parent of the unit. """ self.course.user_partitions = [ UserPartition( id=0, name='User Partition', scheme=UserPartition.get_scheme('cohort'), description='User Partition', groups=[ Group(id=0, name="Group") ], ), ] vertical, __ = self._create_problem_with_content_group( cid=0, group_id=0, name_suffix='0' ) self.client.ajax_post( reverse_usage_url("xblock_handler", vertical.location), data={'metadata': {'group_access': {0: [0]}}} ) actual = self._get_user_partition('cohort') # order of usage list is arbitrary, sort for reliable comparison actual['groups'][0]['usage'].sort(key=itemgetter('label')) expected = { 'id': 0, 'name': 'User Partition', 'scheme': 'cohort', 'description': 'User Partition', 'version': UserPartition.VERSION, 'groups': [ {'id': 0, 'name': 'Group', 'version': 1, 'usage': [ { 'url': u"/container/{}".format(vertical.location), 'label': u"Test Subsection 0 / Test Unit 0" }, { 'url': u"/container/{}".format(vertical.location), 'label': u"Test Unit 0 / Test Problem 0" } ]}, ], u'parameters': {}, u'active': True, } self.maxDiff = None assert actual == expected
def test_published_and_draft_contents_with_update(self): """ Create a draft and publish it then modify the draft and check that published content is not modified """ # Make problem public. resp = self.client.ajax_post( self.problem_update_url, data={'publish': 'make_public'} ) self.assertIsNotNone(self.get_item_from_modulestore(self.problem_usage_key, False)) # Now make a draft resp = self.client.ajax_post( self.problem_update_url, data={ 'id': unicode(self.problem_usage_key), 'metadata': {}, 'data': "<p>Problem content draft.</p>", 'publish': 'create_draft' } ) # Both published and draft content should be different published = self.get_item_from_modulestore(self.problem_usage_key, False) draft = self.get_item_from_modulestore(self.problem_usage_key, True) self.assertNotEqual(draft.data, published.data) # Get problem by 'xblock_handler' view_url = reverse_usage_url("xblock_view_handler", self.problem_usage_key, {"view_name": STUDENT_VIEW}) resp = self.client.get(view_url, HTTP_ACCEPT='application/json') self.assertEqual(resp.status_code, 200) # Activate the editing view view_url = reverse_usage_url("xblock_view_handler", self.problem_usage_key, {"view_name": STUDIO_VIEW}) resp = self.client.get(view_url, HTTP_ACCEPT='application/json') self.assertEqual(resp.status_code, 200) # Both published and draft content should still be different published = self.get_item_from_modulestore(self.problem_usage_key, False) draft = self.get_item_from_modulestore(self.problem_usage_key, True) self.assertNotEqual(draft.data, published.data)
def _get_container_preview(self, usage_key): """ Returns the HTML and resources required for the xblock at the specified UsageKey """ preview_url = reverse_usage_url("xblock_view_handler", usage_key, {'view_name': 'container_preview'}) resp = self.client.get(preview_url, HTTP_ACCEPT='application/json') self.assertEqual(resp.status_code, 200) resp_content = json.loads(resp.content) html = resp_content['html'] self.assertTrue(html) resources = resp_content['resources'] self.assertIsNotNone(resources) return html, resources
def i_click_on_error_dialog(step): world.click_link_by_text('Correct failed component') assert_true(world.css_html("span.inline-error").startswith("Problem i4x://MITx/999/problem")) course_key = SlashSeparatedCourseKey("MITx", "999", "Robot_Super_Course") # we don't know the actual ID of the vertical. So just check that we did go to a # vertical page in the course (there should only be one). vertical_usage_key = course_key.make_usage_key("vertical", None) vertical_url = reverse_usage_url('container_handler', vertical_usage_key) # Remove the trailing "/None" from the URL - we don't know the course ID, so we just want to # check that we visited a vertical URL. if vertical_url.endswith("/None"): vertical_url = vertical_url[:-5] assert_equal(1, world.browser.url.count(vertical_url))
def test_can_get_correct_usage_info_for_unit(self): """ When group access is set on the unit level, the usage info should return a url to the unit, not the sequential parent of the unit. """ self.course.user_partitions = [ UserPartition( id=0, name='User Partition', scheme=UserPartition.get_scheme('cohort'), description='User Partition', groups=[ Group(id=0, name="Group") ], ), ] vertical, __ = self._create_problem_with_content_group( cid=0, group_id=0, name_suffix='0' ) self.client.ajax_post( reverse_usage_url("xblock_handler", vertical.location), data={'metadata': {'group_access': {0: [0]}}} ) actual = self._get_user_partition('cohort') expected = { 'id': 0, 'name': 'User Partition', 'scheme': 'cohort', 'description': 'User Partition', 'version': UserPartition.VERSION, 'groups': [ {'id': 0, 'name': 'Group', 'version': 1, 'usage': [ { 'url': u"/container/{}".format(vertical.location), 'label': u"Test Subsection 0 / Test Unit 0" }, { 'url': u"/container/{}".format(vertical.location), 'label': u"Test Unit 0 / Test Problem 0" } ]}, ], u'parameters': {}, u'active': True, } self.maxDiff = None self.assertEqual(actual, expected)
def _refresh_children(self, lib_content_block, status_code_expected=200): """ Helper method: Uses the REST API to call the 'refresh_children' handler of a LibraryContent block """ if 'user' not in lib_content_block.runtime._services: # pylint: disable=protected-access lib_content_block.runtime._services['user'] = Mock( user_id=self.user.id) # pylint: disable=protected-access handler_url = reverse_usage_url('component_handler', lib_content_block.location, kwargs={'handler': 'refresh_children'}) response = self.client.ajax_post(handler_url) self.assertEqual(response.status_code, status_code_expected) return modulestore().get_item(lib_content_block.location)
def _create_content_experiment(self, cid=-1, name_suffix=''): """ Create content experiment. Assign Group Configuration to the experiment if cid is provided. """ vertical = ItemFactory.create( category='vertical', parent_location=self.course.location, display_name='Test Unit {}'.format(name_suffix) ) c0_url = self.course.id.make_usage_key("vertical", "split_test_cond0") c1_url = self.course.id.make_usage_key("vertical", "split_test_cond1") c2_url = self.course.id.make_usage_key("vertical", "split_test_cond2") split_test = ItemFactory.create( category='split_test', parent_location=vertical.location, user_partition_id=cid, display_name='Test Content Experiment {}'.format(name_suffix), group_id_to_child={"0": c0_url, "1": c1_url, "2": c2_url} ) ItemFactory.create( parent_location=split_test.location, category="vertical", display_name="Condition 0 vertical", location=c0_url, ) ItemFactory.create( parent_location=split_test.location, category="vertical", display_name="Condition 1 vertical", location=c1_url, ) ItemFactory.create( parent_location=split_test.location, category="vertical", display_name="Condition 2 vertical", location=c2_url, ) partitions_json = [p.to_json() for p in self.course.user_partitions] self.client.ajax_post( reverse_usage_url("xblock_handler", split_test.location), data={'metadata': {'user_partitions': partitions_json}} ) self.save_course() return (vertical, split_test)
def i_click_on_error_dialog(step): world.click_link_by_text('Correct failed component') assert_true( world.css_html("span.inline-error").startswith( "Problem i4x://MITx/999/problem")) course_key = SlashSeparatedCourseKey("MITx", "999", "Robot_Super_Course") # we don't know the actual ID of the vertical. So just check that we did go to a # vertical page in the course (there should only be one). vertical_usage_key = course_key.make_usage_key("vertical", None) vertical_url = reverse_usage_url('container_handler', vertical_usage_key) # Remove the trailing "/None" from the URL - we don't know the course ID, so we just want to # check that we visited a vertical URL. if vertical_url.endswith("/None"): vertical_url = vertical_url[:-5] assert_equal(1, world.browser.url.count(vertical_url))
def _refresh_children(self, lib_content_block, status_code_expected=200): """ Helper method: Uses the REST API to call the 'refresh_children' handler of a LibraryContent block """ if 'user' not in lib_content_block.runtime._services: # pylint: disable=protected-access lib_content_block.runtime._services['user'] = Mock(user_id=self.user.id) # pylint: disable=protected-access handler_url = reverse_usage_url( 'component_handler', lib_content_block.location, kwargs={'handler': 'refresh_children'} ) response = self.client.ajax_post(handler_url) self.assertEqual(response.status_code, status_code_expected) return modulestore().get_item(lib_content_block.location)
def xblock_studio_url(xblock, parent_xblock=None): """ Returns the Studio editing URL for the specified xblock. """ if not xblock_has_own_studio_page(xblock, parent_xblock): return None category = xblock.category if category == 'course': return reverse_course_url('course_handler', xblock.location.course_key) elif category in ('chapter', 'sequential'): return u'{url}?show={usage_key}'.format( url=reverse_course_url('course_handler', xblock.location.course_key), usage_key=urllib.quote(unicode(xblock.location))) else: return reverse_usage_url('container_handler', xblock.location)
def xblock_studio_url(xblock, parent_xblock=None): """ Returns the Studio editing URL for the specified xblock. """ if not xblock_has_own_studio_page(xblock, parent_xblock): return None category = xblock.category if category == "course": return reverse_course_url("course_handler", xblock.location.course_key) elif category in ("chapter", "sequential"): return u"{url}?show={usage_key}".format( url=reverse_course_url("course_handler", xblock.location.course_key), usage_key=urllib.quote(unicode(xblock.location)), ) else: return reverse_usage_url("container_handler", xblock.location)
def _refresh_children(self, lib_content_block, status_code_expected=200): """ Helper method: Uses the REST API to call the 'refresh_children' handler of a LibraryContent block """ if "user" not in lib_content_block.runtime._services: # pylint: disable=protected-access mocked_user_service = Mock(user_id=self.user.id) mocked_user_service.get_current_user.return_value = XBlockUser(is_current_user=True) lib_content_block.runtime._services["user"] = mocked_user_service # pylint: disable=protected-access handler_url = reverse_usage_url( "component_handler", lib_content_block.location, kwargs={"handler": "refresh_children"} ) response = self.client.ajax_post(handler_url) self.assertEqual(response.status_code, status_code_expected) return modulestore().get_item(lib_content_block.location)
def test_group_indexed_only_on_assigned_html_block(self): """ indexing course with content groups assigned to one of multiple html units """ group_access_content = {'group_access': {666: [1]}} self.client.ajax_post( reverse_usage_url("xblock_handler", self.html_unit1.location), data={'metadata': group_access_content} ) self.publish_item(self.store, self.html_unit1.location) with patch(settings.SEARCH_ENGINE + '.index') as mock_index: self.reindex_course(self.store) self.assertTrue(mock_index.called) self.assertIn(self._html_group_result(self.html_unit1, [1]), mock_index.mock_calls) self.assertIn(self._html_nogroup_result(self.html_unit2), mock_index.mock_calls) mock_index.reset_mock()
def setUp(self): super(TestEditSplitModule, self).setUp() self.course.user_partitions = [ UserPartition( 0, 'first_partition', 'First Partition', [Group("0", 'alpha'), Group("1", 'beta')] ), UserPartition( 1, 'second_partition', 'Second Partition', [Group("0", 'Group 0'), Group("1", 'Group 1'), Group("2", 'Group 2')] ) ] self.store.update_item(self.course, self.user.id) root_usage_key = self._create_vertical() resp = self.create_xblock(category='split_test', parent_usage_key=root_usage_key) self.split_test_usage_key = self.response_usage_key(resp) self.split_test_update_url = reverse_usage_url("xblock_handler", self.split_test_usage_key)
def i_click_on_error_dialog(step): world.css_click("button.action-primary") problem_string = unicode(world.scenario_dict['COURSE'].id.make_usage_key("problem", 'ignore')) problem_string = u"Problem {}".format(problem_string[:problem_string.rfind('ignore')]) assert_true( world.css_html("span.inline-error").startswith(problem_string), u"{} does not start with {}".format( world.css_html("span.inline-error"), problem_string )) # we don't know the actual ID of the vertical. So just check that we did go to a # vertical page in the course (there should only be one). vertical_usage_key = world.scenario_dict['COURSE'].id.make_usage_key("vertical", "test") vertical_url = reverse_usage_url('container_handler', vertical_usage_key) # Remove the trailing "/None" from the URL - we don't know the course ID, so we just want to # check that we visited a vertical URL. if vertical_url.endswith("/test") or vertical_url.endswith("@test"): vertical_url = vertical_url[:-5] assert_equal(1, world.browser.url.count(vertical_url))
def test_publish_states_of_nested_xblocks(self): """ Test publishing of a unit page containing a nested xblock """ resp = self.create_xblock(parent_usage_key=self.seq_usage_key, display_name='Test Unit', category='vertical') unit_usage_key = self.response_usage_key(resp) resp = self.create_xblock(parent_usage_key=unit_usage_key, category='wrapper') wrapper_usage_key = self.response_usage_key(resp) resp = self.create_xblock(parent_usage_key=wrapper_usage_key, category='html') html_usage_key = self.response_usage_key(resp) # The unit and its children should be private initially unit_update_url = reverse_usage_url('xblock_handler', unit_usage_key) unit = self.get_item_from_modulestore(unit_usage_key, True) html = self.get_item_from_modulestore(html_usage_key, True) self.assertEqual(compute_publish_state(unit), PublishState.private) self.assertEqual(compute_publish_state(html), PublishState.private) # Make the unit public and verify that the problem is also made public resp = self.client.ajax_post(unit_update_url, data={'publish': 'make_public'}) self.assertEqual(resp.status_code, 200) unit = self.get_item_from_modulestore(unit_usage_key, True) html = self.get_item_from_modulestore(html_usage_key, True) self.assertEqual(compute_publish_state(unit), PublishState.public) self.assertEqual(compute_publish_state(html), PublishState.public) # Make a draft for the unit and verify that the problem also has a draft resp = self.client.ajax_post(unit_update_url, data={ 'id': unicode(unit_usage_key), 'metadata': {}, 'publish': 'create_draft' }) self.assertEqual(resp.status_code, 200) unit = self.get_item_from_modulestore(unit_usage_key, True) html = self.get_item_from_modulestore(html_usage_key, True) self.assertEqual(compute_publish_state(unit), PublishState.draft) self.assertEqual(compute_publish_state(html), PublishState.draft)
def _verify_deprecated_info(self, course_id, advanced_modules, info, deprecated_block_types): """ Verify deprecated info. """ expected_blocks = [] for block_type in deprecated_block_types: expected_blocks.append([ reverse_usage_url('container_handler', self.vertical.location), '{} Problem'.format(block_type) ]) self.assertEqual(info['deprecated_enabled_block_types'], [ component for component in advanced_modules if component in deprecated_block_types ]) self.assertItemsEqual(info['blocks'], expected_blocks) self.assertEqual( info['advance_settings_url'], reverse_course_url('advanced_settings_handler', course_id))