mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-24 03:00:15 +00:00
Lots of XEP-0004 bug fixes.
Forms have default type of 'form' setFields now uses a list of tuples instead of a dictionary because ordering is important. getFields defaults to returning a list of tuples, but the use_dict parameter can change that
This commit is contained in:
parent
9724efa123
commit
de24e9ed45
2 changed files with 92 additions and 59 deletions
|
@ -23,10 +23,18 @@ class Form(ElementBase):
|
||||||
sub_interfaces = set(('title',))
|
sub_interfaces = set(('title',))
|
||||||
form_types = set(('cancel', 'form', 'result', 'submit'))
|
form_types = set(('cancel', 'form', 'result', 'submit'))
|
||||||
|
|
||||||
def addField(self, var, ftype='text-single', label='', desc='', required=False, value=None, options=None):
|
def setup(self, xml=None):
|
||||||
|
if ElementBase.setup(self, xml): #if we had to generate xml
|
||||||
|
self['type'] = 'form'
|
||||||
|
|
||||||
|
def addField(self, var='', ftype=None, label='', desc='', required=False, value=None, options=None, **kwargs):
|
||||||
|
kwtype = kwargs.get('type', None)
|
||||||
|
if kwtype is None:
|
||||||
|
kwtype = ftype
|
||||||
|
|
||||||
field = FormField(parent=self)
|
field = FormField(parent=self)
|
||||||
field['var'] = var
|
field['var'] = var
|
||||||
field['type'] = ftype
|
field['type'] = kwtype
|
||||||
field['label'] = label
|
field['label'] = label
|
||||||
field['desc'] = desc
|
field['desc'] = desc
|
||||||
field['required'] = required
|
field['required'] = required
|
||||||
|
@ -55,7 +63,10 @@ class Form(ElementBase):
|
||||||
field['var'] = var
|
field['var'] = var
|
||||||
field['value'] = values.get(var, None)
|
field['value'] = values.get(var, None)
|
||||||
|
|
||||||
def addReported(self, var, ftype='text-single', label='', desc=''):
|
def addReported(self, var, ftype=None, label='', desc='', **kwargs):
|
||||||
|
kwtype = kwargs.get('type', None)
|
||||||
|
if kwtype is None:
|
||||||
|
kwtype = ftype
|
||||||
reported = self.xml.find('{%s}reported' % self.namespace)
|
reported = self.xml.find('{%s}reported' % self.namespace)
|
||||||
if reported is None:
|
if reported is None:
|
||||||
reported = ET.Element('{%s}reported' % self.namespace)
|
reported = ET.Element('{%s}reported' % self.namespace)
|
||||||
|
@ -64,7 +75,7 @@ class Form(ElementBase):
|
||||||
reported.append(fieldXML)
|
reported.append(fieldXML)
|
||||||
field = FormField(xml=fieldXML)
|
field = FormField(xml=fieldXML)
|
||||||
field['var'] = var
|
field['var'] = var
|
||||||
field['type'] = ftype
|
field['type'] = kwtype
|
||||||
field['label'] = label
|
field['label'] = label
|
||||||
field['desc'] = desc
|
field['desc'] = desc
|
||||||
return field
|
return field
|
||||||
|
@ -92,19 +103,21 @@ class Form(ElementBase):
|
||||||
if reportedXML is not None:
|
if reportedXML is not None:
|
||||||
self.xml.remove(reportedXML)
|
self.xml.remove(reportedXML)
|
||||||
|
|
||||||
def getFields(self):
|
def getFields(self, use_dict=False):
|
||||||
fields = {}
|
fields = {} if use_dict else []
|
||||||
fieldsXML = self.xml.findall('{%s}field' % FormField.namespace)
|
fieldsXML = self.xml.findall('{%s}field' % FormField.namespace)
|
||||||
for fieldXML in fieldsXML:
|
for fieldXML in fieldsXML:
|
||||||
field = FormField(xml=fieldXML)
|
field = FormField(xml=fieldXML)
|
||||||
fields[field['var']] = field
|
if use_dict:
|
||||||
|
fields[field['var']] = field
|
||||||
|
else:
|
||||||
|
fields.append((field['var'], field))
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def getInstructions(self):
|
def getInstructions(self):
|
||||||
instructions = ''
|
instructions = ''
|
||||||
instsXML = self.xml.findall('{%s}instructions')
|
instsXML = self.xml.findall('{%s}instructions' % self.namespace)
|
||||||
for instXML in instsXML:
|
return "\n".join([instXML.text for instXML in instsXML])
|
||||||
instructions += instXML.text
|
|
||||||
|
|
||||||
def getItems(self):
|
def getItems(self):
|
||||||
items = []
|
items = []
|
||||||
|
@ -129,7 +142,7 @@ class Form(ElementBase):
|
||||||
|
|
||||||
def getValues(self):
|
def getValues(self):
|
||||||
values = {}
|
values = {}
|
||||||
fields = self.getFields()
|
fields = self.getFields(use_dict=True)
|
||||||
for var in fields:
|
for var in fields:
|
||||||
values[var] = fields[var]['value']
|
values[var] = fields[var]['value']
|
||||||
return values
|
return values
|
||||||
|
@ -140,20 +153,19 @@ class Form(ElementBase):
|
||||||
elif self['type'] == 'submit':
|
elif self['type'] == 'submit':
|
||||||
self['type'] = 'result'
|
self['type'] = 'result'
|
||||||
|
|
||||||
def setFields(self, fields):
|
def setFields(self, fields, default=None):
|
||||||
del self['fields']
|
del self['fields']
|
||||||
for var in fields:
|
for field_data in fields:
|
||||||
field = fields[var]
|
var = field_data[0]
|
||||||
|
field = field_data[1]
|
||||||
|
field['var'] = var
|
||||||
|
|
||||||
# Remap 'type' to 'ftype' to match the addField method
|
self.addField(**field)
|
||||||
ftype = field.get('type', 'text-single')
|
|
||||||
field['type'] = ftype
|
|
||||||
del field['type']
|
|
||||||
field['ftype'] = ftype
|
|
||||||
|
|
||||||
self.addField(var, **field)
|
|
||||||
|
|
||||||
def setInstructions(self, instructions):
|
def setInstructions(self, instructions):
|
||||||
|
del self['instructions']
|
||||||
|
if instructions in [None, '']:
|
||||||
|
return
|
||||||
instructions = instructions.split('\n')
|
instructions = instructions.split('\n')
|
||||||
for instruction in instructions:
|
for instruction in instructions:
|
||||||
inst = ET.Element('{%s}instructions' % self.namespace)
|
inst = ET.Element('{%s}instructions' % self.namespace)
|
||||||
|
@ -164,20 +176,14 @@ class Form(ElementBase):
|
||||||
for item in items:
|
for item in items:
|
||||||
self.addItem(item)
|
self.addItem(item)
|
||||||
|
|
||||||
def setReported(self, reported):
|
def setReported(self, reported, default=None):
|
||||||
for var in reported:
|
for var in reported:
|
||||||
field = reported[var]
|
field = reported[var]
|
||||||
|
field['var'] = var
|
||||||
# Remap 'type' to 'ftype' to match the addReported method
|
|
||||||
ftype = field.get('type', 'text-single')
|
|
||||||
field['type'] = ftype
|
|
||||||
del field['type']
|
|
||||||
field['ftype'] = ftype
|
|
||||||
|
|
||||||
self.addReported(var, **field)
|
self.addReported(var, **field)
|
||||||
|
|
||||||
def setValues(self, values):
|
def setValues(self, values):
|
||||||
fields = self.getFields()
|
fields = self.getFields(use_dict=True)
|
||||||
for field in values:
|
for field in values:
|
||||||
fields[field]['value'] = values[field]
|
fields[field]['value'] = values[field]
|
||||||
|
|
||||||
|
@ -226,7 +232,7 @@ class FormField(ElementBase):
|
||||||
optsXML = self.xml.findall('{%s}option' % self.namespace)
|
optsXML = self.xml.findall('{%s}option' % self.namespace)
|
||||||
for optXML in optsXML:
|
for optXML in optsXML:
|
||||||
opt = FieldOption(xml=optXML)
|
opt = FieldOption(xml=optXML)
|
||||||
options.append({'label': opt['label'], 'value':opt['value']})
|
options.append({'label': opt['label'], 'value':opt['value']})
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def getRequired(self):
|
def getRequired(self):
|
||||||
|
@ -277,22 +283,24 @@ class FormField(ElementBase):
|
||||||
def setValue(self, value):
|
def setValue(self, value):
|
||||||
self.delValue()
|
self.delValue()
|
||||||
valXMLName = '{%s}value' % self.namespace
|
valXMLName = '{%s}value' % self.namespace
|
||||||
|
|
||||||
if self['type'] == 'boolean':
|
if self['type'] == 'boolean':
|
||||||
if value in self.true_values:
|
if value in self.true_values:
|
||||||
valXML = ET.Element(valXMLName)
|
valXML = ET.Element(valXMLName)
|
||||||
valXML.text = 'true'
|
valXML.text = '1'
|
||||||
self.xml.append(valXML)
|
self.xml.append(valXML)
|
||||||
else:
|
else:
|
||||||
valXML = ET.Element(valXMLName)
|
valXML = ET.Element(valXMLName)
|
||||||
valXML.text = 'true'
|
valXML.text = '0'
|
||||||
self.xml.append(valXML)
|
self.xml.append(valXML)
|
||||||
if self['type'] in self.multi_value_types:
|
elif self['type'] in self.multi_value_types or self['type'] in ['', None]:
|
||||||
if self['type'] in self.multi_line_types and isinstance(value, str):
|
if self['type'] in self.multi_line_types and isinstance(value, str):
|
||||||
value = value.split('\n')
|
value = value.split('\n')
|
||||||
if not isinstance(value, list):
|
if not isinstance(value, list):
|
||||||
value = [value]
|
value = [value]
|
||||||
for val in value:
|
for val in value:
|
||||||
|
if self['type'] in ['', None] and val in self.true_values:
|
||||||
|
val = '1'
|
||||||
valXML = ET.Element(valXMLName)
|
valXML = ET.Element(valXMLName)
|
||||||
valXML.text = val
|
valXML.text = val
|
||||||
self.xml.append(valXML)
|
self.xml.append(valXML)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from sleektest import *
|
from sleektest import *
|
||||||
import sleekxmpp.plugins.alt_0004 as xep_0004
|
import sleekxmpp.plugins.xep_0004 as xep_0004
|
||||||
|
|
||||||
|
|
||||||
class TestDataForms(SleekTest):
|
class TestDataForms(SleekTest):
|
||||||
|
@ -16,19 +16,19 @@ class TestDataForms(SleekTest):
|
||||||
|
|
||||||
self.checkMessage(msg, """
|
self.checkMessage(msg, """
|
||||||
<message>
|
<message>
|
||||||
<x xmlns="jabber:x:data">
|
<x xmlns="jabber:x:data" type="form">
|
||||||
<instructions>Instructions</instructions>
|
<instructions>Instructions</instructions>
|
||||||
<instructions>Second batch</instructions>
|
<instructions>Second batch</instructions>
|
||||||
</x>
|
</x>
|
||||||
</message>
|
</message>
|
||||||
""", use_values=False)
|
""")
|
||||||
|
|
||||||
def testAddField(self):
|
def testAddField(self):
|
||||||
"""Testing adding fields to a data form."""
|
"""Testing adding fields to a data form."""
|
||||||
|
|
||||||
msg = self.Message()
|
msg = self.Message()
|
||||||
form = msg['form']
|
form = msg['form']
|
||||||
form.addField('f1',
|
form.addField(var='f1',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
label='Text',
|
label='Text',
|
||||||
desc='A text field',
|
desc='A text field',
|
||||||
|
@ -37,7 +37,7 @@ class TestDataForms(SleekTest):
|
||||||
|
|
||||||
self.checkMessage(msg, """
|
self.checkMessage(msg, """
|
||||||
<message>
|
<message>
|
||||||
<x xmlns="jabber:x:data">
|
<x xmlns="jabber:x:data" type="form">
|
||||||
<field var="f1" type="text-single" label="Text">
|
<field var="f1" type="text-single" label="Text">
|
||||||
<desc>A text field</desc>
|
<desc>A text field</desc>
|
||||||
<required />
|
<required />
|
||||||
|
@ -45,26 +45,26 @@ class TestDataForms(SleekTest):
|
||||||
</field>
|
</field>
|
||||||
</x>
|
</x>
|
||||||
</message>
|
</message>
|
||||||
""", use_values=False)
|
""")
|
||||||
|
|
||||||
form['fields'] = {'f1': {'type': 'text-single',
|
form['fields'] = [('f1', {'type': 'text-single',
|
||||||
'label': 'Username',
|
'label': 'Username',
|
||||||
'required': True},
|
'required': True}),
|
||||||
'f2': {'type': 'text-private',
|
('f2', {'type': 'text-private',
|
||||||
'label': 'Password',
|
'label': 'Password',
|
||||||
'required': True},
|
'required': True}),
|
||||||
'f3': {'type': 'text-multi',
|
('f3', {'type': 'text-multi',
|
||||||
'label': 'Message',
|
'label': 'Message',
|
||||||
'value': 'Enter message.\nA long one even.'},
|
'value': 'Enter message.\nA long one even.'}),
|
||||||
'f4': {'type': 'list-single',
|
('f4', {'type': 'list-single',
|
||||||
'label': 'Message Type',
|
'label': 'Message Type',
|
||||||
'options': [{'label': 'Cool!',
|
'options': [{'label': 'Cool!',
|
||||||
'value': 'cool'},
|
'value': 'cool'},
|
||||||
{'label': 'Urgh!',
|
{'label': 'Urgh!',
|
||||||
'value': 'urgh'}]}}
|
'value': 'urgh'}]})]
|
||||||
self.checkMessage(msg, """
|
self.checkMessage(msg, """
|
||||||
<message>
|
<message>
|
||||||
<x xmlns="jabber:x:data">
|
<x xmlns="jabber:x:data" type="form">
|
||||||
<field var="f1" type="text-single" label="Username">
|
<field var="f1" type="text-single" label="Username">
|
||||||
<required />
|
<required />
|
||||||
</field>
|
</field>
|
||||||
|
@ -85,6 +85,31 @@ class TestDataForms(SleekTest):
|
||||||
</field>
|
</field>
|
||||||
</x>
|
</x>
|
||||||
</message>
|
</message>
|
||||||
""", use_values=False)
|
""")
|
||||||
|
|
||||||
|
def testSetValues(self):
|
||||||
|
"""Testing setting form values"""
|
||||||
|
|
||||||
|
msg = self.Message()
|
||||||
|
form = msg['form']
|
||||||
|
form.setFields([
|
||||||
|
('foo', {'type': 'text-single'}),
|
||||||
|
('bar', {'type': 'list-multi'})])
|
||||||
|
|
||||||
|
form.setValues({'foo': 'Foo!',
|
||||||
|
'bar': ['a', 'b']})
|
||||||
|
|
||||||
|
self.checkMessage(msg, """
|
||||||
|
<message>
|
||||||
|
<x xmlns="jabber:x:data" type="form">
|
||||||
|
<field var="foo" type="text-single">
|
||||||
|
<value>Foo!</value>
|
||||||
|
</field>
|
||||||
|
<field var="bar" type="list-multi">
|
||||||
|
<value>a</value>
|
||||||
|
<value>b</value>
|
||||||
|
</field>
|
||||||
|
</x>
|
||||||
|
</message>""")
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestDataForms)
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestDataForms)
|
||||||
|
|
Loading…
Reference in a new issue