Mercurial > libervia-backend
comparison sat/plugins/plugin_exp_pubsub_schema.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 989b622faff6 |
children | fee60f17ebac |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python3 |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT plugin for Pubsub Schemas | 4 # SAT plugin for Pubsub Schemas |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
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 collections import Iterable | 20 from collections import Iterable |
21 import copy | 21 import copy |
22 import itertools | 22 import itertools |
23 from zope.interface import implements | 23 from zope.interface import implementer |
24 from twisted.words.protocols.jabber import jid | 24 from twisted.words.protocols.jabber import jid |
25 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 25 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
26 from twisted.internet import defer | 26 from twisted.internet import defer |
27 from wokkel import disco, iwokkel | 27 from wokkel import disco, iwokkel |
28 from wokkel import data_form | 28 from wokkel import data_form |
36 from sat.tools.common import data_format | 36 from sat.tools.common import data_format |
37 from sat.core.log import getLogger | 37 from sat.core.log import getLogger |
38 | 38 |
39 log = getLogger(__name__) | 39 log = getLogger(__name__) |
40 | 40 |
41 NS_SCHEMA = u"https://salut-a-toi/protocol/schema:0" | 41 NS_SCHEMA = "https://salut-a-toi/protocol/schema:0" |
42 | 42 |
43 PLUGIN_INFO = { | 43 PLUGIN_INFO = { |
44 C.PI_NAME: u"PubSub Schema", | 44 C.PI_NAME: "PubSub Schema", |
45 C.PI_IMPORT_NAME: u"PUBSUB_SCHEMA", | 45 C.PI_IMPORT_NAME: "PUBSUB_SCHEMA", |
46 C.PI_TYPE: u"EXP", | 46 C.PI_TYPE: "EXP", |
47 C.PI_PROTOCOLS: [], | 47 C.PI_PROTOCOLS: [], |
48 C.PI_DEPENDENCIES: [u"XEP-0060", u"IDENTITY"], | 48 C.PI_DEPENDENCIES: ["XEP-0060", "IDENTITY"], |
49 C.PI_MAIN: u"PubsubSchema", | 49 C.PI_MAIN: "PubsubSchema", |
50 C.PI_HANDLER: u"yes", | 50 C.PI_HANDLER: "yes", |
51 C.PI_DESCRIPTION: _(u"""Handle Pubsub data schemas"""), | 51 C.PI_DESCRIPTION: _("""Handle Pubsub data schemas"""), |
52 } | 52 } |
53 | 53 |
54 | 54 |
55 class PubsubSchema(object): | 55 class PubsubSchema(object): |
56 def __init__(self, host): | 56 def __init__(self, host): |
57 log.info(_(u"PubSub Schema initialization")) | 57 log.info(_("PubSub Schema initialization")) |
58 self.host = host | 58 self.host = host |
59 self._p = self.host.plugins["XEP-0060"] | 59 self._p = self.host.plugins["XEP-0060"] |
60 self._i = self.host.plugins["IDENTITY"] | 60 self._i = self.host.plugins["IDENTITY"] |
61 host.bridge.addMethod( | 61 host.bridge.addMethod( |
62 "psSchemaGet", | 62 "psSchemaGet", |
63 ".plugin", | 63 ".plugin", |
64 in_sign="sss", | 64 in_sign="sss", |
65 out_sign="s", | 65 out_sign="s", |
66 method=self._getSchema, | 66 method=self._getSchema, |
67 async=True, | 67 async_=True, |
68 ) | 68 ) |
69 host.bridge.addMethod( | 69 host.bridge.addMethod( |
70 "psSchemaSet", | 70 "psSchemaSet", |
71 ".plugin", | 71 ".plugin", |
72 in_sign="ssss", | 72 in_sign="ssss", |
73 out_sign="", | 73 out_sign="", |
74 method=self._setSchema, | 74 method=self._setSchema, |
75 async=True, | 75 async_=True, |
76 ) | 76 ) |
77 host.bridge.addMethod( | 77 host.bridge.addMethod( |
78 "psSchemaUIGet", | 78 "psSchemaUIGet", |
79 ".plugin", | 79 ".plugin", |
80 in_sign="sss", | 80 in_sign="sss", |
81 out_sign="s", | 81 out_sign="s", |
82 method=utils.partial(self._getUISchema, default_node=None), | 82 method=lambda service, nodeIdentifier, profile_key: self._getUISchema( |
83 async=True, | 83 service, nodeIdentifier, default_node=None, profile_key=profile_key), |
84 async_=True, | |
84 ) | 85 ) |
85 host.bridge.addMethod( | 86 host.bridge.addMethod( |
86 "psItemsFormGet", | 87 "psItemsFormGet", |
87 ".plugin", | 88 ".plugin", |
88 in_sign="ssssiassa{ss}s", | 89 in_sign="ssssiassa{ss}s", |
89 out_sign="(asa{ss})", | 90 out_sign="(asa{ss})", |
90 method=self._getDataFormItems, | 91 method=self._getDataFormItems, |
91 async=True, | 92 async_=True, |
92 ) | 93 ) |
93 host.bridge.addMethod( | 94 host.bridge.addMethod( |
94 "psItemFormSend", | 95 "psItemFormSend", |
95 ".plugin", | 96 ".plugin", |
96 in_sign="ssa{sas}ssa{ss}s", | 97 in_sign="ssa{sas}ssa{ss}s", |
97 out_sign="s", | 98 out_sign="s", |
98 method=self._sendDataFormItem, | 99 method=self._sendDataFormItem, |
99 async=True, | 100 async_=True, |
100 ) | 101 ) |
101 | 102 |
102 def getHandler(self, client): | 103 def getHandler(self, client): |
103 return SchemaHandler() | 104 return SchemaHandler() |
104 | 105 |
105 def _getSchemaBridgeCb(self, schema_elt): | 106 def _getSchemaBridgeCb(self, schema_elt): |
106 if schema_elt is None: | 107 if schema_elt is None: |
107 return u"" | 108 return "" |
108 return schema_elt.toXml() | 109 return schema_elt.toXml() |
109 | 110 |
110 def _getSchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE): | 111 def _getSchema(self, service, nodeIdentifier, profile_key=C.PROF_KEY_NONE): |
111 client = self.host.getClient(profile_key) | 112 client = self.host.getClient(profile_key) |
112 service = None if not service else jid.JID(service) | 113 service = None if not service else jid.JID(service) |
133 None to use our PEP | 134 None to use our PEP |
134 @param nodeIdentifier(unicode): node to get schema from | 135 @param nodeIdentifier(unicode): node to get schema from |
135 @return (domish.Element, None): schema (<x> element) | 136 @return (domish.Element, None): schema (<x> element) |
136 None if not schema has been set on this node | 137 None if not schema has been set on this node |
137 """ | 138 """ |
138 iq_elt = client.IQ(u"get") | 139 iq_elt = client.IQ("get") |
139 if service is not None: | 140 if service is not None: |
140 iq_elt["to"] = service.full() | 141 iq_elt["to"] = service.full() |
141 pubsub_elt = iq_elt.addElement((NS_SCHEMA, "pubsub")) | 142 pubsub_elt = iq_elt.addElement((NS_SCHEMA, "pubsub")) |
142 schema_elt = pubsub_elt.addElement((NS_SCHEMA, "schema")) | 143 schema_elt = pubsub_elt.addElement((NS_SCHEMA, "schema")) |
143 schema_elt["node"] = nodeIdentifier | 144 schema_elt["node"] = nodeIdentifier |
161 needed when the form is reused and it will be modified (e.g. in sendDataFormItem) | 162 needed when the form is reused and it will be modified (e.g. in sendDataFormItem) |
162 @return(data_form.Form): data form | 163 @return(data_form.Form): data form |
163 the form should not be modified if copy_form is not set | 164 the form should not be modified if copy_form is not set |
164 """ | 165 """ |
165 if schema is None: | 166 if schema is None: |
166 log.debug(_(u"unspecified schema, we need to request it")) | 167 log.debug(_("unspecified schema, we need to request it")) |
167 schema = yield self.getSchema(client, service, nodeIdentifier) | 168 schema = yield self.getSchema(client, service, nodeIdentifier) |
168 if schema is None: | 169 if schema is None: |
169 raise exceptions.DataError( | 170 raise exceptions.DataError( |
170 _( | 171 _( |
171 u"no schema specified, and this node has no schema either, we can't construct the data form" | 172 "no schema specified, and this node has no schema either, we can't construct the data form" |
172 ) | 173 ) |
173 ) | 174 ) |
174 elif isinstance(schema, data_form.Form): | 175 elif isinstance(schema, data_form.Form): |
175 if copy_form: | 176 if copy_form: |
176 schema = copy.deepcopy(schema) | 177 schema = copy.deepcopy(schema) |
177 defer.returnValue(schema) | 178 defer.returnValue(schema) |
178 | 179 |
179 try: | 180 try: |
180 form = data_form.Form.fromElement(schema) | 181 form = data_form.Form.fromElement(schema) |
181 except data_form.Error as e: | 182 except data_form.Error as e: |
182 raise exceptions.DataError(_(u"Invalid Schema: {msg}").format(msg=e)) | 183 raise exceptions.DataError(_("Invalid Schema: {msg}").format(msg=e)) |
183 form.formType = form_type | 184 form.formType = form_type |
184 defer.returnValue(form) | 185 defer.returnValue(form) |
185 | 186 |
186 def schema2XMLUI(self, schema_elt): | 187 def schema2XMLUI(self, schema_elt): |
187 form = data_form.Form.fromElement(schema_elt) | 188 form = data_form.Form.fromElement(schema_elt) |
190 | 191 |
191 def _getUISchema(self, service, nodeIdentifier, default_node=None, | 192 def _getUISchema(self, service, nodeIdentifier, default_node=None, |
192 profile_key=C.PROF_KEY_NONE): | 193 profile_key=C.PROF_KEY_NONE): |
193 if not nodeIdentifier: | 194 if not nodeIdentifier: |
194 if not default_node: | 195 if not default_node: |
195 raise ValueError(_(u"nodeIndentifier needs to be set")) | 196 raise ValueError(_("nodeIndentifier needs to be set")) |
196 nodeIdentifier = default_node | 197 nodeIdentifier = default_node |
197 client = self.host.getClient(profile_key) | 198 client = self.host.getClient(profile_key) |
198 service = None if not service else jid.JID(service) | 199 service = None if not service else jid.JID(service) |
199 d = self.getUISchema(client, service, nodeIdentifier) | 200 d = self.getUISchema(client, service, nodeIdentifier) |
200 d.addCallback(lambda xmlui: xmlui.toXml()) | 201 d.addCallback(lambda xmlui: xmlui.toXml()) |
231 item_ids=None, sub_id=None, extra_dict=None, | 232 item_ids=None, sub_id=None, extra_dict=None, |
232 profile_key=C.PROF_KEY_NONE): | 233 profile_key=C.PROF_KEY_NONE): |
233 client = self.host.getClient(profile_key) | 234 client = self.host.getClient(profile_key) |
234 service = jid.JID(service) if service else None | 235 service = jid.JID(service) if service else None |
235 if not node: | 236 if not node: |
236 raise exceptions.DataError(_(u"empty node is not allowed")) | 237 raise exceptions.DataError(_("empty node is not allowed")) |
237 if schema: | 238 if schema: |
238 schema = generic.parseXml(schema.encode("utf-8")) | 239 schema = generic.parseXml(schema.encode("utf-8")) |
239 else: | 240 else: |
240 schema = None | 241 schema = None |
241 max_items = None if max_items == C.NO_LIMIT else max_items | 242 max_items = None if max_items == C.NO_LIMIT else max_items |
274 @raise ValueError: one argument is invalid | 275 @raise ValueError: one argument is invalid |
275 """ | 276 """ |
276 if not nodeIdentifier: | 277 if not nodeIdentifier: |
277 if not default_node: | 278 if not default_node: |
278 raise ValueError( | 279 raise ValueError( |
279 _(u"default_node must be set if nodeIdentifier is not set") | 280 _("default_node must be set if nodeIdentifier is not set") |
280 ) | 281 ) |
281 nodeIdentifier = default_node | 282 nodeIdentifier = default_node |
282 # we need the initial form to get options of fields when suitable | 283 # we need the initial form to get options of fields when suitable |
283 schema_form = yield self.getSchemaForm( | 284 schema_form = yield self.getSchemaForm( |
284 client, service, nodeIdentifier, schema, form_type="result", copy_form=False | 285 client, service, nodeIdentifier, schema, form_type="result", copy_form=False |
294 extra, | 295 extra, |
295 ) | 296 ) |
296 items, metadata = items_data | 297 items, metadata = items_data |
297 items_xmlui = [] | 298 items_xmlui = [] |
298 for item_elt in items: | 299 for item_elt in items: |
299 for x_elt in item_elt.elements((data_form.NS_X_DATA, u"x")): | 300 for x_elt in item_elt.elements((data_form.NS_X_DATA, "x")): |
300 form = data_form.Form.fromElement(x_elt) | 301 form = data_form.Form.fromElement(x_elt) |
301 if form_ns and form.formNamespace != form_ns: | 302 if form_ns and form.formNamespace != form_ns: |
302 continue | 303 continue |
303 xmlui = xml_tools.dataFormResult2XMLUI( | 304 xmlui = xml_tools.dataFormResult2XMLUI( |
304 form, | 305 form, |
305 schema_form, | 306 schema_form, |
306 # FIXME: conflicts with schema (i.e. if "id" or "publisher" already exists) | 307 # FIXME: conflicts with schema (i.e. if "id" or "publisher" already exists) |
307 # are not checked | 308 # are not checked |
308 prepend=( | 309 prepend=( |
309 ("label", "id"), | 310 ("label", "id"), |
310 ("text", item_elt["id"], u"id"), | 311 ("text", item_elt["id"], "id"), |
311 ("label", "publisher"), | 312 ("label", "publisher"), |
312 ("text", item_elt.getAttribute("publisher", ""), u"publisher"), | 313 ("text", item_elt.getAttribute("publisher", ""), "publisher"), |
313 ), | 314 ), |
314 filters=filters, | 315 filters=filters, |
315 read_only=False, | 316 read_only=False, |
316 ) | 317 ) |
317 items_xmlui.append(xmlui) | 318 items_xmlui.append(xmlui) |
334 schema, | 335 schema, |
335 item_id or None, | 336 item_id or None, |
336 extra, | 337 extra, |
337 deserialise=True, | 338 deserialise=True, |
338 ) | 339 ) |
339 d.addCallback(lambda ret: ret or u"") | 340 d.addCallback(lambda ret: ret or "") |
340 return d | 341 return d |
341 | 342 |
342 @defer.inlineCallbacks | 343 @defer.inlineCallbacks |
343 def sendDataFormItem(self, client, service, nodeIdentifier, values, schema=None, | 344 def sendDataFormItem(self, client, service, nodeIdentifier, values, schema=None, |
344 item_id=None, extra=None, deserialise=False): | 345 item_id=None, extra=None, deserialise=False): |
359 """ | 360 """ |
360 form = yield self.getSchemaForm( | 361 form = yield self.getSchemaForm( |
361 client, service, nodeIdentifier, schema, form_type="submit" | 362 client, service, nodeIdentifier, schema, form_type="submit" |
362 ) | 363 ) |
363 | 364 |
364 for name, values_list in values.iteritems(): | 365 for name, values_list in values.items(): |
365 try: | 366 try: |
366 field = form.fields[name] | 367 field = form.fields[name] |
367 except KeyError: | 368 except KeyError: |
368 log.warning( | 369 log.warning( |
369 _(u"field {name} doesn't exist, ignoring it").format(name=name) | 370 _("field {name} doesn't exist, ignoring it").format(name=name) |
370 ) | 371 ) |
371 continue | 372 continue |
372 if isinstance(values_list, basestring) or not isinstance( | 373 if isinstance(values_list, str) or not isinstance( |
373 values_list, Iterable | 374 values_list, Iterable |
374 ): | 375 ): |
375 values_list = [values_list] | 376 values_list = [values_list] |
376 if deserialise: | 377 if deserialise: |
377 if field.fieldType == u"boolean": | 378 if field.fieldType == "boolean": |
378 values_list = [C.bool(v) for v in values_list] | 379 values_list = [C.bool(v) for v in values_list] |
379 elif field.fieldType == u"text-multi": | 380 elif field.fieldType == "text-multi": |
380 # for text-multi, lines must be put on separate values | 381 # for text-multi, lines must be put on separate values |
381 values_list = list( | 382 values_list = list( |
382 itertools.chain(*[v.splitlines() for v in values_list]) | 383 itertools.chain(*[v.splitlines() for v in values_list]) |
383 ) | 384 ) |
384 elif xml_tools.isXHTMLField(field): | 385 elif xml_tools.isXHTMLField(field): |
385 values_list = [generic.parseXml(v.encode("utf-8")) | 386 values_list = [generic.parseXml(v.encode("utf-8")) |
386 for v in values_list] | 387 for v in values_list] |
387 elif u"jid" in (field.fieldType or u""): | 388 elif "jid" in (field.fieldType or ""): |
388 values_list = [jid.JID(v) for v in values_list] | 389 values_list = [jid.JID(v) for v in values_list] |
389 if u"list" in (field.fieldType or u""): | 390 if "list" in (field.fieldType or ""): |
390 # for lists, we check that given values are allowed in form | 391 # for lists, we check that given values are allowed in form |
391 allowed_values = [o.value for o in field.options] | 392 allowed_values = [o.value for o in field.options] |
392 values_list = [v for v in values_list if v in allowed_values] | 393 values_list = [v for v in values_list if v in allowed_values] |
393 if not values_list: | 394 if not values_list: |
394 # if values don't map to allowed values, we use default ones | 395 # if values don't map to allowed values, we use default ones |
417 def textbox2ListFilter(self, form_xmlui, widget_type, args, kwargs): | 418 def textbox2ListFilter(self, form_xmlui, widget_type, args, kwargs): |
418 """Split lines of a textbox in a list | 419 """Split lines of a textbox in a list |
419 | 420 |
420 main use case is using a textbox for labels | 421 main use case is using a textbox for labels |
421 """ | 422 """ |
422 if widget_type != u"textbox": | 423 if widget_type != "textbox": |
423 return widget_type, args, kwargs | 424 return widget_type, args, kwargs |
424 widget_type = u"list" | 425 widget_type = "list" |
425 options = [o for o in args.pop(0).split(u"\n") if o] | 426 options = [o for o in args.pop(0).split("\n") if o] |
426 kwargs = { | 427 kwargs = { |
427 "options": options, | 428 "options": options, |
428 "name": kwargs.get("name"), | 429 "name": kwargs.get("name"), |
429 "styles": (u"noselect", u"extensible", u"reducible"), | 430 "styles": ("noselect", "extensible", "reducible"), |
430 } | 431 } |
431 return widget_type, args, kwargs | 432 return widget_type, args, kwargs |
432 | 433 |
433 def dateFilter(self, form_xmlui, widget_type, args, kwargs): | 434 def dateFilter(self, form_xmlui, widget_type, args, kwargs): |
434 """Convert a string with a date to a unix timestamp""" | 435 """Convert a string with a date to a unix timestamp""" |
435 if widget_type != u"string" or not args[0]: | 436 if widget_type != "string" or not args[0]: |
436 return widget_type, args, kwargs | 437 return widget_type, args, kwargs |
437 # we convert XMPP date to timestamp | 438 # we convert XMPP date to timestamp |
438 try: | 439 try: |
439 args[0] = unicode(date_utils.date_parse(args[0])) | 440 args[0] = str(date_utils.date_parse(args[0])) |
440 except Exception as e: | 441 except Exception as e: |
441 log.warning(_(u"Can't parse date field: {msg}").format(msg=e)) | 442 log.warning(_("Can't parse date field: {msg}").format(msg=e)) |
442 return widget_type, args, kwargs | 443 return widget_type, args, kwargs |
443 | 444 |
444 ## Helper methods ## | 445 ## Helper methods ## |
445 | 446 |
446 def prepareBridgeGet(self, service, node, max_items, sub_id, extra_dict, profile_key): | 447 def prepareBridgeGet(self, service, node, max_items, sub_id, extra_dict, profile_key): |
477 extra = {} | 478 extra = {} |
478 # XXX: Q&D way to get list for labels when displaying them, but text when we | 479 # XXX: Q&D way to get list for labels when displaying them, but text when we |
479 # have to modify them | 480 # have to modify them |
480 if C.bool(extra.get("labels_as_list", C.BOOL_FALSE)): | 481 if C.bool(extra.get("labels_as_list", C.BOOL_FALSE)): |
481 filters = filters.copy() | 482 filters = filters.copy() |
482 filters[u"labels"] = self.textbox2ListFilter | 483 filters["labels"] = self.textbox2ListFilter |
483 client, service, node, max_items, extra, sub_id = self.prepareBridgeGet( | 484 client, service, node, max_items, extra, sub_id = self.prepareBridgeGet( |
484 service, node, max_items, sub_id, extra, profile_key | 485 service, node, max_items, sub_id, extra, profile_key |
485 ) | 486 ) |
486 d = self.getDataFormItems( | 487 d = self.getDataFormItems( |
487 client, | 488 client, |
534 client, service, node, item_ids=[item_id] | 535 client, service, node, item_ids=[item_id] |
535 ) | 536 ) |
536 item_elt = items_data[0][0] | 537 item_elt = items_data[0][0] |
537 except Exception as e: | 538 except Exception as e: |
538 log.warning( | 539 log.warning( |
539 _(u"Can't get previous item, update ignored: {reason}").format( | 540 _("Can't get previous item, update ignored: {reason}").format( |
540 reason=e | 541 reason=e |
541 ) | 542 ) |
542 ) | 543 ) |
543 else: | 544 else: |
544 # and parse it | 545 # and parse it |
545 form = data_form.findForm(item_elt, form_ns) | 546 form = data_form.findForm(item_elt, form_ns) |
546 if form is None: | 547 if form is None: |
547 log.warning( | 548 log.warning( |
548 _( | 549 _( |
549 u"Can't parse previous item, update ignored: data form not found" | 550 "Can't parse previous item, update ignored: data form not found" |
550 ).format(reason=e) | 551 ).format(reason=e) |
551 ) | 552 ) |
552 else: | 553 else: |
553 for name, field in form.fields.iteritems(): | 554 for name, field in form.fields.items(): |
554 if name not in values: | 555 if name not in values: |
555 values[name] = u"\n".join(unicode(v) for v in field.values) | 556 values[name] = "\n".join(str(v) for v in field.values) |
556 | 557 |
557 def _set(self, service, node, values, schema=None, item_id=None, extra=None, | 558 def _set(self, service, node, values, schema=None, item_id=None, extra=None, |
558 default_node=None, form_ns=None, fill_author=True, | 559 default_node=None, form_ns=None, fill_author=True, |
559 profile_key=C.PROF_KEY_NONE): | 560 profile_key=C.PROF_KEY_NONE): |
560 """Bridge method to set item in node with schema | 561 """Bridge method to set item in node with schema |
576 deserialise=True, | 577 deserialise=True, |
577 form_ns=form_ns, | 578 form_ns=form_ns, |
578 default_node=default_node, | 579 default_node=default_node, |
579 fill_author=fill_author, | 580 fill_author=fill_author, |
580 ) | 581 ) |
581 d.addCallback(lambda ret: ret or u"") | 582 d.addCallback(lambda ret: ret or "") |
582 return d | 583 return d |
583 | 584 |
584 @defer.inlineCallbacks | 585 @defer.inlineCallbacks |
585 def set(self, client, service, node, values, schema, item_id, extra, deserialise, | 586 def set(self, client, service, node, values, schema, item_id, extra, deserialise, |
586 form_ns, default_node=None, fill_author=True): | 587 form_ns, default_node=None, fill_author=True): |
603 """ | 604 """ |
604 if extra is None: | 605 if extra is None: |
605 extra = {} | 606 extra = {} |
606 if not node: | 607 if not node: |
607 if default_node is None: | 608 if default_node is None: |
608 raise ValueError(_(u"default_node must be set if node is not set")) | 609 raise ValueError(_("default_node must be set if node is not set")) |
609 node = default_node | 610 node = default_node |
610 now = utils.xmpp_date() | 611 now = utils.xmpp_date() |
611 if not item_id: | 612 if not item_id: |
612 values["created"] = now | 613 values["created"] = now |
613 elif extra.get(u"update", False): | 614 elif extra.get("update", False): |
614 if item_id is None: | 615 if item_id is None: |
615 raise exceptions.DataError( | 616 raise exceptions.DataError( |
616 _(u'if extra["update"] is set, item_id must be set too') | 617 _('if extra["update"] is set, item_id must be set too') |
617 ) | 618 ) |
618 yield self.copyMissingValues(client, service, node, item_id, form_ns, values) | 619 yield self.copyMissingValues(client, service, node, item_id, form_ns, values) |
619 | 620 |
620 values["updated"] = now | 621 values["updated"] = now |
621 if fill_author: | 622 if fill_author: |
628 client, service, node, values, schema, item_id, extra, deserialise | 629 client, service, node, values, schema, item_id, extra, deserialise |
629 ) | 630 ) |
630 defer.returnValue(item_id) | 631 defer.returnValue(item_id) |
631 | 632 |
632 | 633 |
634 @implementer(iwokkel.IDisco) | |
633 class SchemaHandler(XMPPHandler): | 635 class SchemaHandler(XMPPHandler): |
634 implements(iwokkel.IDisco) | |
635 | 636 |
636 def getDiscoInfo(self, requestor, service, nodeIdentifier=""): | 637 def getDiscoInfo(self, requestor, service, nodeIdentifier=""): |
637 return [disco.DiscoFeature(NS_SCHEMA)] | 638 return [disco.DiscoFeature(NS_SCHEMA)] |
638 | 639 |
639 def getDiscoItems(self, requestor, service, nodeIdentifier=""): | 640 def getDiscoItems(self, requestor, service, nodeIdentifier=""): |