Commit 8f743424 by chrisndodge

Merge pull request #387 from edx/fix/cdodge/unescape-quote-strings

[STUD-406] Fix/cdodge/unescape quote strings
parents 5a5b3cfe ac4e20b4
...@@ -137,7 +137,6 @@ class EditableMetadataFieldsTest(unittest.TestCase): ...@@ -137,7 +137,6 @@ class EditableMetadataFieldsTest(unittest.TestCase):
type='Float', options={'min': 0, 'step': .3} type='Float', options={'min': 0, 'step': .3}
) )
# Start of helper methods # Start of helper methods
def get_xml_editable_fields(self, model_data): def get_xml_editable_fields(self, model_data):
system = get_test_system() system = get_test_system()
...@@ -179,19 +178,19 @@ class TestSerialize(unittest.TestCase): ...@@ -179,19 +178,19 @@ class TestSerialize(unittest.TestCase):
def test_serialize(self): def test_serialize(self):
assert_equals('null', serialize_field(None)) assert_equals('null', serialize_field(None))
assert_equals('-2', serialize_field(-2)) assert_equals('-2', serialize_field(-2))
assert_equals('"2"', serialize_field('2')) assert_equals('2', serialize_field('2'))
assert_equals('-3.41', serialize_field(-3.41)) assert_equals('-3.41', serialize_field(-3.41))
assert_equals('"2.589"', serialize_field('2.589')) assert_equals('2.589', serialize_field('2.589'))
assert_equals('false', serialize_field(False)) assert_equals('false', serialize_field(False))
assert_equals('"false"', serialize_field('false')) assert_equals('false', serialize_field('false'))
assert_equals('"fAlse"', serialize_field('fAlse')) assert_equals('fAlse', serialize_field('fAlse'))
assert_equals('"hat box"', serialize_field('hat box')) assert_equals('hat box', serialize_field('hat box'))
assert_equals('{"bar": "hat", "frog": "green"}', serialize_field({'bar': 'hat', 'frog' : 'green'})) assert_equals('{"bar": "hat", "frog": "green"}', serialize_field({'bar': 'hat', 'frog': 'green'}))
assert_equals('[3.5, 5.6]', serialize_field([3.5, 5.6])) assert_equals('[3.5, 5.6]', serialize_field([3.5, 5.6]))
assert_equals('["foo", "bar"]', serialize_field(['foo', 'bar'])) assert_equals('["foo", "bar"]', serialize_field(['foo', 'bar']))
assert_equals('"2012-12-31T23:59:59Z"', serialize_field("2012-12-31T23:59:59Z")) assert_equals('2012-12-31T23:59:59Z', serialize_field("2012-12-31T23:59:59Z"))
assert_equals('"1 day 12 hours 59 minutes 59 seconds"', assert_equals('1 day 12 hours 59 minutes 59 seconds',
serialize_field("1 day 12 hours 59 minutes 59 seconds")) serialize_field("1 day 12 hours 59 minutes 59 seconds"))
class TestDeserialize(unittest.TestCase): class TestDeserialize(unittest.TestCase):
...@@ -201,7 +200,6 @@ class TestDeserialize(unittest.TestCase): ...@@ -201,7 +200,6 @@ class TestDeserialize(unittest.TestCase):
""" """
assert_equals(expected, deserialize_field(self.test_field(), arg)) assert_equals(expected, deserialize_field(self.test_field(), arg))
def assertDeserializeNonString(self): def assertDeserializeNonString(self):
""" """
Asserts input value is returned for None or something that is not a string. Asserts input value is returned for None or something that is not a string.
......
...@@ -81,10 +81,14 @@ class AttrMap(_AttrMapBase): ...@@ -81,10 +81,14 @@ class AttrMap(_AttrMapBase):
def serialize_field(value): def serialize_field(value):
""" """
Return a string version of the value (where value is the JSON-formatted, internally stored value). Return a string version of the value (where value is the JSON-formatted, internally stored value).
If the value is a string, then we simply return what was passed in.
Otherwise, we return json.dumps on the input value.
"""
if isinstance(value, basestring):
return value
By default, this is the result of calling json.dumps on the input value.
"""
return json.dumps(value, cls=EdxJSONEncoder) return json.dumps(value, cls=EdxJSONEncoder)
...@@ -126,7 +130,7 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -126,7 +130,7 @@ class XmlDescriptor(XModuleDescriptor):
""" """
xml_attributes = Dict(help="Map of unhandled xml attributes, used only for storage between import and export", xml_attributes = Dict(help="Map of unhandled xml attributes, used only for storage between import and export",
default={}, scope=Scope.settings) default={}, scope=Scope.settings)
# Extension to append to filename paths # Extension to append to filename paths
filename_extension = 'xml' filename_extension = 'xml'
...@@ -141,23 +145,23 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -141,23 +145,23 @@ class XmlDescriptor(XModuleDescriptor):
# understand? And if we do, is this the place? # understand? And if we do, is this the place?
# Related: What's the right behavior for clean_metadata? # Related: What's the right behavior for clean_metadata?
metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize', metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize',
'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc', 'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc',
'ispublic', # if True, then course is listed for all users; see 'ispublic', # if True, then course is listed for all users; see
'xqa_key', # for xqaa server access 'xqa_key', # for xqaa server access
'giturl', # url of git server for origin of file 'giturl', # url of git server for origin of file
# information about testcenter exams is a dict (of dicts), not a string, # information about testcenter exams is a dict (of dicts), not a string,
# so it cannot be easily exportable as a course element's attribute. # so it cannot be easily exportable as a course element's attribute.
'testcenter_info', 'testcenter_info',
# VS[compat] Remove once unused. # VS[compat] Remove once unused.
'name', 'slug') 'name', 'slug')
metadata_to_strip = ('data_dir', metadata_to_strip = ('data_dir',
'tabs', 'grading_policy', 'published_by', 'published_date', 'tabs', 'grading_policy', 'published_by', 'published_date',
'discussion_blackouts', 'testcenter_info', 'discussion_blackouts', 'testcenter_info',
# VS[compat] -- remove the below attrs once everything is in the CMS # VS[compat] -- remove the below attrs once everything is in the CMS
'course', 'org', 'url_name', 'filename', 'course', 'org', 'url_name', 'filename',
# Used for storing xml attributes between import and export, for roundtrips # Used for storing xml attributes between import and export, for roundtrips
'xml_attributes') 'xml_attributes')
metadata_to_export_to_policy = ('discussion_topics') metadata_to_export_to_policy = ('discussion_topics')
...@@ -166,7 +170,7 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -166,7 +170,7 @@ class XmlDescriptor(XModuleDescriptor):
for field in set(cls.fields + cls.lms.fields): for field in set(cls.fields + cls.lms.fields):
if field.name == attr: if field.name == attr:
from_xml = lambda val: deserialize_field(field, val) from_xml = lambda val: deserialize_field(field, val)
to_xml = lambda val : serialize_field(val) to_xml = lambda val: serialize_field(val)
return AttrMap(from_xml, to_xml) return AttrMap(from_xml, to_xml)
return AttrMap() return AttrMap()
...@@ -254,7 +258,7 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -254,7 +258,7 @@ class XmlDescriptor(XModuleDescriptor):
definition, children = cls.definition_from_xml(definition_xml, system) definition, children = cls.definition_from_xml(definition_xml, system)
if definition_metadata: if definition_metadata:
definition['definition_metadata'] = definition_metadata definition['definition_metadata'] = definition_metadata
definition['filename'] = [ filepath, filename ] definition['filename'] = [filepath, filename]
return definition, children return definition, children
...@@ -280,7 +284,6 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -280,7 +284,6 @@ class XmlDescriptor(XModuleDescriptor):
metadata[attr] = attr_map.from_xml(val) metadata[attr] = attr_map.from_xml(val)
return metadata return metadata
@classmethod @classmethod
def apply_policy(cls, metadata, policy): def apply_policy(cls, metadata, policy):
""" """
...@@ -374,7 +377,6 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -374,7 +377,6 @@ class XmlDescriptor(XModuleDescriptor):
""" """
return True return True
def export_to_xml(self, resource_fs): def export_to_xml(self, resource_fs):
""" """
Returns an xml string representing this module, and all modules Returns an xml string representing this module, and all modules
......
<course name="A Simple Course" org="edX" course="simple" graceperiod="1 day 5 hours 59 minutes 59 seconds" slug="2012_Fall"> <course name="A Simple Course" org="edX" course="simple" graceperiod="1 day 5 hours 59 minutes 59 seconds" slug="2012_Fall">
<chapter name="Overview"> <chapter name="Overview">
<video name="Welcome" youtube_id_0_75="&quot;izygArpw-Qo&quot;" youtube_id_1_0="&quot;p2Q6BrNhdh8&quot;" youtube_id_1_25="&quot;1EeWXzPdhSA&quot;" youtube_id_1_5="&quot;rABDYkeK0x8&quot;"/> <video name="Welcome" youtube_id_0_75="izygArpw-Qo" youtube_id_1_0="p2Q6BrNhdh8" youtube_id_1_25="1EeWXzPdhSA" youtube_id_1_5="rABDYkeK0x8"/>
<videosequence format="Lecture Sequence" name="A simple sequence"> <videosequence format="Lecture Sequence" name="A simple sequence">
<html name="toylab" filename="toylab"/> <html name="toylab" filename="toylab"/>
<video name="S0V1: Video Resources" youtube_id_0_75="&quot;EuzkdzfR0i8&quot;" youtube_id_1_0="&quot;1bK-WdDi6Qw&quot;" youtube_id_1_25="&quot;0v1VzoDVUTM&quot;" youtube_id_1_5="&quot;Bxk_-ZJb240&quot;"/> <video name="S0V1: Video Resources" youtube_id_0_75="EuzkdzfR0i8" youtube_id_1_0="1bK-WdDi6Qw" youtube_id_1_25="0v1VzoDVUTM" youtube_id_1_5="Bxk_-ZJb240"/>
</videosequence> </videosequence>
<section name="Lecture 2"> <section name="Lecture 2">
<sequential> <sequential>
<video youtube_id_1_0="&quot;TBvX7HzxexQ&quot;"/> <video youtube_id_1_0="TBvX7HzxexQ"/>
<problem name="L1 Problem 1" points="1" type="lecture" showanswer="attempted" filename="L1_Problem_1" rerandomize="never"/> <problem name="L1 Problem 1" points="1" type="lecture" showanswer="attempted" filename="L1_Problem_1" rerandomize="never"/>
</sequential> </sequential>
</section> </section>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<problem type="lecture" showanswer="attempted" rerandomize="true" display_name="A simple coding problem" name="Simple coding problem" filename="ps01-simple" url_name="ps01-simple"/> <problem type="lecture" showanswer="attempted" rerandomize="true" display_name="A simple coding problem" name="Simple coding problem" filename="ps01-simple" url_name="ps01-simple"/>
</sequential> </sequential>
</section> </section>
<video name="Lost Video" youtube_id_1_0="&quot;TBvX7HzxexQ&quot;"/> <video name="Lost Video" youtube_id_1_0="TBvX7HzxexQ"/>
<sequential format="Lecture Sequence" url_name='test_sequence'> <sequential format="Lecture Sequence" url_name='test_sequence'>
<vertical url_name='test_vertical'> <vertical url_name='test_vertical'>
<html url_name='test_html'> <html url_name='test_html'>
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<chapter url_name="Overview"> <chapter url_name="Overview">
<videosequence url_name="Toy_Videos"> <videosequence url_name="Toy_Videos">
<html url_name="toylab"/> <html url_name="toylab"/>
<video url_name="Video_Resources" youtube_id_1_0="&quot;1bK-WdDi6Qw&quot;"/> <video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw"/>
</videosequence> </videosequence>
<video url_name="Welcome" youtube_id_1_0="&quot;p2Q6BrNhdh8&quot;"/> <video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8"/>
</chapter> </chapter>
<chapter url_name="Ch2"> <chapter url_name="Ch2">
<html url_name="test_html"> <html url_name="test_html">
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<chapter url_name="Overview"> <chapter url_name="Overview">
<videosequence url_name="Toy_Videos"> <videosequence url_name="Toy_Videos">
<html url_name="toylab"/> <html url_name="toylab"/>
<video url_name="Video_Resources" youtube_id_1_0="&quot;1bK-WdDi6Qw&quot;"/> <video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw"/>
</videosequence> </videosequence>
<video url_name="Welcome" youtube_id_1_0="&quot;p2Q6BrNhdh8&quot;"/> <video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8"/>
</chapter> </chapter>
<chapter url_name="Ch2"> <chapter url_name="Ch2">
<html url_name="test_html"> <html url_name="test_html">
......
<chapter> <chapter>
<video url_name="toyvideo" youtube_id_1_0="&quot;OEoXaMPEzfM&quot;"/> <video url_name="toyvideo" youtube_id_1_0="OEoXaMPEzfM"/>
</chapter> </chapter>
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
<chapter url_name="Overview"> <chapter url_name="Overview">
<videosequence url_name="Toy_Videos"> <videosequence url_name="Toy_Videos">
<html url_name="secret:toylab"/> <html url_name="secret:toylab"/>
<video url_name="Video_Resources" youtube_id_1_0="&quot;1bK-WdDi6Qw&quot;"/> <video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw"/>
</videosequence> </videosequence>
<video url_name="Welcome" youtube_id_1_0="&quot;p2Q6BrNhdh8&quot;"/> <video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8"/>
<video url_name="video_123456789012" youtube_id_1_0="&quot;p2Q6BrNhdh8&quot;"/> <video url_name="video_123456789012" youtube_id_1_0="p2Q6BrNhdh8"/>
<video url_name="video_4f66f493ac8f" youtube_id_1_0="&quot;p2Q6BrNhdh8&quot;"/> <video url_name="video_4f66f493ac8f" youtube_id_1_0="p2Q6BrNhdh8"/>
</chapter> </chapter>
<chapter url_name="secret:magic"/> <chapter url_name="secret:magic"/>
<chapter url_name="poll_test"/> <chapter url_name="poll_test"/>
......
<video youtube_id_1_0="&quot;1bK-WdDi6Qw&quot;" display_name="Video Resources"/> <video youtube_id_1_0="1bK-WdDi6Qw" display_name="Video Resources"/>
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