From 25d6de243e36618e29e8359610a9349d68aa8d99 Mon Sep 17 00:00:00 2001 From: Chris Dodge Date: Fri, 9 Aug 2013 00:09:37 -0400 Subject: [PATCH] add portable link rewriting on clone. Added tests. --- .../contentstore/tests/test_contentstore.py | 51 +++++++++++++++++++ .../xmodule/modulestore/store_utilities.py | 12 +++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index f6dd5a24b7..e33fb27cde 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -644,6 +644,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): content_store = contentstore() + # now do the actual cloning clone_course(module_store, content_store, source_location, dest_location) # first assert that all draft content got cloned as well @@ -693,6 +694,56 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): expected_children.append(child_loc.url()) self.assertEqual(expected_children, lookup_item.children) + def test_portable_link_rewrites_during_clone_course(self): + course_data = { + 'org': 'MITx', + 'number': '999', + 'display_name': 'Robot Super Course', + 'run': '2013_Spring' + } + + module_store = modulestore('direct') + draft_store = modulestore('draft') + content_store = contentstore() + + import_from_xml(module_store, 'common/test/data/', ['toy']) + + source_course_id = 'edX/toy/2012_Fall' + dest_course_id = 'MITx/999/2013_Spring' + source_location = CourseDescriptor.id_to_location(source_course_id) + dest_location = CourseDescriptor.id_to_location(dest_course_id) + + # let's force a non-portable link in the clone source + # as a final check, make sure that any non-portable links are rewritten during cloning + html_module_location = Location([ + source_location.tag, source_location.org, source_location.course, 'html', 'nonportable']) + html_module = module_store.get_instance(source_location.course_id, html_module_location) + + self.assertTrue(isinstance(html_module.data, basestring)) + new_data = html_module.data.replace('/static/', '/c4x/{0}/{1}/asset/'.format( + source_location.org, source_location.course)) + module_store.update_item(html_module_location, new_data) + + html_module = module_store.get_instance(source_location.course_id, html_module_location) + self.assertEqual(new_data, html_module.data) + + # create the destination course + + resp = self.client.post(reverse('create_new_course'), course_data) + self.assertEqual(resp.status_code, 200) + data = parse_json(resp) + self.assertEqual(data['id'], 'i4x://MITx/999/course/2013_Spring') + + # do the actual cloning + clone_course(module_store, content_store, source_location, dest_location) + + # make sure that any non-portable links are rewritten during cloning + html_module_location = Location([ + dest_location.tag, dest_location.org, dest_location.course, 'html', 'nonportable']) + html_module = module_store.get_instance(dest_location.course_id, html_module_location) + + self.assertIn('/static/foo.jpg', html_module.data) + def test_illegal_draft_crud_ops(self): draft_store = modulestore('draft') direct_store = modulestore('direct') diff --git a/common/lib/xmodule/xmodule/modulestore/store_utilities.py b/common/lib/xmodule/xmodule/modulestore/store_utilities.py index bd871ad9d0..fd07d3f774 100644 --- a/common/lib/xmodule/xmodule/modulestore/store_utilities.py +++ b/common/lib/xmodule/xmodule/modulestore/store_utilities.py @@ -29,7 +29,7 @@ def convert_to_portable_links(source_course_id, text): return text -def _clone_modules(modulestore, modules, dest_location): +def _clone_modules(modulestore, modules, source_location, dest_location): for module in modules: original_loc = Location(module.location) @@ -44,7 +44,11 @@ def _clone_modules(modulestore, modules, dest_location): print "Cloning module {0} to {1}....".format(original_loc, module.location) # NOTE: usage of the the internal module.xblock_kvs._data does not include any 'default' values for the fields - modulestore.update_item(module.location, module.xblock_kvs._data) + data = module.xblock_kvs._data + if isinstance(data, basestring): + data = convert_to_portable_links(source_location.course_id, data) + + modulestore.update_item(module.location, data) # repoint children if module.has_children: @@ -96,10 +100,10 @@ def clone_course(modulestore, contentstore, source_location, dest_location, dele # Get all modules under this namespace which is (tag, org, course) tuple modules = modulestore.get_items([source_location.tag, source_location.org, source_location.course, None, None, None]) - _clone_modules(modulestore, modules, dest_location) + _clone_modules(modulestore, modules, source_location, dest_location) modules = modulestore.get_items([source_location.tag, source_location.org, source_location.course, None, None, 'draft']) - _clone_modules(modulestore, modules, dest_location) + _clone_modules(modulestore, modules, source_location, dest_location) # now iterate through all of the assets and clone them # first the thumbnails