# HG changeset patch # User Goffi # Date 1560508654 -7200 # Node ID 989b622faff617d02f92699c8ce9b510085bc8fb # Parent e2cb04b381bbdc526c604dc3098488ed0fed93ee plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes diff -r e2cb04b381bb -r 989b622faff6 sat/plugins/plugin_exp_pubsub_schema.py --- a/sat/plugins/plugin_exp_pubsub_schema.py Wed Jun 12 09:11:28 2019 +0200 +++ b/sat/plugins/plugin_exp_pubsub_schema.py Fri Jun 14 12:37:34 2019 +0200 @@ -17,37 +17,38 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from collections import Iterable +import copy +import itertools +from zope.interface import implements +from twisted.words.protocols.jabber import jid +from twisted.words.protocols.jabber.xmlstream import XMPPHandler +from twisted.internet import defer +from wokkel import disco, iwokkel +from wokkel import data_form +from wokkel import generic 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 sat.tools import utils from sat.tools.common import date_utils -from twisted.words.protocols.jabber import jid -from twisted.words.protocols.jabber.xmlstream import XMPPHandler -from twisted.internet import defer +from sat.tools.common import data_format from sat.core.log import getLogger log = getLogger(__name__) -from wokkel import disco, iwokkel -from wokkel import data_form -from wokkel import generic -from zope.interface import implements -from collections import Iterable -import copy -import itertools -NS_SCHEMA = "https://salut-a-toi/protocol/schema:0" +NS_SCHEMA = u"https://salut-a-toi/protocol/schema:0" PLUGIN_INFO = { - C.PI_NAME: "PubSub Schema", - C.PI_IMPORT_NAME: "PUBSUB_SCHEMA", - C.PI_TYPE: "EXP", + C.PI_NAME: u"PubSub Schema", + C.PI_IMPORT_NAME: u"PUBSUB_SCHEMA", + C.PI_TYPE: u"EXP", C.PI_PROTOCOLS: [], - C.PI_DEPENDENCIES: ["XEP-0060", "IDENTITY"], - C.PI_MAIN: "PubsubSchema", - C.PI_HANDLER: "yes", - C.PI_DESCRIPTION: _("""Handle Pubsub data schemas"""), + C.PI_DEPENDENCIES: [u"XEP-0060", u"IDENTITY"], + C.PI_MAIN: u"PubsubSchema", + C.PI_HANDLER: u"yes", + C.PI_DESCRIPTION: _(u"""Handle Pubsub data schemas"""), } @@ -510,10 +511,49 @@ schema = generic.parseXml(schema.encode("utf-8")) else: schema = None - if extra and u"update" in extra: - extra[u"update"] = C.bool(extra[u"update"]) + extra = data_format.deserialise(extra) return client, service, node or None, schema, item_id or None, extra + @defer.inlineCallbacks + def copyMissingValues(self, client, service, node, item_id, form_ns, values): + """Retrieve values existing in original item and missing in update + + Existing item will be retrieve, and values not already specified in values will + be filled + @param service: same as for [XEP_0060.getItems] + @param node: same as for [XEP_0060.getItems] + @param item_id(unicode): id of the item to retrieve + @param form_ns (unicode, None): namespace of the form + @param values(dict): values to fill + This dict will be modified *in place* to fill value present in existing + item and missing in the dict. + """ + try: + # we get previous item + items_data = yield self._p.getItems( + client, service, node, item_ids=[item_id] + ) + item_elt = items_data[0][0] + except Exception as e: + log.warning( + _(u"Can't get previous item, update ignored: {reason}").format( + reason=e + ) + ) + else: + # and parse it + form = data_form.findForm(item_elt, form_ns) + if form is None: + log.warning( + _( + u"Can't parse previous item, update ignored: data form not found" + ).format(reason=e) + ) + else: + for name, field in form.fields.iteritems(): + if name not in values: + values[name] = u"\n".join(unicode(v) for v in field.values) + 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): @@ -561,6 +601,8 @@ other arguments are same as for [self._s.sendDataFormItem] @return (unicode): id of the created item """ + if extra is None: + extra = {} if not node: if default_node is None: raise ValueError(_(u"default_node must be set if node is not set")) @@ -573,31 +615,7 @@ raise exceptions.DataError( _(u'if extra["update"] is set, item_id must be set too') ) - try: - # we get previous item - items_data = yield self._p.getItems( - client, service, node, item_ids=[item_id] - ) - item_elt = items_data[0][0] - except Exception as e: - log.warning( - _(u"Can't get previous item, update ignored: {reason}").format( - reason=e - ) - ) - else: - # and parse it - form = data_form.findForm(item_elt, form_ns) - if form is None: - log.warning( - _( - u"Can't parse previous item, update ignored: data form not found" - ).format(reason=e) - ) - else: - for name, field in form.fields.iteritems(): - if name not in values: - values[name] = u"\n".join(unicode(v) for v in field.values) + yield self.copyMissingValues(client, service, node, item_id, form_ns, values) values["updated"] = now if fill_author: diff -r e2cb04b381bb -r 989b622faff6 sat/plugins/plugin_misc_forums.py --- a/sat/plugins/plugin_misc_forums.py Wed Jun 12 09:11:28 2019 +0200 +++ b/sat/plugins/plugin_misc_forums.py Fri Jun 14 12:37:34 2019 +0200 @@ -1,7 +1,7 @@ #!/usr/bin/env python2 # -*- coding: utf-8 -*- -# SAT plugin for Pubsub Schemas +# SAT plugin for pubsub forums # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify @@ -83,7 +83,7 @@ @defer.inlineCallbacks def _createForums(self, client, forums, service, node, forums_elt=None, names=None): - """recursively create element(s) + """Recursively create element(s) @param forums(list): forums which may have subforums @param service(jid.JID): service where the new nodes will be created @@ -139,7 +139,7 @@ defer.returnValue(forums_elt) def _parseForums(self, parent_elt=None, forums=None): - """recursivly parse a elements and return corresponding forums data + """Recursivly parse a elements and return corresponding forums data @param item(domish.Element): item with element @param parent_elt(domish.Element, None): element to parse @@ -220,7 +220,7 @@ @defer.inlineCallbacks def set(self, client, forums, service=None, node=None, forums_key=None): - """create or replace forums structure + """Create or replace forums structure @param forums(list): list of dictionary as follow: a dictionary represent a forum metadata, with the following keys: @@ -254,7 +254,7 @@ @defer.inlineCallbacks def getTopics(self, client, service, node, rsm_request=None, extra=None): - """retrieve topics data + """Retrieve topics data Topics are simple microblog URIs with some metadata duplicated from first post """ diff -r e2cb04b381bb -r 989b622faff6 sat/plugins/plugin_misc_merge_requests.py --- a/sat/plugins/plugin_misc_merge_requests.py Wed Jun 12 09:11:28 2019 +0200 +++ b/sat/plugins/plugin_misc_merge_requests.py Fri Jun 14 12:37:34 2019 +0200 @@ -79,7 +79,7 @@ async=True ) host.bridge.addMethod("mergeRequestSet", ".plugin", - in_sign='ssssa{sas}ssa{ss}s', out_sign='s', + in_sign='ssssa{sas}ssss', out_sign='s', method=self._set, async=True) host.bridge.addMethod("mergeRequestsSchemaGet", ".plugin", @@ -191,7 +191,7 @@ defer.returnValue((tickets_xmlui, metadata, parsed_patches)) def _set(self, service, node, repository, method, values, schema=None, item_id=None, - extra=None, profile_key=C.PROF_KEY_NONE): + extra=u"", profile_key=C.PROF_KEY_NONE): client, service, node, schema, item_id, extra = self._s.prepareBridgeSet( service, node, schema, item_id, extra, profile_key) d = self.set(client, service, node, repository, method, values, schema, diff -r e2cb04b381bb -r 989b622faff6 sat/plugins/plugin_misc_tickets.py --- a/sat/plugins/plugin_misc_tickets.py Wed Jun 12 09:11:28 2019 +0200 +++ b/sat/plugins/plugin_misc_tickets.py Fri Jun 14 12:37:34 2019 +0200 @@ -30,14 +30,14 @@ NS_TICKETS = "org.salut-a-toi.tickets:0" PLUGIN_INFO = { - C.PI_NAME: _("Tickets management"), - C.PI_IMPORT_NAME: "TICKETS", - C.PI_TYPE: "EXP", + C.PI_NAME: _(u"Tickets management"), + C.PI_IMPORT_NAME: u"TICKETS", + C.PI_TYPE: u"EXP", C.PI_PROTOCOLS: [], - C.PI_DEPENDENCIES: ["XEP-0060", "PUBSUB_SCHEMA", "XEP-0277", "IDENTITY"], - C.PI_MAIN: "Tickets", - C.PI_HANDLER: "no", - C.PI_DESCRIPTION: _("""Tickets management plugin"""), + C.PI_DEPENDENCIES: [u"XEP-0060", u"PUBSUB_SCHEMA", u"XEP-0277", u"IDENTITY"], + C.PI_MAIN: u"Tickets", + C.PI_HANDLER: u"no", + C.PI_DESCRIPTION: _(u"""Tickets management plugin"""), } @@ -45,15 +45,15 @@ def __init__(self, host): log.info(_(u"Tickets plugin initialization")) self.host = host - host.registerNamespace("tickets", NS_TICKETS) - self._p = self.host.plugins["XEP-0060"] - self._s = self.host.plugins["PUBSUB_SCHEMA"] - self._m = self.host.plugins["XEP-0277"] + host.registerNamespace(u"tickets", NS_TICKETS) + self._p = self.host.plugins[u"XEP-0060"] + self._s = self.host.plugins[u"PUBSUB_SCHEMA"] + self._m = self.host.plugins[u"XEP-0277"] host.bridge.addMethod( - "ticketsGet", - ".plugin", - in_sign="ssiassa{ss}s", - out_sign="(asa{ss})", + u"ticketsGet", + u".plugin", + in_sign=u"ssiassa{ss}s", + out_sign=u"(asa{ss})", method=utils.partial( self._s._get, default_node=NS_TICKETS, @@ -69,7 +69,7 @@ host.bridge.addMethod( "ticketSet", ".plugin", - in_sign="ssa{sas}ssa{ss}s", + in_sign="ssa{sas}ssss", out_sign="s", method=self._set, async=True, @@ -83,7 +83,7 @@ async=True, ) - def _set(self, service, node, values, schema=None, item_id=None, extra=None, + def _set(self, service, node, values, schema=None, item_id=None, extra=u'', profile_key=C.PROF_KEY_NONE): client, service, node, schema, item_id, extra = self._s.prepareBridgeSet( service, node, schema, item_id, extra, profile_key @@ -102,6 +102,7 @@ @param node(unicode, None): Pubsub node to use None to use default tickets node @param values(dict[key(unicode), [iterable[object]|object]]): values of the ticket + if value is not iterable, it will be put in a list 'created' and 'updated' will be forced to current time: - 'created' is set if item_id is None, i.e. if it's a new ticket @@ -114,6 +115,7 @@ """ if not node: node = NS_TICKETS + if not item_id: comments_service = yield self._m.getCommentsService(client, service) @@ -132,12 +134,13 @@ self._p.OPT_PUBLISH_MODEL: self._p.ACCESS_OPEN, } yield self._p.createNode(client, comments_service, comments_node, options) - values["comments_uri"] = uri.buildXMPPUri( + values[u"comments_uri"] = uri.buildXMPPUri( u"pubsub", subtype="microblog", path=comments_service.full(), node=comments_node, ) + item_id = yield self._s.set( client, service, node, values, schema, item_id, extra, deserialise, form_ns ) diff -r e2cb04b381bb -r 989b622faff6 sat_frontends/jp/cmd_merge_request.py --- a/sat_frontends/jp/cmd_merge_request.py Wed Jun 12 09:11:28 2019 +0200 +++ b/sat_frontends/jp/cmd_merge_request.py Fri Jun 14 12:37:34 2019 +0200 @@ -20,6 +20,7 @@ import base from sat.core.i18n import _ +from sat.tools.common import data_format from sat_frontends.jp.constants import Const as C from sat_frontends.jp import xmlui_manager from sat_frontends.jp import common @@ -80,7 +81,7 @@ self.host.quit(C.EXIT_OK) def sendRequest(self): - extra = {"update": "true"} if self.args.item else {} + extra = {"update": True} if self.args.item else {} values = {} if self.args.labels is not None: values[u"labels"] = self.args.labels @@ -92,7 +93,7 @@ values, u"", self.args.item, - extra, + data_format.serialise(extra), self.profile, callback=self.mergeRequestSetCb, errback=partial(