changeset 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 5d13d357896c
files sat/plugins/plugin_exp_pubsub_schema.py sat/plugins/plugin_misc_forums.py sat/plugins/plugin_misc_merge_requests.py sat/plugins/plugin_misc_tickets.py sat_frontends/jp/cmd_merge_request.py
diffstat 5 files changed, 94 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- 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 <http://www.gnu.org/licenses/>.
 
+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:
--- 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 <forums> element(s)
+        """Recursively create <forums> 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 <forums> elements and return corresponding forums data
+        """Recursivly parse a <forums> elements and return corresponding forums data
 
         @param item(domish.Element): item with <forums> 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
         """
--- 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,
--- 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
         )
--- 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(