diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index 89079e0371..881b887867 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -258,6 +258,8 @@ class ImportRequiredTestCases(ContentStoreTestCase): # and assert that they contain the created modules self.assertIn(self.DRAFT_HTML + ".xml", draft_dir.listdir('html')) self.assertIn(self.DRAFT_VIDEO + ".xml", draft_dir.listdir('video')) + # and assert the child of the orphaned draft wasn't exported + self.assertNotIn(self.ORPHAN_DRAFT_HTML + ".xml", draft_dir.listdir('html')) # check for grading_policy.json filesystem = OSFS(root_dir / 'test_export/policies/2012_Fall') diff --git a/cms/djangoapps/contentstore/tests/utils.py b/cms/djangoapps/contentstore/tests/utils.py index a147ad30f6..9eb26acf7d 100644 --- a/cms/djangoapps/contentstore/tests/utils.py +++ b/cms/djangoapps/contentstore/tests/utils.py @@ -134,6 +134,8 @@ class CourseTestCase(ModuleStoreTestCase): self.store.update_item(self.course, self.user.id) TEST_VERTICAL = 'vertical_test' + ORPHAN_DRAFT_VERTICAL = 'orphan_draft_vertical' + ORPHAN_DRAFT_HTML = 'orphan_draft_html' PRIVATE_VERTICAL = 'a_private_vertical' PUBLISHED_VERTICAL = 'a_published_vertical' SEQUENTIAL = 'vertical_sequential' @@ -158,6 +160,18 @@ class CourseTestCase(ModuleStoreTestCase): self.assertEqual(orphan_vertical.location.name, 'no_references') self.assertEqual(len(orphan_vertical.children), len(vertical.children)) + # create an orphan vertical and html; we already don't try to import + # the orphaned vertical, but we should make sure we don't import + # the orphaned vertical's child html, too + orphan_draft_vertical = self.store.create_item( + self.user.id, course_id, 'vertical', self.ORPHAN_DRAFT_VERTICAL + ) + orphan_draft_html = self.store.create_item( + self.user.id, course_id, 'html', self.ORPHAN_DRAFT_HTML + ) + orphan_draft_vertical.children.append(orphan_draft_html.location) + self.store.update_item(orphan_draft_vertical, self.user.id) + # create a Draft vertical vertical = self.store.get_item(course_id.make_usage_key('vertical', self.TEST_VERTICAL), depth=1) draft_vertical = self.store.convert_to_draft(vertical.location, self.user.id) diff --git a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py index f1bae5f536..3cc691153e 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py @@ -131,18 +131,21 @@ def export_to_xml(modulestore, contentstore, course_key, root_dir, course_dir): draft_module.location, revision=ModuleStoreEnum.RevisionOption.draft_preferred ) - # Don't try to export orphaned items. - if parent_loc is not None: - logging.debug('parent_loc = {0}'.format(parent_loc)) - draft_node = draft_node_constructor( - draft_module, - location=draft_module.location, - url=draft_module.location.to_deprecated_string(), - parent_location=parent_loc, - parent_url=parent_loc.to_deprecated_string(), - ) - draft_node_list.append(draft_node) + # if module has no parent, set its parent_url to `None` + parent_url = None + if parent_loc is not None: + parent_url = parent_loc.to_deprecated_string() + + draft_node = draft_node_constructor( + draft_module, + location=draft_module.location, + url=draft_module.location.to_deprecated_string(), + parent_location=parent_loc, + parent_url=parent_url, + ) + + draft_node_list.append(draft_node) for draft_node in get_draft_subtree_roots(draft_node_list): # only export the roots of the draft subtrees @@ -153,6 +156,13 @@ def export_to_xml(modulestore, contentstore, course_key, root_dir, course_dir): if not hasattr(draft_node.module, 'xml_attributes'): draft_node.module.xml_attributes = {} + # Don't try to export orphaned items + # and their descendents + if draft_node.parent_location is None: + continue + + logging.debug('parent_loc = {0}'.format(draft_node.parent_location)) + draft_node.module.xml_attributes['parent_url'] = draft_node.parent_url parent = modulestore.get_item(draft_node.parent_location) index = parent.children.index(draft_node.module.location)