diff 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
line wrap: on
line diff
--- a/sat/plugins/plugin_pubsub_attachments.py	Thu Jul 21 18:05:20 2022 +0200
+++ b/sat/plugins/plugin_pubsub_attachments.py	Thu Jul 21 18:07:35 2022 +0200
@@ -61,7 +61,7 @@
         host.registerNamespace("pubsub-attachments", NS_PUBSUB_ATTACHMENTS)
         self.host = host
         self._p = host.plugins["XEP-0060"]
-        self.handlers = {}
+        self.handlers: Dict[Tuple[str, str], dict[str, Any]] = {}
         host.trigger.add("XEP-0277_send", self.onMBSend)
         self.registerAttachmentHandler(
             "noticed", NS_PUBSUB_ATTACHMENTS, self.noticedGet, self.noticedSet
@@ -270,12 +270,73 @@
     ) -> None:
         client = self.host.getClient(profile_key)
         attachments = data_format.deserialise(attachments_s)  or {}
-        return defer.ensureDeferred(self.setAttachments( client, attachments))
+        return defer.ensureDeferred(self.setAttachments(client, attachments))
+
+    def applySetHandler(
+        self,
+        client: SatXMPPEntity,
+        attachments_data: dict,
+        item_elt: Optional[domish.Element],
+        handlers: Optional[List[Tuple[str, str]]] = None,
+        from_jid: Optional[jid.JID] = None,
+    ) -> domish.Element:
+        """Apply all ``set`` callbacks to an attachments item
+
+        @param attachments_data: data describing the attachments
+            ``extra`` key will be used, and created if not found
+        @param from_jid: jid of the author of the attachments
+            ``client.jid.userhostJID()`` will be used if not specified
+        @param item_elt: item containing an <attachments> element
+            will be modified in place
+            if None, a new element will be created
+        @param handlers: list of (name, namespace) of handlers to use.
+            if None, all registered handlers will be used.
+        @return: updated item_elt if given, otherwise a new item_elt
+        """
+        attachments_data.setdefault("extra", {})
+        if item_elt is None:
+            item_id = client.jid.userhost() if from_jid is None else from_jid.userhost()
+            item_elt = pubsub.Item(item_id)
+            item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments"))
+
+        try:
+            attachments_elt = next(
+                item_elt.elements(NS_PUBSUB_ATTACHMENTS, "attachments")
+            )
+        except StopIteration:
+            log.warning(
+                f"no <attachments> element found, creating a new one: {item_elt.toXml()}"
+            )
+            attachments_elt = item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments"))
+
+        if handlers is None:
+            handlers = list(self.handlers.keys())
+
+        for name, namespace in handlers:
+            try:
+                handler = self.handlers[(name, namespace)]
+            except KeyError:
+                log.error(
+                    f"unregistered handler ({name!r}, {namespace!r}) is requested, "
+                    "ignoring"
+                )
+                continue
+            try:
+                former_elt = next(attachments_elt.elements(namespace, name))
+            except StopIteration:
+                former_elt = None
+            new_elt = handler["set"](client, attachments_data, former_elt)
+            if new_elt != former_elt:
+                if former_elt is not None:
+                    attachments_elt.children.remove(former_elt)
+                if new_elt is not None:
+                    attachments_elt.addChild(new_elt)
+        return item_elt
 
     async def setAttachments(
         self,
         client: SatXMPPEntity,
-        data: Dict[str, Any]
+        attachments_data: Dict[str, Any]
     ) -> None:
         """Set or update attachments
 
@@ -287,51 +348,39 @@
         used in attachments where "update" makes sense (e.g. it's used for "reactions"
         but not for "noticed").
 
-        @param data: microblog data data. Various keys (usually stored in
-            data["extra"]) may be used depending on the attachments handlers
-            registered. The keys "service", "node" and "id" MUST be set.
+        @param attachments_data: data describing attachments. Various keys (usually stored
+            in attachments_data["extra"]) may be used depending on the attachments
+            handlers registered. The keys "service", "node" and "id" MUST be set.
+            ``attachments_data`` is thought to be compatible with microblog data.
+
         """
-        data.setdefault("extra", {})
         try:
-            service = jid.JID(data["service"])
-            node = data["node"]
-            item = data["id"]
+            service = jid.JID(attachments_data["service"])
+            node = attachments_data["node"]
+            item = attachments_data["id"]
         except (KeyError, RuntimeError):
             raise ValueError(
                 'data must have "service", "node" and "id" set'
             )
         attachment_node = self.getAttachmentNodeName(service, node, item)
-        items, __ = await self._p.getItems(
-            client, service, attachment_node, item_ids=[client.jid.userhost()]
-        )
-        if not items:
-            # the item doesn't exist, we create a new one
-            item_elt = pubsub.Item(client.jid.userhost())
-            item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments"))
-        else:
-            item_elt = items[0]
-
         try:
-            attachments_elt = next(
-                item_elt.elements(NS_PUBSUB_ATTACHMENTS, "attachments")
+            items, __ = await self._p.getItems(
+                client, service, attachment_node, item_ids=[client.jid.userhost()]
             )
-        except StopIteration:
-            log.warning(
-                f"no <attachments> element found, creating a new one: {item_elt.toXml()}"
-            )
-            attachments_elt = item_elt.addElement((NS_PUBSUB_ATTACHMENTS, "attachments"))
+        except exceptions.NotFound:
+            item_elt = None
+        else:
+            if not items:
+                item_elt = None
+            else:
+                item_elt = items[0]
 
-        for (name, namespace), handler in self.handlers.items():
-            try:
-                former_elt = next(attachments_elt.elements(namespace, name))
-            except StopIteration:
-                former_elt = None
-            new_elt = handler["set"](client, data, former_elt)
-            if new_elt != former_elt:
-                if former_elt is not None:
-                    attachments_elt.children.remove(former_elt)
-                if new_elt is not None:
-                    attachments_elt.addChild(new_elt)
+        item_elt = self.applySetHandler(
+            client,
+            attachments_data,
+            item_elt=item_elt,
+        )
+
         try:
             await self._p.sendItems(client, service, attachment_node, [item_elt])
         except error.StanzaError as e: