Mercurial > libervia-backend
comparison 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 |
comparison
equal
deleted
inserted
replaced
4022:cdb7de398c85 | 4023:78b5f356900c |
---|---|
107 C.PI_TYPE: C.PLUG_TYPE_ENTRY_POINT, | 107 C.PI_TYPE: C.PLUG_TYPE_ENTRY_POINT, |
108 C.PI_PROTOCOLS: [], | 108 C.PI_PROTOCOLS: [], |
109 C.PI_DEPENDENCIES: [ | 109 C.PI_DEPENDENCIES: [ |
110 "XEP-0050", "XEP-0054", "XEP-0060", "XEP-0084", "XEP-0106", "XEP-0277", | 110 "XEP-0050", "XEP-0054", "XEP-0060", "XEP-0084", "XEP-0106", "XEP-0277", |
111 "XEP-0292", "XEP-0329", "XEP-0372", "XEP-0424", "XEP-0465", "XEP-0470", | 111 "XEP-0292", "XEP-0329", "XEP-0372", "XEP-0424", "XEP-0465", "XEP-0470", |
112 "PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "EVENTS" | 112 "XEP-0447", "PUBSUB_CACHE", "TEXT_SYNTAXES", "IDENTITY", "EVENTS" |
113 ], | 113 ], |
114 C.PI_RECOMMENDATIONS: [], | 114 C.PI_RECOMMENDATIONS: [], |
115 C.PI_MAIN: "APGateway", | 115 C.PI_MAIN: "APGateway", |
116 C.PI_HANDLER: C.BOOL_TRUE, | 116 C.PI_HANDLER: C.BOOL_TRUE, |
117 C.PI_DESCRIPTION: _( | 117 C.PI_DESCRIPTION: _( |
129 IMPORT_NAME = IMPORT_NAME | 129 IMPORT_NAME = IMPORT_NAME |
130 # show data send or received through HTTP, used for debugging | 130 # show data send or received through HTTP, used for debugging |
131 # 1: log POST objects | 131 # 1: log POST objects |
132 # 2: log POST and GET objects | 132 # 2: log POST and GET objects |
133 # 3: log POST and GET objects with HTTP headers for GET requests | 133 # 3: log POST and GET objects with HTTP headers for GET requests |
134 verbose = 0 | 134 verbose = 3 |
135 | 135 |
136 def __init__(self, host): | 136 def __init__(self, host): |
137 self.host = host | 137 self.host = host |
138 self.initialised = False | 138 self.initialised = False |
139 self.client = None | 139 self.client = None |
142 self._e = host.plugins["XEP-0106"] | 142 self._e = host.plugins["XEP-0106"] |
143 self._m = host.plugins["XEP-0277"] | 143 self._m = host.plugins["XEP-0277"] |
144 self._v = host.plugins["XEP-0292"] | 144 self._v = host.plugins["XEP-0292"] |
145 self._refs = host.plugins["XEP-0372"] | 145 self._refs = host.plugins["XEP-0372"] |
146 self._r = host.plugins["XEP-0424"] | 146 self._r = host.plugins["XEP-0424"] |
147 self._sfs = host.plugins["XEP-0447"] | |
147 self._pps = host.plugins["XEP-0465"] | 148 self._pps = host.plugins["XEP-0465"] |
149 self._pa = host.plugins["XEP-0470"] | |
148 self._c = host.plugins["PUBSUB_CACHE"] | 150 self._c = host.plugins["PUBSUB_CACHE"] |
149 self._t = host.plugins["TEXT_SYNTAXES"] | 151 self._t = host.plugins["TEXT_SYNTAXES"] |
150 self._i = host.plugins["IDENTITY"] | 152 self._i = host.plugins["IDENTITY"] |
151 self._pa = host.plugins["XEP-0470"] | |
152 self._events = host.plugins["EVENTS"] | 153 self._events = host.plugins["EVENTS"] |
153 self._p.addManagedNode( | 154 self._p.addManagedNode( |
154 "", | 155 "", |
155 items_cb=self._itemsReceived, | 156 items_cb=self._itemsReceived, |
156 # we want to be sure that the callbacks are launched before pubsub cache's | 157 # we want to be sure that the callbacks are launched before pubsub cache's |
485 # the URL must return the object and not the activity | 486 # the URL must return the object and not the activity |
486 ap_item["object"]["@context"] = ap_item["@context"] | 487 ap_item["object"]["@context"] = ap_item["@context"] |
487 return ap_item["object"] | 488 return ap_item["object"] |
488 else: | 489 else: |
489 # this is a blog item | 490 # this is a blog item |
490 mb_data = await self._m.item2mbdata( | 491 mb_data = await self._m.item_2_mb_data( |
491 self.client, found_item, author_jid, node | 492 self.client, found_item, author_jid, node |
492 ) | 493 ) |
493 ap_item = await self.mb_data_2_ap_item(self.client, mb_data) | 494 ap_item = await self.mb_data_2_ap_item(self.client, mb_data) |
494 # the URL must return the object and not the activity | 495 # the URL must return the object and not the activity |
495 return ap_item["object"] | 496 return ap_item["object"] |
899 owner = pub_key_data["owner"] | 900 owner = pub_key_data["owner"] |
900 pub_key_pem = pub_key_data["publicKeyPem"] | 901 pub_key_pem = pub_key_data["publicKeyPem"] |
901 pub_key = serialization.load_pem_public_key(pub_key_pem.encode()) | 902 pub_key = serialization.load_pem_public_key(pub_key_pem.encode()) |
902 return key_id, owner, pub_key | 903 return key_id, owner, pub_key |
903 | 904 |
904 def createActivity( | 905 def create_activity( |
905 self, | 906 self, |
906 activity: str, | 907 activity: str, |
907 actor_id: str, | 908 actor_id: str, |
908 object_: Optional[Union[str, dict]] = None, | 909 object_: Optional[Union[str, dict]] = None, |
909 target: Optional[Union[str, dict]] = None, | 910 target: Optional[Union[str, dict]] = None, |
1092 ap_item = await self.ap_events.event_data_2_ap_item( | 1093 ap_item = await self.ap_events.event_data_2_ap_item( |
1093 event_data, author_jid, is_new=is_new | 1094 event_data, author_jid, is_new=is_new |
1094 ) | 1095 ) |
1095 else: | 1096 else: |
1096 # blog item | 1097 # blog item |
1097 mb_data = await self._m.item2mbdata(client, item, service, node) | 1098 mb_data = await self._m.item_2_mb_data(client, item, service, node) |
1098 author_jid = jid.JID(mb_data["author_jid"]) | 1099 author_jid = jid.JID(mb_data["author_jid"]) |
1099 if subscribe_extra_nodes and not self.isVirtualJID(author_jid): | 1100 if subscribe_extra_nodes and not self.isVirtualJID(author_jid): |
1100 # we subscribe automatically to comment nodes if any | 1101 # we subscribe automatically to comment nodes if any |
1101 recipient_jid = self.getLocalJIDFromAccount(ap_account) | 1102 recipient_jid = self.getLocalJIDFromAccount(ap_account) |
1102 recipient_client = self.client.getVirtualClient(recipient_jid) | 1103 recipient_client = self.client.getVirtualClient(recipient_jid) |
1230 # noticed | 1231 # noticed |
1231 if "noticed" in attachments: | 1232 if "noticed" in attachments: |
1232 if not "noticed" in old_attachment: | 1233 if not "noticed" in old_attachment: |
1233 # new "noticed" attachment, we translate to "Like" activity | 1234 # new "noticed" attachment, we translate to "Like" activity |
1234 activity_id = self.buildAPURL("like", item_account, item_id) | 1235 activity_id = self.buildAPURL("like", item_account, item_id) |
1235 activity = self.createActivity( | 1236 activity = self.create_activity( |
1236 TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id | 1237 TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id |
1237 ) | 1238 ) |
1238 activity["to"] = [ap_account] | 1239 activity["to"] = [ap_account] |
1239 activity["cc"] = [NS_AP_PUBLIC] | 1240 activity["cc"] = [NS_AP_PUBLIC] |
1240 await self.signAndPost(inbox, publisher_actor_id, activity) | 1241 await self.signAndPost(inbox, publisher_actor_id, activity) |
1241 else: | 1242 else: |
1242 if "noticed" in old_attachment: | 1243 if "noticed" in old_attachment: |
1243 # "noticed" attachment has been removed, we undo the "Like" activity | 1244 # "noticed" attachment has been removed, we undo the "Like" activity |
1244 activity_id = self.buildAPURL("like", item_account, item_id) | 1245 activity_id = self.buildAPURL("like", item_account, item_id) |
1245 activity = self.createActivity( | 1246 activity = self.create_activity( |
1246 TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id | 1247 TYPE_LIKE, publisher_actor_id, item_url, activity_id=activity_id |
1247 ) | 1248 ) |
1248 activity["to"] = [ap_account] | 1249 activity["to"] = [ap_account] |
1249 activity["cc"] = [NS_AP_PUBLIC] | 1250 activity["cc"] = [NS_AP_PUBLIC] |
1250 undo = self.createActivity("Undo", publisher_actor_id, activity) | 1251 undo = self.create_activity("Undo", publisher_actor_id, activity) |
1251 await self.signAndPost(inbox, publisher_actor_id, undo) | 1252 await self.signAndPost(inbox, publisher_actor_id, undo) |
1252 | 1253 |
1253 # reactions | 1254 # reactions |
1254 new_reactions = set(attachments.get("reactions", {}).get("reactions", [])) | 1255 new_reactions = set(attachments.get("reactions", {}).get("reactions", [])) |
1255 old_reactions = set(old_attachment.get("reactions", {}).get("reactions", [])) | 1256 old_reactions = set(old_attachment.get("reactions", {}).get("reactions", [])) |
1258 for reactions, undo in ((reactions_remove, True), (reactions_add, False)): | 1259 for reactions, undo in ((reactions_remove, True), (reactions_add, False)): |
1259 for reaction in reactions: | 1260 for reaction in reactions: |
1260 activity_id = self.buildAPURL( | 1261 activity_id = self.buildAPURL( |
1261 "reaction", item_account, item_id, reaction.encode().hex() | 1262 "reaction", item_account, item_id, reaction.encode().hex() |
1262 ) | 1263 ) |
1263 reaction_activity = self.createActivity( | 1264 reaction_activity = self.create_activity( |
1264 TYPE_REACTION, publisher_actor_id, item_url, | 1265 TYPE_REACTION, publisher_actor_id, item_url, |
1265 activity_id=activity_id | 1266 activity_id=activity_id |
1266 ) | 1267 ) |
1267 reaction_activity["content"] = reaction | 1268 reaction_activity["content"] = reaction |
1268 reaction_activity["to"] = [ap_account] | 1269 reaction_activity["to"] = [ap_account] |
1269 reaction_activity["cc"] = [NS_AP_PUBLIC] | 1270 reaction_activity["cc"] = [NS_AP_PUBLIC] |
1270 if undo: | 1271 if undo: |
1271 activy = self.createActivity( | 1272 activy = self.create_activity( |
1272 "Undo", publisher_actor_id, reaction_activity | 1273 "Undo", publisher_actor_id, reaction_activity |
1273 ) | 1274 ) |
1274 else: | 1275 else: |
1275 activy = reaction_activity | 1276 activy = reaction_activity |
1276 await self.signAndPost(inbox, publisher_actor_id, activy) | 1277 await self.signAndPost(inbox, publisher_actor_id, activy) |
1280 attending = attachments["rsvp"].get("attending", "no") | 1281 attending = attachments["rsvp"].get("attending", "no") |
1281 old_attending = old_attachment.get("rsvp", {}).get("attending", "no") | 1282 old_attending = old_attachment.get("rsvp", {}).get("attending", "no") |
1282 if attending != old_attending: | 1283 if attending != old_attending: |
1283 activity_type = TYPE_JOIN if attending == "yes" else TYPE_LEAVE | 1284 activity_type = TYPE_JOIN if attending == "yes" else TYPE_LEAVE |
1284 activity_id = self.buildAPURL(activity_type.lower(), item_account, item_id) | 1285 activity_id = self.buildAPURL(activity_type.lower(), item_account, item_id) |
1285 activity = self.createActivity( | 1286 activity = self.create_activity( |
1286 activity_type, publisher_actor_id, item_url, activity_id=activity_id | 1287 activity_type, publisher_actor_id, item_url, activity_id=activity_id |
1287 ) | 1288 ) |
1288 activity["to"] = [ap_account] | 1289 activity["to"] = [ap_account] |
1289 activity["cc"] = [NS_AP_PUBLIC] | 1290 activity["cc"] = [NS_AP_PUBLIC] |
1290 await self.signAndPost(inbox, publisher_actor_id, activity) | 1291 await self.signAndPost(inbox, publisher_actor_id, activity) |
1291 else: | 1292 else: |
1292 if "rsvp" in old_attachment: | 1293 if "rsvp" in old_attachment: |
1293 old_attending = old_attachment.get("rsvp", {}).get("attending", "no") | 1294 old_attending = old_attachment.get("rsvp", {}).get("attending", "no") |
1294 if old_attending == "yes": | 1295 if old_attending == "yes": |
1295 activity_id = self.buildAPURL(TYPE_LEAVE.lower(), item_account, item_id) | 1296 activity_id = self.buildAPURL(TYPE_LEAVE.lower(), item_account, item_id) |
1296 activity = self.createActivity( | 1297 activity = self.create_activity( |
1297 TYPE_LEAVE, publisher_actor_id, item_url, activity_id=activity_id | 1298 TYPE_LEAVE, publisher_actor_id, item_url, activity_id=activity_id |
1298 ) | 1299 ) |
1299 activity["to"] = [ap_account] | 1300 activity["to"] = [ap_account] |
1300 activity["cc"] = [NS_AP_PUBLIC] | 1301 activity["cc"] = [NS_AP_PUBLIC] |
1301 await self.signAndPost(inbox, publisher_actor_id, activity) | 1302 await self.signAndPost(inbox, publisher_actor_id, activity) |
1643 | 1644 |
1644 return items, rsm.RSMResponse(**rsm_resp) | 1645 return items, rsm.RSMResponse(**rsm_resp) |
1645 | 1646 |
1646 async def ap_item_2_mb_data_and_elt(self, ap_item: dict) -> Tuple[dict, domish.Element]: | 1647 async def ap_item_2_mb_data_and_elt(self, ap_item: dict) -> Tuple[dict, domish.Element]: |
1647 """Convert AP item to parsed microblog data and corresponding item element""" | 1648 """Convert AP item to parsed microblog data and corresponding item element""" |
1648 mb_data = await self.apItem2MBdata(ap_item) | 1649 mb_data = await self.ap_item_2_mb_data(ap_item) |
1649 item_elt = await self._m.data2entry( | 1650 item_elt = await self._m.mb_data_2_entry_elt( |
1650 self.client, mb_data, mb_data["id"], None, self._m.namespace | 1651 self.client, mb_data, mb_data["id"], None, self._m.namespace |
1651 ) | 1652 ) |
1652 if "repeated" in mb_data["extra"]: | 1653 if "repeated" in mb_data["extra"]: |
1653 item_elt["publisher"] = mb_data["extra"]["repeated"]["by"] | 1654 item_elt["publisher"] = mb_data["extra"]["repeated"]["by"] |
1654 else: | 1655 else: |
1740 return ( | 1741 return ( |
1741 self._m.getCommentsNode(last_level_item["id"]), | 1742 self._m.getCommentsNode(last_level_item["id"]), |
1742 None | 1743 None |
1743 ) | 1744 ) |
1744 | 1745 |
1745 async def apItem2MBdata(self, ap_item: dict) -> dict: | 1746 async def ap_item_2_mb_data(self, ap_item: dict) -> dict: |
1746 """Convert AP activity or object to microblog data | 1747 """Convert AP activity or object to microblog data |
1747 | 1748 |
1748 @param ap_item: ActivityPub item to convert | 1749 @param ap_item: ActivityPub item to convert |
1749 Can be either an activity of an object | 1750 Can be either an activity of an object |
1750 @return: AP Item's Object and microblog data | 1751 @return: AP Item's Object and microblog data |
1783 mb_data["content_xhtml"], | 1784 mb_data["content_xhtml"], |
1784 self._t.SYNTAX_XHTML, | 1785 self._t.SYNTAX_XHTML, |
1785 self._t.SYNTAX_TEXT, | 1786 self._t.SYNTAX_TEXT, |
1786 False, | 1787 False, |
1787 ) | 1788 ) |
1789 | |
1790 if "attachment" in ap_object: | |
1791 attachments = mb_data["extra"][C.KEY_ATTACHMENTS] = [] | |
1792 for ap_attachment in ap_object["attachment"]: | |
1793 try: | |
1794 url = ap_attachment["url"] | |
1795 except KeyError: | |
1796 log.warning( | |
1797 f'"url" missing in AP attachment, ignoring: {ap_attachment}' | |
1798 ) | |
1799 continue | |
1800 | |
1801 if not url.startswith("http"): | |
1802 log.warning(f"non HTTP URL in attachment, ignoring: {ap_attachment}") | |
1803 continue | |
1804 attachment = {"url": url} | |
1805 for ap_key, key in ( | |
1806 ("mediaType", "media_type"), | |
1807 # XXX: as weird as it seems, "name" is actually used for description | |
1808 # in AP world | |
1809 ("name", "desc"), | |
1810 ): | |
1811 value = ap_attachment.get(ap_key) | |
1812 if value: | |
1813 attachment[key] = value | |
1814 attachments.append(attachment) | |
1788 | 1815 |
1789 # author | 1816 # author |
1790 if is_activity: | 1817 if is_activity: |
1791 authors = await self.apGetActors(ap_item, "actor") | 1818 authors = await self.apGetActors(ap_item, "actor") |
1792 else: | 1819 else: |
1897 | 1924 |
1898 return self.buildAPURL( | 1925 return self.buildAPURL( |
1899 TYPE_ITEM, parent_ap_account, parent_item | 1926 TYPE_ITEM, parent_ap_account, parent_item |
1900 ) | 1927 ) |
1901 | 1928 |
1902 async def repeatedMB2APItem( | 1929 async def repeated_mb_2_ap_item( |
1903 self, | 1930 self, |
1904 mb_data: dict | 1931 mb_data: dict |
1905 ) -> dict: | 1932 ) -> dict: |
1906 """Convert repeated blog item to suitable AP Announce activity | 1933 """Convert repeated blog item to suitable AP Announce activity |
1907 | 1934 |
1950 repeated_account = await self.getAPAccountFromJidAndNode( | 1977 repeated_account = await self.getAPAccountFromJidAndNode( |
1951 rep_service, rep_node | 1978 rep_service, rep_node |
1952 ) | 1979 ) |
1953 announced_uri = self.buildAPURL("item", repeated_account, rep_item) | 1980 announced_uri = self.buildAPURL("item", repeated_account, rep_item) |
1954 | 1981 |
1955 announce = self.createActivity( | 1982 announce = self.create_activity( |
1956 "Announce", repeater_id, announced_uri, activity_id=activity_id | 1983 "Announce", repeater_id, announced_uri, activity_id=activity_id |
1957 ) | 1984 ) |
1958 announce["to"] = [NS_AP_PUBLIC] | 1985 announce["to"] = [NS_AP_PUBLIC] |
1959 announce["cc"] = [ | 1986 announce["cc"] = [ |
1960 self.buildAPURL(TYPE_FOLLOWERS, repeater_account), | 1987 self.buildAPURL(TYPE_FOLLOWERS, repeater_account), |
1986 be. | 2013 be. |
1987 @return: Activity item | 2014 @return: Activity item |
1988 """ | 2015 """ |
1989 extra = mb_data.get("extra", {}) | 2016 extra = mb_data.get("extra", {}) |
1990 if "repeated" in extra: | 2017 if "repeated" in extra: |
1991 return await self.repeatedMB2APItem(mb_data) | 2018 return await self.repeated_mb_2_ap_item(mb_data) |
1992 if not mb_data.get("id"): | 2019 if not mb_data.get("id"): |
1993 mb_data["id"] = shortuuid.uuid() | 2020 mb_data["id"] = shortuuid.uuid() |
1994 if not mb_data.get("author_jid"): | 2021 if not mb_data.get("author_jid"): |
1995 mb_data["author_jid"] = client.jid.userhost() | 2022 mb_data["author_jid"] = client.jid.userhost() |
1996 ap_account = await self.getAPAccountFromJidAndNode( | 2023 ap_account = await self.getAPAccountFromJidAndNode( |
2008 } | 2035 } |
2009 | 2036 |
2010 language = mb_data.get("language") | 2037 language = mb_data.get("language") |
2011 if language: | 2038 if language: |
2012 ap_object["contentMap"] = {language: ap_object["content"]} | 2039 ap_object["contentMap"] = {language: ap_object["content"]} |
2040 | |
2041 attachments = extra.get(C.KEY_ATTACHMENTS) | |
2042 if attachments: | |
2043 ap_attachments = ap_object["attachment"] = [] | |
2044 for attachment in attachments: | |
2045 try: | |
2046 url = next( | |
2047 s['url'] for s in attachment["sources"] if 'url' in s | |
2048 ) | |
2049 except (StopIteration, KeyError): | |
2050 log.warning( | |
2051 f"Ignoring attachment without URL: {attachment}" | |
2052 ) | |
2053 continue | |
2054 ap_attachment = { | |
2055 "url": url | |
2056 } | |
2057 for key, ap_key in ( | |
2058 ("media_type", "mediaType"), | |
2059 # XXX: yes "name", cf. [ap_item_2_mb_data] | |
2060 ("desc", "name"), | |
2061 ): | |
2062 value = attachment.get(key) | |
2063 if value: | |
2064 ap_attachment[ap_key] = value | |
2065 ap_attachments.append(ap_attachment) | |
2013 | 2066 |
2014 if public: | 2067 if public: |
2015 ap_object["to"] = [NS_AP_PUBLIC] | 2068 ap_object["to"] = [NS_AP_PUBLIC] |
2016 if self.auto_mentions: | 2069 if self.auto_mentions: |
2017 for m in RE_MENTION.finditer(ap_object["content"]): | 2070 for m in RE_MENTION.finditer(ap_object["content"]): |
2066 ap_account, | 2119 ap_account, |
2067 parent_item, | 2120 parent_item, |
2068 mb_data | 2121 mb_data |
2069 ) | 2122 ) |
2070 | 2123 |
2071 return self.createActivity( | 2124 return self.create_activity( |
2072 "Create" if is_new else "Update", url_actor, ap_object, activity_id=url_item | 2125 "Create" if is_new else "Update", url_actor, ap_object, activity_id=url_item |
2073 ) | 2126 ) |
2074 | 2127 |
2075 async def publishMessage( | 2128 async def publishMessage( |
2076 self, | 2129 self, |
2142 f"Deleting an unknown item at service {jid_}, node {node} and id " | 2195 f"Deleting an unknown item at service {jid_}, node {node} and id " |
2143 f"{item_id}" | 2196 f"{item_id}" |
2144 ) | 2197 ) |
2145 else: | 2198 else: |
2146 try: | 2199 try: |
2147 mb_data = await self._m.item2mbdata(self.client, items[0].data, jid_, node) | 2200 mb_data = await self._m.item_2_mb_data(self.client, items[0].data, jid_, node) |
2148 if "repeated" in mb_data["extra"]: | 2201 if "repeated" in mb_data["extra"]: |
2149 # we are deleting a repeated item, we must translate this to an | 2202 # we are deleting a repeated item, we must translate this to an |
2150 # "Undo" of the "Announce" activity instead of a "Delete" one | 2203 # "Undo" of the "Announce" activity instead of a "Delete" one |
2151 announce = await self.repeatedMB2APItem(mb_data) | 2204 announce = await self.repeated_mb_2_ap_item(mb_data) |
2152 undo = self.createActivity("Undo", author_actor_id, announce) | 2205 undo = self.create_activity("Undo", author_actor_id, announce) |
2153 return author_actor_id, undo | 2206 return author_actor_id, undo |
2154 except Exception as e: | 2207 except Exception as e: |
2155 log.debug( | 2208 log.debug( |
2156 f"Can't parse item, maybe it's not a blog item: {e}\n" | 2209 f"Can't parse item, maybe it's not a blog item: {e}\n" |
2157 f"{items[0].toXml()}" | 2210 f"{items[0].toXml()}" |
2158 ) | 2211 ) |
2159 | 2212 |
2160 url_item = self.buildAPURL(TYPE_ITEM, author_account, item_id) | 2213 url_item = self.buildAPURL(TYPE_ITEM, author_account, item_id) |
2161 ap_item = self.createActivity( | 2214 ap_item = self.create_activity( |
2162 "Delete", | 2215 "Delete", |
2163 author_actor_id, | 2216 author_actor_id, |
2164 { | 2217 { |
2165 "id": url_item, | 2218 "id": url_item, |
2166 "type": TYPE_TOMBSTONE | 2219 "type": TYPE_TOMBSTONE |
2221 mb_data["language"] = language | 2274 mb_data["language"] = language |
2222 origin_id = mess_data["extra"].get("origin_id") | 2275 origin_id = mess_data["extra"].get("origin_id") |
2223 if origin_id: | 2276 if origin_id: |
2224 # we need to use origin ID when present to be able to retract the message | 2277 # we need to use origin ID when present to be able to retract the message |
2225 mb_data["id"] = origin_id | 2278 mb_data["id"] = origin_id |
2279 attachments = mess_data["extra"].get(C.KEY_ATTACHMENTS) | |
2280 if attachments: | |
2281 mb_data["extra"] = { | |
2282 C.KEY_ATTACHMENTS: attachments | |
2283 } | |
2284 | |
2226 client = self.client.getVirtualClient(mess_data["from"]) | 2285 client = self.client.getVirtualClient(mess_data["from"]) |
2227 ap_item = await self.mb_data_2_ap_item(client, mb_data, public=False) | 2286 ap_item = await self.mb_data_2_ap_item(client, mb_data, public=False) |
2228 ap_object = ap_item["object"] | 2287 ap_object = ap_item["object"] |
2229 ap_object["to"] = ap_item["to"] = [actor_id] | 2288 ap_object["to"] = ap_item["to"] = [actor_id] |
2230 # we add a mention to direct message, otherwise peer is not notified in some AP | 2289 # we add a mention to direct message, otherwise peer is not notified in some AP |
2337 ) | 2396 ) |
2338 return False | 2397 return False |
2339 | 2398 |
2340 cached_item = cached_items[0] | 2399 cached_item = cached_items[0] |
2341 | 2400 |
2342 mb_data = await self._m.item2mbdata( | 2401 mb_data = await self._m.item_2_mb_data( |
2343 client, cached_item.data, pubsub_service, pubsub_node | 2402 client, cached_item.data, pubsub_service, pubsub_node |
2344 ) | 2403 ) |
2345 ap_item = await self.mb_data_2_ap_item(client, mb_data) | 2404 ap_item = await self.mb_data_2_ap_item(client, mb_data) |
2346 ap_object = ap_item["object"] | 2405 ap_object = ap_item["object"] |
2347 ap_object["to"] = [actor_id] | 2406 ap_object["to"] = [actor_id] |
2394 except IndexError: | 2453 except IndexError: |
2395 log.warning( | 2454 log.warning( |
2396 f"Can't find parent item at {parent_item_service} (node " | 2455 f"Can't find parent item at {parent_item_service} (node " |
2397 f"{parent_item_node!r})\n{pformat(ap_item)}") | 2456 f"{parent_item_node!r})\n{pformat(ap_item)}") |
2398 return | 2457 return |
2399 parent_item_parsed = await self._m.item2mbdata( | 2458 parent_item_parsed = await self._m.item_2_mb_data( |
2400 client, parent_item_elt, parent_item_service, parent_item_node | 2459 client, parent_item_elt, parent_item_service, parent_item_node |
2401 ) | 2460 ) |
2402 try: | 2461 try: |
2403 comment_service = jid.JID(parent_item_parsed["comments"][0]["service"]) | 2462 comment_service = jid.JID(parent_item_parsed["comments"][0]["service"]) |
2404 comment_node = parent_item_parsed["comments"][0]["node"] | 2463 comment_node = parent_item_parsed["comments"][0]["node"] |
2486 @param item: AP object payload | 2545 @param item: AP object payload |
2487 """ | 2546 """ |
2488 is_public, targets, mentions = self.getAPItemTargets(item) | 2547 is_public, targets, mentions = self.getAPItemTargets(item) |
2489 if not is_public and targets.keys() == {TYPE_ACTOR}: | 2548 if not is_public and targets.keys() == {TYPE_ACTOR}: |
2490 # this is a direct message | 2549 # this is a direct message |
2491 await self.handleMessageAPItem( | 2550 await self.handle_message_ap_item( |
2492 client, targets, mentions, destinee, item | 2551 client, targets, mentions, destinee, item |
2493 ) | 2552 ) |
2494 else: | 2553 else: |
2495 await self.handlePubsubAPItem( | 2554 await self.handlePubsubAPItem( |
2496 client, targets, mentions, destinee, node, item, is_public | 2555 client, targets, mentions, destinee, node, item, is_public |
2497 ) | 2556 ) |
2498 | 2557 |
2499 async def handleMessageAPItem( | 2558 async def handle_message_ap_item( |
2500 self, | 2559 self, |
2501 client: SatXMPPEntity, | 2560 client: SatXMPPEntity, |
2502 targets: Dict[str, Set[str]], | 2561 targets: Dict[str, Set[str]], |
2503 mentions: List[Dict[str, str]], | 2562 mentions: List[Dict[str, str]], |
2504 destinee: Optional[jid.JID], | 2563 destinee: Optional[jid.JID], |
2515 for t_set in targets.values() | 2574 for t_set in targets.values() |
2516 for t in t_set | 2575 for t in t_set |
2517 } | 2576 } |
2518 if destinee is not None: | 2577 if destinee is not None: |
2519 targets_jids.add(destinee) | 2578 targets_jids.add(destinee) |
2520 mb_data = await self.apItem2MBdata(item) | 2579 mb_data = await self.ap_item_2_mb_data(item) |
2580 extra = { | |
2581 "origin_id": mb_data["id"] | |
2582 } | |
2583 attachments = mb_data["extra"].get(C.KEY_ATTACHMENTS) | |
2584 if attachments: | |
2585 extra[C.KEY_ATTACHMENTS] = attachments | |
2586 | |
2521 defer_l = [] | 2587 defer_l = [] |
2522 for target_jid in targets_jids: | 2588 for target_jid in targets_jids: |
2523 defer_l.append( | 2589 defer_l.append( |
2524 client.sendMessage( | 2590 client.sendMessage( |
2525 target_jid, | 2591 target_jid, |
2526 {'': mb_data.get("content", "")}, | 2592 {'': mb_data.get("content", "")}, |
2527 mb_data.get("title"), | 2593 mb_data.get("title"), |
2528 extra={"origin_id": mb_data["id"]} | 2594 extra=extra |
2529 ) | 2595 ) |
2530 ) | 2596 ) |
2531 await defer.DeferredList(defer_l) | 2597 await defer.DeferredList(defer_l) |
2532 | 2598 |
2533 async def notifyMentions( | 2599 async def notifyMentions( |