comparison sat/plugins/plugin_exp_pubsub_schema.py @ 2959:989b622faff6

plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes
author Goffi <goffi@goffi.org>
date Fri, 14 Jun 2019 12:37:34 +0200
parents e2cb04b381bb
children ab2696e34d29
comparison
equal deleted inserted replaced
2958:e2cb04b381bb 2959:989b622faff6
15 # GNU Affero General Public License for more details. 15 # GNU Affero General Public License for more details.
16 16
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
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
21 import copy
22 import itertools
23 from zope.interface import implements
24 from twisted.words.protocols.jabber import jid
25 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
26 from twisted.internet import defer
27 from wokkel import disco, iwokkel
28 from wokkel import data_form
29 from wokkel import generic
20 from sat.core.i18n import _ 30 from sat.core.i18n import _
21 from sat.core import exceptions 31 from sat.core import exceptions
22 from sat.core.constants import Const as C 32 from sat.core.constants import Const as C
23 from sat.tools import xml_tools 33 from sat.tools import xml_tools
24 from sat.tools import utils 34 from sat.tools import utils
25 from sat.tools.common import date_utils 35 from sat.tools.common import date_utils
26 from twisted.words.protocols.jabber import jid 36 from sat.tools.common import data_format
27 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
28 from twisted.internet import defer
29 from sat.core.log import getLogger 37 from sat.core.log import getLogger
30 38
31 log = getLogger(__name__) 39 log = getLogger(__name__)
32 from wokkel import disco, iwokkel 40
33 from wokkel import data_form 41 NS_SCHEMA = u"https://salut-a-toi/protocol/schema:0"
34 from wokkel import generic
35 from zope.interface import implements
36 from collections import Iterable
37 import copy
38 import itertools
39
40 NS_SCHEMA = "https://salut-a-toi/protocol/schema:0"
41 42
42 PLUGIN_INFO = { 43 PLUGIN_INFO = {
43 C.PI_NAME: "PubSub Schema", 44 C.PI_NAME: u"PubSub Schema",
44 C.PI_IMPORT_NAME: "PUBSUB_SCHEMA", 45 C.PI_IMPORT_NAME: u"PUBSUB_SCHEMA",
45 C.PI_TYPE: "EXP", 46 C.PI_TYPE: u"EXP",
46 C.PI_PROTOCOLS: [], 47 C.PI_PROTOCOLS: [],
47 C.PI_DEPENDENCIES: ["XEP-0060", "IDENTITY"], 48 C.PI_DEPENDENCIES: [u"XEP-0060", u"IDENTITY"],
48 C.PI_MAIN: "PubsubSchema", 49 C.PI_MAIN: u"PubsubSchema",
49 C.PI_HANDLER: "yes", 50 C.PI_HANDLER: u"yes",
50 C.PI_DESCRIPTION: _("""Handle Pubsub data schemas"""), 51 C.PI_DESCRIPTION: _(u"""Handle Pubsub data schemas"""),
51 } 52 }
52 53
53 54
54 class PubsubSchema(object): 55 class PubsubSchema(object):
55 def __init__(self, host): 56 def __init__(self, host):
508 service = None if not service else jid.JID(service) 509 service = None if not service else jid.JID(service)
509 if schema: 510 if schema:
510 schema = generic.parseXml(schema.encode("utf-8")) 511 schema = generic.parseXml(schema.encode("utf-8"))
511 else: 512 else:
512 schema = None 513 schema = None
513 if extra and u"update" in extra: 514 extra = data_format.deserialise(extra)
514 extra[u"update"] = C.bool(extra[u"update"])
515 return client, service, node or None, schema, item_id or None, extra 515 return client, service, node or None, schema, item_id or None, extra
516
517 @defer.inlineCallbacks
518 def copyMissingValues(self, client, service, node, item_id, form_ns, values):
519 """Retrieve values existing in original item and missing in update
520
521 Existing item will be retrieve, and values not already specified in values will
522 be filled
523 @param service: same as for [XEP_0060.getItems]
524 @param node: same as for [XEP_0060.getItems]
525 @param item_id(unicode): id of the item to retrieve
526 @param form_ns (unicode, None): namespace of the form
527 @param values(dict): values to fill
528 This dict will be modified *in place* to fill value present in existing
529 item and missing in the dict.
530 """
531 try:
532 # we get previous item
533 items_data = yield self._p.getItems(
534 client, service, node, item_ids=[item_id]
535 )
536 item_elt = items_data[0][0]
537 except Exception as e:
538 log.warning(
539 _(u"Can't get previous item, update ignored: {reason}").format(
540 reason=e
541 )
542 )
543 else:
544 # and parse it
545 form = data_form.findForm(item_elt, form_ns)
546 if form is None:
547 log.warning(
548 _(
549 u"Can't parse previous item, update ignored: data form not found"
550 ).format(reason=e)
551 )
552 else:
553 for name, field in form.fields.iteritems():
554 if name not in values:
555 values[name] = u"\n".join(unicode(v) for v in field.values)
516 556
517 def _set(self, service, node, values, schema=None, item_id=None, extra=None, 557 def _set(self, service, node, values, schema=None, item_id=None, extra=None,
518 default_node=None, form_ns=None, fill_author=True, 558 default_node=None, form_ns=None, fill_author=True,
519 profile_key=C.PROF_KEY_NONE): 559 profile_key=C.PROF_KEY_NONE):
520 """Bridge method to set item in node with schema 560 """Bridge method to set item in node with schema
559 needed when an update is done 599 needed when an update is done
560 @param default_node(unicode, None): value to use if node is not set 600 @param default_node(unicode, None): value to use if node is not set
561 other arguments are same as for [self._s.sendDataFormItem] 601 other arguments are same as for [self._s.sendDataFormItem]
562 @return (unicode): id of the created item 602 @return (unicode): id of the created item
563 """ 603 """
604 if extra is None:
605 extra = {}
564 if not node: 606 if not node:
565 if default_node is None: 607 if default_node is None:
566 raise ValueError(_(u"default_node must be set if node is not set")) 608 raise ValueError(_(u"default_node must be set if node is not set"))
567 node = default_node 609 node = default_node
568 now = utils.xmpp_date() 610 now = utils.xmpp_date()
571 elif extra.get(u"update", False): 613 elif extra.get(u"update", False):
572 if item_id is None: 614 if item_id is None:
573 raise exceptions.DataError( 615 raise exceptions.DataError(
574 _(u'if extra["update"] is set, item_id must be set too') 616 _(u'if extra["update"] is set, item_id must be set too')
575 ) 617 )
576 try: 618 yield self.copyMissingValues(client, service, node, item_id, form_ns, values)
577 # we get previous item
578 items_data = yield self._p.getItems(
579 client, service, node, item_ids=[item_id]
580 )
581 item_elt = items_data[0][0]
582 except Exception as e:
583 log.warning(
584 _(u"Can't get previous item, update ignored: {reason}").format(
585 reason=e
586 )
587 )
588 else:
589 # and parse it
590 form = data_form.findForm(item_elt, form_ns)
591 if form is None:
592 log.warning(
593 _(
594 u"Can't parse previous item, update ignored: data form not found"
595 ).format(reason=e)
596 )
597 else:
598 for name, field in form.fields.iteritems():
599 if name not in values:
600 values[name] = u"\n".join(unicode(v) for v in field.values)
601 619
602 values["updated"] = now 620 values["updated"] = now
603 if fill_author: 621 if fill_author:
604 if not values.get("author"): 622 if not values.get("author"):
605 identity = yield self._i.getIdentity(client, client.jid) 623 identity = yield self._i.getIdentity(client, client.jid)