diff libervia/backend/plugins/plugin_comp_ap_gateway/pubsub_service.py @ 4259:49019947cc76

component AP Gateway: implement HTTP GET signature.
author Goffi <goffi@goffi.org>
date Wed, 05 Jun 2024 22:34:09 +0200
parents 92551baea115
children 0d7bb4df2343
line wrap: on
line diff
--- a/libervia/backend/plugins/plugin_comp_ap_gateway/pubsub_service.py	Wed Jun 05 22:33:37 2024 +0200
+++ b/libervia/backend/plugins/plugin_comp_ap_gateway/pubsub_service.py	Wed Jun 05 22:34:09 2024 +0200
@@ -144,27 +144,51 @@
                     [(subscription.subscriber, None, items)]
                 )
 
-    async def ap_following_2_elt(self, ap_item: dict) -> domish.Element:
-        """Convert actor ID from following collection to XMPP item"""
+    async def ap_following_2_elt(self, requestor_actor_id: str, ap_item: dict) -> domish.Element:
+        """Convert actor ID from following collection to XMPP item
+
+        @param requestor_actor_id: ID of the actor doing the request.
+        @param ap_item: AP item from which actor ID must be extracted.
+        """
         actor_id = ap_item["id"]
-        actor_jid = await self.apg.get_jid_from_id(actor_id)
+        actor_jid = await self.apg.get_jid_from_id(requestor_actor_id, actor_id)
         subscription_elt = self.apg._pps.build_subscription_elt(
             self.apg._m.namespace, actor_jid
         )
         item_elt = pubsub.Item(id=actor_id, payload=subscription_elt)
         return item_elt
 
-    async def ap_follower_2_elt(self, ap_item: dict) -> domish.Element:
-        """Convert actor ID from followers collection to XMPP item"""
+    async def ap_follower_2_elt(
+        self,
+        requestor_actor_id: str,
+        ap_item: dict
+    ) -> domish.Element:
+        """Convert actor ID from followers collection to XMPP item
+
+        @param requestor_actor_id: ID of the actor doing the request.
+        @param ap_item: AP item from which actor ID must be extracted.
+        """
         actor_id = ap_item["id"]
-        actor_jid = await self.apg.get_jid_from_id(actor_id)
+        actor_jid = await self.apg.get_jid_from_id(requestor_actor_id, actor_id)
         subscriber_elt = self.apg._pps.build_subscriber_elt(actor_jid)
         item_elt = pubsub.Item(id=actor_id, payload=subscriber_elt)
         return item_elt
 
-    async def generate_v_card(self, ap_account: str) -> domish.Element:
-        """Generate vCard4 (XEP-0292) item element from ap_account's metadata"""
-        actor_data = await self.apg.get_ap_actor_data_from_account(ap_account)
+    async def generate_v_card(
+        self,
+        requestor_actor_id: str,
+        ap_account: str
+    ) -> domish.Element:
+        """Generate vCard4 (XEP-0292) item element from ap_account's metadata
+
+        @param requestor_actor_id: ID of the actor doing the request.
+        @param ap_account: AP account from where the vcard must be retrieved.
+        @return: <item> with the <vcard> element
+        """
+        actor_data = await self.apg.get_ap_actor_data_from_account(
+            requestor_actor_id,
+            ap_account
+        )
         identity_data = {}
 
         summary = actor_data.get("summary")
@@ -190,16 +214,21 @@
     async def get_avatar_data(
         self,
         client: SatXMPPEntity,
+        requestor_actor_id: str,
         ap_account: str
-    ) -> Dict[str, Any]:
+    ) -> dict[str, Any]:
         """Retrieve actor's avatar if any, cache it and file actor_data
 
-        ``cache_uid``, `path``` and ``media_type`` keys are always files
-        ``base64`` key is only filled if the file was not already in cache
+        @param client: client to use for the request.
+        @param requestor_actor_id: ID of the actor doing the request.
+        @param ap_account: AP account from where the avatar data must be retrieved.
+        @return: Avatar data.
+            ``cache_uid``, `path``` and ``media_type`` keys are always filed.
+            ``base64`` key is only filled if the file was not already in cache.
         """
         actor_data = await self.apg.get_ap_actor_data_from_account(ap_account)
 
-        for icon in await self.apg.ap_get_list(actor_data, "icon"):
+        for icon in await self.apg.ap_get_list(requestor_actor_id, actor_data, "icon"):
             url = icon.get("url")
             if icon["type"] != "Image" or not url:
                 continue
@@ -249,14 +278,16 @@
     async def generate_avatar_metadata(
         self,
         client: SatXMPPEntity,
+        requestor_actor_id: str,
         ap_account: str
     ) -> domish.Element:
         """Generate the metadata element for user avatar
 
+        @param requestor_actor_id: ID of the actor doing the request.
         @raise StanzaError("item-not-found"): no avatar is present in actor data (in
             ``icon`` field)
         """
-        avatar_data = await self.get_avatar_data(client, ap_account)
+        avatar_data = await self.get_avatar_data(client, requestor_actor_id, ap_account)
         return self.apg._a.build_item_metadata_elt(avatar_data)
 
     def _blocking_b_6_4_encode_avatar(self, avatar_data: Dict[str, Any]) -> None:
@@ -266,17 +297,26 @@
     async def generate_avatar_data(
         self,
         client: SatXMPPEntity,
+        requestor_actor_id: str,
         ap_account: str,
         itemIdentifiers: Optional[List[str]],
     ) -> domish.Element:
         """Generate the data element for user avatar
 
+        @param requestor_actor_id: ID of the actor doing the request.
         @raise StanzaError("item-not-found"): no avatar cached with requested ID
         """
         if not itemIdentifiers:
-            avatar_data = await self.get_avatar_data(client, ap_account)
+            avatar_data = await self.get_avatar_data(
+                client,
+                requestor_actor_id,
+                ap_account
+            )
             if "base64" not in avatar_data:
-                await threads.deferToThread(self._blocking_b_6_4_encode_avatar, avatar_data)
+                await threads.deferToThread(
+                    self._blocking_b_6_4_encode_avatar,
+                    avatar_data
+                )
         else:
             if len(itemIdentifiers) > 1:
                 # only a single item ID is supported
@@ -312,6 +352,11 @@
             log.warning(f"Invalid AP account used by {requestor}: {ap_account!r}")
             return [], None
 
+        requestor_actor_id = self.apg.build_apurl(
+            TYPE_ACTOR,
+            await self.apg.get_ap_account_from_jid_and_node(service, node)
+        )
+
         # cached_node may be pre-filled with some nodes (e.g. attachments nodes),
         # otherwise it is filled when suitable
         cached_node = None
@@ -330,14 +375,21 @@
             use_cache = False
         elif node == self.apg._v.node:
             # vCard4 request
-            item_elt = await self.generate_v_card(ap_account)
+            item_elt = await self.generate_v_card(requestor_actor_id, ap_account)
             return [item_elt], None
         elif node == self.apg._a.namespace_metadata:
-            item_elt = await self.generate_avatar_metadata(self.apg.client, ap_account)
+            item_elt = await self.generate_avatar_metadata(
+                self.apg.client,
+                requestor_actor_id,
+                ap_account
+            )
             return [item_elt], None
         elif node == self.apg._a.namespace_data:
             item_elt = await self.generate_avatar_data(
-                self.apg.client, ap_account, itemIdentifiers
+                self.apg.client,
+                requestor_actor_id,
+                ap_account,
+                itemIdentifiers
             )
             return [item_elt], None
         elif self.apg._pa.is_attachment_node(node):
@@ -384,8 +436,8 @@
         if itemIdentifiers:
             items = []
             for item_id in itemIdentifiers:
-                item_data = await self.apg.ap_get(item_id)
-                item_elt = await parser(item_data)
+                item_data = await self.apg.ap_get(item_id, requestor_actor_id)
+                item_elt = await parser(requestor_actor_id, item_data)
                 items.append(item_elt)
             return items, None
         else:
@@ -422,8 +474,9 @@
             if self.apg._m.is_comment_node(node):
                 parent_item = self.apg._m.get_parent_item(node)
                 try:
-                    parent_data = await self.apg.ap_get(parent_item)
+                    parent_data = await self.apg.ap_get(parent_item, requestor_actor_id)
                     collection = await self.apg.ap_get_object(
+                        requestor_actor_id,
                         parent_data.get("object", {}),
                         "replies"
                     )
@@ -433,8 +486,11 @@
                         text=str(e)
                     )
             else:
-                actor_data = await self.apg.get_ap_actor_data_from_account(ap_account)
-                collection = await self.apg.ap_get_object(actor_data, collection_name)
+                actor_data = await self.apg.get_ap_actor_data_from_account(
+                    requestor_actor_id,
+                    ap_account
+                )
+                collection = await self.apg.ap_get_object(requestor_actor_id, actor_data, collection_name)
             if not collection:
                 raise error.StanzaError(
                     "item-not-found",
@@ -442,7 +498,7 @@
                 )
 
             kwargs["parser"] = parser
-            return await self.apg.get_ap_items(collection, **kwargs)
+            return await self.apg.get_ap_items(requestor_actor_id, collection, **kwargs)
 
     @ensure_deferred
     async def retract(self, requestor, service, nodeIdentifier, itemIdentifiers):