Mercurial > libervia-backend
changeset 3742:bf0505d41c09
comp AP: helper methods to get AP objects:
rel 364
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 22 Mar 2022 17:00:42 +0100 |
parents | eddab3798aca |
children | 54c249ec35ce |
files | sat/plugins/plugin_comp_ap_gateway/__init__.py |
diffstat | 1 files changed, 129 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/sat/plugins/plugin_comp_ap_gateway/__init__.py Tue Mar 22 17:00:42 2022 +0100 +++ b/sat/plugins/plugin_comp_ap_gateway/__init__.py Tue Mar 22 17:00:42 2022 +0100 @@ -211,6 +211,135 @@ text=f"Can't get AP data at {url}: {e}" ) + @overload + async def apGetObject(self, data: dict, key: str) -> Optional[dict]: + ... + + @overload + async def apGetObject( + self, data: Union[str, dict], key: None = None + ) -> dict: + ... + + async def apGetObject(self, data, key = None): + """Retrieve an AP object, dereferencing when necessary + + This method is to be used with attributes marked as "Functional" in + https://www.w3.org/TR/activitystreams-vocabulary + @param data: AP object where an other object is looked for, or the object itself + @param key: name of the object to look for, or None if data is the object directly + @return: found object if any + """ + if key is not None: + value = data.get(key) + else: + value = data + if value is None: + if key is None: + raise ValueError("None can't be used with apGetObject is key is None") + return None + elif isinstance(value, dict): + return value + elif isinstance(value, str): + return await self.apGet(value) + else: + raise NotImplementedError( + "was expecting a string or a dict, got {type(value)}: {value!r}}" + ) + + async def apGetList(self, data: dict, key: str) -> Optional[List[dict]]: + """Retrieve a list of objects from AP data, dereferencing when necessary + + This method is to be used with non functional vocabularies. Use ``apGetObject`` + otherwise. + If the value is a dictionary, it will be wrapped in a list + @param data: AP object where a list of objects is looked for + @param key: key of the list to look for + @return: list of objects, or None if the key is not present + """ + value = data.get(key) + if value is None: + return None + elif isinstance(value, str): + value = await self.apGet(value) + if isinstance(value, dict): + return [value] + if not isinstance(value, list): + raise ValueError(f"A list was expected, got {type(value)}: {value!r}") + return [await self.apGetObject(i) for i in value] + + async def apGetActors( + self, + data: dict, + key: str, + as_account: bool = True + ) -> List[str]: + """Retrieve AP actors from data + + @param data: AP object containing a field with actors + @param key: field to use to retrieve actors + @param as_account: if True returns account handles, otherwise will return actor + IDs + @raise exceptions.DataError: there is not actor data or it is invalid + """ + value = data.get(key) + if value is None: + raise exceptions.DataError( + f"no actor associated to object {data.get('id')!r}" + ) + elif isinstance(value, dict): + actor_id = value.get("id") + if actor_id is None: + raise exceptions.DataError( + f"invalid actor associated to object {data.get('id')!r}: {value!r}" + ) + value = [actor_id] + elif isinstance(value, str): + value = [value] + elif isinstance(value, list): + try: + value = [a if isinstance(a, str) else a["id"] for a in value] + except (TypeError, KeyError): + raise exceptions.DataError( + f"invalid actors list to object {data.get('id')!r}: {value!r}" + ) + if not value: + raise exceptions.DataError( + f"list of actors is empty" + ) + if as_account: + return [await self.getAPAccountFromId(actor_id) for actor_id in value] + else: + return value + + async def apGetSenderActor( + self, + data: dict, + ) -> str: + """Retrieve actor who sent data + + This is done by checking "attributedTo" field first, then "actor" field. + Only the first found actor is taken into accoun + @param data: AP object + @return: actor id of the sender + @raise exceptions.NotFound: no actor has been found in data + """ + try: + actors = await self.apGetActors(data, "attributedTo", as_account=False) + except exceptions.DataError: + actors = None + if not actors: + try: + actors = await self.apGetActors(data, "actor", as_account=False) + except exceptions.DataError: + raise exceptions.NotFound( + 'actor not specified in "attributedTo" or "actor"' + ) + try: + return actors[0] + except IndexError: + raise exceptions.NotFound("list of actors is empty") + def mustEncode(self, text: str) -> bool: """Indicate if a text must be period encoded""" return (