Commit 2699ba65 by chrisndodge

Merge pull request #756 from edx/fix/cdodge/incorrect-html-serialization

Fix/cdodge/incorrect html serialization
parents a7851a98 938b0946
...@@ -1057,6 +1057,38 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): ...@@ -1057,6 +1057,38 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
# It should now contain empty data # It should now contain empty data
self.assertEquals(imported_word_cloud.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('<p style="font:italic bold 72px/30px Georgia, serif; color: red; ">', html_module.data)
# get the sample HTML with just a simple <img> tag information
html_module = module_store.get_instance(
'edX/toy/2012_Fall',
Location(['i4x', 'edX', 'toy', 'html', 'just_img'])
)
self.assertIn('<img src="/static/foo_bar.jpg" />', html_module.data)
def test_course_handouts_rewrites(self): def test_course_handouts_rewrites(self):
module_store = modulestore('direct') module_store = modulestore('direct')
......
...@@ -33,11 +33,13 @@ class HtmlFields(object): ...@@ -33,11 +33,13 @@ class HtmlFields(object):
class HtmlModule(HtmlFields, XModule): class HtmlModule(HtmlFields, XModule):
js = {'coffee': [resource_string(__name__, 'js/src/javascript_loader.coffee'), js = {
resource_string(__name__, 'js/src/collapsible.coffee'), 'coffee': [
resource_string(__name__, 'js/src/html/display.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" js_module_name = "HTMLModule"
css = {'scss': [resource_string(__name__, 'css/html/display.scss')]} css = {'scss': [resource_string(__name__, 'css/html/display.scss')]}
...@@ -118,8 +120,10 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor): ...@@ -118,8 +120,10 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
# from .html # from .html
# 'filename' in html pointers is a relative path # 'filename' in html pointers is a relative path
# (not same as 'html/blah.html' when the pointer is in a directory itself) # (not same as 'html/blah.html' when the pointer is in a directory itself)
pointer_path = "{category}/{url_path}".format(category='html', pointer_path = "{category}/{url_path}".format(
url_path=name_to_pathname(location.name)) category='html',
url_path=name_to_pathname(location.name)
)
base = path(pointer_path).dirname() base = path(pointer_path).dirname()
# log.debug("base = {0}, base.dirname={1}, filename={2}".format(base, base.dirname(), filename)) # log.debug("base = {0}, base.dirname={1}, filename={2}".format(base, base.dirname(), filename))
filepath = "{base}/{name}.html".format(base=base, name=filename) filepath = "{base}/{name}.html".format(base=base, name=filename)
...@@ -164,19 +168,16 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor): ...@@ -164,19 +168,16 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
# TODO (vshnayder): make export put things in the right places. # TODO (vshnayder): make export put things in the right places.
def definition_to_xml(self, resource_fs): def definition_to_xml(self, resource_fs):
'''If the contents are valid xml, write them to filename.xml. Otherwise, ''' Write <html filename="" [meta-attrs="..."]> to filename.xml, and the html
write just <html filename="" [meta-attrs="..."]> to filename.xml, and the html
string to filename.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) pathname = name_to_pathname(self.url_name)
filepath = u'{category}/{pathname}.html'.format(category=self.category, filepath = u'{category}/{pathname}.html'.format(
pathname=pathname) category=self.category,
pathname=pathname
)
resource_fs.makedir(os.path.dirname(filepath), recursive=True, allow_recreate=True) resource_fs.makedir(os.path.dirname(filepath), recursive=True, allow_recreate=True)
with resource_fs.open(filepath, 'w') as filestream: with resource_fs.open(filepath, 'w') as filestream:
...@@ -190,6 +191,7 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor): ...@@ -190,6 +191,7 @@ class HtmlDescriptor(HtmlFields, XmlDescriptor, EditingDescriptor):
elt.set("filename", relname) elt.set("filename", relname)
return elt return elt
class AboutFields(object): class AboutFields(object):
display_name = String( display_name = String(
help="Display name for this module", help="Display name for this module",
...@@ -202,12 +204,14 @@ class AboutFields(object): ...@@ -202,12 +204,14 @@ class AboutFields(object):
scope=Scope.content scope=Scope.content
) )
class AboutModule(AboutFields, HtmlModule): class AboutModule(AboutFields, HtmlModule):
""" """
Overriding defaults but otherwise treated as HtmlModule. Overriding defaults but otherwise treated as HtmlModule.
""" """
pass pass
class AboutDescriptor(AboutFields, HtmlDescriptor): class AboutDescriptor(AboutFields, HtmlDescriptor):
""" """
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located 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): ...@@ -216,6 +220,7 @@ class AboutDescriptor(AboutFields, HtmlDescriptor):
template_dir_name = "about" template_dir_name = "about"
module_class = AboutModule module_class = AboutModule
class StaticTabFields(object): class StaticTabFields(object):
""" """
The overrides for Static Tabs The overrides for Static Tabs
...@@ -241,6 +246,7 @@ class StaticTabModule(StaticTabFields, HtmlModule): ...@@ -241,6 +246,7 @@ class StaticTabModule(StaticTabFields, HtmlModule):
""" """
pass pass
class StaticTabDescriptor(StaticTabFields, HtmlDescriptor): class StaticTabDescriptor(StaticTabFields, HtmlDescriptor):
""" """
These pieces of course content are treated as HtmlModules but we need to overload where the templates are located These pieces of course content are treated as HtmlModules but we need to overload where the templates are located
......
...@@ -89,12 +89,6 @@ class RoundTripTestCase(unittest.TestCase): ...@@ -89,12 +89,6 @@ class RoundTripTestCase(unittest.TestCase):
print("Checking module equality") print("Checking module equality")
for location in initial_import.modules[course_id].keys(): for location in initial_import.modules[course_id].keys():
print("Checking", location) 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], self.assertEquals(initial_import.modules[course_id][location],
second_import.modules[course_id][location]) second_import.modules[course_id][location])
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
<html url_name="nonportable"/> <html url_name="nonportable"/>
<html url_name="nonportable_link"/> <html url_name="nonportable_link"/>
<html url_name="badlink"/> <html url_name="badlink"/>
<html url_name="with_styling"/>
<html url_name="just_img"/>
<video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw" display_name="Video Resources"/> <video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw" display_name="Video Resources"/>
</videosequence> </videosequence>
<video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8" display_name="Welcome"/> <video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8" display_name="Welcome"/>
......
<img src="/static/foo_bar.jpg" />
\ No newline at end of file
<html filename="just_img.html"/>
\ No newline at end of file
<p style="font:italic bold 72px/30px Georgia, serif; color: red; ">Red text here</p>
\ No newline at end of file
<html filename="with_styling.html"/>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment