diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index 7491e5ab4a..c8a21a3a86 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -1057,6 +1057,38 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): # It should now contain empty data self.assertEquals(imported_word_cloud.data, '') + def test_html_export_roundtrip(self): + """ + Test that a course which has HTML that has style formatting is preserved in export/import + """ + module_store = modulestore('direct') + content_store = contentstore() + + import_from_xml(module_store, 'common/test/data/', ['toy']) + + location = CourseDescriptor.id_to_location('edX/toy/2012_Fall') + + # Export the course + root_dir = path(mkdtemp_clean()) + export_to_xml(module_store, content_store, location, root_dir, 'test_roundtrip') + + # Reimport and get the video back + import_from_xml(module_store, root_dir) + + # get the sample HTML with styling information + html_module = module_store.get_instance( + 'edX/toy/2012_Fall', + Location(['i4x', 'edX', 'toy', 'html', 'with_styling']) + ) + self.assertIn('
', html_module.data)
+
+ # get the sample HTML with just a simple tag information
+ html_module = module_store.get_instance(
+ 'edX/toy/2012_Fall',
+ Location(['i4x', 'edX', 'toy', 'html', 'just_img'])
+ )
+ self.assertIn('
', html_module.data)
+
def test_course_handouts_rewrites(self):
module_store = modulestore('direct')
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 567f5c7eef..7a68c42ac9 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -33,11 +33,13 @@ class HtmlFields(object):
class HtmlModule(HtmlFields, XModule):
- js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'),
- resource_string(__name__, 'js/src/collapsible.coffee'),
- resource_string(__name__, 'js/src/html/display.coffee')
- ]
- }
+ js = {
+ 'coffee': [
+ resource_string(__name__, 'js/src/javascript_loader.coffee'),
+ resource_string(__name__, 'js/src/collapsible.coffee'),
+ resource_string(__name__, 'js/src/html/display.coffee')
+ ]
+ }
js_module_name = "HTMLModule"
css = {'scss': [resource_string(__name__, 'css/html/display.scss')]}
@@ -118,8 +120,10 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
# from .html
# 'filename' in html pointers is a relative path
# (not same as 'html/blah.html' when the pointer is in a directory itself)
- pointer_path = "{category}/{url_path}".format(category='html',
- url_path=name_to_pathname(location.name))
+ pointer_path = "{category}/{url_path}".format(
+ category='html',
+ url_path=name_to_pathname(location.name)
+ )
base = path(pointer_path).dirname()
# log.debug("base = {0}, base.dirname={1}, filename={2}".format(base, base.dirname(), filename))
filepath = "{base}/{name}.html".format(base=base, name=filename)
@@ -164,19 +168,16 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
# TODO (vshnayder): make export put things in the right places.
def definition_to_xml(self, resource_fs):
- '''If the contents are valid xml, write them to filename.xml. Otherwise,
- write just to filename.xml, and the html
+ ''' Write to filename.xml, and the html
string to filename.html.
'''
- try:
- return etree.fromstring(self.data)
- except etree.XMLSyntaxError:
- pass
- # Not proper format. Write html to file, return an empty tag
+ # Write html to file, return an empty tag
pathname = name_to_pathname(self.url_name)
- filepath = u'{category}/{pathname}.html'.format(category=self.category,
- pathname=pathname)
+ filepath = u'{category}/{pathname}.html'.format(
+ category=self.category,
+ pathname=pathname
+ )
resource_fs.makedir(os.path.dirname(filepath), recursive=True, allow_recreate=True)
with resource_fs.open(filepath, 'w') as filestream:
@@ -190,6 +191,7 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
elt.set("filename", relname)
return elt
+
class AboutFields(object):
display_name = String(
help="Display name for this module",
@@ -202,12 +204,14 @@ class AboutFields(object):
scope=Scope.content
)
+
class AboutModule(AboutFields, HtmlModule):
"""
Overriding defaults but otherwise treated as HtmlModule.
"""
pass
+
class AboutDescriptor(AboutFields, HtmlDescriptor):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
@@ -216,6 +220,7 @@ class AboutDescriptor(AboutFields, HtmlDescriptor):
template_dir_name = "about"
module_class = AboutModule
+
class StaticTabFields(object):
"""
The overrides for Static Tabs
@@ -241,6 +246,7 @@ class StaticTabModule(StaticTabFields, HtmlModule):
"""
pass
+
class StaticTabDescriptor(StaticTabFields, HtmlDescriptor):
"""
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
diff --git a/common/lib/xmodule/xmodule/tests/test_export.py b/common/lib/xmodule/xmodule/tests/test_export.py
index d9b80422e9..5c5d8307af 100644
--- a/common/lib/xmodule/xmodule/tests/test_export.py
+++ b/common/lib/xmodule/xmodule/tests/test_export.py
@@ -89,12 +89,6 @@ class RoundTripTestCase(unittest.TestCase):
print("Checking module equality")
for location in initial_import.modules[course_id].keys():
print("Checking", location)
- if location.category == 'html':
- print(
- "Skipping html modules--they can't import in"
- " final form without writing files..."
- )
- continue
self.assertEquals(initial_import.modules[course_id][location],
second_import.modules[course_id][location])
diff --git a/common/test/data/toy/course/2012_Fall.xml b/common/test/data/toy/course/2012_Fall.xml
index ec75ef0b9d..ce8a2399b5 100644
--- a/common/test/data/toy/course/2012_Fall.xml
+++ b/common/test/data/toy/course/2012_Fall.xml
@@ -8,6 +8,8 @@