Mercurial > libervia-backend
diff sat/plugins/plugin_comp_ap_gateway/http_server.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 | aaa4e7815ba8 |
children | bd84d289fc94 |
line wrap: on
line diff
--- a/sat/plugins/plugin_comp_ap_gateway/http_server.py Thu Jul 21 18:05:20 2022 +0200 +++ b/sat/plugins/plugin_comp_ap_gateway/http_server.py Thu Jul 21 18:07:35 2022 +0200 @@ -34,6 +34,7 @@ from sat.core import exceptions from sat.core.constants import Const as C from sat.core.i18n import _ +from sat.core.core_types import SatXMPPEntity from sat.core.log import getLogger from sat.tools.common import date_utils, uri from sat.memory.sqla_mapping import SubscriptionState @@ -41,7 +42,7 @@ from .constants import ( NS_AP, CONTENT_TYPE_AP, TYPE_ACTOR, TYPE_INBOX, TYPE_SHARED_INBOX, TYPE_OUTBOX, AP_REQUEST_TYPES, PAGE_SIZE, ACTIVITY_TYPES_LOWER, ACTIVIY_NO_ACCOUNT_ALLOWED, - SIGN_HEADERS, HS2019, SIGN_EXP, TYPE_FOLLOWERS, TYPE_FOLLOWING + SIGN_HEADERS, HS2019, SIGN_EXP, TYPE_FOLLOWERS, TYPE_FOLLOWING, TYPE_ITEM, TYPE_LIKE ) from .regex import RE_SIG_PARAM @@ -149,6 +150,8 @@ # we can use directly the Announce object, as only the "id" field is # needed await self.apg.newAPDeleteItem(client, None, node, obj) + elif type_ == TYPE_LIKE: + await self.handleNewLikeItem(client, obj, True) else: log.warning(f"Unmanaged undo type: {type_!r}") @@ -339,6 +342,108 @@ repeated=True ) + async def handleNewLikeItem( + self, + client: SatXMPPEntity, + data: dict, + undo: bool = False, + ) -> None: + liked_ids = data.get("object") + if not liked_ids: + raise exceptions.DataError("object should be set") + elif isinstance(liked_ids, list): + try: + liked_ids = [o["id"] for o in liked_ids] + except (KeyError, TypeError): + raise exceptions.DataError(f"invalid object: {liked_ids!r}") + elif isinstance(liked_ids, dict): + obj_id = liked_ids.get("id") + if not obj_id or not isinstance(obj_id, str): + raise exceptions.DataError(f"invalid object: {liked_ids!r}") + liked_ids = [obj_id] + elif isinstance(liked_ids, str): + liked_ids = [liked_ids] + + for liked_id in liked_ids: + if not self.apg.isLocalURL(liked_id): + log.debug(f"ignoring non local liked ID: {liked_id}") + continue + url_type, url_args = self.apg.parseAPURL(liked_id) + if url_type != TYPE_ITEM: + log.warning(f"unexpected local URL for liked item: {liked_id}") + continue + try: + account, item_id = url_args + except ValueError: + raise ValueError(f"invalid URL: {liked_id}") + author_jid, item_node = await self.apg.getJIDAndNode(account) + if item_node is None: + item_node = self.apg._m.namespace + attachment_node = self.apg._pa.getAttachmentNodeName( + author_jid, item_node, item_id + ) + cached_node = await self.apg.host.memory.storage.getPubsubNode( + client, + author_jid, + attachment_node, + with_subscriptions=True, + create=True + ) + found_items, __ = await self.apg.host.memory.storage.getItems( + cached_node, item_ids=[item_id] + ) + if not found_items: + old_item_elt = None + else: + found_item = found_items[0] + old_item_elt = found_item.data + + item_elt = self.apg._pa.applySetHandler( + client, + {"extra": {"noticed": not undo}}, + old_item_elt, + [("noticed", self.apg._pa.namespace)] + ) + # we reparse the element, as there can be other attachments + attachments_data = self.apg._pa.items2attachmentData(client, [item_elt]) + # and we update the cache + await self.apg.host.memory.storage.cachePubsubItems( + client, + cached_node, + [item_elt], + attachments_data or [{}] + ) + + if self.apg.isVirtualJID(author_jid): + # the attachment is on t a virtual pubsub service (linking to an AP item), + # we notify all subscribers + for subscription in cached_node.subscriptions: + if subscription.state != SubscriptionState.SUBSCRIBED: + continue + self.apg.pubsub_service.notifyPublish( + author_jid, + attachment_node, + [(subscription.subscriber, None, [item_elt])] + ) + else: + # the attachment is on an XMPP item, we publish it to the attachment node + await self.apg._p.sendItems( + client, author_jid, attachment_node, [item_elt] + ) + + async def handleLikeActivity( + self, + request: "HTTPRequest", + data: dict, + account_jid: Optional[jid.JID], + node: Optional[str], + ap_account: Optional[str], + ap_url: str, + signing_actor: str + ): + client = await self.apg.getVirtualClient(signing_actor) + await self.handleNewLikeItem(client, data) + async def APActorRequest( self, request: "HTTPRequest", @@ -623,7 +728,7 @@ ) followers = [] for subscriber in subscribers.keys(): - if subscriber.host == self.apg.client.jid.userhost(): + if self.apg.isVirtualJID(subscriber): # the subscriber is an AP user subscribed with this gateway ap_account = self.apg._e.unescape(subscriber.user) else: @@ -660,7 +765,7 @@ following = [] for sub_dict in subscriptions: service = jid.JID(sub_dict["service"]) - if service.host == self.apg.client.jid.userhost(): + if self.apg.isVirtualJID(service): # the subscription is to an AP actor with this gateway ap_account = self.apg._e.unescape(service.user) else: