Merge pull request #756 from edx/fix/cdodge/incorrect-html-serialization
Fix/cdodge/incorrect html serialization
This commit is contained in:
@@ -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('<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):
|
||||
module_store = modulestore('direct')
|
||||
|
||||
|
||||
@@ -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 <html filename="" [meta-attrs="..."]> to filename.xml, and the html
|
||||
''' Write <html filename="" [meta-attrs="..."]> 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
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
<html url_name="nonportable"/>
|
||||
<html url_name="nonportable_link"/>
|
||||
<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"/>
|
||||
</videosequence>
|
||||
<video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8" display_name="Welcome"/>
|
||||
|
||||
1
common/test/data/toy/html/just_img.html
Normal file
1
common/test/data/toy/html/just_img.html
Normal file
@@ -0,0 +1 @@
|
||||
<img src="/static/foo_bar.jpg" />
|
||||
1
common/test/data/toy/html/just_img.xml
Normal file
1
common/test/data/toy/html/just_img.xml
Normal file
@@ -0,0 +1 @@
|
||||
<html filename="just_img.html"/>
|
||||
1
common/test/data/toy/html/with_styling.html
Normal file
1
common/test/data/toy/html/with_styling.html
Normal file
@@ -0,0 +1 @@
|
||||
<p style="font:italic bold 72px/30px Georgia, serif; color: red; ">Red text here</p>
|
||||
1
common/test/data/toy/html/with_styling.xml
Normal file
1
common/test/data/toy/html/with_styling.xml
Normal file
@@ -0,0 +1 @@
|
||||
<html filename="with_styling.html"/>
|
||||
Reference in New Issue
Block a user