Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_lists.py @ 3460:d4a71a1dac88
plugin misc lists: templates:
Templates are a way to create lists with pre-filled schemas.
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 19 Feb 2021 15:49:58 +0100 |
parents | 8dc26e5edcd3 |
children | 02a8d227d5bb |
comparison
equal
deleted
inserted
replaced
3459:8dc26e5edcd3 | 3460:d4a71a1dac88 |
---|---|
13 # GNU Affero General Public License for more details. | 13 # GNU Affero General Public License for more details. |
14 | 14 |
15 # You should have received a copy of the GNU Affero General Public License | 15 # You should have received a copy of the GNU Affero General Public License |
16 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 |
18 import shortuuid | |
19 from typing import Tuple | |
20 from twisted.internet import defer | |
21 from twisted.words.xish import domish | |
22 from twisted.words.protocols.jabber import jid | |
23 from wokkel import data_form | |
18 from sat.core.i18n import _, D_ | 24 from sat.core.i18n import _, D_ |
19 from sat.core.constants import Const as C | 25 from sat.core.constants import Const as C |
20 from twisted.internet import defer | |
21 from sat.tools.common import uri | 26 from sat.tools.common import uri |
22 import shortuuid | 27 from sat.tools.common import data_format |
23 from sat.core.log import getLogger | 28 from sat.core.log import getLogger |
24 | 29 |
25 log = getLogger(__name__) | 30 log = getLogger(__name__) |
26 | 31 |
27 # XXX: this plugin was formely named "tickets", thus the namespace keeps this | 32 # XXX: this plugin was formely named "tickets", thus the namespace keeps this |
28 # name | 33 # name |
29 APP_NS_TICKETS = "org.salut-a-toi.tickets:0" | 34 APP_NS_TICKETS = "org.salut-a-toi.tickets:0" |
35 NS_TICKETS_TYPE = "org.salut-a-toi.tickets#type:0" | |
30 | 36 |
31 PLUGIN_INFO = { | 37 PLUGIN_INFO = { |
32 C.PI_NAME: _("Pubsub Lists"), | 38 C.PI_NAME: _("Pubsub Lists"), |
33 C.PI_IMPORT_NAME: "LISTS", | 39 C.PI_IMPORT_NAME: "LISTS", |
34 C.PI_TYPE: "EXP", | 40 C.PI_TYPE: "EXP", |
35 C.PI_PROTOCOLS: [], | 41 C.PI_PROTOCOLS: [], |
36 C.PI_DEPENDENCIES: ["XEP-0060", "XEP-0346", "XEP-0277", "IDENTITY"], | 42 C.PI_DEPENDENCIES: ["XEP-0060", "XEP-0346", "XEP-0277", "IDENTITY"], |
37 C.PI_MAIN: "PubsubLists", | 43 C.PI_MAIN: "PubsubLists", |
38 C.PI_HANDLER: "no", | 44 C.PI_HANDLER: "no", |
39 C.PI_DESCRIPTION: _("""Pubsub lists management plugin"""), | 45 C.PI_DESCRIPTION: _("""Pubsub lists management plugin"""), |
46 } | |
47 | |
48 TEMPLATES = { | |
49 "todo": { | |
50 "name": D_("TODO List"), | |
51 "icon": "check", | |
52 "fields": [ | |
53 {"name": "title"}, | |
54 {"name": "author"}, | |
55 {"name": "created"}, | |
56 {"name": "updated"}, | |
57 {"name": "time_limit"}, | |
58 {"name": "labels", "type": "text-multi"}, | |
59 { | |
60 "name": "status", | |
61 "label": D_("status"), | |
62 "type": "list-single", | |
63 "options": [ | |
64 { | |
65 "label": D_("to do"), | |
66 "value": "todo" | |
67 }, | |
68 { | |
69 "label": D_("in progress"), | |
70 "value": "in_progress" | |
71 }, | |
72 { | |
73 "label": D_("done"), | |
74 "value": "done" | |
75 }, | |
76 ], | |
77 "value": "todo" | |
78 }, | |
79 { | |
80 "name": "priority", | |
81 "label": D_("priority"), | |
82 "type": "list-single", | |
83 "options": [ | |
84 { | |
85 "label": D_("major"), | |
86 "value": "major" | |
87 }, | |
88 { | |
89 "label": D_("normal"), | |
90 "value": "normal" | |
91 }, | |
92 { | |
93 "label": D_("minor"), | |
94 "value": "minor" | |
95 }, | |
96 ], | |
97 "value": "normal" | |
98 }, | |
99 {"name": "body", "type": "xhtml"}, | |
100 {"name": "comments_uri"}, | |
101 ] | |
102 }, | |
103 "shopping": { | |
104 "name": D_("Shopping List"), | |
105 "icon": "basket", | |
106 "fields": [ | |
107 {"name": "name", "label": D_("name")}, | |
108 {"name": "quantity", "label": D_("quantity")}, | |
109 { | |
110 "name": "status", | |
111 "label": D_("status"), | |
112 "type": "list-single", | |
113 "options": [ | |
114 { | |
115 "label": D_("to buy"), | |
116 "value": "to_buy" | |
117 }, | |
118 { | |
119 "label": D_("bought"), | |
120 "value": "bought" | |
121 }, | |
122 ], | |
123 "value": "to_buy" | |
124 }, | |
125 ] | |
126 }, | |
127 "tickets": { | |
128 "name": D_("Tickets"), | |
129 "icon": "clipboard", | |
130 "fields": [ | |
131 {"name": "title"}, | |
132 {"name": "author"}, | |
133 {"name": "created"}, | |
134 {"name": "updated"}, | |
135 {"name": "labels", "type": "text-multi"}, | |
136 { | |
137 "name": "type", | |
138 "label": D_("type"), | |
139 "type": "list-single", | |
140 "options": [ | |
141 { | |
142 "label": D_("bug"), | |
143 "value": "bug" | |
144 }, | |
145 { | |
146 "label": D_("feature request"), | |
147 "value": "feature" | |
148 }, | |
149 ], | |
150 "value": "bug" | |
151 }, | |
152 { | |
153 "name": "status", | |
154 "label": D_("status"), | |
155 "type": "list-single", | |
156 "options": [ | |
157 { | |
158 "label": D_("queued"), | |
159 "value": "queued" | |
160 }, | |
161 { | |
162 "label": D_("started"), | |
163 "value": "started" | |
164 }, | |
165 { | |
166 "label": D_("review"), | |
167 "value": "review" | |
168 }, | |
169 { | |
170 "label": D_("closed"), | |
171 "value": "closed" | |
172 }, | |
173 ], | |
174 "value": "queued" | |
175 }, | |
176 { | |
177 "name": "priority", | |
178 "label": D_("priority"), | |
179 "type": "list-single", | |
180 "options": [ | |
181 { | |
182 "label": D_("major"), | |
183 "value": "major" | |
184 }, | |
185 { | |
186 "label": D_("normal"), | |
187 "value": "normal" | |
188 }, | |
189 { | |
190 "label": D_("minor"), | |
191 "value": "minor" | |
192 }, | |
193 ], | |
194 "value": "normal" | |
195 }, | |
196 {"name": "body", "type": "xhtml"}, | |
197 {"name": "comments_uri"}, | |
198 ] | |
199 } | |
40 } | 200 } |
41 | 201 |
42 | 202 |
43 class PubsubLists: | 203 class PubsubLists: |
44 | 204 |
67 form_ns=APP_NS_TICKETS, | 227 form_ns=APP_NS_TICKETS, |
68 filters={ | 228 filters={ |
69 "author": self._s.valueOrPublisherFilter, | 229 "author": self._s.valueOrPublisherFilter, |
70 "created": self._s.dateFilter, | 230 "created": self._s.dateFilter, |
71 "updated": self._s.dateFilter, | 231 "updated": self._s.dateFilter, |
232 "time_limit": self._s.dateFilter, | |
72 }, | 233 }, |
73 profile_key=profile_key), | 234 profile_key=profile_key), |
74 async_=True, | 235 async_=True, |
75 ) | 236 ) |
76 host.bridge.addMethod( | 237 host.bridge.addMethod( |
89 method=lambda service, nodeIdentifier, profile_key: self._s._getUISchema( | 250 method=lambda service, nodeIdentifier, profile_key: self._s._getUISchema( |
90 service, nodeIdentifier, default_node=self.namespace, | 251 service, nodeIdentifier, default_node=self.namespace, |
91 profile_key=profile_key), | 252 profile_key=profile_key), |
92 async_=True, | 253 async_=True, |
93 ) | 254 ) |
255 host.bridge.addMethod( | |
256 "listTemplatesNamesGet", | |
257 ".plugin", | |
258 in_sign="ss", | |
259 out_sign="s", | |
260 method=self._getTemplatesNames, | |
261 ) | |
262 host.bridge.addMethod( | |
263 "listTemplateGet", | |
264 ".plugin", | |
265 in_sign="sss", | |
266 out_sign="s", | |
267 method=self._getTemplate, | |
268 ) | |
269 host.bridge.addMethod( | |
270 "listTemplateCreate", | |
271 ".plugin", | |
272 in_sign="ssss", | |
273 out_sign="(ss)", | |
274 method=self._createTemplate, | |
275 async_=True, | |
276 ) | |
94 | 277 |
95 def _set(self, service, node, values, schema=None, item_id=None, extra='', | 278 def _set(self, service, node, values, schema=None, item_id=None, extra='', |
96 profile_key=C.PROF_KEY_NONE): | 279 profile_key=C.PROF_KEY_NONE): |
97 client, service, node, schema, item_id, extra = self._s.prepareBridgeSet( | 280 client, service, node, schema, item_id, extra = self._s.prepareBridgeSet( |
98 service, node, schema, item_id, extra, profile_key | 281 service, node, schema, item_id, extra, profile_key |
101 client, service, node, values, schema, item_id, extra, deserialise=True | 284 client, service, node, values, schema, item_id, extra, deserialise=True |
102 )) | 285 )) |
103 d.addCallback(lambda ret: ret or "") | 286 d.addCallback(lambda ret: ret or "") |
104 return d | 287 return d |
105 | 288 |
106 async def set(self, client, service, node, values, schema=None, item_id=None, extra=None, | 289 async def set( |
107 deserialise=False, form_ns=APP_NS_TICKETS): | 290 self, client, service, node, values, schema=None, item_id=None, extra=None, |
291 deserialise=False, form_ns=APP_NS_TICKETS | |
292 ): | |
108 """Publish a tickets | 293 """Publish a tickets |
109 | 294 |
110 @param node(unicode, None): Pubsub node to use | 295 @param node(unicode, None): Pubsub node to use |
111 None to use default tickets node | 296 None to use default tickets node |
112 @param values(dict[key(unicode), [iterable[object]|object]]): values of the ticket | 297 @param values(dict[key(unicode), [iterable[object]|object]]): values of the ticket |
150 ) | 335 ) |
151 | 336 |
152 return await self._s.set( | 337 return await self._s.set( |
153 client, service, node, values, schema, item_id, extra, deserialise, form_ns | 338 client, service, node, values, schema, item_id, extra, deserialise, form_ns |
154 ) | 339 ) |
340 | |
341 def _getTemplatesNames(self, language, profile): | |
342 client = self.host.getClient(profile) | |
343 return data_format.serialise(self.getTemplatesNames(client, language)) | |
344 | |
345 def getTemplatesNames(self, client, language: str) -> list: | |
346 """Retrieve well known list templates""" | |
347 | |
348 templates = [{"id": tpl_id, "name": d["name"], "icon": d["icon"]} | |
349 for tpl_id, d in TEMPLATES.items()] | |
350 return templates | |
351 | |
352 def _getTemplate(self, name, language, profile): | |
353 client = self.host.getClient(profile) | |
354 return data_format.serialise(self.getTemplate(client, name, language)) | |
355 | |
356 def getTemplate(self, client, name: str, language: str) -> dict: | |
357 """Retrieve a well known template""" | |
358 return TEMPLATES[name] | |
359 | |
360 def _createTemplate(self, template_id, name, access_model, profile): | |
361 client = self.host.getClient(profile) | |
362 d = defer.ensureDeferred(self.createTemplate( | |
363 client, template_id, name, access_model | |
364 )) | |
365 d.addCallback(lambda node_data: (node_data[0].full(), node_data[1])) | |
366 return d | |
367 | |
368 async def createTemplate( | |
369 self, client, template_id: str, name: str, access_model: str | |
370 ) -> Tuple[jid.JID, str]: | |
371 """Create a list from a template""" | |
372 name = name.strip() | |
373 if not name: | |
374 name = shortuuid.uuid() | |
375 template = TEMPLATES[template_id] | |
376 | |
377 fields = [ | |
378 data_form.Field(fieldType="hidden", var=NS_TICKETS_TYPE, value=template_id) | |
379 ] | |
380 for field_data in template['fields']: | |
381 field_type = field_data.get('type', 'text-single') | |
382 kwargs = { | |
383 "fieldType": field_type, | |
384 "var": field_data["name"], | |
385 "label": field_data.get('label'), | |
386 "value": field_data.get("value"), | |
387 } | |
388 if field_type == "xhtml": | |
389 kwargs.update({ | |
390 "fieldType": None, | |
391 "ext_type": "xml", | |
392 }) | |
393 if kwargs["value"] is None: | |
394 kwargs["value"] = domish.Element((C.NS_XHTML, "div")) | |
395 elif "options" in field_data: | |
396 kwargs["options"] = [ | |
397 data_form.Option(o["value"], o.get("label")) | |
398 for o in field_data["options"] | |
399 ] | |
400 field = data_form.Field(**kwargs) | |
401 fields.append(field) | |
402 | |
403 schema = data_form.Form( | |
404 "form", | |
405 formNamespace=APP_NS_TICKETS, | |
406 fields=fields | |
407 ).toElement() | |
408 | |
409 service = client.jid.userhostJID() | |
410 node = self._s.getSubmittedNS(f"{APP_NS_TICKETS}_{name}") | |
411 options = { | |
412 self._p.OPT_ACCESS_MODEL: access_model | |
413 } | |
414 await self._p.createNode(client, service, node, options) | |
415 await self._s.setSchema(client, service, node, schema) | |
416 list_elt = domish.Element((APP_NS_TICKETS, "list")) | |
417 list_elt["type"] = template_id | |
418 try: | |
419 await self.host.plugins['LIST_INTEREST'].registerPubsub( | |
420 client, APP_NS_TICKETS, service, node, creator=True, | |
421 name=name, element=list_elt) | |
422 except Exception as e: | |
423 log.warning(f"Can't add list to interests: {e}") | |
424 return service, node |