diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py index 3f9194031e..e703f74812 100644 --- a/common/lib/xmodule/xmodule/poll_module.py +++ b/common/lib/xmodule/xmodule/poll_module.py @@ -13,6 +13,7 @@ from copy import deepcopy from collections import OrderedDict from lxml import etree +from openedx.core.djangolib.markup import Text from pkg_resources import resource_string from xmodule.x_module import XModule @@ -195,9 +196,11 @@ class PollDescriptor(PollFields, MakoModuleDescriptor, XmlDescriptor): xml_object.set('display_name', self.display_name) def add_child(xml_obj, answer): + # Escape answer text before adding to xml tree. + answer_text = unicode(Text(answer['text'])) child_str = u'<{tag_name} id="{id}">{text}'.format( tag_name=self._child_tag_name, id=answer['id'], - text=answer['text']) + text=answer_text) child_node = etree.fromstring(child_str) xml_object.append(child_node) diff --git a/common/lib/xmodule/xmodule/tests/test_poll.py b/common/lib/xmodule/xmodule/tests/test_poll.py index ea9fba7948..d65caac7b2 100644 --- a/common/lib/xmodule/xmodule/tests/test_poll.py +++ b/common/lib/xmodule/xmodule/tests/test_poll.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- """Test for Poll Xmodule functional logic.""" +from mock import Mock + from xmodule.poll_module import PollDescriptor from . import LogicTest +from .test_import import DummySystem class PollModuleTest(LogicTest): @@ -30,3 +33,32 @@ class PollModuleTest(LogicTest): self.assertEqual(total, 2) self.assertDictEqual(callback, {'objectName': 'Conditional'}) self.assertEqual(self.xmodule.poll_answer, 'No') + + def test_poll_export_with_unescaped_characters_xml(self): + """ + Make sure that poll_module will export fine if its xml contains + unescaped characters. + """ + module_system = DummySystem(load_error_modules=True) + id_generator = Mock() + id_generator.target_course_id = self.xmodule.course_id + sample_poll_xml = ''' + +

How old are you?

+ 18 +
+ ''' + + output = PollDescriptor.from_xml(sample_poll_xml, module_system, id_generator) + # Update the answer with invalid character. + invalid_characters_poll_answer = output.answers[0] + # Invalid less-than character. + invalid_characters_poll_answer['text'] = '< 18' + output.answers[0] = invalid_characters_poll_answer + output.save() + + xml = output.definition_to_xml(None) + # Extract texts of all children. + child_texts = xml.xpath('//text()') + # Last index of child_texts contains text of answer tag. + self.assertEqual(child_texts[-1], '< 18')