comparison sat/plugins/plugin_misc_lists.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents 26c3e1bc7fb7
children
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
206 206
207 def __init__(self, host): 207 def __init__(self, host):
208 log.info(_("Pubsub lists plugin initialization")) 208 log.info(_("Pubsub lists plugin initialization"))
209 self.host = host 209 self.host = host
210 self._s = self.host.plugins["XEP-0346"] 210 self._s = self.host.plugins["XEP-0346"]
211 self.namespace = self._s.getSubmittedNS(APP_NS_TICKETS) 211 self.namespace = self._s.get_submitted_ns(APP_NS_TICKETS)
212 host.registerNamespace("tickets", APP_NS_TICKETS) 212 host.register_namespace("tickets", APP_NS_TICKETS)
213 host.registerNamespace("tickets_type", NS_TICKETS_TYPE) 213 host.register_namespace("tickets_type", NS_TICKETS_TYPE)
214 self.host.plugins["PUBSUB_INVITATION"].register( 214 self.host.plugins["PUBSUB_INVITATION"].register(
215 APP_NS_TICKETS, self 215 APP_NS_TICKETS, self
216 ) 216 )
217 self._p = self.host.plugins["XEP-0060"] 217 self._p = self.host.plugins["XEP-0060"]
218 self._m = self.host.plugins["XEP-0277"] 218 self._m = self.host.plugins["XEP-0277"]
219 host.bridge.addMethod( 219 host.bridge.add_method(
220 "listGet", 220 "list_get",
221 ".plugin", 221 ".plugin",
222 in_sign="ssiassss", 222 in_sign="ssiassss",
223 out_sign="s", 223 out_sign="s",
224 method=lambda service, node, max_items, items_ids, sub_id, extra, profile_key: 224 method=lambda service, node, max_items, items_ids, sub_id, extra, profile_key:
225 self._s._get( 225 self._s._get(
230 sub_id, 230 sub_id,
231 extra, 231 extra,
232 default_node=self.namespace, 232 default_node=self.namespace,
233 form_ns=APP_NS_TICKETS, 233 form_ns=APP_NS_TICKETS,
234 filters={ 234 filters={
235 "author": self._s.valueOrPublisherFilter, 235 "author": self._s.value_or_publisher_filter,
236 "created": self._s.dateFilter, 236 "created": self._s.date_filter,
237 "updated": self._s.dateFilter, 237 "updated": self._s.date_filter,
238 "time_limit": self._s.dateFilter, 238 "time_limit": self._s.date_filter,
239 }, 239 },
240 profile_key=profile_key), 240 profile_key=profile_key),
241 async_=True, 241 async_=True,
242 ) 242 )
243 host.bridge.addMethod( 243 host.bridge.add_method(
244 "listSet", 244 "list_set",
245 ".plugin", 245 ".plugin",
246 in_sign="ssa{sas}ssss", 246 in_sign="ssa{sas}ssss",
247 out_sign="s", 247 out_sign="s",
248 method=self._set, 248 method=self._set,
249 async_=True, 249 async_=True,
250 ) 250 )
251 host.bridge.addMethod( 251 host.bridge.add_method(
252 "listDeleteItem", 252 "list_delete_item",
253 ".plugin", 253 ".plugin",
254 in_sign="sssbs", 254 in_sign="sssbs",
255 out_sign="", 255 out_sign="",
256 method=self._delete, 256 method=self._delete,
257 async_=True, 257 async_=True,
258 ) 258 )
259 host.bridge.addMethod( 259 host.bridge.add_method(
260 "listSchemaGet", 260 "list_schema_get",
261 ".plugin", 261 ".plugin",
262 in_sign="sss", 262 in_sign="sss",
263 out_sign="s", 263 out_sign="s",
264 method=lambda service, nodeIdentifier, profile_key: self._s._getUISchema( 264 method=lambda service, nodeIdentifier, profile_key: self._s._get_ui_schema(
265 service, nodeIdentifier, default_node=self.namespace, 265 service, nodeIdentifier, default_node=self.namespace,
266 profile_key=profile_key), 266 profile_key=profile_key),
267 async_=True, 267 async_=True,
268 ) 268 )
269 host.bridge.addMethod( 269 host.bridge.add_method(
270 "listsList", 270 "lists_list",
271 ".plugin", 271 ".plugin",
272 in_sign="sss", 272 in_sign="sss",
273 out_sign="s", 273 out_sign="s",
274 method=self._listsList, 274 method=self._lists_list,
275 async_=True, 275 async_=True,
276 ) 276 )
277 host.bridge.addMethod( 277 host.bridge.add_method(
278 "listTemplatesNamesGet", 278 "list_templates_names_get",
279 ".plugin", 279 ".plugin",
280 in_sign="ss", 280 in_sign="ss",
281 out_sign="s", 281 out_sign="s",
282 method=self._getTemplatesNames, 282 method=self._get_templates_names,
283 ) 283 )
284 host.bridge.addMethod( 284 host.bridge.add_method(
285 "listTemplateGet", 285 "list_template_get",
286 ".plugin", 286 ".plugin",
287 in_sign="sss", 287 in_sign="sss",
288 out_sign="s", 288 out_sign="s",
289 method=self._getTemplate, 289 method=self._get_template,
290 ) 290 )
291 host.bridge.addMethod( 291 host.bridge.add_method(
292 "listTemplateCreate", 292 "list_template_create",
293 ".plugin", 293 ".plugin",
294 in_sign="ssss", 294 in_sign="ssss",
295 out_sign="(ss)", 295 out_sign="(ss)",
296 method=self._createTemplate, 296 method=self._create_template,
297 async_=True, 297 async_=True,
298 ) 298 )
299 299
300 async def on_invitation_preflight( 300 async def on_invitation_preflight(
301 self, 301 self,
307 node: str, 307 node: str,
308 item_id: Optional[str], 308 item_id: Optional[str],
309 item_elt: domish.Element 309 item_elt: domish.Element
310 ) -> None: 310 ) -> None:
311 try: 311 try:
312 schema = await self._s.getSchemaForm(client, service, node) 312 schema = await self._s.get_schema_form(client, service, node)
313 except Exception as e: 313 except Exception as e:
314 log.warning(f"Can't retrive node schema as {node!r} [{service}]: {e}") 314 log.warning(f"Can't retrive node schema as {node!r} [{service}]: {e}")
315 else: 315 else:
316 try: 316 try:
317 field_type = schema[NS_TICKETS_TYPE] 317 field_type = schema[NS_TICKETS_TYPE]
321 list_elt = extra["element"] = domish.Element((APP_NS_TICKETS, "list")) 321 list_elt = extra["element"] = domish.Element((APP_NS_TICKETS, "list"))
322 list_elt["type"] = field_type 322 list_elt["type"] = field_type
323 323
324 def _set(self, service, node, values, schema=None, item_id=None, extra_s='', 324 def _set(self, service, node, values, schema=None, item_id=None, extra_s='',
325 profile_key=C.PROF_KEY_NONE): 325 profile_key=C.PROF_KEY_NONE):
326 client, service, node, schema, item_id, extra = self._s.prepareBridgeSet( 326 client, service, node, schema, item_id, extra = self._s.prepare_bridge_set(
327 service, node, schema, item_id, extra_s, profile_key 327 service, node, schema, item_id, extra_s, profile_key
328 ) 328 )
329 d = defer.ensureDeferred(self.set( 329 d = defer.ensureDeferred(self.set(
330 client, service, node, values, schema, item_id, extra, deserialise=True 330 client, service, node, values, schema, item_id, extra, deserialise=True
331 )) 331 ))
344 344
345 if value is not iterable, it will be put in a list 345 if value is not iterable, it will be put in a list
346 'created' and 'updated' will be forced to current time: 346 'created' and 'updated' will be forced to current time:
347 - 'created' is set if item_id is None, i.e. if it's a new ticket 347 - 'created' is set if item_id is None, i.e. if it's a new ticket
348 - 'updated' is set everytime 348 - 'updated' is set everytime
349 @param extra(dict, None): same as for [XEP-0060.sendItem] with additional keys: 349 @param extra(dict, None): same as for [XEP-0060.send_item] with additional keys:
350 - update(bool): if True, get previous item data to merge with current one 350 - update(bool): if True, get previous item data to merge with current one
351 if True, item_id must be set 351 if True, item_id must be set
352 other arguments are same as for [self._s.sendDataFormItem] 352 other arguments are same as for [self._s.send_data_form_item]
353 @return (unicode): id of the created item 353 @return (unicode): id of the created item
354 """ 354 """
355 if not node: 355 if not node:
356 node = self.namespace 356 node = self.namespace
357 357
358 if not item_id: 358 if not item_id:
359 comments_service = await self._m.getCommentsService(client, service) 359 comments_service = await self._m.get_comments_service(client, service)
360 360
361 # we need to use uuid for comments node, because we don't know item id in 361 # 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 362 # 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) 363 # can have a nicer id if serial ids is activated)
364 comments_node = self._m.getCommentsNode( 364 comments_node = self._m.get_comments_node(
365 node + "_" + str(shortuuid.uuid()) 365 node + "_" + str(shortuuid.uuid())
366 ) 366 )
367 options = { 367 options = {
368 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN, 368 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN,
369 self._p.OPT_PERSIST_ITEMS: 1, 369 self._p.OPT_PERSIST_ITEMS: 1,
370 self._p.OPT_DELIVER_PAYLOADS: 1, 370 self._p.OPT_DELIVER_PAYLOADS: 1,
371 self._p.OPT_SEND_ITEM_SUBSCRIBE: 1, 371 self._p.OPT_SEND_ITEM_SUBSCRIBE: 1,
372 self._p.OPT_PUBLISH_MODEL: self._p.ACCESS_OPEN, 372 self._p.OPT_PUBLISH_MODEL: self._p.ACCESS_OPEN,
373 } 373 }
374 await self._p.createNode(client, comments_service, comments_node, options) 374 await self._p.createNode(client, comments_service, comments_node, options)
375 values["comments_uri"] = uri.buildXMPPUri( 375 values["comments_uri"] = uri.build_xmpp_uri(
376 "pubsub", 376 "pubsub",
377 subtype="microblog", 377 subtype="microblog",
378 path=comments_service.full(), 378 path=comments_service.full(),
379 node=comments_node, 379 node=comments_node,
380 ) 380 )
384 ) 384 )
385 385
386 def _delete( 386 def _delete(
387 self, service_s, nodeIdentifier, itemIdentifier, notify, profile_key 387 self, service_s, nodeIdentifier, itemIdentifier, notify, profile_key
388 ): 388 ):
389 client = self.host.getClient(profile_key) 389 client = self.host.get_client(profile_key)
390 return defer.ensureDeferred(self.delete( 390 return defer.ensureDeferred(self.delete(
391 client, 391 client,
392 jid.JID(service_s) if service_s else None, 392 jid.JID(service_s) if service_s else None,
393 nodeIdentifier, 393 nodeIdentifier,
394 itemIdentifier, 394 itemIdentifier,
403 itemIdentifier: str, 403 itemIdentifier: str,
404 notify: Optional[bool] = None 404 notify: Optional[bool] = None
405 ) -> None: 405 ) -> None:
406 if not node: 406 if not node:
407 node = self.namespace 407 node = self.namespace
408 return await self._p.retractItems( 408 return await self._p.retract_items(
409 service, node, (itemIdentifier,), notify, client.profile 409 service, node, (itemIdentifier,), notify, client.profile
410 ) 410 )
411 411
412 def _listsList(self, service, node, profile): 412 def _lists_list(self, service, node, profile):
413 service = jid.JID(service) if service else None 413 service = jid.JID(service) if service else None
414 node = node or None 414 node = node or None
415 client = self.host.getClient(profile) 415 client = self.host.get_client(profile)
416 d = defer.ensureDeferred(self.listsList(client, service, node)) 416 d = defer.ensureDeferred(self.lists_list(client, service, node))
417 d.addCallback(data_format.serialise) 417 d.addCallback(data_format.serialise)
418 return d 418 return d
419 419
420 async def listsList( 420 async def lists_list(
421 self, client, service: Optional[jid.JID], node: Optional[str]=None 421 self, client, service: Optional[jid.JID], node: Optional[str]=None
422 ) -> List[dict]: 422 ) -> List[dict]:
423 """Retrieve list of pubsub lists registered in personal interests 423 """Retrieve list of pubsub lists registered in personal interests
424 424
425 @return list: list of lists metadata 425 @return list: list of lists metadata
426 """ 426 """
427 items, metadata = await self.host.plugins['LIST_INTEREST'].listInterests( 427 items, metadata = await self.host.plugins['LIST_INTEREST'].list_interests(
428 client, service, node, namespace=APP_NS_TICKETS) 428 client, service, node, namespace=APP_NS_TICKETS)
429 lists = [] 429 lists = []
430 for item in items: 430 for item in items:
431 interest_elt = item.interest 431 interest_elt = item.interest
432 if interest_elt is None: 432 if interest_elt is None:
452 list_data["icon_name"] = TEMPLATES[list_type]["icon"] 452 list_data["icon_name"] = TEMPLATES[list_type]["icon"]
453 lists.append(list_data) 453 lists.append(list_data)
454 454
455 return lists 455 return lists
456 456
457 def _getTemplatesNames(self, language, profile): 457 def _get_templates_names(self, language, profile):
458 client = self.host.getClient(profile) 458 client = self.host.get_client(profile)
459 return data_format.serialise(self.getTemplatesNames(client, language)) 459 return data_format.serialise(self.get_templates_names(client, language))
460 460
461 def getTemplatesNames(self, client, language: str) -> list: 461 def get_templates_names(self, client, language: str) -> list:
462 """Retrieve well known list templates""" 462 """Retrieve well known list templates"""
463 463
464 templates = [{"id": tpl_id, "name": d["name"], "icon": d["icon"]} 464 templates = [{"id": tpl_id, "name": d["name"], "icon": d["icon"]}
465 for tpl_id, d in TEMPLATES.items()] 465 for tpl_id, d in TEMPLATES.items()]
466 return templates 466 return templates
467 467
468 def _getTemplate(self, name, language, profile): 468 def _get_template(self, name, language, profile):
469 client = self.host.getClient(profile) 469 client = self.host.get_client(profile)
470 return data_format.serialise(self.getTemplate(client, name, language)) 470 return data_format.serialise(self.get_template(client, name, language))
471 471
472 def getTemplate(self, client, name: str, language: str) -> dict: 472 def get_template(self, client, name: str, language: str) -> dict:
473 """Retrieve a well known template""" 473 """Retrieve a well known template"""
474 return TEMPLATES[name] 474 return TEMPLATES[name]
475 475
476 def _createTemplate(self, template_id, name, access_model, profile): 476 def _create_template(self, template_id, name, access_model, profile):
477 client = self.host.getClient(profile) 477 client = self.host.get_client(profile)
478 d = defer.ensureDeferred(self.createTemplate( 478 d = defer.ensureDeferred(self.create_template(
479 client, template_id, name, access_model 479 client, template_id, name, access_model
480 )) 480 ))
481 d.addCallback(lambda node_data: (node_data[0].full(), node_data[1])) 481 d.addCallback(lambda node_data: (node_data[0].full(), node_data[1]))
482 return d 482 return d
483 483
484 async def createTemplate( 484 async def create_template(
485 self, client, template_id: str, name: str, access_model: str 485 self, client, template_id: str, name: str, access_model: str
486 ) -> Tuple[jid.JID, str]: 486 ) -> Tuple[jid.JID, str]:
487 """Create a list from a template""" 487 """Create a list from a template"""
488 name = name.strip() 488 name = name.strip()
489 if not name: 489 if not name:
491 fields = TEMPLATES[template_id]["fields"].copy() 491 fields = TEMPLATES[template_id]["fields"].copy()
492 fields.insert( 492 fields.insert(
493 0, 493 0,
494 {"type": "hidden", "name": NS_TICKETS_TYPE, "value": template_id} 494 {"type": "hidden", "name": NS_TICKETS_TYPE, "value": template_id}
495 ) 495 )
496 schema = xml_tools.dataDict2dataForm( 496 schema = xml_tools.data_dict_2_data_form(
497 {"namespace": APP_NS_TICKETS, "fields": fields} 497 {"namespace": APP_NS_TICKETS, "fields": fields}
498 ).toElement() 498 ).toElement()
499 499
500 service = client.jid.userhostJID() 500 service = client.jid.userhostJID()
501 node = self._s.getSubmittedNS(f"{APP_NS_TICKETS}_{name}") 501 node = self._s.get_submitted_ns(f"{APP_NS_TICKETS}_{name}")
502 options = { 502 options = {
503 self._p.OPT_ACCESS_MODEL: access_model, 503 self._p.OPT_ACCESS_MODEL: access_model,
504 } 504 }
505 if template_id == "grocery": 505 if template_id == "grocery":
506 # for grocery list, we want all publishers to be able to set all items 506 # for grocery list, we want all publishers to be able to set all items
507 # XXX: should node options be in TEMPLATE? 507 # XXX: should node options be in TEMPLATE?
508 options[self._p.OPT_OVERWRITE_POLICY] = self._p.OWPOL_ANY_PUB 508 options[self._p.OPT_OVERWRITE_POLICY] = self._p.OWPOL_ANY_PUB
509 await self._p.createNode(client, service, node, options) 509 await self._p.createNode(client, service, node, options)
510 await self._s.setSchema(client, service, node, schema) 510 await self._s.set_schema(client, service, node, schema)
511 list_elt = domish.Element((APP_NS_TICKETS, "list")) 511 list_elt = domish.Element((APP_NS_TICKETS, "list"))
512 list_elt["type"] = template_id 512 list_elt["type"] = template_id
513 try: 513 try:
514 await self.host.plugins['LIST_INTEREST'].registerPubsub( 514 await self.host.plugins['LIST_INTEREST'].register_pubsub(
515 client, APP_NS_TICKETS, service, node, creator=True, 515 client, APP_NS_TICKETS, service, node, creator=True,
516 name=name, element=list_elt) 516 name=name, element=list_elt)
517 except Exception as e: 517 except Exception as e:
518 log.warning(f"Can't add list to interests: {e}") 518 log.warning(f"Can't add list to interests: {e}")
519 return service, node 519 return service, node