0b14ef82d4
Previous stanza test cases didn't have test cases for reported and item field types in forms. This fixes that issue. Modified stanzabase to use an ordered dict so that can guarentee the that 'items' in a form are added after reported. Also updated the set of interfaces that are stored in Form to be a ordered set. Used the order set implementation from: https://code.activestate.com/recipes/576694/ The OrderedSet implementation is licensed under the MIT license and is developed by the same developer of the ordereddict.
279 lines
8.9 KiB
Python
279 lines
8.9 KiB
Python
"""
|
|
SleekXMPP: The Sleek XMPP Library
|
|
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
|
This file is part of SleekXMPP.
|
|
|
|
See the file LICENSE for copying permission.
|
|
"""
|
|
|
|
import copy
|
|
import logging
|
|
|
|
from sleekxmpp.thirdparty import OrderedDict, OrderedSet
|
|
|
|
from sleekxmpp.xmlstream import ElementBase, ET
|
|
from sleekxmpp.plugins.xep_0004.stanza import FormField
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class Form(ElementBase):
|
|
namespace = 'jabber:x:data'
|
|
name = 'x'
|
|
plugin_attrib = 'form'
|
|
interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', ))
|
|
sub_interfaces = set(('title',))
|
|
form_types = set(('cancel', 'form', 'result', 'submit'))
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
title = None
|
|
if 'title' in kwargs:
|
|
title = kwargs['title']
|
|
del kwargs['title']
|
|
ElementBase.__init__(self, *args, **kwargs)
|
|
if title is not None:
|
|
self['title'] = title
|
|
|
|
def setup(self, xml=None):
|
|
if ElementBase.setup(self, xml):
|
|
# If we had to generate xml
|
|
self['type'] = 'form'
|
|
|
|
@property
|
|
def field(self):
|
|
return self.get_fields()
|
|
|
|
def set_type(self, ftype):
|
|
self._set_attr('type', ftype)
|
|
if ftype == 'submit':
|
|
fields = self.get_fields()
|
|
for var in fields:
|
|
field = fields[var]
|
|
del field['type']
|
|
del field['label']
|
|
del field['desc']
|
|
del field['required']
|
|
del field['options']
|
|
elif ftype == 'cancel':
|
|
del self['fields']
|
|
|
|
def add_field(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()
|
|
field['var'] = var
|
|
field['type'] = kwtype
|
|
field['value'] = value
|
|
if self['type'] in ('form', 'result'):
|
|
field['label'] = label
|
|
field['desc'] = desc
|
|
field['required'] = required
|
|
if options is not None:
|
|
for option in options:
|
|
field.add_option(**option)
|
|
else:
|
|
del field['type']
|
|
self.append(field)
|
|
return field
|
|
|
|
def getXML(self, type='submit'):
|
|
self['type'] = type
|
|
log.warning("Form.getXML() is deprecated API compatibility " + \
|
|
"with plugins/old_0004.py")
|
|
return self.xml
|
|
|
|
def fromXML(self, xml):
|
|
log.warning("Form.fromXML() is deprecated API compatibility " + \
|
|
"with plugins/old_0004.py")
|
|
n = Form(xml=xml)
|
|
return n
|
|
|
|
def add_item(self, values):
|
|
itemXML = ET.Element('{%s}item' % self.namespace)
|
|
self.xml.append(itemXML)
|
|
reported_vars = self['reported'].keys()
|
|
for var in reported_vars:
|
|
field = FormField()
|
|
field._type = self['reported'][var]['type']
|
|
field['var'] = var
|
|
field['value'] = values.get(var, None)
|
|
itemXML.append(field.xml)
|
|
|
|
def add_reported(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)
|
|
if reported is None:
|
|
reported = ET.Element('{%s}reported' % self.namespace)
|
|
self.xml.append(reported)
|
|
fieldXML = ET.Element('{%s}field' % FormField.namespace)
|
|
reported.append(fieldXML)
|
|
field = FormField(xml=fieldXML)
|
|
field['var'] = var
|
|
field['type'] = kwtype
|
|
field['label'] = label
|
|
field['desc'] = desc
|
|
return field
|
|
|
|
def cancel(self):
|
|
self['type'] = 'cancel'
|
|
|
|
def del_fields(self):
|
|
fieldsXML = self.xml.findall('{%s}field' % FormField.namespace)
|
|
for fieldXML in fieldsXML:
|
|
self.xml.remove(fieldXML)
|
|
|
|
def del_instructions(self):
|
|
instsXML = self.xml.findall('{%s}instructions')
|
|
for instXML in instsXML:
|
|
self.xml.remove(instXML)
|
|
|
|
def del_items(self):
|
|
itemsXML = self.xml.find('{%s}item' % self.namespace)
|
|
for itemXML in itemsXML:
|
|
self.xml.remove(itemXML)
|
|
|
|
def del_reported(self):
|
|
reportedXML = self.xml.find('{%s}reported' % self.namespace)
|
|
if reportedXML is not None:
|
|
self.xml.remove(reportedXML)
|
|
|
|
def get_fields(self, use_dict=False):
|
|
fields = OrderedDict()
|
|
for stanza in self['substanzas']:
|
|
if isinstance(stanza, FormField):
|
|
fields[stanza['var']] = stanza
|
|
return fields
|
|
|
|
def get_instructions(self):
|
|
instsXML = self.xml.findall('{%s}instructions' % self.namespace)
|
|
return "\n".join([instXML.text for instXML in instsXML])
|
|
|
|
def get_items(self):
|
|
items = []
|
|
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
|
for itemXML in itemsXML:
|
|
item = OrderedDict()
|
|
fieldsXML = itemXML.findall('{%s}field' % FormField.namespace)
|
|
for fieldXML in fieldsXML:
|
|
field = FormField(xml=fieldXML)
|
|
item[field['var']] = field['value']
|
|
items.append(item)
|
|
return items
|
|
|
|
def get_reported(self):
|
|
fields = OrderedDict()
|
|
xml = self.xml.findall('{%s}reported/{%s}field' % (self.namespace,
|
|
FormField.namespace))
|
|
for field in xml:
|
|
field = FormField(xml=field)
|
|
fields[field['var']] = field
|
|
return fields
|
|
|
|
def get_values(self):
|
|
values = OrderedDict()
|
|
fields = self.get_fields()
|
|
for var in fields:
|
|
values[var] = fields[var]['value']
|
|
return values
|
|
|
|
def reply(self):
|
|
if self['type'] == 'form':
|
|
self['type'] = 'submit'
|
|
elif self['type'] == 'submit':
|
|
self['type'] = 'result'
|
|
|
|
def set_fields(self, fields):
|
|
del self['fields']
|
|
if not isinstance(fields, list):
|
|
fields = fields.items()
|
|
for var, field in fields:
|
|
field['var'] = var
|
|
self.add_field(
|
|
var = field.get('var'),
|
|
label = field.get('label'),
|
|
desc = field.get('desc'),
|
|
required = field.get('required'),
|
|
value = field.get('value'),
|
|
options = field.get('options'),
|
|
type = field.get('type'))
|
|
|
|
def set_instructions(self, instructions):
|
|
del self['instructions']
|
|
if instructions in [None, '']:
|
|
return
|
|
if not isinstance(instructions, list):
|
|
instructions = instructions.split('\n')
|
|
for instruction in instructions:
|
|
inst = ET.Element('{%s}instructions' % self.namespace)
|
|
inst.text = instruction
|
|
self.xml.append(inst)
|
|
|
|
def set_items(self, items):
|
|
for item in items:
|
|
self.add_item(item)
|
|
|
|
def set_reported(self, reported):
|
|
"""
|
|
This either needs a dictionary or dictionaries or a dictionary of form fields.
|
|
:param reported:
|
|
:return:
|
|
"""
|
|
for var in reported:
|
|
field = reported[var]
|
|
|
|
if isinstance(field, dict):
|
|
self.add_reported(**field)
|
|
else:
|
|
reported = self.xml.find('{%s}reported' % self.namespace)
|
|
if reported is None:
|
|
reported = ET.Element('{%s}reported' % self.namespace)
|
|
self.xml.append(reported)
|
|
|
|
fieldXML = ET.Element('{%s}field' % FormField.namespace)
|
|
reported.append(fieldXML)
|
|
new_field = FormField(xml=fieldXML)
|
|
new_field.values = field.values
|
|
|
|
def set_values(self, values):
|
|
fields = self.get_fields()
|
|
for field in values:
|
|
if field not in self.get_fields():
|
|
fields[field] = self.add_field(var=field)
|
|
self.get_fields()[field]['value'] = values[field]
|
|
|
|
def merge(self, other):
|
|
new = copy.copy(self)
|
|
if type(other) == dict:
|
|
new['values'] = other
|
|
return new
|
|
nfields = new['fields']
|
|
ofields = other['fields']
|
|
nfields.update(ofields)
|
|
new['fields'] = nfields
|
|
return new
|
|
|
|
|
|
Form.setType = Form.set_type
|
|
Form.addField = Form.add_field
|
|
Form.addItem = Form.add_item
|
|
Form.addReported = Form.add_reported
|
|
Form.delFields = Form.del_fields
|
|
Form.delInstructions = Form.del_instructions
|
|
Form.delItems = Form.del_items
|
|
Form.delReported = Form.del_reported
|
|
Form.getFields = Form.get_fields
|
|
Form.getInstructions = Form.get_instructions
|
|
Form.getItems = Form.get_items
|
|
Form.getReported = Form.get_reported
|
|
Form.getValues = Form.get_values
|
|
Form.setFields = Form.set_fields
|
|
Form.setInstructions = Form.set_instructions
|
|
Form.setItems = Form.set_items
|
|
Form.setReported = Form.set_reported
|
|
Form.setValues = Form.set_values
|