plugin PubSub Schema: schema helper methods:
3 new methods are introduced by this patch: - psSchemaUIGet to get XMLUI from node schema - psItemsFormGet to get items as XMLUI when we know they are data forms - psItemFormSend to set item from values when we know it's a node with schema. For this method, schema can be specified, and if it is not it will be retrieved from node (which imply an additional XMPP request)
This commit is contained in:
parent
04d851c5c5
commit
499f2525cc
1 changed files with 138 additions and 0 deletions
|
|
@ -20,8 +20,10 @@
|
|||
from sat.core.i18n import _
|
||||
from sat.core import exceptions
|
||||
from sat.core.constants import Const as C
|
||||
from sat.tools import xml_tools
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from twisted.words.protocols.jabber.xmlstream import XMPPHandler
|
||||
from twisted.internet import defer
|
||||
from sat.core.log import getLogger
|
||||
log = getLogger(__name__)
|
||||
from wokkel import disco, iwokkel
|
||||
|
|
@ -49,6 +51,7 @@ class PubsubSchema(object):
|
|||
def __init__(self, host):
|
||||
log.info(_(u"PubSub Schema initialization"))
|
||||
self.host = host
|
||||
self._p = self.host.plugins["XEP-0060"]
|
||||
host.bridge.addMethod("psSchemaGet", ".plugin",
|
||||
in_sign='sss', out_sign='s',
|
||||
method=self._getSchema,
|
||||
|
|
@ -59,6 +62,19 @@ class PubsubSchema(object):
|
|||
method=self._setSchema,
|
||||
async=True
|
||||
)
|
||||
host.bridge.addMethod("psSchemaUIGet", ".plugin",
|
||||
in_sign='sss', out_sign='s',
|
||||
method=self._getUISchema,
|
||||
async=True
|
||||
)
|
||||
host.bridge.addMethod("psItemsFormGet", ".plugin",
|
||||
in_sign='ssssiassa{ss}s', out_sign='(asa{ss})',
|
||||
method=self._getDataFormItems,
|
||||
async=True)
|
||||
host.bridge.addMethod("psItemFormSend", ".plugin",
|
||||
in_sign='ssa{sas}ssa{ss}s', out_sign='s',
|
||||
method=self._sendDataFormItem,
|
||||
async=True)
|
||||
|
||||
def getHandler(self, client):
|
||||
return SchemaHandler()
|
||||
|
|
@ -108,6 +124,47 @@ class PubsubSchema(object):
|
|||
d.addCallback(self._getSchemaCb)
|
||||
return d
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def getSchemaForm(self, client, service, nodeIdentifier, schema=None, form_type='form'):
|
||||
"""get data form from node's schema
|
||||
|
||||
@param service(None, jid.JID): PubSub service
|
||||
@param nodeIdentifier(unicode): node
|
||||
@param schema(domish.Element, None): node schema
|
||||
if None, it will be retrieved from node (imply one additional XMPP request)
|
||||
@return(data_form.Form): data form
|
||||
"""
|
||||
if schema is None:
|
||||
log.debug(_(u"unspecified schema, we need to request it"))
|
||||
schema = yield self.getSchema(client, service, nodeIdentifier)
|
||||
if schema is None:
|
||||
raise exceptions.DataError(_(u"no schema specified, and this node has no schema either, we can't construct the data form"))
|
||||
|
||||
try:
|
||||
form = data_form.Form.fromElement(schema)
|
||||
except data_form.Error as e:
|
||||
raise exceptions.DataError(_(u"Invalid Schema: {msg}").format(
|
||||
msg = e))
|
||||
form.formType = form_type
|
||||
defer.returnValue(form)
|
||||
|
||||
def schema2XMLUI(self, schema_elt):
|
||||
form = data_form.Form.fromElement(schema_elt)
|
||||
xmlui = xml_tools.dataForm2XMLUI(form, '')
|
||||
return xmlui
|
||||
|
||||
def _getUISchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE):
|
||||
client = self.host.getClient(profile_key)
|
||||
service = None if not service else jid.JID(service)
|
||||
d = self.getUISchema(client, service, nodeIdentifier)
|
||||
d.addCallback(lambda xmlui: xmlui.toXml())
|
||||
return d
|
||||
|
||||
def getUISchema(self, client, service, nodeIdentifier):
|
||||
d = self.getSchema(client, service, nodeIdentifier)
|
||||
d.addCallback(self.schema2XMLUI)
|
||||
return d
|
||||
|
||||
def _setSchema(self, service, nodeIdentifier, schema, profile_key=C.PROF_KEY_NONE):
|
||||
client = self.host.getClient(profile_key)
|
||||
service = None if not service else jid.JID(service)
|
||||
|
|
@ -130,6 +187,87 @@ class PubsubSchema(object):
|
|||
schema_elt.addChild(schema)
|
||||
return iq_elt.send()
|
||||
|
||||
def _getDataFormItems(self, form_ns='', service='', node='', schema='', max_items=10, item_ids=None, sub_id=None, extra_dict=None, profile_key=C.PROF_KEY_NONE):
|
||||
client = self.host.getClient(profile_key)
|
||||
service = jid.JID(service) if service else None
|
||||
if schema:
|
||||
schema = generic.parseXml(schema.encode('utf-8'))
|
||||
else:
|
||||
schema = None
|
||||
max_items = None if max_items == C.NO_LIMIT else max_items
|
||||
extra = self._p.parseExtra(extra_dict)
|
||||
d = self.getDataFormItems(client, form_ns or None, service, node or None, schema, max_items or None, item_ids, sub_id or None, extra.rsm_request, extra.extra)
|
||||
d.addCallback(self._p.serItemsData)
|
||||
return d
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def getDataFormItems(self, client, form_ns, service, nodeIdentifier, schema=None, max_items=None, item_ids=None, sub_id=None, rsm_request=None, extra=None):
|
||||
"""Get items known as being data forms, and convert them to XMLUI
|
||||
|
||||
@param form_ns (unicode, None): namespace of the form
|
||||
None to accept everything, even if form has no namespace
|
||||
@param schema(domish.Element, None): schema of the node if known
|
||||
if None, it will be retrieved from node
|
||||
other parameters as the same as for [getItems]
|
||||
@return (list[unicode]): XMLUI of the forms
|
||||
if an item is invalid (not corresponding to form_ns or not a data_form)
|
||||
it will be skipped
|
||||
"""
|
||||
# we need the initial form to get options of fields when suitable
|
||||
schema_form = yield self.getSchemaForm(client, service, nodeIdentifier, schema, form_type='result')
|
||||
items_data = yield self._p.getItems(client, service, nodeIdentifier, max_items, item_ids, sub_id, rsm_request, extra)
|
||||
items, metadata = items_data
|
||||
items_xmlui = []
|
||||
for item_elt in items:
|
||||
for x_elt in item_elt.elements((data_form.NS_X_DATA, u'x')):
|
||||
form = data_form.Form.fromElement(x_elt)
|
||||
if form_ns and form.formNamespace != form_ns:
|
||||
continue
|
||||
xmlui = xml_tools.dataFormResult2XMLUI(form, schema_form)
|
||||
xmlui.addLabel('id')
|
||||
xmlui.addText(item_elt['id'], name='_id')
|
||||
items_xmlui.append(xmlui)
|
||||
break
|
||||
defer.returnValue((items_xmlui, metadata))
|
||||
|
||||
|
||||
def _sendDataFormItem(self, service, nodeIdentifier, values, schema=None, item_id=None, extra=None, profile_key=C.PROF_KEY_NONE):
|
||||
client = self.host.getClient(profile_key)
|
||||
service = None if not service else jid.JID(service)
|
||||
if schema:
|
||||
schema = generic.parseXml(schema.encode('utf-8'))
|
||||
else:
|
||||
schema = None
|
||||
d = self.sendDataFormItem(client, service, nodeIdentifier, values, schema, item_id or None, extra)
|
||||
d.addCallback(lambda ret: ret or u'')
|
||||
return d
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def sendDataFormItem(self, client, service, nodeIdentifier, values, schema=None, item_id=None, extra=None):
|
||||
"""Publish an item as a dataform when we know that there is a schema
|
||||
|
||||
@param values(dict[unicode, list[unicode]]): values set for the form
|
||||
@param schema(unicode, None): data schema
|
||||
None to retrieve data schema from node (need to do a additional XMPP call)
|
||||
Schema is need to construct data form to publish
|
||||
other parameters as the same as for [self._p.sendItem]
|
||||
"""
|
||||
form = yield self.getSchemaForm(client, service, nodeIdentifier, schema, form_type='submit')
|
||||
|
||||
for name, values_list in values.iteritems():
|
||||
try:
|
||||
field = form.fields[name]
|
||||
except KeyError:
|
||||
log.warning(_(u"field {name} doesn't exist, ignoring it").format(name=name))
|
||||
continue
|
||||
if field.fieldType == 'boolean':
|
||||
values_list = [C.bool(v) for v in values_list]
|
||||
elif 'jid' in field.fieldType:
|
||||
values_list = [jid.JID(v) for v in values_list]
|
||||
field.values = values_list
|
||||
|
||||
yield self._p.sendItem(client, service, nodeIdentifier, form.toElement(), item_id, extra)
|
||||
|
||||
|
||||
class SchemaHandler(XMPPHandler):
|
||||
implements(iwokkel.IDisco)
|
||||
|
|
|
|||
Loading…
Reference in a new issue