diff --git a/sat/plugins/plugin_exp_pubsub_schema.py b/sat/plugins/plugin_exp_pubsub_schema.py
index ef69d334..eab89831 100644
--- a/sat/plugins/plugin_exp_pubsub_schema.py
+++ b/sat/plugins/plugin_exp_pubsub_schema.py
@@ -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 @@ class PubsubSchema(object):
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 @@ class PubsubSchema(object):
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 @@ class PubsubSchema(object):
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 --git a/sat/plugins/plugin_misc_forums.py b/sat/plugins/plugin_misc_forums.py
index 3837c01e..08281b38 100644
--- a/sat/plugins/plugin_misc_forums.py
+++ b/sat/plugins/plugin_misc_forums.py
@@ -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 @@ class forums(object):
@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 @@ class forums(object):
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 @@ class forums(object):
@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 @@ class forums(object):
@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 --git a/sat/plugins/plugin_misc_merge_requests.py b/sat/plugins/plugin_misc_merge_requests.py
index c1f4a35d..454276b8 100644
--- a/sat/plugins/plugin_misc_merge_requests.py
+++ b/sat/plugins/plugin_misc_merge_requests.py
@@ -79,7 +79,7 @@ class MergeRequests(object):
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 @@ class MergeRequests(object):
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 --git a/sat/plugins/plugin_misc_tickets.py b/sat/plugins/plugin_misc_tickets.py
index 7f2d807a..ae83b20c 100644
--- a/sat/plugins/plugin_misc_tickets.py
+++ b/sat/plugins/plugin_misc_tickets.py
@@ -30,14 +30,14 @@ log = getLogger(__name__)
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 @@ class Tickets(object):
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 @@ class Tickets(object):
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 @@ class Tickets(object):
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 @@ class Tickets(object):
@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 @@ class Tickets(object):
"""
if not node:
node = NS_TICKETS
+
if not item_id:
comments_service = yield self._m.getCommentsService(client, service)
@@ -132,12 +134,13 @@ class Tickets(object):
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 --git a/sat_frontends/jp/cmd_merge_request.py b/sat_frontends/jp/cmd_merge_request.py
index 826d32cd..db8e9edd 100644
--- a/sat_frontends/jp/cmd_merge_request.py
+++ b/sat_frontends/jp/cmd_merge_request.py
@@ -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 @@ class Set(base.CommandBase):
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 @@ class Set(base.CommandBase):
values,
u"",
self.args.item,
- extra,
+ data_format.serialise(extra),
self.profile,
callback=self.mergeRequestSetCb,
errback=partial(