XEP-0004: fix: prevent multiple <values> for 'text-single' field
According to XEP-0004: - if there is no "type" attribute on a <field />, we should assume it is "text-single"; - "text-single" MUST NOT contain morethan one <value />. Before this patch, not specifying a field type and passing a multi-line string would result in an illegal stanza. While it would be cleaner to log a warning or even raise an exception if set_value() is called with an incompatible type, this breaks a lot of tests and backward-compatibility, so we introduce some heuristic in FormField.set_value() to infer the field type based on the provided value instead. I also changed FormField.get_value() so that it returns a list by default for 'text-multi' fields. This is a breaking change, but I have not found the justification for the previous behaviour.
This commit is contained in:
parent
100014651c
commit
8d984cd8a1
@ -1,8 +1,9 @@
|
||||
|
||||
# Slixmpp: The Slick XMPP Library
|
||||
# Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
# This file is part of Slixmpp.
|
||||
# See the file LICENSE for copying permission.
|
||||
import logging
|
||||
|
||||
from slixmpp.xmlstream import ElementBase, ET
|
||||
|
||||
|
||||
@ -78,7 +79,14 @@ class FormField(ElementBase):
|
||||
reqXML = self.xml.find('{%s}required' % self.namespace)
|
||||
return reqXML is not None
|
||||
|
||||
def get_value(self, convert=True):
|
||||
def get_value(self, convert=True, convert_list=False):
|
||||
"""
|
||||
Gets the value for this field
|
||||
|
||||
:param convert: Convert truthy values to boolean
|
||||
:param convert_list: Convert text-multi fields to a string with
|
||||
\n as separator for values
|
||||
"""
|
||||
valsXML = self.xml.findall('{%s}value' % self.namespace)
|
||||
if len(valsXML) == 0:
|
||||
return None
|
||||
@ -92,7 +100,7 @@ class FormField(ElementBase):
|
||||
if valXML.text is None:
|
||||
valXML.text = ''
|
||||
values.append(valXML.text)
|
||||
if self._type == 'text-multi' and convert:
|
||||
if self._type == 'text-multi' and convert_list:
|
||||
values = "\n".join(values)
|
||||
return values
|
||||
else:
|
||||
@ -127,6 +135,17 @@ class FormField(ElementBase):
|
||||
del self['value']
|
||||
valXMLName = '{%s}value' % self.namespace
|
||||
|
||||
if not self._type:
|
||||
if isinstance(value, bool):
|
||||
log.debug("Passed a 'boolean' as value of an untyped field, assuming it is a 'boolean'")
|
||||
self._type = "boolean"
|
||||
elif isinstance(value, str):
|
||||
log.debug("Passed a 'str' as value of an untyped field, assuming it is a 'text-single'")
|
||||
self._type = "text-single"
|
||||
elif isinstance(value, (list, tuple)):
|
||||
log.debug("Passed a %s as value of an untyped field, assuming it is a 'text-multi'")
|
||||
self._type = "text-multi"
|
||||
|
||||
if self._type == 'boolean':
|
||||
if value in self.true_values:
|
||||
valXML = ET.Element(valXMLName)
|
||||
@ -180,3 +199,6 @@ FormField.setOptions = FormField.set_options
|
||||
FormField.setRequired = FormField.set_required
|
||||
FormField.setTrue = FormField.set_true
|
||||
FormField.setValue = FormField.set_value
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -95,6 +95,21 @@ class TestDataForms(SlixTest):
|
||||
</message>
|
||||
""")
|
||||
|
||||
def testMultiLineField(self):
|
||||
msg = self.Message()
|
||||
form = msg['form']
|
||||
form.addField(var='f1',
|
||||
value='Some text\non several\n\nlines')
|
||||
self.check(msg, """
|
||||
<message>
|
||||
<x xmlns="jabber:x:data" type="form">
|
||||
<field var="f1">
|
||||
<value>Some text\non several\n\nlines</value>
|
||||
</field>
|
||||
</x>
|
||||
</message>
|
||||
""")
|
||||
|
||||
def testSetValues(self):
|
||||
"""Testing setting form values"""
|
||||
|
||||
@ -117,7 +132,7 @@ class TestDataForms(SlixTest):
|
||||
<value>b</value>
|
||||
</field>
|
||||
</x>
|
||||
</message>""")
|
||||
</message>""", use_values=False)
|
||||
|
||||
def testSubmitType(self):
|
||||
"""Test that setting type to 'submit' clears extra details"""
|
||||
|
Loading…
Reference in New Issue
Block a user