Mercurial > libervia-backend
comparison src/plugins/plugin_exp_pubsub_schema.py @ 2363:41c7717b52cd
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)
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 01 Oct 2017 12:21:21 +0200 |
parents | 388226e9c3ff |
children | 2268df8c99bf |
comparison
equal
deleted
inserted
replaced
2362:3acbaf5c29f5 | 2363:41c7717b52cd |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _ | 20 from sat.core.i18n import _ |
21 from sat.core import exceptions | 21 from sat.core import exceptions |
22 from sat.core.constants import Const as C | 22 from sat.core.constants import Const as C |
23 from sat.tools import xml_tools | |
23 from twisted.words.protocols.jabber import jid | 24 from twisted.words.protocols.jabber import jid |
24 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 25 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
26 from twisted.internet import defer | |
25 from sat.core.log import getLogger | 27 from sat.core.log import getLogger |
26 log = getLogger(__name__) | 28 log = getLogger(__name__) |
27 from wokkel import disco, iwokkel | 29 from wokkel import disco, iwokkel |
28 from wokkel import data_form | 30 from wokkel import data_form |
29 from wokkel import generic | 31 from wokkel import generic |
47 class PubsubSchema(object): | 49 class PubsubSchema(object): |
48 | 50 |
49 def __init__(self, host): | 51 def __init__(self, host): |
50 log.info(_(u"PubSub Schema initialization")) | 52 log.info(_(u"PubSub Schema initialization")) |
51 self.host = host | 53 self.host = host |
54 self._p = self.host.plugins["XEP-0060"] | |
52 host.bridge.addMethod("psSchemaGet", ".plugin", | 55 host.bridge.addMethod("psSchemaGet", ".plugin", |
53 in_sign='sss', out_sign='s', | 56 in_sign='sss', out_sign='s', |
54 method=self._getSchema, | 57 method=self._getSchema, |
55 async=True | 58 async=True |
56 ) | 59 ) |
57 host.bridge.addMethod("psSchemaSet", ".plugin", | 60 host.bridge.addMethod("psSchemaSet", ".plugin", |
58 in_sign='ssss', out_sign='', | 61 in_sign='ssss', out_sign='', |
59 method=self._setSchema, | 62 method=self._setSchema, |
60 async=True | 63 async=True |
61 ) | 64 ) |
65 host.bridge.addMethod("psSchemaUIGet", ".plugin", | |
66 in_sign='sss', out_sign='s', | |
67 method=self._getUISchema, | |
68 async=True | |
69 ) | |
70 host.bridge.addMethod("psItemsFormGet", ".plugin", | |
71 in_sign='ssssiassa{ss}s', out_sign='(asa{ss})', | |
72 method=self._getDataFormItems, | |
73 async=True) | |
74 host.bridge.addMethod("psItemFormSend", ".plugin", | |
75 in_sign='ssa{sas}ssa{ss}s', out_sign='s', | |
76 method=self._sendDataFormItem, | |
77 async=True) | |
62 | 78 |
63 def getHandler(self, client): | 79 def getHandler(self, client): |
64 return SchemaHandler() | 80 return SchemaHandler() |
65 | 81 |
66 def _getSchemaBridgeCb(self, schema_elt): | 82 def _getSchemaBridgeCb(self, schema_elt): |
106 schema_elt['node'] = nodeIdentifier | 122 schema_elt['node'] = nodeIdentifier |
107 d = iq_elt.send() | 123 d = iq_elt.send() |
108 d.addCallback(self._getSchemaCb) | 124 d.addCallback(self._getSchemaCb) |
109 return d | 125 return d |
110 | 126 |
127 @defer.inlineCallbacks | |
128 def getSchemaForm(self, client, service, nodeIdentifier, schema=None, form_type='form'): | |
129 """get data form from node's schema | |
130 | |
131 @param service(None, jid.JID): PubSub service | |
132 @param nodeIdentifier(unicode): node | |
133 @param schema(domish.Element, None): node schema | |
134 if None, it will be retrieved from node (imply one additional XMPP request) | |
135 @return(data_form.Form): data form | |
136 """ | |
137 if schema is None: | |
138 log.debug(_(u"unspecified schema, we need to request it")) | |
139 schema = yield self.getSchema(client, service, nodeIdentifier) | |
140 if schema is None: | |
141 raise exceptions.DataError(_(u"no schema specified, and this node has no schema either, we can't construct the data form")) | |
142 | |
143 try: | |
144 form = data_form.Form.fromElement(schema) | |
145 except data_form.Error as e: | |
146 raise exceptions.DataError(_(u"Invalid Schema: {msg}").format( | |
147 msg = e)) | |
148 form.formType = form_type | |
149 defer.returnValue(form) | |
150 | |
151 def schema2XMLUI(self, schema_elt): | |
152 form = data_form.Form.fromElement(schema_elt) | |
153 xmlui = xml_tools.dataForm2XMLUI(form, '') | |
154 return xmlui | |
155 | |
156 def _getUISchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE): | |
157 client = self.host.getClient(profile_key) | |
158 service = None if not service else jid.JID(service) | |
159 d = self.getUISchema(client, service, nodeIdentifier) | |
160 d.addCallback(lambda xmlui: xmlui.toXml()) | |
161 return d | |
162 | |
163 def getUISchema(self, client, service, nodeIdentifier): | |
164 d = self.getSchema(client, service, nodeIdentifier) | |
165 d.addCallback(self.schema2XMLUI) | |
166 return d | |
167 | |
111 def _setSchema(self, service, nodeIdentifier, schema, profile_key=C.PROF_KEY_NONE): | 168 def _setSchema(self, service, nodeIdentifier, schema, profile_key=C.PROF_KEY_NONE): |
112 client = self.host.getClient(profile_key) | 169 client = self.host.getClient(profile_key) |
113 service = None if not service else jid.JID(service) | 170 service = None if not service else jid.JID(service) |
114 schema = generic.parseXml(schema.encode('utf-8')) | 171 schema = generic.parseXml(schema.encode('utf-8')) |
115 return self.setSchema(client, service, nodeIdentifier, schema) | 172 return self.setSchema(client, service, nodeIdentifier, schema) |
128 schema_elt['node'] = nodeIdentifier | 185 schema_elt['node'] = nodeIdentifier |
129 if schema is not None: | 186 if schema is not None: |
130 schema_elt.addChild(schema) | 187 schema_elt.addChild(schema) |
131 return iq_elt.send() | 188 return iq_elt.send() |
132 | 189 |
190 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): | |
191 client = self.host.getClient(profile_key) | |
192 service = jid.JID(service) if service else None | |
193 if schema: | |
194 schema = generic.parseXml(schema.encode('utf-8')) | |
195 else: | |
196 schema = None | |
197 max_items = None if max_items == C.NO_LIMIT else max_items | |
198 extra = self._p.parseExtra(extra_dict) | |
199 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) | |
200 d.addCallback(self._p.serItemsData) | |
201 return d | |
202 | |
203 @defer.inlineCallbacks | |
204 def getDataFormItems(self, client, form_ns, service, nodeIdentifier, schema=None, max_items=None, item_ids=None, sub_id=None, rsm_request=None, extra=None): | |
205 """Get items known as being data forms, and convert them to XMLUI | |
206 | |
207 @param form_ns (unicode, None): namespace of the form | |
208 None to accept everything, even if form has no namespace | |
209 @param schema(domish.Element, None): schema of the node if known | |
210 if None, it will be retrieved from node | |
211 other parameters as the same as for [getItems] | |
212 @return (list[unicode]): XMLUI of the forms | |
213 if an item is invalid (not corresponding to form_ns or not a data_form) | |
214 it will be skipped | |
215 """ | |
216 # we need the initial form to get options of fields when suitable | |
217 schema_form = yield self.getSchemaForm(client, service, nodeIdentifier, schema, form_type='result') | |
218 items_data = yield self._p.getItems(client, service, nodeIdentifier, max_items, item_ids, sub_id, rsm_request, extra) | |
219 items, metadata = items_data | |
220 items_xmlui = [] | |
221 for item_elt in items: | |
222 for x_elt in item_elt.elements((data_form.NS_X_DATA, u'x')): | |
223 form = data_form.Form.fromElement(x_elt) | |
224 if form_ns and form.formNamespace != form_ns: | |
225 continue | |
226 xmlui = xml_tools.dataFormResult2XMLUI(form, schema_form) | |
227 xmlui.addLabel('id') | |
228 xmlui.addText(item_elt['id'], name='_id') | |
229 items_xmlui.append(xmlui) | |
230 break | |
231 defer.returnValue((items_xmlui, metadata)) | |
232 | |
233 | |
234 def _sendDataFormItem(self, service, nodeIdentifier, values, schema=None, item_id=None, extra=None, profile_key=C.PROF_KEY_NONE): | |
235 client = self.host.getClient(profile_key) | |
236 service = None if not service else jid.JID(service) | |
237 if schema: | |
238 schema = generic.parseXml(schema.encode('utf-8')) | |
239 else: | |
240 schema = None | |
241 d = self.sendDataFormItem(client, service, nodeIdentifier, values, schema, item_id or None, extra) | |
242 d.addCallback(lambda ret: ret or u'') | |
243 return d | |
244 | |
245 @defer.inlineCallbacks | |
246 def sendDataFormItem(self, client, service, nodeIdentifier, values, schema=None, item_id=None, extra=None): | |
247 """Publish an item as a dataform when we know that there is a schema | |
248 | |
249 @param values(dict[unicode, list[unicode]]): values set for the form | |
250 @param schema(unicode, None): data schema | |
251 None to retrieve data schema from node (need to do a additional XMPP call) | |
252 Schema is need to construct data form to publish | |
253 other parameters as the same as for [self._p.sendItem] | |
254 """ | |
255 form = yield self.getSchemaForm(client, service, nodeIdentifier, schema, form_type='submit') | |
256 | |
257 for name, values_list in values.iteritems(): | |
258 try: | |
259 field = form.fields[name] | |
260 except KeyError: | |
261 log.warning(_(u"field {name} doesn't exist, ignoring it").format(name=name)) | |
262 continue | |
263 if field.fieldType == 'boolean': | |
264 values_list = [C.bool(v) for v in values_list] | |
265 elif 'jid' in field.fieldType: | |
266 values_list = [jid.JID(v) for v in values_list] | |
267 field.values = values_list | |
268 | |
269 yield self._p.sendItem(client, service, nodeIdentifier, form.toElement(), item_id, extra) | |
270 | |
133 | 271 |
134 class SchemaHandler(XMPPHandler): | 272 class SchemaHandler(XMPPHandler): |
135 implements(iwokkel.IDisco) | 273 implements(iwokkel.IDisco) |
136 | 274 |
137 def getDiscoInfo(self, requestor, service, nodeIdentifier=''): | 275 def getDiscoInfo(self, requestor, service, nodeIdentifier=''): |