Mercurial > libervia-backend
comparison sat/plugins/plugin_exp_pubsub_schema.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 3e4e78de9cca |
children | 3480d4fdf83a |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
25 from sat.tools.common import date_utils | 25 from sat.tools.common import date_utils |
26 from twisted.words.protocols.jabber import jid | 26 from twisted.words.protocols.jabber import jid |
27 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 27 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
28 from twisted.internet import defer | 28 from twisted.internet import defer |
29 from sat.core.log import getLogger | 29 from sat.core.log import getLogger |
30 | |
30 log = getLogger(__name__) | 31 log = getLogger(__name__) |
31 from wokkel import disco, iwokkel | 32 from wokkel import disco, iwokkel |
32 from wokkel import data_form | 33 from wokkel import data_form |
33 from wokkel import generic | 34 from wokkel import generic |
34 from zope.interface import implements | 35 from zope.interface import implements |
35 from collections import Iterable | 36 from collections import Iterable |
36 import copy | 37 import copy |
37 import itertools | 38 import itertools |
38 | 39 |
39 NS_SCHEMA = 'https://salut-a-toi/protocol/schema:0' | 40 NS_SCHEMA = "https://salut-a-toi/protocol/schema:0" |
40 | 41 |
41 PLUGIN_INFO = { | 42 PLUGIN_INFO = { |
42 C.PI_NAME: "PubSub Schema", | 43 C.PI_NAME: "PubSub Schema", |
43 C.PI_IMPORT_NAME: "PUBSUB_SCHEMA", | 44 C.PI_IMPORT_NAME: "PUBSUB_SCHEMA", |
44 C.PI_TYPE: "EXP", | 45 C.PI_TYPE: "EXP", |
45 C.PI_PROTOCOLS: [], | 46 C.PI_PROTOCOLS: [], |
46 C.PI_DEPENDENCIES: ["XEP-0060", "IDENTITY"], | 47 C.PI_DEPENDENCIES: ["XEP-0060", "IDENTITY"], |
47 C.PI_MAIN: "PubsubSchema", | 48 C.PI_MAIN: "PubsubSchema", |
48 C.PI_HANDLER: "yes", | 49 C.PI_HANDLER: "yes", |
49 C.PI_DESCRIPTION: _("""Handle Pubsub data schemas""") | 50 C.PI_DESCRIPTION: _("""Handle Pubsub data schemas"""), |
50 } | 51 } |
51 | 52 |
52 | 53 |
53 class PubsubSchema(object): | 54 class PubsubSchema(object): |
54 | |
55 def __init__(self, host): | 55 def __init__(self, host): |
56 log.info(_(u"PubSub Schema initialization")) | 56 log.info(_(u"PubSub Schema initialization")) |
57 self.host = host | 57 self.host = host |
58 self._p = self.host.plugins["XEP-0060"] | 58 self._p = self.host.plugins["XEP-0060"] |
59 self._i = self.host.plugins["IDENTITY"] | 59 self._i = self.host.plugins["IDENTITY"] |
60 host.bridge.addMethod("psSchemaGet", ".plugin", | 60 host.bridge.addMethod( |
61 in_sign='sss', out_sign='s', | 61 "psSchemaGet", |
62 method=self._getSchema, | 62 ".plugin", |
63 async=True | 63 in_sign="sss", |
64 ) | 64 out_sign="s", |
65 host.bridge.addMethod("psSchemaSet", ".plugin", | 65 method=self._getSchema, |
66 in_sign='ssss', out_sign='', | 66 async=True, |
67 method=self._setSchema, | 67 ) |
68 async=True | 68 host.bridge.addMethod( |
69 ) | 69 "psSchemaSet", |
70 host.bridge.addMethod("psSchemaUIGet", ".plugin", | 70 ".plugin", |
71 in_sign='sss', out_sign='s', | 71 in_sign="ssss", |
72 method=utils.partial(self._getUISchema, default_node=None), | 72 out_sign="", |
73 async=True | 73 method=self._setSchema, |
74 ) | 74 async=True, |
75 host.bridge.addMethod("psItemsFormGet", ".plugin", | 75 ) |
76 in_sign='ssssiassa{ss}s', out_sign='(asa{ss})', | 76 host.bridge.addMethod( |
77 method=self._getDataFormItems, | 77 "psSchemaUIGet", |
78 async=True) | 78 ".plugin", |
79 host.bridge.addMethod("psItemFormSend", ".plugin", | 79 in_sign="sss", |
80 in_sign='ssa{sas}ssa{ss}s', out_sign='s', | 80 out_sign="s", |
81 method=self._sendDataFormItem, | 81 method=utils.partial(self._getUISchema, default_node=None), |
82 async=True) | 82 async=True, |
83 ) | |
84 host.bridge.addMethod( | |
85 "psItemsFormGet", | |
86 ".plugin", | |
87 in_sign="ssssiassa{ss}s", | |
88 out_sign="(asa{ss})", | |
89 method=self._getDataFormItems, | |
90 async=True, | |
91 ) | |
92 host.bridge.addMethod( | |
93 "psItemFormSend", | |
94 ".plugin", | |
95 in_sign="ssa{sas}ssa{ss}s", | |
96 out_sign="s", | |
97 method=self._sendDataFormItem, | |
98 async=True, | |
99 ) | |
83 | 100 |
84 def getHandler(self, client): | 101 def getHandler(self, client): |
85 return SchemaHandler() | 102 return SchemaHandler() |
86 | 103 |
87 def _getSchemaBridgeCb(self, schema_elt): | 104 def _getSchemaBridgeCb(self, schema_elt): |
88 if schema_elt is None: | 105 if schema_elt is None: |
89 return u'' | 106 return u"" |
90 return schema_elt.toXml() | 107 return schema_elt.toXml() |
91 | 108 |
92 def _getSchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE): | 109 def _getSchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE): |
93 client = self.host.getClient(profile_key) | 110 client = self.host.getClient(profile_key) |
94 service = None if not service else jid.JID(service) | 111 service = None if not service else jid.JID(service) |
96 d.addCallback(self._getSchemaBridgeCb) | 113 d.addCallback(self._getSchemaBridgeCb) |
97 return d | 114 return d |
98 | 115 |
99 def _getSchemaCb(self, iq_elt): | 116 def _getSchemaCb(self, iq_elt): |
100 try: | 117 try: |
101 schema_elt = next(iq_elt.elements(NS_SCHEMA, 'schema')) | 118 schema_elt = next(iq_elt.elements(NS_SCHEMA, "schema")) |
102 except StopIteration: | 119 except StopIteration: |
103 raise exceptions.DataError('missing <schema> element') | 120 raise exceptions.DataError("missing <schema> element") |
104 try: | 121 try: |
105 x_elt = next(schema_elt.elements((data_form.NS_X_DATA, 'x'))) | 122 x_elt = next(schema_elt.elements((data_form.NS_X_DATA, "x"))) |
106 except StopIteration: | 123 except StopIteration: |
107 # there is not schema on this node | 124 # there is not schema on this node |
108 return None | 125 return None |
109 return x_elt | 126 return x_elt |
110 | 127 |
115 None to use our PEP | 132 None to use our PEP |
116 @param nodeIdentifier(unicode): node to get schema from | 133 @param nodeIdentifier(unicode): node to get schema from |
117 @return (domish.Element, None): schema (<x> element) | 134 @return (domish.Element, None): schema (<x> element) |
118 None if not schema has been set on this node | 135 None if not schema has been set on this node |
119 """ | 136 """ |
120 iq_elt = client.IQ(u'get') | 137 iq_elt = client.IQ(u"get") |
121 if service is not None: | 138 if service is not None: |
122 iq_elt['to'] = service.full() | 139 iq_elt["to"] = service.full() |
123 pubsub_elt = iq_elt.addElement((NS_SCHEMA, 'pubsub')) | 140 pubsub_elt = iq_elt.addElement((NS_SCHEMA, "pubsub")) |
124 schema_elt = pubsub_elt.addElement((NS_SCHEMA, 'schema')) | 141 schema_elt = pubsub_elt.addElement((NS_SCHEMA, "schema")) |
125 schema_elt['node'] = nodeIdentifier | 142 schema_elt["node"] = nodeIdentifier |
126 d = iq_elt.send() | 143 d = iq_elt.send() |
127 d.addCallback(self._getSchemaCb) | 144 d.addCallback(self._getSchemaCb) |
128 return d | 145 return d |
129 | 146 |
130 @defer.inlineCallbacks | 147 @defer.inlineCallbacks |
131 def getSchemaForm(self, client, service, nodeIdentifier, schema=None, form_type='form', copy_form=True): | 148 def getSchemaForm( |
149 self, | |
150 client, | |
151 service, | |
152 nodeIdentifier, | |
153 schema=None, | |
154 form_type="form", | |
155 copy_form=True, | |
156 ): | |
132 """get data form from node's schema | 157 """get data form from node's schema |
133 | 158 |
134 @param service(None, jid.JID): PubSub service | 159 @param service(None, jid.JID): PubSub service |
135 @param nodeIdentifier(unicode): node | 160 @param nodeIdentifier(unicode): node |
136 @param schema(domish.Element, data_form.Form, None): node schema | 161 @param schema(domish.Element, data_form.Form, None): node schema |
145 """ | 170 """ |
146 if schema is None: | 171 if schema is None: |
147 log.debug(_(u"unspecified schema, we need to request it")) | 172 log.debug(_(u"unspecified schema, we need to request it")) |
148 schema = yield self.getSchema(client, service, nodeIdentifier) | 173 schema = yield self.getSchema(client, service, nodeIdentifier) |
149 if schema is None: | 174 if schema is None: |
150 raise exceptions.DataError(_(u"no schema specified, and this node has no schema either, we can't construct the data form")) | 175 raise exceptions.DataError( |
176 _( | |
177 u"no schema specified, and this node has no schema either, we can't construct the data form" | |
178 ) | |
179 ) | |
151 elif isinstance(schema, data_form.Form): | 180 elif isinstance(schema, data_form.Form): |
152 if copy_form: | 181 if copy_form: |
153 schema = copy.deepcopy(schema) | 182 schema = copy.deepcopy(schema) |
154 defer.returnValue(schema) | 183 defer.returnValue(schema) |
155 | 184 |
156 try: | 185 try: |
157 form = data_form.Form.fromElement(schema) | 186 form = data_form.Form.fromElement(schema) |
158 except data_form.Error as e: | 187 except data_form.Error as e: |
159 raise exceptions.DataError(_(u"Invalid Schema: {msg}").format( | 188 raise exceptions.DataError(_(u"Invalid Schema: {msg}").format(msg=e)) |
160 msg = e)) | |
161 form.formType = form_type | 189 form.formType = form_type |
162 defer.returnValue(form) | 190 defer.returnValue(form) |
163 | 191 |
164 def schema2XMLUI(self, schema_elt): | 192 def schema2XMLUI(self, schema_elt): |
165 form = data_form.Form.fromElement(schema_elt) | 193 form = data_form.Form.fromElement(schema_elt) |
166 xmlui = xml_tools.dataForm2XMLUI(form, '') | 194 xmlui = xml_tools.dataForm2XMLUI(form, "") |
167 return xmlui | 195 return xmlui |
168 | 196 |
169 def _getUISchema(self, service, nodeIdentifier, default_node=None, profile_key=C.PROF_KEY_NONE): | 197 def _getUISchema( |
198 self, service, nodeIdentifier, default_node=None, profile_key=C.PROF_KEY_NONE | |
199 ): | |
170 if not nodeIdentifier: | 200 if not nodeIdentifier: |
171 if not default_node: | 201 if not default_node: |
172 raise ValueError(_(u"nodeIndentifier needs to be set")) | 202 raise ValueError(_(u"nodeIndentifier needs to be set")) |
173 nodeIdentifier = default_node | 203 nodeIdentifier = default_node |
174 client = self.host.getClient(profile_key) | 204 client = self.host.getClient(profile_key) |
183 return d | 213 return d |
184 | 214 |
185 def _setSchema(self, service, nodeIdentifier, schema, profile_key=C.PROF_KEY_NONE): | 215 def _setSchema(self, service, nodeIdentifier, schema, profile_key=C.PROF_KEY_NONE): |
186 client = self.host.getClient(profile_key) | 216 client = self.host.getClient(profile_key) |
187 service = None if not service else jid.JID(service) | 217 service = None if not service else jid.JID(service) |
188 schema = generic.parseXml(schema.encode('utf-8')) | 218 schema = generic.parseXml(schema.encode("utf-8")) |
189 return self.setSchema(client, service, nodeIdentifier, schema) | 219 return self.setSchema(client, service, nodeIdentifier, schema) |
190 | 220 |
191 def setSchema(self, client, service, nodeIdentifier, schema): | 221 def setSchema(self, client, service, nodeIdentifier, schema): |
192 """set or replace PubSub node schema | 222 """set or replace PubSub node schema |
193 | 223 |
194 @param schema(domish.Element, None): schema to set | 224 @param schema(domish.Element, None): schema to set |
195 None if schema need to be removed | 225 None if schema need to be removed |
196 """ | 226 """ |
197 iq_elt = client.IQ() | 227 iq_elt = client.IQ() |
198 if service is not None: | 228 if service is not None: |
199 iq_elt['to'] = service.full() | 229 iq_elt["to"] = service.full() |
200 pubsub_elt = iq_elt.addElement((NS_SCHEMA, 'pubsub')) | 230 pubsub_elt = iq_elt.addElement((NS_SCHEMA, "pubsub")) |
201 schema_elt = pubsub_elt.addElement((NS_SCHEMA, 'schema')) | 231 schema_elt = pubsub_elt.addElement((NS_SCHEMA, "schema")) |
202 schema_elt['node'] = nodeIdentifier | 232 schema_elt["node"] = nodeIdentifier |
203 if schema is not None: | 233 if schema is not None: |
204 schema_elt.addChild(schema) | 234 schema_elt.addChild(schema) |
205 return iq_elt.send() | 235 return iq_elt.send() |
206 | 236 |
207 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): | 237 def _getDataFormItems( |
238 self, | |
239 form_ns="", | |
240 service="", | |
241 node="", | |
242 schema="", | |
243 max_items=10, | |
244 item_ids=None, | |
245 sub_id=None, | |
246 extra_dict=None, | |
247 profile_key=C.PROF_KEY_NONE, | |
248 ): | |
208 client = self.host.getClient(profile_key) | 249 client = self.host.getClient(profile_key) |
209 service = jid.JID(service) if service else None | 250 service = jid.JID(service) if service else None |
210 if not node: | 251 if not node: |
211 raise exceptions.DataError(_(u'empty node is not allowed')) | 252 raise exceptions.DataError(_(u"empty node is not allowed")) |
212 if schema: | 253 if schema: |
213 schema = generic.parseXml(schema.encode('utf-8')) | 254 schema = generic.parseXml(schema.encode("utf-8")) |
214 else: | 255 else: |
215 schema = None | 256 schema = None |
216 max_items = None if max_items == C.NO_LIMIT else max_items | 257 max_items = None if max_items == C.NO_LIMIT else max_items |
217 extra = self._p.parseExtra(extra_dict) | 258 extra = self._p.parseExtra(extra_dict) |
218 d = self.getDataFormItems(client, service, node, schema, max_items or None, item_ids, sub_id or None, extra.rsm_request, extra.extra, form_ns=form_ns or None) | 259 d = self.getDataFormItems( |
260 client, | |
261 service, | |
262 node, | |
263 schema, | |
264 max_items or None, | |
265 item_ids, | |
266 sub_id or None, | |
267 extra.rsm_request, | |
268 extra.extra, | |
269 form_ns=form_ns or None, | |
270 ) | |
219 d.addCallback(self._p.serItemsData) | 271 d.addCallback(self._p.serItemsData) |
220 return d | 272 return d |
221 | 273 |
222 @defer.inlineCallbacks | 274 @defer.inlineCallbacks |
223 def getDataFormItems(self, client, service, nodeIdentifier, schema=None, max_items=None, item_ids=None, sub_id=None, rsm_request=None, extra=None, default_node=None, form_ns=None, filters=None): | 275 def getDataFormItems( |
276 self, | |
277 client, | |
278 service, | |
279 nodeIdentifier, | |
280 schema=None, | |
281 max_items=None, | |
282 item_ids=None, | |
283 sub_id=None, | |
284 rsm_request=None, | |
285 extra=None, | |
286 default_node=None, | |
287 form_ns=None, | |
288 filters=None, | |
289 ): | |
224 """Get items known as being data forms, and convert them to XMLUI | 290 """Get items known as being data forms, and convert them to XMLUI |
225 | 291 |
226 @param schema(domish.Element, data_form.Form, None): schema of the node if known | 292 @param schema(domish.Element, data_form.Form, None): schema of the node if known |
227 if None, it will be retrieved from node | 293 if None, it will be retrieved from node |
228 @param default_node(unicode): node to use if nodeIdentifier is None or empty | 294 @param default_node(unicode): node to use if nodeIdentifier is None or empty |
235 it will be skipped | 301 it will be skipped |
236 @raise ValueError: one argument is invalid | 302 @raise ValueError: one argument is invalid |
237 """ | 303 """ |
238 if not nodeIdentifier: | 304 if not nodeIdentifier: |
239 if not default_node: | 305 if not default_node: |
240 raise ValueError(_(u"default_node must be set if nodeIdentifier is not set")) | 306 raise ValueError( |
307 _(u"default_node must be set if nodeIdentifier is not set") | |
308 ) | |
241 nodeIdentifier = default_node | 309 nodeIdentifier = default_node |
242 # we need the initial form to get options of fields when suitable | 310 # we need the initial form to get options of fields when suitable |
243 schema_form = yield self.getSchemaForm(client, service, nodeIdentifier, schema, form_type='result', copy_form=False) | 311 schema_form = yield self.getSchemaForm( |
244 items_data = yield self._p.getItems(client, service, nodeIdentifier, max_items, item_ids, sub_id, rsm_request, extra) | 312 client, service, nodeIdentifier, schema, form_type="result", copy_form=False |
313 ) | |
314 items_data = yield self._p.getItems( | |
315 client, | |
316 service, | |
317 nodeIdentifier, | |
318 max_items, | |
319 item_ids, | |
320 sub_id, | |
321 rsm_request, | |
322 extra, | |
323 ) | |
245 items, metadata = items_data | 324 items, metadata = items_data |
246 items_xmlui = [] | 325 items_xmlui = [] |
247 for item_elt in items: | 326 for item_elt in items: |
248 for x_elt in item_elt.elements((data_form.NS_X_DATA, u'x')): | 327 for x_elt in item_elt.elements((data_form.NS_X_DATA, u"x")): |
249 form = data_form.Form.fromElement(x_elt) | 328 form = data_form.Form.fromElement(x_elt) |
250 if form_ns and form.formNamespace != form_ns: | 329 if form_ns and form.formNamespace != form_ns: |
251 continue | 330 continue |
252 xmlui = xml_tools.dataFormResult2XMLUI( | 331 xmlui = xml_tools.dataFormResult2XMLUI( |
253 form, | 332 form, |
254 schema_form, | 333 schema_form, |
255 # FIXME: conflicts with schema (i.e. if "id" or "publisher" already exists) | 334 # FIXME: conflicts with schema (i.e. if "id" or "publisher" already exists) |
256 # are not checked | 335 # are not checked |
257 prepend = (('label', 'id'),('text', item_elt['id'], u'id'), | 336 prepend=( |
258 ('label', 'publisher'),('text', item_elt.getAttribute('publisher',''), u'publisher')), | 337 ("label", "id"), |
259 filters = filters, | 338 ("text", item_elt["id"], u"id"), |
260 ) | 339 ("label", "publisher"), |
340 ("text", item_elt.getAttribute("publisher", ""), u"publisher"), | |
341 ), | |
342 filters=filters, | |
343 ) | |
261 items_xmlui.append(xmlui) | 344 items_xmlui.append(xmlui) |
262 break | 345 break |
263 defer.returnValue((items_xmlui, metadata)) | 346 defer.returnValue((items_xmlui, metadata)) |
264 | 347 |
265 | 348 def _sendDataFormItem( |
266 def _sendDataFormItem(self, service, nodeIdentifier, values, schema=None, item_id=None, extra=None, profile_key=C.PROF_KEY_NONE): | 349 self, |
350 service, | |
351 nodeIdentifier, | |
352 values, | |
353 schema=None, | |
354 item_id=None, | |
355 extra=None, | |
356 profile_key=C.PROF_KEY_NONE, | |
357 ): | |
267 client = self.host.getClient(profile_key) | 358 client = self.host.getClient(profile_key) |
268 service = None if not service else jid.JID(service) | 359 service = None if not service else jid.JID(service) |
269 if schema: | 360 if schema: |
270 schema = generic.parseXml(schema.encode('utf-8')) | 361 schema = generic.parseXml(schema.encode("utf-8")) |
271 else: | 362 else: |
272 schema = None | 363 schema = None |
273 d = self.sendDataFormItem(client, service, nodeIdentifier, values, schema, item_id or None, extra, deserialise=True) | 364 d = self.sendDataFormItem( |
274 d.addCallback(lambda ret: ret or u'') | 365 client, |
366 service, | |
367 nodeIdentifier, | |
368 values, | |
369 schema, | |
370 item_id or None, | |
371 extra, | |
372 deserialise=True, | |
373 ) | |
374 d.addCallback(lambda ret: ret or u"") | |
275 return d | 375 return d |
276 | 376 |
277 @defer.inlineCallbacks | 377 @defer.inlineCallbacks |
278 def sendDataFormItem(self, client, service, nodeIdentifier, values, schema=None, item_id=None, extra=None, deserialise=False): | 378 def sendDataFormItem( |
379 self, | |
380 client, | |
381 service, | |
382 nodeIdentifier, | |
383 values, | |
384 schema=None, | |
385 item_id=None, | |
386 extra=None, | |
387 deserialise=False, | |
388 ): | |
279 """Publish an item as a dataform when we know that there is a schema | 389 """Publish an item as a dataform when we know that there is a schema |
280 | 390 |
281 @param values(dict[key(unicode), [iterable[object], object]]): values set for the form | 391 @param values(dict[key(unicode), [iterable[object], object]]): values set for the form |
282 if not iterable, will be put in a list | 392 if not iterable, will be put in a list |
283 @param schema(domish.Element, data_form.Form, None): data schema | 393 @param schema(domish.Element, data_form.Form, None): data schema |
287 This is done in this method and not directly in _sendDataFormItem because we need to know the data type | 397 This is done in this method and not directly in _sendDataFormItem because we need to know the data type |
288 which is in the form, not availablable in _sendDataFormItem | 398 which is in the form, not availablable in _sendDataFormItem |
289 other parameters as the same as for [self._p.sendItem] | 399 other parameters as the same as for [self._p.sendItem] |
290 @return (unicode): id of the created item | 400 @return (unicode): id of the created item |
291 """ | 401 """ |
292 form = yield self.getSchemaForm(client, service, nodeIdentifier, schema, form_type='submit') | 402 form = yield self.getSchemaForm( |
403 client, service, nodeIdentifier, schema, form_type="submit" | |
404 ) | |
293 | 405 |
294 for name, values_list in values.iteritems(): | 406 for name, values_list in values.iteritems(): |
295 try: | 407 try: |
296 field = form.fields[name] | 408 field = form.fields[name] |
297 except KeyError: | 409 except KeyError: |
298 log.warning(_(u"field {name} doesn't exist, ignoring it").format(name=name)) | 410 log.warning( |
411 _(u"field {name} doesn't exist, ignoring it").format(name=name) | |
412 ) | |
299 continue | 413 continue |
300 if isinstance(values_list, basestring) or not isinstance(values_list, Iterable): | 414 if isinstance(values_list, basestring) or not isinstance( |
415 values_list, Iterable | |
416 ): | |
301 values_list = [values_list] | 417 values_list = [values_list] |
302 if deserialise: | 418 if deserialise: |
303 if field.fieldType == 'boolean': | 419 if field.fieldType == "boolean": |
304 values_list = [C.bool(v) for v in values_list] | 420 values_list = [C.bool(v) for v in values_list] |
305 elif field.fieldType == 'text-multi': | 421 elif field.fieldType == "text-multi": |
306 # for text-multi, lines must be put on separate values | 422 # for text-multi, lines must be put on separate values |
307 values_list = list(itertools.chain(*[v.splitlines() for v in values_list])) | 423 values_list = list( |
308 | 424 itertools.chain(*[v.splitlines() for v in values_list]) |
309 elif 'jid' in field.fieldType: | 425 ) |
426 | |
427 elif "jid" in field.fieldType: | |
310 values_list = [jid.JID(v) for v in values_list] | 428 values_list = [jid.JID(v) for v in values_list] |
311 if 'list' in field.fieldType: | 429 if "list" in field.fieldType: |
312 # for lists, we check that given values are allowed in form | 430 # for lists, we check that given values are allowed in form |
313 allowed_values = [o.value for o in field.options] | 431 allowed_values = [o.value for o in field.options] |
314 values_list = [v for v in values_list if v in allowed_values] | 432 values_list = [v for v in values_list if v in allowed_values] |
315 if not values_list: | 433 if not values_list: |
316 # if values don't map to allowed values, we use default ones | 434 # if values don't map to allowed values, we use default ones |
317 values_list = field.values | 435 values_list = field.values |
318 field.values = values_list | 436 field.values = values_list |
319 | 437 |
320 yield self._p.sendItem(client, service, nodeIdentifier, form.toElement(), item_id, extra) | 438 yield self._p.sendItem( |
439 client, service, nodeIdentifier, form.toElement(), item_id, extra | |
440 ) | |
321 | 441 |
322 ## filters ## | 442 ## filters ## |
323 # filters useful for data form to XMLUI conversion # | 443 # filters useful for data form to XMLUI conversion # |
324 | 444 |
325 def valueOrPublisherFilter(self, form_xmlui, widget_type, args, kwargs): | 445 def valueOrPublisherFilter(self, form_xmlui, widget_type, args, kwargs): |
326 """Replace missing value by publisher's user part""" | 446 """Replace missing value by publisher's user part""" |
327 if not args[0]: | 447 if not args[0]: |
328 # value is not filled: we use user part of publisher (if we have it) | 448 # value is not filled: we use user part of publisher (if we have it) |
329 try: | 449 try: |
330 publisher = jid.JID(form_xmlui.named_widgets['publisher'].value) | 450 publisher = jid.JID(form_xmlui.named_widgets["publisher"].value) |
331 except (KeyError, RuntimeError): | 451 except (KeyError, RuntimeError): |
332 pass | 452 pass |
333 else: | 453 else: |
334 args[0] = publisher.user.capitalize() | 454 args[0] = publisher.user.capitalize() |
335 return widget_type, args, kwargs | 455 return widget_type, args, kwargs |
337 def textbox2ListFilter(self, form_xmlui, widget_type, args, kwargs): | 457 def textbox2ListFilter(self, form_xmlui, widget_type, args, kwargs): |
338 """Split lines of a textbox in a list | 458 """Split lines of a textbox in a list |
339 | 459 |
340 main use case is using a textbox for labels | 460 main use case is using a textbox for labels |
341 """ | 461 """ |
342 if widget_type != u'textbox': | 462 if widget_type != u"textbox": |
343 return widget_type, args, kwargs | 463 return widget_type, args, kwargs |
344 widget_type = u'list' | 464 widget_type = u"list" |
345 options = [o for o in args.pop(0).split(u'\n') if o] | 465 options = [o for o in args.pop(0).split(u"\n") if o] |
346 kwargs = {'options': options, | 466 kwargs = { |
347 'name': kwargs.get('name'), | 467 "options": options, |
348 'styles': (u'noselect', u'extensible', u'reducible')} | 468 "name": kwargs.get("name"), |
469 "styles": (u"noselect", u"extensible", u"reducible"), | |
470 } | |
349 return widget_type, args, kwargs | 471 return widget_type, args, kwargs |
350 | 472 |
351 def dateFilter(self, form_xmlui, widget_type, args, kwargs): | 473 def dateFilter(self, form_xmlui, widget_type, args, kwargs): |
352 """Convert a string with a date to a unix timestamp""" | 474 """Convert a string with a date to a unix timestamp""" |
353 if widget_type != u'string' or not args[0]: | 475 if widget_type != u"string" or not args[0]: |
354 return widget_type, args, kwargs | 476 return widget_type, args, kwargs |
355 # we convert XMPP date to timestamp | 477 # we convert XMPP date to timestamp |
356 try: | 478 try: |
357 args[0] = unicode(date_utils.date_parse(args[0])) | 479 args[0] = unicode(date_utils.date_parse(args[0])) |
358 except Exception as e: | 480 except Exception as e: |
375 sub_id = None | 497 sub_id = None |
376 extra = self._p.parseExtra(extra_dict) | 498 extra = self._p.parseExtra(extra_dict) |
377 | 499 |
378 return client, service, node, max_items, extra, sub_id | 500 return client, service, node, max_items, extra, sub_id |
379 | 501 |
380 def _get(self, service='', node='', max_items=10, item_ids=None, sub_id=None, extra=None, default_node=None, form_ns=None, filters=None, profile_key=C.PROF_KEY_NONE): | 502 def _get( |
503 self, | |
504 service="", | |
505 node="", | |
506 max_items=10, | |
507 item_ids=None, | |
508 sub_id=None, | |
509 extra=None, | |
510 default_node=None, | |
511 form_ns=None, | |
512 filters=None, | |
513 profile_key=C.PROF_KEY_NONE, | |
514 ): | |
381 """Bridge method to retrieve data from node with schema | 515 """Bridge method to retrieve data from node with schema |
382 | 516 |
383 this method is a helper so dependant plugins can use it directly | 517 this method is a helper so dependant plugins can use it directly |
384 when adding *Get methods | 518 when adding *Get methods |
385 extra can have the key "labels_as_list" which is a hack to convert | 519 extra can have the key "labels_as_list" which is a hack to convert |
390 filters = {} | 524 filters = {} |
391 if extra is None: | 525 if extra is None: |
392 extra = {} | 526 extra = {} |
393 # XXX: Q&D way to get list for labels when displaying them, but text when we | 527 # XXX: Q&D way to get list for labels when displaying them, but text when we |
394 # have to modify them | 528 # have to modify them |
395 if C.bool(extra.get('labels_as_list', C.BOOL_FALSE)): | 529 if C.bool(extra.get("labels_as_list", C.BOOL_FALSE)): |
396 filters = filters.copy() | 530 filters = filters.copy() |
397 filters[u'labels'] = self.textbox2ListFilter | 531 filters[u"labels"] = self.textbox2ListFilter |
398 client, service, node, max_items, extra, sub_id = self.prepareBridgeGet(service, node, max_items, sub_id, extra, profile_key) | 532 client, service, node, max_items, extra, sub_id = self.prepareBridgeGet( |
399 d = self.getDataFormItems(client, service, node or None, | 533 service, node, max_items, sub_id, extra, profile_key |
534 ) | |
535 d = self.getDataFormItems( | |
536 client, | |
537 service, | |
538 node or None, | |
400 max_items=max_items, | 539 max_items=max_items, |
401 item_ids=item_ids, | 540 item_ids=item_ids, |
402 sub_id=sub_id, | 541 sub_id=sub_id, |
403 rsm_request=extra.rsm_request, | 542 rsm_request=extra.rsm_request, |
404 extra=extra.extra, | 543 extra=extra.extra, |
405 default_node=default_node, | 544 default_node=default_node, |
406 form_ns=form_ns, | 545 form_ns=form_ns, |
407 filters=filters) | 546 filters=filters, |
547 ) | |
408 d.addCallback(self._p.serItemsData) | 548 d.addCallback(self._p.serItemsData) |
409 return d | 549 return d |
410 | 550 |
411 def prepareBridgeSet(self, service, node, schema, item_id, extra, profile_key): | 551 def prepareBridgeSet(self, service, node, schema, item_id, extra, profile_key): |
412 """Parse arguments received from bridge *Set methods and return higher level data | 552 """Parse arguments received from bridge *Set methods and return higher level data |
414 @return (tuple): (client, service, node, schema, item_id, extra) usable for internal methods | 554 @return (tuple): (client, service, node, schema, item_id, extra) usable for internal methods |
415 """ | 555 """ |
416 client = self.host.getClient(profile_key) | 556 client = self.host.getClient(profile_key) |
417 service = None if not service else jid.JID(service) | 557 service = None if not service else jid.JID(service) |
418 if schema: | 558 if schema: |
419 schema = generic.parseXml(schema.encode('utf-8')) | 559 schema = generic.parseXml(schema.encode("utf-8")) |
420 else: | 560 else: |
421 schema = None | 561 schema = None |
422 if extra and u'update' in extra: | 562 if extra and u"update" in extra: |
423 extra[u'update'] = C.bool(extra[u'update']) | 563 extra[u"update"] = C.bool(extra[u"update"]) |
424 return client, service, node or None, schema, item_id or None, extra | 564 return client, service, node or None, schema, item_id or None, extra |
425 | 565 |
426 def _set(self, service, node, values, schema=None, item_id=None, extra=None, default_node=None, form_ns=None, fill_author=True, profile_key=C.PROF_KEY_NONE): | 566 def _set( |
567 self, | |
568 service, | |
569 node, | |
570 values, | |
571 schema=None, | |
572 item_id=None, | |
573 extra=None, | |
574 default_node=None, | |
575 form_ns=None, | |
576 fill_author=True, | |
577 profile_key=C.PROF_KEY_NONE, | |
578 ): | |
427 """Bridge method to set item in node with schema | 579 """Bridge method to set item in node with schema |
428 | 580 |
429 this method is a helper so dependant plugins can use it directly | 581 this method is a helper so dependant plugins can use it directly |
430 when adding *Set methods | 582 when adding *Set methods |
431 """ | 583 """ |
432 client, service, node, schema, item_id, extra = self.prepareBridgeSet(service, node, schema, item_id, extra) | 584 client, service, node, schema, item_id, extra = self.prepareBridgeSet( |
433 d = self.set(client, service, node, values, schema, item_id, extra, | 585 service, node, schema, item_id, extra |
434 deserialise=True, | 586 ) |
435 form_ns=form_ns, | 587 d = self.set( |
436 default_node=default_node, | 588 client, |
437 fill_author=fill_author) | 589 service, |
438 d.addCallback(lambda ret: ret or u'') | 590 node, |
591 values, | |
592 schema, | |
593 item_id, | |
594 extra, | |
595 deserialise=True, | |
596 form_ns=form_ns, | |
597 default_node=default_node, | |
598 fill_author=fill_author, | |
599 ) | |
600 d.addCallback(lambda ret: ret or u"") | |
439 return d | 601 return d |
440 | 602 |
441 @defer.inlineCallbacks | 603 @defer.inlineCallbacks |
442 def set(self, client, service, node, values, schema, item_id, extra, deserialise, form_ns, default_node=None, fill_author=True): | 604 def set( |
605 self, | |
606 client, | |
607 service, | |
608 node, | |
609 values, | |
610 schema, | |
611 item_id, | |
612 extra, | |
613 deserialise, | |
614 form_ns, | |
615 default_node=None, | |
616 fill_author=True, | |
617 ): | |
443 """Set an item in a node with a schema | 618 """Set an item in a node with a schema |
444 | 619 |
445 This method can be used directly by *Set methods added by dependant plugin | 620 This method can be used directly by *Set methods added by dependant plugin |
446 @param values(dict[key(unicode), [iterable[object]|object]]): values of the items | 621 @param values(dict[key(unicode), [iterable[object]|object]]): values of the items |
447 if value is not iterable, it will be put in a list | 622 if value is not iterable, it will be put in a list |
461 if default_node is None: | 636 if default_node is None: |
462 raise ValueError(_(u"default_node must be set if node is not set")) | 637 raise ValueError(_(u"default_node must be set if node is not set")) |
463 node = default_node | 638 node = default_node |
464 now = utils.xmpp_date() | 639 now = utils.xmpp_date() |
465 if not item_id: | 640 if not item_id: |
466 values['created'] = now | 641 values["created"] = now |
467 elif extra.get(u'update', False): | 642 elif extra.get(u"update", False): |
468 if item_id is None: | 643 if item_id is None: |
469 raise exceptions.DataError(_(u'if extra["update"] is set, item_id must be set too')) | 644 raise exceptions.DataError( |
645 _(u'if extra["update"] is set, item_id must be set too') | |
646 ) | |
470 try: | 647 try: |
471 # we get previous item | 648 # we get previous item |
472 items_data = yield self._p.getItems(client, service, node, item_ids=[item_id]) | 649 items_data = yield self._p.getItems( |
650 client, service, node, item_ids=[item_id] | |
651 ) | |
473 item_elt = items_data[0][0] | 652 item_elt = items_data[0][0] |
474 except Exception as e: | 653 except Exception as e: |
475 log.warning(_(u"Can't get previous item, update ignored: {reason}").format( | 654 log.warning( |
476 reason = e)) | 655 _(u"Can't get previous item, update ignored: {reason}").format( |
656 reason=e | |
657 ) | |
658 ) | |
477 else: | 659 else: |
478 # and parse it | 660 # and parse it |
479 form = data_form.findForm(item_elt, form_ns) | 661 form = data_form.findForm(item_elt, form_ns) |
480 if form is None: | 662 if form is None: |
481 log.warning(_(u"Can't parse previous item, update ignored: data form not found").format( | 663 log.warning( |
482 reason = e)) | 664 _( |
665 u"Can't parse previous item, update ignored: data form not found" | |
666 ).format(reason=e) | |
667 ) | |
483 else: | 668 else: |
484 for name, field in form.fields.iteritems(): | 669 for name, field in form.fields.iteritems(): |
485 if name not in values: | 670 if name not in values: |
486 values[name] = u'\n'.join(unicode(v) for v in field.values) | 671 values[name] = u"\n".join(unicode(v) for v in field.values) |
487 | 672 |
488 values['updated'] = now | 673 values["updated"] = now |
489 if fill_author: | 674 if fill_author: |
490 if not values.get('author'): | 675 if not values.get("author"): |
491 identity = yield self._i.getIdentity(client, client.jid) | 676 identity = yield self._i.getIdentity(client, client.jid) |
492 values['author'] = identity['nick'] | 677 values["author"] = identity["nick"] |
493 if not values.get('author_jid'): | 678 if not values.get("author_jid"): |
494 values['author_jid'] = client.jid.full() | 679 values["author_jid"] = client.jid.full() |
495 item_id = yield self.sendDataFormItem(client, service, node, values, schema, item_id, extra, deserialise) | 680 item_id = yield self.sendDataFormItem( |
681 client, service, node, values, schema, item_id, extra, deserialise | |
682 ) | |
496 defer.returnValue(item_id) | 683 defer.returnValue(item_id) |
497 | 684 |
498 | 685 |
499 class SchemaHandler(XMPPHandler): | 686 class SchemaHandler(XMPPHandler): |
500 implements(iwokkel.IDisco) | 687 implements(iwokkel.IDisco) |
501 | 688 |
502 def getDiscoInfo(self, requestor, service, nodeIdentifier=''): | 689 def getDiscoInfo(self, requestor, service, nodeIdentifier=""): |
503 return [disco.DiscoFeature(NS_SCHEMA)] | 690 return [disco.DiscoFeature(NS_SCHEMA)] |
504 | 691 |
505 def getDiscoItems(self, requestor, service, nodeIdentifier=''): | 692 def getDiscoItems(self, requestor, service, nodeIdentifier=""): |
506 return [] | 693 return [] |