comparison libervia/backend/plugins/plugin_misc_lists.py @ 4270:0d7bb4df2343

Reformatted code base using black.
author Goffi <goffi@goffi.org>
date Wed, 19 Jun 2024 18:44:57 +0200
parents 4b842c1fb686
children a5d27f69eedb
comparison
equal deleted inserted replaced
4269:64a85ce8be70 4270:0d7bb4df2343
38 PLUGIN_INFO = { 38 PLUGIN_INFO = {
39 C.PI_NAME: _("Pubsub Lists"), 39 C.PI_NAME: _("Pubsub Lists"),
40 C.PI_IMPORT_NAME: "LISTS", 40 C.PI_IMPORT_NAME: "LISTS",
41 C.PI_TYPE: "EXP", 41 C.PI_TYPE: "EXP",
42 C.PI_PROTOCOLS: [], 42 C.PI_PROTOCOLS: [],
43 C.PI_DEPENDENCIES: ["XEP-0060", "XEP-0346", "XEP-0277", "IDENTITY", 43 C.PI_DEPENDENCIES: [
44 "PUBSUB_INVITATION"], 44 "XEP-0060",
45 "XEP-0346",
46 "XEP-0277",
47 "IDENTITY",
48 "PUBSUB_INVITATION",
49 ],
45 C.PI_MAIN: "PubsubLists", 50 C.PI_MAIN: "PubsubLists",
46 C.PI_HANDLER: "no", 51 C.PI_HANDLER: "no",
47 C.PI_DESCRIPTION: _("""Pubsub lists management plugin"""), 52 C.PI_DESCRIPTION: _("""Pubsub lists management plugin"""),
48 } 53 }
49 54
61 { 66 {
62 "name": "status", 67 "name": "status",
63 "label": D_("status"), 68 "label": D_("status"),
64 "type": "list-single", 69 "type": "list-single",
65 "options": [ 70 "options": [
66 { 71 {"label": D_("to do"), "value": "todo"},
67 "label": D_("to do"), 72 {"label": D_("in progress"), "value": "in_progress"},
68 "value": "todo" 73 {"label": D_("done"), "value": "done"},
69 }, 74 ],
70 { 75 "value": "todo",
71 "label": D_("in progress"),
72 "value": "in_progress"
73 },
74 {
75 "label": D_("done"),
76 "value": "done"
77 },
78 ],
79 "value": "todo"
80 }, 76 },
81 { 77 {
82 "name": "priority", 78 "name": "priority",
83 "label": D_("priority"), 79 "label": D_("priority"),
84 "type": "list-single", 80 "type": "list-single",
85 "options": [ 81 "options": [
86 { 82 {"label": D_("major"), "value": "major"},
87 "label": D_("major"), 83 {"label": D_("normal"), "value": "normal"},
88 "value": "major" 84 {"label": D_("minor"), "value": "minor"},
89 }, 85 ],
90 { 86 "value": "normal",
91 "label": D_("normal"),
92 "value": "normal"
93 },
94 {
95 "label": D_("minor"),
96 "value": "minor"
97 },
98 ],
99 "value": "normal"
100 }, 87 },
101 {"name": "body", "type": "xhtml"}, 88 {"name": "body", "type": "xhtml"},
102 {"name": "comments_uri"}, 89 {"name": "comments_uri"},
103 ] 90 ],
104 }, 91 },
105 "grocery": { 92 "grocery": {
106 "name": D_("Grocery List"), 93 "name": D_("Grocery List"),
107 "icon": "basket", 94 "icon": "basket",
108 "fields": [ 95 "fields": [
111 { 98 {
112 "name": "status", 99 "name": "status",
113 "label": D_("status"), 100 "label": D_("status"),
114 "type": "list-single", 101 "type": "list-single",
115 "options": [ 102 "options": [
116 { 103 {"label": D_("to buy"), "value": "to_buy"},
117 "label": D_("to buy"), 104 {"label": D_("bought"), "value": "bought"},
118 "value": "to_buy" 105 ],
119 }, 106 "value": "to_buy",
120 { 107 },
121 "label": D_("bought"), 108 ],
122 "value": "bought"
123 },
124 ],
125 "value": "to_buy"
126 },
127 ]
128 }, 109 },
129 "tickets": { 110 "tickets": {
130 "name": D_("Tickets"), 111 "name": D_("Tickets"),
131 "icon": "clipboard", 112 "icon": "clipboard",
132 "fields": [ 113 "fields": [
138 { 119 {
139 "name": "type", 120 "name": "type",
140 "label": D_("type"), 121 "label": D_("type"),
141 "type": "list-single", 122 "type": "list-single",
142 "options": [ 123 "options": [
143 { 124 {"label": D_("bug"), "value": "bug"},
144 "label": D_("bug"), 125 {"label": D_("feature request"), "value": "feature"},
145 "value": "bug" 126 ],
146 }, 127 "value": "bug",
147 {
148 "label": D_("feature request"),
149 "value": "feature"
150 },
151 ],
152 "value": "bug"
153 }, 128 },
154 { 129 {
155 "name": "status", 130 "name": "status",
156 "label": D_("status"), 131 "label": D_("status"),
157 "type": "list-single", 132 "type": "list-single",
158 "options": [ 133 "options": [
159 { 134 {"label": D_("queued"), "value": "queued"},
160 "label": D_("queued"), 135 {"label": D_("started"), "value": "started"},
161 "value": "queued" 136 {"label": D_("review"), "value": "review"},
162 }, 137 {"label": D_("closed"), "value": "closed"},
163 { 138 ],
164 "label": D_("started"), 139 "value": "queued",
165 "value": "started"
166 },
167 {
168 "label": D_("review"),
169 "value": "review"
170 },
171 {
172 "label": D_("closed"),
173 "value": "closed"
174 },
175 ],
176 "value": "queued"
177 }, 140 },
178 { 141 {
179 "name": "priority", 142 "name": "priority",
180 "label": D_("priority"), 143 "label": D_("priority"),
181 "type": "list-single", 144 "type": "list-single",
182 "options": [ 145 "options": [
183 { 146 {"label": D_("major"), "value": "major"},
184 "label": D_("major"), 147 {"label": D_("normal"), "value": "normal"},
185 "value": "major" 148 {"label": D_("minor"), "value": "minor"},
186 }, 149 ],
187 { 150 "value": "normal",
188 "label": D_("normal"),
189 "value": "normal"
190 },
191 {
192 "label": D_("minor"),
193 "value": "minor"
194 },
195 ],
196 "value": "normal"
197 }, 151 },
198 {"name": "body", "type": "xhtml"}, 152 {"name": "body", "type": "xhtml"},
199 {"name": "comments_uri"}, 153 {"name": "comments_uri"},
200 ] 154 ],
201 } 155 },
202 } 156 }
203 157
204 158
205 class PubsubLists: 159 class PubsubLists:
206 160
209 self.host = host 163 self.host = host
210 self._s = self.host.plugins["XEP-0346"] 164 self._s = self.host.plugins["XEP-0346"]
211 self.namespace = self._s.get_submitted_ns(APP_NS_TICKETS) 165 self.namespace = self._s.get_submitted_ns(APP_NS_TICKETS)
212 host.register_namespace("tickets", APP_NS_TICKETS) 166 host.register_namespace("tickets", APP_NS_TICKETS)
213 host.register_namespace("tickets_type", NS_TICKETS_TYPE) 167 host.register_namespace("tickets_type", NS_TICKETS_TYPE)
214 self.host.plugins["PUBSUB_INVITATION"].register( 168 self.host.plugins["PUBSUB_INVITATION"].register(APP_NS_TICKETS, self)
215 APP_NS_TICKETS, self
216 )
217 self._p = self.host.plugins["XEP-0060"] 169 self._p = self.host.plugins["XEP-0060"]
218 self._m = self.host.plugins["XEP-0277"] 170 self._m = self.host.plugins["XEP-0277"]
219 host.bridge.add_method( 171 host.bridge.add_method(
220 "list_get", 172 "list_get",
221 ".plugin", 173 ".plugin",
222 in_sign="ssiassss", 174 in_sign="ssiassss",
223 out_sign="s", 175 out_sign="s",
224 method=lambda service, node, max_items, items_ids, sub_id, extra, profile_key: 176 method=lambda service, node, max_items, items_ids, sub_id, extra, profile_key: self._s._get(
225 self._s._get(
226 service, 177 service,
227 node, 178 node,
228 max_items, 179 max_items,
229 items_ids, 180 items_ids,
230 sub_id, 181 sub_id,
235 "author": self._s.value_or_publisher_filter, 186 "author": self._s.value_or_publisher_filter,
236 "created": self._s.date_filter, 187 "created": self._s.date_filter,
237 "updated": self._s.date_filter, 188 "updated": self._s.date_filter,
238 "time_limit": self._s.date_filter, 189 "time_limit": self._s.date_filter,
239 }, 190 },
240 profile_key=profile_key), 191 profile_key=profile_key,
192 ),
241 async_=True, 193 async_=True,
242 ) 194 )
243 host.bridge.add_method( 195 host.bridge.add_method(
244 "list_set", 196 "list_set",
245 ".plugin", 197 ".plugin",
260 "list_schema_get", 212 "list_schema_get",
261 ".plugin", 213 ".plugin",
262 in_sign="sss", 214 in_sign="sss",
263 out_sign="s", 215 out_sign="s",
264 method=lambda service, nodeIdentifier, profile_key: self._s._get_ui_schema( 216 method=lambda service, nodeIdentifier, profile_key: self._s._get_ui_schema(
265 service, nodeIdentifier, default_node=self.namespace, 217 service,
266 profile_key=profile_key), 218 nodeIdentifier,
219 default_node=self.namespace,
220 profile_key=profile_key,
221 ),
267 async_=True, 222 async_=True,
268 ) 223 )
269 host.bridge.add_method( 224 host.bridge.add_method(
270 "lists_list", 225 "lists_list",
271 ".plugin", 226 ".plugin",
304 name: str, 259 name: str,
305 extra: dict, 260 extra: dict,
306 service: jid.JID, 261 service: jid.JID,
307 node: str, 262 node: str,
308 item_id: Optional[str], 263 item_id: Optional[str],
309 item_elt: domish.Element 264 item_elt: domish.Element,
310 ) -> None: 265 ) -> None:
311 try: 266 try:
312 schema = await self._s.get_schema_form(client, service, node) 267 schema = await self._s.get_schema_form(client, service, node)
313 except Exception as e: 268 except Exception as e:
314 log.warning(f"Can't retrive node schema as {node!r} [{service}]: {e}") 269 log.warning(f"Can't retrive node schema as {node!r} [{service}]: {e}")
319 log.debug("no type found in list schema") 274 log.debug("no type found in list schema")
320 else: 275 else:
321 list_elt = extra["element"] = domish.Element((APP_NS_TICKETS, "list")) 276 list_elt = extra["element"] = domish.Element((APP_NS_TICKETS, "list"))
322 list_elt["type"] = field_type 277 list_elt["type"] = field_type
323 278
324 def _set(self, service, node, values, schema=None, item_id=None, extra_s='', 279 def _set(
325 profile_key=C.PROF_KEY_NONE): 280 self,
281 service,
282 node,
283 values,
284 schema=None,
285 item_id=None,
286 extra_s="",
287 profile_key=C.PROF_KEY_NONE,
288 ):
326 client, service, node, schema, item_id, extra = self._s.prepare_bridge_set( 289 client, service, node, schema, item_id, extra = self._s.prepare_bridge_set(
327 service, node, schema, item_id, extra_s, profile_key 290 service, node, schema, item_id, extra_s, profile_key
328 ) 291 )
329 d = defer.ensureDeferred(self.set( 292 d = defer.ensureDeferred(
330 client, service, node, values, schema, item_id, extra, deserialise=True 293 self.set(
331 )) 294 client, service, node, values, schema, item_id, extra, deserialise=True
295 )
296 )
332 d.addCallback(lambda ret: ret or "") 297 d.addCallback(lambda ret: ret or "")
333 return d 298 return d
334 299
335 async def set( 300 async def set(
336 self, client, service, node, values, schema=None, item_id=None, extra=None, 301 self,
337 deserialise=False, form_ns=APP_NS_TICKETS 302 client,
303 service,
304 node,
305 values,
306 schema=None,
307 item_id=None,
308 extra=None,
309 deserialise=False,
310 form_ns=APP_NS_TICKETS,
338 ): 311 ):
339 """Publish a tickets 312 """Publish a tickets
340 313
341 @param node(unicode, None): Pubsub node to use 314 @param node(unicode, None): Pubsub node to use
342 None to use default tickets node 315 None to use default tickets node
359 comments_service = await self._m.get_comments_service(client, service) 332 comments_service = await self._m.get_comments_service(client, service)
360 333
361 # we need to use uuid for comments node, because we don't know item id in 334 # we need to use uuid for comments node, because we don't know item id in
362 # advance (we don't want to set it ourselves to let the server choose, so we 335 # advance (we don't want to set it ourselves to let the server choose, so we
363 # can have a nicer id if serial ids is activated) 336 # can have a nicer id if serial ids is activated)
364 comments_node = self._m.get_comments_node( 337 comments_node = self._m.get_comments_node(node + "_" + str(shortuuid.uuid()))
365 node + "_" + str(shortuuid.uuid())
366 )
367 options = { 338 options = {
368 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN, 339 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN,
369 self._p.OPT_PERSIST_ITEMS: 1, 340 self._p.OPT_PERSIST_ITEMS: 1,
370 self._p.OPT_DELIVER_PAYLOADS: 1, 341 self._p.OPT_DELIVER_PAYLOADS: 1,
371 self._p.OPT_SEND_ITEM_SUBSCRIBE: 1, 342 self._p.OPT_SEND_ITEM_SUBSCRIBE: 1,
381 352
382 return await self._s.set( 353 return await self._s.set(
383 client, service, node, values, schema, item_id, extra, deserialise, form_ns 354 client, service, node, values, schema, item_id, extra, deserialise, form_ns
384 ) 355 )
385 356
386 def _delete( 357 def _delete(self, service_s, nodeIdentifier, itemIdentifier, notify, profile_key):
387 self, service_s, nodeIdentifier, itemIdentifier, notify, profile_key
388 ):
389 client = self.host.get_client(profile_key) 358 client = self.host.get_client(profile_key)
390 return defer.ensureDeferred(self.delete( 359 return defer.ensureDeferred(
391 client, 360 self.delete(
392 jid.JID(service_s) if service_s else None, 361 client,
393 nodeIdentifier, 362 jid.JID(service_s) if service_s else None,
394 itemIdentifier, 363 nodeIdentifier,
395 notify 364 itemIdentifier,
396 )) 365 notify,
366 )
367 )
397 368
398 async def delete( 369 async def delete(
399 self, 370 self,
400 client: SatXMPPEntity, 371 client: SatXMPPEntity,
401 service: Optional[jid.JID], 372 service: Optional[jid.JID],
402 node: Optional[str], 373 node: Optional[str],
403 itemIdentifier: str, 374 itemIdentifier: str,
404 notify: Optional[bool] = None 375 notify: Optional[bool] = None,
405 ) -> None: 376 ) -> None:
406 if not node: 377 if not node:
407 node = self.namespace 378 node = self.namespace
408 return await self._p.retract_items( 379 return await self._p.retract_items(
409 service, node, (itemIdentifier,), notify, client.profile 380 service, node, (itemIdentifier,), notify, client.profile
416 d = defer.ensureDeferred(self.lists_list(client, service, node)) 387 d = defer.ensureDeferred(self.lists_list(client, service, node))
417 d.addCallback(data_format.serialise) 388 d.addCallback(data_format.serialise)
418 return d 389 return d
419 390
420 async def lists_list( 391 async def lists_list(
421 self, client, service: Optional[jid.JID], node: Optional[str]=None 392 self, client, service: Optional[jid.JID], node: Optional[str] = None
422 ) -> List[dict]: 393 ) -> List[dict]:
423 """Retrieve list of pubsub lists registered in personal interests 394 """Retrieve list of pubsub lists registered in personal interests
424 395
425 @return list: list of lists metadata 396 @return list: list of lists metadata
426 """ 397 """
427 items, metadata = await self.host.plugins['LIST_INTEREST'].list_interests( 398 items, metadata = await self.host.plugins["LIST_INTEREST"].list_interests(
428 client, service, node, namespace=APP_NS_TICKETS) 399 client, service, node, namespace=APP_NS_TICKETS
400 )
429 lists = [] 401 lists = []
430 for item in items: 402 for item in items:
431 interest_elt = item.interest 403 interest_elt = item.interest
432 if interest_elt is None: 404 if interest_elt is None:
433 log.warning(f"invalid interest for {client.profile}: {item.toXml}") 405 log.warning(f"invalid interest for {client.profile}: {item.toXml}")
459 return data_format.serialise(self.get_templates_names(client, language)) 431 return data_format.serialise(self.get_templates_names(client, language))
460 432
461 def get_templates_names(self, client, language: str) -> list: 433 def get_templates_names(self, client, language: str) -> list:
462 """Retrieve well known list templates""" 434 """Retrieve well known list templates"""
463 435
464 templates = [{"id": tpl_id, "name": d["name"], "icon": d["icon"]} 436 templates = [
465 for tpl_id, d in TEMPLATES.items()] 437 {"id": tpl_id, "name": d["name"], "icon": d["icon"]}
438 for tpl_id, d in TEMPLATES.items()
439 ]
466 return templates 440 return templates
467 441
468 def _get_template(self, name, language, profile): 442 def _get_template(self, name, language, profile):
469 client = self.host.get_client(profile) 443 client = self.host.get_client(profile)
470 return data_format.serialise(self.get_template(client, name, language)) 444 return data_format.serialise(self.get_template(client, name, language))
473 """Retrieve a well known template""" 447 """Retrieve a well known template"""
474 return TEMPLATES[name] 448 return TEMPLATES[name]
475 449
476 def _create_template(self, template_id, name, access_model, profile): 450 def _create_template(self, template_id, name, access_model, profile):
477 client = self.host.get_client(profile) 451 client = self.host.get_client(profile)
478 d = defer.ensureDeferred(self.create_template( 452 d = defer.ensureDeferred(
479 client, template_id, name, access_model 453 self.create_template(client, template_id, name, access_model)
480 )) 454 )
481 d.addCallback(lambda node_data: (node_data[0].full(), node_data[1])) 455 d.addCallback(lambda node_data: (node_data[0].full(), node_data[1]))
482 return d 456 return d
483 457
484 async def create_template( 458 async def create_template(
485 self, client, template_id: str, name: str, access_model: str 459 self, client, template_id: str, name: str, access_model: str
488 name = name.strip() 462 name = name.strip()
489 if not name: 463 if not name:
490 name = shortuuid.uuid() 464 name = shortuuid.uuid()
491 fields = TEMPLATES[template_id]["fields"].copy() 465 fields = TEMPLATES[template_id]["fields"].copy()
492 fields.insert( 466 fields.insert(
493 0, 467 0, {"type": "hidden", "name": NS_TICKETS_TYPE, "value": template_id}
494 {"type": "hidden", "name": NS_TICKETS_TYPE, "value": template_id}
495 ) 468 )
496 schema = xml_tools.data_dict_2_data_form( 469 schema = xml_tools.data_dict_2_data_form(
497 {"namespace": APP_NS_TICKETS, "fields": fields} 470 {"namespace": APP_NS_TICKETS, "fields": fields}
498 ).toElement() 471 ).toElement()
499 472
509 await self._p.createNode(client, service, node, options) 482 await self._p.createNode(client, service, node, options)
510 await self._s.set_schema(client, service, node, schema) 483 await self._s.set_schema(client, service, node, schema)
511 list_elt = domish.Element((APP_NS_TICKETS, "list")) 484 list_elt = domish.Element((APP_NS_TICKETS, "list"))
512 list_elt["type"] = template_id 485 list_elt["type"] = template_id
513 try: 486 try:
514 await self.host.plugins['LIST_INTEREST'].register_pubsub( 487 await self.host.plugins["LIST_INTEREST"].register_pubsub(
515 client, APP_NS_TICKETS, service, node, creator=True, 488 client,
516 name=name, element=list_elt) 489 APP_NS_TICKETS,
490 service,
491 node,
492 creator=True,
493 name=name,
494 element=list_elt,
495 )
517 except Exception as e: 496 except Exception as e:
518 log.warning(f"Can't add list to interests: {e}") 497 log.warning(f"Can't add list to interests: {e}")
519 return service, node 498 return service, node