Mercurial > libervia-backend
comparison sat/plugins/plugin_pubsub_attachments.py @ 3869:c0bcbcf5b4b7
component AP gateway: handle `Like` and `Undo`/`Like` activities:
rel 370
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 21 Jul 2022 18:07:35 +0200 |
parents | ac255a0fbd4c |
children |
comparison
equal
deleted
inserted
replaced
3868:37d2c0282304 | 3869:c0bcbcf5b4b7 |
---|---|
59 def __init__(self, host): | 59 def __init__(self, host): |
60 log.info(_("Pubsub Attachments plugin initialization")) | 60 log.info(_("Pubsub Attachments plugin initialization")) |
61 host.registerNamespace("pubsub-attachments", NS_PUBSUB_ATTACHMENTS) | 61 host.registerNamespace("pubsub-attachments", NS_PUBSUB_ATTACHMENTS) |
62 self.host = host | 62 self.host = host |
63 self._p = host.plugins["XEP-0060"] | 63 self._p = host.plugins["XEP-0060"] |
64 self.handlers = {} | 64 self.handlers: Dict[Tuple[str, str], dict[str, Any]] = {} |
65 host.trigger.add("XEP-0277_send", self.onMBSend) | 65 host.trigger.add("XEP-0277_send", self.onMBSend) |
66 self.registerAttachmentHandler( | 66 self.registerAttachmentHandler( |
67 "noticed", NS_PUBSUB_ATTACHMENTS, self.noticedGet, self.noticedSet | 67 "noticed", NS_PUBSUB_ATTACHMENTS, self.noticedGet, self.noticedSet |
68 ) | 68 ) |
69 self.registerAttachmentHandler( | 69 self.registerAttachmentHandler( |
268 attachments_s: str, | 268 attachments_s: str, |
269 profile_key: str | 269 profile_key: str |
270 ) -> None: | 270 ) -> None: |
271 client = self.host.getClient(profile_key) | 271 client = self.host.getClient(profile_key) |
272 attachments = data_format.deserialise(attachments_s) or {} | 272 attachments = data_format.deserialise(attachments_s) or {} |
273 return defer.ensureDeferred(self.setAttachments( client, attachments)) | 273 return defer.ensureDeferred(self.setAttachments(client, attachments)) |
274 | 274 |
275 async def setAttachments( | 275 def applySetHandler( |
276 self, | 276 self, |
277 client: SatXMPPEntity, | 277 client: SatXMPPEntity, |
278 data: Dict[str, Any] | 278 attachments_data: dict, |
279 ) -> None: | 279 item_elt: Optional[domish.Element], |
280 """Set or update attachments | 280 handlers: Optional[List[Tuple[str, str]]] = None, |
281 | 281 from_jid: Optional[jid.JID] = None, |
282 Former <attachments> element will be retrieved and updated. Individual | 282 ) -> domish.Element: |
283 attachments replace or update their elements individually, according to the | 283 """Apply all ``set`` callbacks to an attachments item |
284 "operation" key. | 284 |
285 | 285 @param attachments_data: data describing the attachments |
286 "operation" key may be "update" or "replace", and defaults to update, it is only | 286 ``extra`` key will be used, and created if not found |
287 used in attachments where "update" makes sense (e.g. it's used for "reactions" | 287 @param from_jid: jid of the author of the attachments |
288 but not for "noticed"). | 288 ``client.jid.userhostJID()`` will be used if not specified |
289 | 289 @param item_elt: item containing an <attachments> element |
290 @param data: microblog data data. Various keys (usually stored in | 290 will be modified in place |
291 data["extra"]) may be used depending on the attachments handlers | 291 if None, a new element will be created |
292 registered. The keys "service", "node" and "id" MUST be set. | 292 @param handlers: list of (name, namespace) of handlers to use. |
293 if None, all registered handlers will be used. | |
294 @return: updated item_elt if given, otherwise a new item_elt | |
293 """ | 295 """ |
294 data.setdefault("extra", {}) | 296 attachments_data.setdefault("extra", {}) |
295 try: | 297 if item_elt is None: |
296 service = jid.JID(data["service"]) | 298 item_id = client.jid.userhost() if from_jid is None else from_jid.userhost() |
297 node = data["node"] | 299 item_elt = pubsub.Item(item_id) |
298 item = data["id"] | |
299 except (KeyError, RuntimeError): | |
300 raise ValueError( | |
301 'data must have "service", "node" and "id" set' | |
302 ) | |
303 attachment_node = self.getAttachmentNodeName(service, node, item) | |
304 items, __ = await self._p.getItems( | |
305 client, service, attachment_node, item_ids=[client.jid.userhost()] | |
306 ) | |
307 if not items: | |
308 # the item doesn't exist, we create a new one | |
309 item_elt = pubsub.Item(client.jid.userhost()) | |
310 item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments")) | 300 item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments")) |
311 else: | |
312 item_elt = items[0] | |
313 | 301 |
314 try: | 302 try: |
315 attachments_elt = next( | 303 attachments_elt = next( |
316 item_elt.elements(NS_PUBSUB_ATTACHMENTS, "attachments") | 304 item_elt.elements(NS_PUBSUB_ATTACHMENTS, "attachments") |
317 ) | 305 ) |
319 log.warning( | 307 log.warning( |
320 f"no <attachments> element found, creating a new one: {item_elt.toXml()}" | 308 f"no <attachments> element found, creating a new one: {item_elt.toXml()}" |
321 ) | 309 ) |
322 attachments_elt = item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments")) | 310 attachments_elt = item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments")) |
323 | 311 |
324 for (name, namespace), handler in self.handlers.items(): | 312 if handlers is None: |
313 handlers = list(self.handlers.keys()) | |
314 | |
315 for name, namespace in handlers: | |
316 try: | |
317 handler = self.handlers[(name, namespace)] | |
318 except KeyError: | |
319 log.error( | |
320 f"unregistered handler ({name!r}, {namespace!r}) is requested, " | |
321 "ignoring" | |
322 ) | |
323 continue | |
325 try: | 324 try: |
326 former_elt = next(attachments_elt.elements(namespace, name)) | 325 former_elt = next(attachments_elt.elements(namespace, name)) |
327 except StopIteration: | 326 except StopIteration: |
328 former_elt = None | 327 former_elt = None |
329 new_elt = handler["set"](client, data, former_elt) | 328 new_elt = handler["set"](client, attachments_data, former_elt) |
330 if new_elt != former_elt: | 329 if new_elt != former_elt: |
331 if former_elt is not None: | 330 if former_elt is not None: |
332 attachments_elt.children.remove(former_elt) | 331 attachments_elt.children.remove(former_elt) |
333 if new_elt is not None: | 332 if new_elt is not None: |
334 attachments_elt.addChild(new_elt) | 333 attachments_elt.addChild(new_elt) |
334 return item_elt | |
335 | |
336 async def setAttachments( | |
337 self, | |
338 client: SatXMPPEntity, | |
339 attachments_data: Dict[str, Any] | |
340 ) -> None: | |
341 """Set or update attachments | |
342 | |
343 Former <attachments> element will be retrieved and updated. Individual | |
344 attachments replace or update their elements individually, according to the | |
345 "operation" key. | |
346 | |
347 "operation" key may be "update" or "replace", and defaults to update, it is only | |
348 used in attachments where "update" makes sense (e.g. it's used for "reactions" | |
349 but not for "noticed"). | |
350 | |
351 @param attachments_data: data describing attachments. Various keys (usually stored | |
352 in attachments_data["extra"]) may be used depending on the attachments | |
353 handlers registered. The keys "service", "node" and "id" MUST be set. | |
354 ``attachments_data`` is thought to be compatible with microblog data. | |
355 | |
356 """ | |
357 try: | |
358 service = jid.JID(attachments_data["service"]) | |
359 node = attachments_data["node"] | |
360 item = attachments_data["id"] | |
361 except (KeyError, RuntimeError): | |
362 raise ValueError( | |
363 'data must have "service", "node" and "id" set' | |
364 ) | |
365 attachment_node = self.getAttachmentNodeName(service, node, item) | |
366 try: | |
367 items, __ = await self._p.getItems( | |
368 client, service, attachment_node, item_ids=[client.jid.userhost()] | |
369 ) | |
370 except exceptions.NotFound: | |
371 item_elt = None | |
372 else: | |
373 if not items: | |
374 item_elt = None | |
375 else: | |
376 item_elt = items[0] | |
377 | |
378 item_elt = self.applySetHandler( | |
379 client, | |
380 attachments_data, | |
381 item_elt=item_elt, | |
382 ) | |
383 | |
335 try: | 384 try: |
336 await self._p.sendItems(client, service, attachment_node, [item_elt]) | 385 await self._p.sendItems(client, service, attachment_node, [item_elt]) |
337 except error.StanzaError as e: | 386 except error.StanzaError as e: |
338 if e.condition == "item-not-found": | 387 if e.condition == "item-not-found": |
339 # the node doesn't exist, we can't publish attachments | 388 # the node doesn't exist, we can't publish attachments |