Mercurial > libervia-backend
diff sat/plugins/plugin_comp_ap_gateway/__init__.py @ 4023:78b5f356900c
component AP gateway: handle attachments
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 23 Mar 2023 15:42:21 +0100 |
parents | 4a2c261646b6 |
children | 44abce96ac6b |
line wrap: on
line diff
--- a/sat/plugins/plugin_comp_ap_gateway/__init__.py Thu Mar 23 15:39:48 2023 +0100 +++ b/sat/plugins/plugin_comp_ap_gateway/__init__.py Thu Mar 23 15:42:21 2023 +0100 @@ -109,7 +109,7 @@ C.PI_DEPENDENCIES: [ "XEP-0050", "XEP-0054", "XEP-0060", "XEP-0084", "XEP-0106", "XEP-0277", "XEP-0292", "XEP-0329", "XEP-0372", "XEP-0424", "XEP-0465", "XEP-0470", - "PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "EVENTS" + "XEP-0447", "PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "EVENTS" ], C.PI_RECOMMENDATIONS: [], C.PI_MAIN: "APGateway", @@ -131,7 +131,7 @@ # 1: log POST objects # 2: log POST and GET objects # 3: log POST and GET objects with HTTP headers for GET requests - verbose = 0 + verbose = 3 def __init__(self, host): self.host = host @@ -144,11 +144,12 @@ self._v = host.plugins["XEP-0292"] self._refs = host.plugins["XEP-0372"] self._r = host.plugins["XEP-0424"] + self._sfs = host.plugins["XEP-0447"] self._pps = host.plugins["XEP-0465"] + self._pa = host.plugins["XEP-0470"] self._c = host.plugins["PUBSUB_CACHE"] self._t = host.plugins["TEXT_SYNTAXES"] self._i = host.plugins["IDENTITY"] - self._pa = host.plugins["XEP-0470"] self._events = host.plugins["EVENTS"] self._p.addManagedNode( "", @@ -487,7 +488,7 @@ return ap_item["object"] else: # this is a blog item - mb_data = await self._m.item2mbdata( + mb_data = await self._m.item_2_mb_data( self.client, found_item, author_jid, node ) ap_item = await self.mb_data_2_ap_item(self.client, mb_data) @@ -901,7 +902,7 @@ pub_key = serialization.load_pem_public_key(pub_key_pem.encode()) return key_id, owner, pub_key - def createActivity( + def create_activity( self, activity: str, actor_id: str, @@ -1094,7 +1095,7 @@ ) else: # blog item - mb_data = await self._m.item2mbdata(client, item, service, node) + mb_data = await self._m.item_2_mb_data(client, item, service, node) author_jid = jid.JID(mb_data["author_jid"]) if subscribe_extra_nodes and not self.isVirtualJID(author_jid): # we subscribe automatically to comment nodes if any @@ -1232,7 +1233,7 @@ if not "noticed" in old_attachment: # new "noticed" attachment, we translate to "Like" activity activity_id = self.buildAPURL("like", item_account, item_id) - activity = self.createActivity( + activity = self.create_activity( TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id ) activity["to"] = [ap_account] @@ -1242,12 +1243,12 @@ if "noticed" in old_attachment: # "noticed" attachment has been removed, we undo the "Like" activity activity_id = self.buildAPURL("like", item_account, item_id) - activity = self.createActivity( + activity = self.create_activity( TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id ) activity["to"] = [ap_account] activity["cc"] = [NS_AP_PUBLIC] - undo = self.createActivity("Undo", publisher_actor_id, activity) + undo = self.create_activity("Undo", publisher_actor_id, activity) await self.signAndPost(inbox, publisher_actor_id, undo) # reactions @@ -1260,7 +1261,7 @@ activity_id = self.buildAPURL( "reaction", item_account, item_id, reaction.encode().hex() ) - reaction_activity = self.createActivity( + reaction_activity = self.create_activity( TYPE_REACTION, publisher_actor_id, item_url, activity_id=activity_id ) @@ -1268,7 +1269,7 @@ reaction_activity["to"] = [ap_account] reaction_activity["cc"] = [NS_AP_PUBLIC] if undo: - activy = self.createActivity( + activy = self.create_activity( "Undo", publisher_actor_id, reaction_activity ) else: @@ -1282,7 +1283,7 @@ if attending != old_attending: activity_type = TYPE_JOIN if attending == "yes" else TYPE_LEAVE activity_id = self.buildAPURL(activity_type.lower(), item_account, item_id) - activity = self.createActivity( + activity = self.create_activity( activity_type, publisher_actor_id, item_url, activity_id=activity_id ) activity["to"] = [ap_account] @@ -1293,7 +1294,7 @@ old_attending = old_attachment.get("rsvp", {}).get("attending", "no") if old_attending == "yes": activity_id = self.buildAPURL(TYPE_LEAVE.lower(), item_account, item_id) - activity = self.createActivity( + activity = self.create_activity( TYPE_LEAVE, publisher_actor_id, item_url, activity_id=activity_id ) activity["to"] = [ap_account] @@ -1645,8 +1646,8 @@ async def ap_item_2_mb_data_and_elt(self, ap_item: dict) -> Tuple[dict, domish.Element]: """Convert AP item to parsed microblog data and corresponding item element""" - mb_data = await self.apItem2MBdata(ap_item) - item_elt = await self._m.data2entry( + mb_data = await self.ap_item_2_mb_data(ap_item) + item_elt = await self._m.mb_data_2_entry_elt( self.client, mb_data, mb_data["id"], None, self._m.namespace ) if "repeated" in mb_data["extra"]: @@ -1742,7 +1743,7 @@ None ) - async def apItem2MBdata(self, ap_item: dict) -> dict: + async def ap_item_2_mb_data(self, ap_item: dict) -> dict: """Convert AP activity or object to microblog data @param ap_item: ActivityPub item to convert @@ -1786,6 +1787,32 @@ False, ) + if "attachment" in ap_object: + attachments = mb_data["extra"][C.KEY_ATTACHMENTS] = [] + for ap_attachment in ap_object["attachment"]: + try: + url = ap_attachment["url"] + except KeyError: + log.warning( + f'"url" missing in AP attachment, ignoring: {ap_attachment}' + ) + continue + + if not url.startswith("http"): + log.warning(f"non HTTP URL in attachment, ignoring: {ap_attachment}") + continue + attachment = {"url": url} + for ap_key, key in ( + ("mediaType", "media_type"), + # XXX: as weird as it seems, "name" is actually used for description + # in AP world + ("name", "desc"), + ): + value = ap_attachment.get(ap_key) + if value: + attachment[key] = value + attachments.append(attachment) + # author if is_activity: authors = await self.apGetActors(ap_item, "actor") @@ -1899,7 +1926,7 @@ TYPE_ITEM, parent_ap_account, parent_item ) - async def repeatedMB2APItem( + async def repeated_mb_2_ap_item( self, mb_data: dict ) -> dict: @@ -1952,7 +1979,7 @@ ) announced_uri = self.buildAPURL("item", repeated_account, rep_item) - announce = self.createActivity( + announce = self.create_activity( "Announce", repeater_id, announced_uri, activity_id=activity_id ) announce["to"] = [NS_AP_PUBLIC] @@ -1988,7 +2015,7 @@ """ extra = mb_data.get("extra", {}) if "repeated" in extra: - return await self.repeatedMB2APItem(mb_data) + return await self.repeated_mb_2_ap_item(mb_data) if not mb_data.get("id"): mb_data["id"] = shortuuid.uuid() if not mb_data.get("author_jid"): @@ -2011,6 +2038,32 @@ if language: ap_object["contentMap"] = {language: ap_object["content"]} + attachments = extra.get(C.KEY_ATTACHMENTS) + if attachments: + ap_attachments = ap_object["attachment"] = [] + for attachment in attachments: + try: + url = next( + s['url'] for s in attachment["sources"] if 'url' in s + ) + except (StopIteration, KeyError): + log.warning( + f"Ignoring attachment without URL: {attachment}" + ) + continue + ap_attachment = { + "url": url + } + for key, ap_key in ( + ("media_type", "mediaType"), + # XXX: yes "name", cf. [ap_item_2_mb_data] + ("desc", "name"), + ): + value = attachment.get(key) + if value: + ap_attachment[ap_key] = value + ap_attachments.append(ap_attachment) + if public: ap_object["to"] = [NS_AP_PUBLIC] if self.auto_mentions: @@ -2068,7 +2121,7 @@ mb_data ) - return self.createActivity( + return self.create_activity( "Create" if is_new else "Update", url_actor, ap_object, activity_id=url_item ) @@ -2144,12 +2197,12 @@ ) else: try: - mb_data = await self._m.item2mbdata(self.client, items[0].data, jid_, node) + mb_data = await self._m.item_2_mb_data(self.client, items[0].data, jid_, node) if "repeated" in mb_data["extra"]: # we are deleting a repeated item, we must translate this to an # "Undo" of the "Announce" activity instead of a "Delete" one - announce = await self.repeatedMB2APItem(mb_data) - undo = self.createActivity("Undo", author_actor_id, announce) + announce = await self.repeated_mb_2_ap_item(mb_data) + undo = self.create_activity("Undo", author_actor_id, announce) return author_actor_id, undo except Exception as e: log.debug( @@ -2158,7 +2211,7 @@ ) url_item = self.buildAPURL(TYPE_ITEM, author_account, item_id) - ap_item = self.createActivity( + ap_item = self.create_activity( "Delete", author_actor_id, { @@ -2223,6 +2276,12 @@ if origin_id: # we need to use origin ID when present to be able to retract the message mb_data["id"] = origin_id + attachments = mess_data["extra"].get(C.KEY_ATTACHMENTS) + if attachments: + mb_data["extra"] = { + C.KEY_ATTACHMENTS: attachments + } + client = self.client.getVirtualClient(mess_data["from"]) ap_item = await self.mb_data_2_ap_item(client, mb_data, public=False) ap_object = ap_item["object"] @@ -2339,7 +2398,7 @@ cached_item = cached_items[0] - mb_data = await self._m.item2mbdata( + mb_data = await self._m.item_2_mb_data( client, cached_item.data, pubsub_service, pubsub_node ) ap_item = await self.mb_data_2_ap_item(client, mb_data) @@ -2396,7 +2455,7 @@ f"Can't find parent item at {parent_item_service} (node " f"{parent_item_node!r})\n{pformat(ap_item)}") return - parent_item_parsed = await self._m.item2mbdata( + parent_item_parsed = await self._m.item_2_mb_data( client, parent_item_elt, parent_item_service, parent_item_node ) try: @@ -2488,7 +2547,7 @@ is_public, targets, mentions = self.getAPItemTargets(item) if not is_public and targets.keys() == {TYPE_ACTOR}: # this is a direct message - await self.handleMessageAPItem( + await self.handle_message_ap_item( client, targets, mentions, destinee, item ) else: @@ -2496,7 +2555,7 @@ client, targets, mentions, destinee, node, item, is_public ) - async def handleMessageAPItem( + async def handle_message_ap_item( self, client: SatXMPPEntity, targets: Dict[str, Set[str]], @@ -2517,7 +2576,14 @@ } if destinee is not None: targets_jids.add(destinee) - mb_data = await self.apItem2MBdata(item) + mb_data = await self.ap_item_2_mb_data(item) + extra = { + "origin_id": mb_data["id"] + } + attachments = mb_data["extra"].get(C.KEY_ATTACHMENTS) + if attachments: + extra[C.KEY_ATTACHMENTS] = attachments + defer_l = [] for target_jid in targets_jids: defer_l.append( @@ -2525,7 +2591,7 @@ target_jid, {'': mb_data.get("content", "")}, mb_data.get("title"), - extra={"origin_id": mb_data["id"]} + extra=extra ) ) await defer.DeferredList(defer_l)