# HG changeset patch # User Goffi # Date 1508482121 -7200 # Node ID f57a8eaec8edcd424a083b00fcbe6f405487be4d # Parent 5675af9057252798a616ea8a590e38309c0083ec plugins import, tickets import, bugzilla import: comments handling: - comments are put in "comments" key in import data, it's a list of microblog data - in resulting item, the comments uri is put in comments_uri field - (plugin import) root_service and root_node are kept in session - (plugin ticket) reporter name is now in "reporter" key instead of "reporter_name" - (plugin bugizlla): if not reporter name is found, first part of email address is used diff -r 5675af905725 -r f57a8eaec8ed src/plugins/plugin_import.py --- a/src/plugins/plugin_import.py Fri Oct 20 08:44:09 2017 +0200 +++ b/src/plugins/plugin_import.py Fri Oct 20 08:48:41 2017 +0200 @@ -53,8 +53,10 @@ @param import_handler(object): specialized import handler instance must have the following methods: - importItem: import a single main item (i.e. prepare data for publishing) - - importSubitems: import sub items (i.e. items linked to main item, e.g. comments). Must return a dict with kwargs for recursiveImport if items are to be imported. At east "items_import_data", "service" and "node" keys must be provided. - if None is returned, no subitems will be imported + - importSubitems: import sub items (i.e. items linked to main item, e.g. comments). + Must return a dict with kwargs for recursiveImport if items are to be imported recursively. + At least "items_import_data", "service" and "node" keys must be provided. + if None is returned, no recursion will be done to import subitems, but import can still be done directly by the method. - publishItem: actualy publish an item - itemFilters: modify item according to options @param name(unicode): import handler name @@ -139,6 +141,7 @@ else: if not value: del options[opt_name] + try: importer = import_handler.importers[name] except KeyError: @@ -159,7 +162,10 @@ } self.host.registerProgressCb(progress_id, partial(self.getProgress, import_handler), metadata, profile=client.profile) self.host.bridge.progressStarted(progress_id, metadata, client.profile) - session = {} # session data, can be use by importers + session = { # session data, can be used by importers + u'root_service': pubsub_service, + u'root_node': pubsub_node + } self.recursiveImport(client, import_handler, items_import_data, progress_id, session, options, None, pubsub_service, pubsub_node) defer.returnValue(progress_id) @@ -172,6 +178,7 @@ @param progress_id(unicode): id of progression @param session(dict): data for this import session can be used by importer so store any useful data + "root_service" and "root_node" are set to the main pubsub service and node of the import @param options(dict): import options @param return_data(dict): data to return on progressFinished @param service(jid.JID, None): PubSub service to use diff -r 5675af905725 -r f57a8eaec8ed src/plugins/plugin_tickets_import.py --- a/src/plugins/plugin_tickets_import.py Fri Oct 20 08:44:09 2017 +0200 +++ b/src/plugins/plugin_tickets_import.py Fri Oct 20 08:48:41 2017 +0200 @@ -19,16 +19,18 @@ from sat.core.i18n import _ from sat.core.constants import Const as C +from sat.core import exceptions from sat.core.log import getLogger log = getLogger(__name__) from twisted.internet import defer +from sat.tools.common import uri PLUGIN_INFO = { C.PI_NAME: "tickets import", C.PI_IMPORT_NAME: "TICKETS_IMPORT", C.PI_TYPE: C.PLUG_TYPE_IMPORT, - C.PI_DEPENDENCIES: ["IMPORT", "XEP-0060", "PUBSUB_SCHEMA"], + C.PI_DEPENDENCIES: ["IMPORT", "XEP-0060", "XEP-0277", "PUBSUB_SCHEMA"], C.PI_MAIN: "TicketsImportPlugin", C.PI_HANDLER: "no", C.PI_DESCRIPTION: _(u"""Tickets import management: @@ -47,6 +49,7 @@ self.host = host self._importers = {} self._p = host.plugins['XEP-0060'] + self._m = host.plugins['XEP-0277'] self._s = host.plugins['PUBSUB_SCHEMA'] host.plugins['IMPORT'].initialize(self, u'tickets') @@ -61,7 +64,8 @@ 'body': main description of the ticket 'creation': date of creation 'update': date of last update - 'reporter_name': full name of reporter + 'reporter': full name of reporter + 'reporter_jid': jid of reporter 'reporter_email': email of reporter 'assigned_to_name': full name of person working on it 'assigned_to_email': email of person working on it @@ -79,13 +83,29 @@ - "review": ticket is fixed and waiting for review - "closed": ticket is finished or invalid 'milestone': target milestone for this ticket + 'comments': list of microblog data (comment metadata, check [XEP_0277.send] data argument) """ + if 'comments_uri' in item_import_data: + raise exceptions.DataError(_(u'comments_uri key will be generated and must not be used by importer')) + if session[u'root_node'] is None: + session[u'root_node'] = NS_TICKETS if not 'schema' in session: - session['schema'] = yield self._s.getSchemaForm(client, service, node or NS_TICKETS) + session['schema'] = yield self._s.getSchemaForm(client, service, node or session[u'root_node']) defer.returnValue(item_import_data) + @defer.inlineCallbacks def importSubItems(self, client, item_import_data, ticket_data, session, options): - return None + # TODO: force "open" permission (except if private, check below) + # TODO: handle "private" metadata, to have non public access for node + comments = ticket_data.get('comments', []) + service, node = self._m.getCommentsService(client), self._m.getCommentsNode(session['root_node'] + u'_' + ticket_data['id']) + yield self._p.createIfNewNode(client, service, node) + ticket_data['comments_uri'] = uri.buildXMPPUri(u'pubsub', subtype='microblog', path=service.full(), node=node) + for comment in comments: + if 'updated' not in comment and 'published' in comment: + # we don't want an automatic update date + comment['updated'] = comment['published'] + yield self._m.send(client, comment, service, node) def publishItem(self, client, ticket_data, service, node, session): if node is None: diff -r 5675af905725 -r f57a8eaec8ed src/plugins/plugin_tickets_import_bugzilla.py --- a/src/plugins/plugin_tickets_import_bugzilla.py Fri Oct 20 08:44:09 2017 +0200 +++ b/src/plugins/plugin_tickets_import_bugzilla.py Fri Oct 20 08:48:41 2017 +0200 @@ -26,6 +26,7 @@ from twisted.internet import defer import os.path from lxml import etree +from sat.tools import utils PLUGIN_INFO = { @@ -71,7 +72,12 @@ ticket['update'] = bug.findtext('delta_ts') ticket['title'] = bug.findtext('short_desc') reporter_elt = bug.find('reporter') - ticket['reporter_name'] = reporter_elt.get('name') + ticket['reporter'] = reporter_elt.get('name') + if ticket['reporter'] is None: + if '@' in reporter_elt.text: + ticket['reporter'] = reporter_elt.text[:reporter_elt.text.find('@')].title() + else: + ticket['reporter'] = u'no name' ticket['reporter_email'] = reporter_elt.text assigned_to_elt = bug.find('assigned_to') ticket['assigned_to_name'] = assigned_to_elt.get('name') @@ -95,10 +101,11 @@ body = longdesc.findtext('thetext') else: who = longdesc.find('who') - comment = {'from': who.text, - 'date': longdesc.findtext('bug_when'), - 'nick': who.get('name'), - 'body': longdesc.findtext('thetext')} + comment = {'id': longdesc.findtext('commentid'), + 'author_email': who.text, + 'published': utils.date_parse(longdesc.findtext('bug_when')), + 'author': who.get('name', who.text), + 'content': longdesc.findtext('thetext')} comments.append(comment) ticket['body'] = body diff -r 5675af905725 -r f57a8eaec8ed src/plugins/plugin_xep_0277.py --- a/src/plugins/plugin_xep_0277.py Fri Oct 20 08:44:09 2017 +0200 +++ b/src/plugins/plugin_xep_0277.py Fri Oct 20 08:48:41 2017 +0200 @@ -662,12 +662,9 @@ @param access: Node access model, according to xep-0060 #4.5 @param profile_key: profile key """ + # FIXME: check if this mehtod is needed, deprecate it if not client = self.host.getClient(profile_key) - _jid, xmlstream = self.host.getJidNStream(profile_key) - if not _jid: - log.error(_(u"Can't find profile's jid")) - return _options = {self._p.OPT_ACCESS_MODEL: access, self._p.OPT_PERSIST_ITEMS: 1, self._p.OPT_MAX_ITEMS: -1, self._p.OPT_DELIVER_PAYLOADS: 1, self._p.OPT_SEND_ITEM_SUBSCRIBE: 1} def cb(result): @@ -683,17 +680,17 @@ #If the node already exists, the condition is "conflict", #else we have an unmanaged error if s_error.value.condition == 'conflict': - #d = self.host.plugins["XEP-0060"].deleteNode(client, _jid.userhostJID(), NS_MICROBLOG) + #d = self.host.plugins["XEP-0060"].deleteNode(client, client.jid.userhostJID(), NS_MICROBLOG) #d.addCallback(lambda x: create_node().addCallback(cb).addErrback(fatal_err)) change_node_options().addCallback(cb).addErrback(fatal_err) else: fatal_err(s_error) def create_node(): - return self._p.createNode(client, _jid.userhostJID(), NS_MICROBLOG, _options) + return self._p.createNode(client, client.jid.userhostJID(), NS_MICROBLOG, _options) def change_node_options(): - return self._p.setOptions(_jid.userhostJID(), NS_MICROBLOG, _jid.userhostJID(), _options, profile_key=profile_key) + return self._p.setOptions(client.jid.userhostJID(), NS_MICROBLOG, client.jid.userhostJID(), _options, profile_key=profile_key) create_node().addCallback(cb).addErrback(err_cb)