Mercurial > libervia-backend
comparison src/plugins/plugin_tickets_import.py @ 2396:66baa687c682
plugins tickets import, jp (ticket/import): implemented mapping:
- mapping is an option allowing do map imported field to a specific field in the newly created item
- importers can now use complexe data types in options using JSON
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 27 Oct 2017 17:58:05 +0200 |
parents | 8ed4ac10cb5e |
children | 8b37a62336c3 |
comparison
equal
deleted
inserted
replaced
2395:713cedc99752 | 2396:66baa687c682 |
---|---|
22 from sat.core import exceptions | 22 from sat.core import exceptions |
23 from sat.core.log import getLogger | 23 from sat.core.log import getLogger |
24 log = getLogger(__name__) | 24 log = getLogger(__name__) |
25 from twisted.internet import defer | 25 from twisted.internet import defer |
26 from sat.tools.common import uri | 26 from sat.tools.common import uri |
27 from sat.tools import utils | |
27 | 28 |
28 | 29 |
29 PLUGIN_INFO = { | 30 PLUGIN_INFO = { |
30 C.PI_NAME: "tickets import", | 31 C.PI_NAME: "tickets import", |
31 C.PI_IMPORT_NAME: "TICKETS_IMPORT", | 32 C.PI_IMPORT_NAME: "TICKETS_IMPORT", |
35 C.PI_HANDLER: "no", | 36 C.PI_HANDLER: "no", |
36 C.PI_DESCRIPTION: _(u"""Tickets import management: | 37 C.PI_DESCRIPTION: _(u"""Tickets import management: |
37 This plugin manage the different tickets importers which can register to it, and handle generic importing tasks.""") | 38 This plugin manage the different tickets importers which can register to it, and handle generic importing tasks.""") |
38 } | 39 } |
39 | 40 |
41 OPT_MAPPING = 'mapping' | |
42 FIELDS_LIST = (u'labels', u'cc_emails') # fields which must have a list as value | |
43 FIELDS_DATE = (u'created', u'updated') | |
44 | |
40 NS_TICKETS = 'org.salut-a-toi.tickets:0' | 45 NS_TICKETS = 'org.salut-a-toi.tickets:0' |
41 | 46 |
42 | 47 |
43 class TicketsImportPlugin(object): | 48 class TicketsImportPlugin(object): |
44 BOOL_OPTIONS = () | 49 BOOL_OPTIONS = () |
50 JSON_OPTIONS = (OPT_MAPPING,) | |
45 OPT_DEFAULTS = {} | 51 OPT_DEFAULTS = {} |
46 | 52 |
47 def __init__(self, host): | 53 def __init__(self, host): |
48 log.info(_("plugin Tickets Import initialization")) | 54 log.info(_("plugin Tickets Import initialization")) |
49 self.host = host | 55 self.host = host |
57 def importItem(self, client, item_import_data, session, options, return_data, service, node): | 63 def importItem(self, client, item_import_data, session, options, return_data, service, node): |
58 """ | 64 """ |
59 | 65 |
60 @param item_import_data(dict): no key is mandatory, but if a key doesn't exists in dest form, it will be ignored. | 66 @param item_import_data(dict): no key is mandatory, but if a key doesn't exists in dest form, it will be ignored. |
61 Following names are recommendations which should be used where suitable in importers. | 67 Following names are recommendations which should be used where suitable in importers. |
68 except if specified in description, values are unicode | |
62 'id': unique id (must be unique in the node) of the ticket | 69 'id': unique id (must be unique in the node) of the ticket |
63 'title': title (or short description/summary) of the ticket | 70 'title': title (or short description/summary) of the ticket |
64 'body': main description of the ticket | 71 'body': main description of the ticket |
65 'creation': date of creation | 72 'created': date of creation (unix time) |
66 'update': date of last update | 73 'updated': date of last update (unix time) |
67 'reporter': full name of reporter | 74 'reporter': full name of reporter |
68 'reporter_jid': jid of reporter | 75 'reporter_jid': jid of reporter |
69 'reporter_email': email of reporter | 76 'reporter_email': email of reporter |
70 'assigned_to_name': full name of person working on it | 77 'assigned_to_name': full name of person working on it |
71 'assigned_to_email': email of person working on it | 78 'assigned_to_email': email of person working on it |
72 'cc_emails': iterable of emails subscribed to the ticket | 79 'cc_emails': list of emails subscribed to the ticket |
73 'priority': priority of the ticket | 80 'priority': priority of the ticket |
74 'severity': severity of the ticket | 81 'severity': severity of the ticket |
82 'labels': list of unicode values to use as label | |
75 'product': product concerned by this ticket | 83 'product': product concerned by this ticket |
76 'component': part of the product concerned by this ticket | 84 'component': part of the product concerned by this ticket |
77 'version': version of the product/component concerned by this ticket | 85 'version': version of the product/component concerned by this ticket |
78 'platform': platform converned by this ticket | 86 'platform': platform converned by this ticket |
79 'os': operating system concerned by this ticket | 87 'os': operating system concerned by this ticket |
82 - "started": progress is ongoing | 90 - "started": progress is ongoing |
83 - "review": ticket is fixed and waiting for review | 91 - "review": ticket is fixed and waiting for review |
84 - "closed": ticket is finished or invalid | 92 - "closed": ticket is finished or invalid |
85 'milestone': target milestone for this ticket | 93 'milestone': target milestone for this ticket |
86 'comments': list of microblog data (comment metadata, check [XEP_0277.send] data argument) | 94 'comments': list of microblog data (comment metadata, check [XEP_0277.send] data argument) |
95 @param options(dict, None): Below are the generic options, | |
96 tickets importer can have specific ones. All options are serialized unicode values | |
97 generic options: | |
98 - OPT_MAPPING (json): dict of imported ticket key => exported ticket key | |
99 e.g.: if you want to map "component" to "labels", you can specify: | |
100 {'component': 'labels'} | |
101 If you specify several import ticket key to the same dest key, | |
102 the values will be joined with line feeds | |
87 """ | 103 """ |
88 if 'comments_uri' in item_import_data: | 104 if 'comments_uri' in item_import_data: |
89 raise exceptions.DataError(_(u'comments_uri key will be generated and must not be used by importer')) | 105 raise exceptions.DataError(_(u'comments_uri key will be generated and must not be used by importer')) |
106 for key in FIELDS_LIST: | |
107 if not isinstance(item_import_data.get(key, []), list): | |
108 raise exceptions.DataError(_(u'{key} must be a list').format(key=key)) | |
109 for key in FIELDS_DATE: | |
110 try: | |
111 item_import_data[key] = utils.xmpp_date(item_import_data[key]) | |
112 except KeyError: | |
113 continue | |
90 if session[u'root_node'] is None: | 114 if session[u'root_node'] is None: |
91 session[u'root_node'] = NS_TICKETS | 115 session[u'root_node'] = NS_TICKETS |
92 if not 'schema' in session: | 116 if not 'schema' in session: |
93 session['schema'] = yield self._s.getSchemaForm(client, service, node or session[u'root_node']) | 117 session['schema'] = yield self._s.getSchemaForm(client, service, node or session[u'root_node']) |
94 defer.returnValue(item_import_data) | 118 defer.returnValue(item_import_data) |
121 id_ = ticket_data.pop('id', None) | 145 id_ = ticket_data.pop('id', None) |
122 log.debug(u"uploading item [{id}]: {title}".format(id=id_, title=ticket_data.get('title',''))) | 146 log.debug(u"uploading item [{id}]: {title}".format(id=id_, title=ticket_data.get('title',''))) |
123 return self._s.sendDataFormItem(client, service, node, ticket_data, session['schema'], id_) | 147 return self._s.sendDataFormItem(client, service, node, ticket_data, session['schema'], id_) |
124 | 148 |
125 def itemFilters(self, client, ticket_data, session, options): | 149 def itemFilters(self, client, ticket_data, session, options): |
126 return None | 150 mapping = options.get(OPT_MAPPING) |
151 if mapping is not None: | |
152 if not isinstance(mapping, dict): | |
153 raise exceptions.DataError(_(u'mapping option must be a dictionary')) | |
154 | |
155 for source, dest in mapping.iteritems(): | |
156 if not isinstance(source, unicode) or not isinstance(dest, unicode): | |
157 raise exceptions.DataError(_(u'keys and values of mapping must be sources and destinations ticket fields')) | |
158 if source in ticket_data: | |
159 value = ticket_data.pop(source) | |
160 if dest in FIELDS_LIST: | |
161 values = ticket_data[dest] = ticket_data.get(dest, []) | |
162 values.append(value) | |
163 else: | |
164 if dest in ticket_data: | |
165 ticket_data[dest] = ticket_data[dest] + u'\n' + value | |
166 else: | |
167 ticket_data[dest] = value |