annotate libervia/backend/plugins/plugin_xep_0084.py @ 4306:94e0968987cd

plugin XEP-0033: code modernisation, improve delivery, data validation: - Code has been rewritten using Pydantic models and `async` coroutines for data validation and cleaner element parsing/generation. - Delivery has been completely rewritten. It now works even if server doesn't support multicast, and send to local multicast service first. Delivering to local multicast service first is due to bad support of XEP-0033 in server (notably Prosody which has an incomplete implementation), and the current impossibility to detect if a sub-domain service handles fully multicast or only for local domains. This is a workaround to have a good balance between backward compatilibity and use of bandwith, and to make it work with the incoming email gateway implementation (the gateway will only deliver to entities of its own domain). - disco feature checking now uses `async` corountines. `host` implementation still use Deferred return values for compatibility with legacy code. rel 450
author Goffi <goffi@goffi.org>
date Thu, 26 Sep 2024 16:12:01 +0200
parents 0d7bb4df2343
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python3
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
2
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
3 # Libervia plugin for XEP-0084
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # Copyright (C) 2009-2022 Jérôme Poisson (goffi@goffi.org)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
5
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # (at your option) any later version.
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
10
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
15
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
18
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
19 from typing import Optional, Dict, Any
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from pathlib import Path
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from base64 import b64decode, b64encode
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
22
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from twisted.internet import defer
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.words.protocols.jabber import jid, error
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.words.xish import domish
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 from zope.interface import implementer
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 from wokkel import disco, iwokkel, pubsub
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
4071
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
30 from libervia.backend.core.constants import Const as C
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
31 from libervia.backend.core.i18n import _
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
32 from libervia.backend.core.log import getLogger
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
33 from libervia.backend.core.core_types import SatXMPPEntity
4b842c1fb686 refactoring: renamed `sat` package to `libervia.backend`
Goffi <goffi@goffi.org>
parents: 4037
diff changeset
34 from libervia.backend.core import exceptions
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
35
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
36
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 log = getLogger(__name__)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
38
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 IMPORT_NAME = "XEP-0084"
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
40
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 PLUGIN_INFO = {
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
42 C.PI_NAME: "User Avatar",
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 C.PI_IMPORT_NAME: IMPORT_NAME,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 C.PI_TYPE: C.PLUG_TYPE_XEP,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 C.PI_MODES: C.PLUG_MODE_BOTH,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 C.PI_PROTOCOLS: ["XEP-0084"],
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 C.PI_DEPENDENCIES: ["IDENTITY", "XEP-0060", "XEP-0163"],
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 C.PI_MAIN: "XEP_0084",
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 C.PI_HANDLER: "yes",
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 C.PI_DESCRIPTION: _("""XEP-0084 (User Avatar) implementation"""),
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 }
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
52
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 NS_AVATAR = "urn:xmpp:avatar"
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 NS_AVATAR_METADATA = f"{NS_AVATAR}:metadata"
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 NS_AVATAR_DATA = f"{NS_AVATAR}:data"
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
56
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
57
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 class XEP_0084:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 namespace_metadata = NS_AVATAR_METADATA
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 namespace_data = NS_AVATAR_DATA
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
61
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 def __init__(self, host):
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 log.info(_("XEP-0084 (User Avatar) plugin initialization"))
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
64 host.register_namespace("avatar_metadata", NS_AVATAR_METADATA)
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
65 host.register_namespace("avatar_data", NS_AVATAR_DATA)
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 self.host = host
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 self._p = host.plugins["XEP-0060"]
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
68 self._i = host.plugins["IDENTITY"]
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 self._i.register(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
70 IMPORT_NAME, "avatar", self.get_avatar, self.set_avatar, priority=2000
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
72 host.plugins["XEP-0163"].add_pep_event(
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
73 None, NS_AVATAR_METADATA, self._on_metadata_update
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
75
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
76 def get_handler(self, client):
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 return XEP_0084_Handler()
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
78
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
79 def _on_metadata_update(self, itemsEvent, profile):
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
80 client = self.host.get_client(profile)
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
81 defer.ensureDeferred(self.on_metadata_update(client, itemsEvent))
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
82
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
83 async def on_metadata_update(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
84 self, client: SatXMPPEntity, itemsEvent: pubsub.ItemsEvent
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 ) -> None:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 entity = client.jid.userhostJID()
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
87 avatar_metadata = await self.get_avatar(client, entity)
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 await self._i.update(client, IMPORT_NAME, "avatar", avatar_metadata, entity)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
89
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
90 async def get_avatar(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
91 self, client: SatXMPPEntity, entity_jid: jid.JID
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
92 ) -> Optional[dict]:
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 """Get avatar data
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
94
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 @param entity: entity to get avatar from
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 @return: avatar metadata, or None if no avatar has been found
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 """
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 service = entity_jid.userhostJID()
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 # metadata
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 try:
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
101 items, __ = await self._p.get_items(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
102 client, service, NS_AVATAR_METADATA, max_items=1
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 except exceptions.NotFound:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 return None
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
106
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 if not items:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 return None
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
109
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 item_elt = items[0]
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 try:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 metadata_elt = next(item_elt.elements(NS_AVATAR_METADATA, "metadata"))
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 except StopIteration:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 log.warning(f"missing metadata element: {item_elt.toXml()}")
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 return None
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
116
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 for info_elt in metadata_elt.elements(NS_AVATAR_METADATA, "info"):
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 try:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 metadata = {
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
120 "id": str(info_elt["id"]),
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
121 "size": int(info_elt["bytes"]),
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
122 "media_type": str(info_elt["type"]),
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 }
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
124 avatar_id = metadata["id"]
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 if not avatar_id:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 raise ValueError
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 except (KeyError, ValueError):
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
128 log.warning(f"invalid <info> element: {item_elt.toXml()}")
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
129 return None
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
130 # FIXME: to simplify, we only handle image/png for now
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 if metadata["media_type"] == "image/png":
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
132 break
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 else:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 # mandatory image/png is missing, or avatar is disabled
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 # (https://xmpp.org/extensions/xep-0084.html#pub-disable)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 return None
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
137
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
138 cache_data = self.host.common_cache.get_metadata(avatar_id)
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 if not cache_data:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 try:
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
141 data_items, __ = await self._p.get_items(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
142 client, service, NS_AVATAR_DATA, item_ids=[avatar_id]
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 data_item_elt = data_items[0]
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 except (error.StanzaError, IndexError) as e:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 log.warning(
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 f"Can't retrieve avatar of {service.full()} with ID {avatar_id!r}: "
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 f"{e}"
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 return None
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 try:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 avatar_buf = b64decode(
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 str(next(data_item_elt.elements(NS_AVATAR_DATA, "data")))
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 except Exception as e:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
156 log.warning(
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 f"invalid data element for {service.full()} with avatar ID "
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 f"{avatar_id!r}: {e}\n{data_item_elt.toXml()}"
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 return None
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
161 with self.host.common_cache.cache_data(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
162 IMPORT_NAME, avatar_id, metadata["media_type"]
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 ) as f:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 f.write(avatar_buf)
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
165 cache_data = {"path": Path(f.name), "mime_type": metadata["media_type"]}
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
166
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
167 return self._i.avatar_build_metadata(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
168 cache_data["path"], cache_data["mime_type"], avatar_id
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 )
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
170
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
171 def build_item_data_elt(self, avatar_data: Dict[str, Any]) -> domish.Element:
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 """Generate the item for the data node
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
173
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 @param avatar_data: data as build by identity plugin (need to be filled with
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 "cache_uid" and "base64" keys)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
176 """
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 data_elt = domish.Element((NS_AVATAR_DATA, "data"))
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 data_elt.addContent(avatar_data["base64"])
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 return pubsub.Item(id=avatar_data["cache_uid"], payload=data_elt)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
180
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
181 def build_item_metadata_elt(self, avatar_data: Dict[str, Any]) -> domish.Element:
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 """Generate the item for the metadata node
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
183
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 @param avatar_data: data as build by identity plugin (need to be filled with
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 "cache_uid", "path", and "media_type" keys)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
186 """
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 metadata_elt = domish.Element((NS_AVATAR_METADATA, "metadata"))
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 info_elt = metadata_elt.addElement("info")
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 # FIXME: we only fill required elements for now (see
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 # https://xmpp.org/extensions/xep-0084.html#table-1)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 info_elt["id"] = avatar_data["cache_uid"]
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 info_elt["type"] = avatar_data["media_type"]
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 info_elt["bytes"] = str(avatar_data["path"].stat().st_size)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 return pubsub.Item(id=self._p.ID_SINGLETON, payload=metadata_elt)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
195
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
196 async def set_avatar(
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
197 self, client: SatXMPPEntity, avatar_data: Dict[str, Any], entity: jid.JID
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 ) -> None:
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 """Set avatar of the profile
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
200
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 @param avatar_data(dict): data of the image to use as avatar, as built by
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 IDENTITY plugin.
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 @param entity(jid.JID): entity whose avatar must be changed
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
204 """
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 service = entity.userhostJID()
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
206
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 # Data
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
208 await self._p.create_if_new_node(
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 client,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 service,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 NS_AVATAR_DATA,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 options={
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
213 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 self._p.OPT_PERSIST_ITEMS: 1,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
215 self._p.OPT_MAX_ITEMS: 1,
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
216 },
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
218 item_data_elt = self.build_item_data_elt(avatar_data)
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
219 await self._p.send_items(client, service, NS_AVATAR_DATA, [item_data_elt])
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
220
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 # Metadata
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
222 await self._p.create_if_new_node(
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 client,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
224 service,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 NS_AVATAR_METADATA,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 options={
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
227 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 self._p.OPT_PERSIST_ITEMS: 1,
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
229 self._p.OPT_MAX_ITEMS: 1,
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
230 },
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 )
4037
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
232 item_metadata_elt = self.build_item_metadata_elt(avatar_data)
524856bd7b19 massive refactoring to switch from camelCase to snake_case:
Goffi <goffi@goffi.org>
parents: 3820
diff changeset
233 await self._p.send_items(client, service, NS_AVATAR_METADATA, [item_metadata_elt])
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
234
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
235
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 @implementer(iwokkel.IDisco)
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
237 class XEP_0084_Handler(XMPPHandler):
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
238
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 def getDiscoInfo(self, requestor, service, nodeIdentifier=""):
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 return [
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 disco.DiscoFeature(NS_AVATAR_METADATA),
4270
0d7bb4df2343 Reformatted code base using black.
Goffi <goffi@goffi.org>
parents: 4071
diff changeset
242 disco.DiscoFeature(NS_AVATAR_DATA),
3820
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 ]
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
244
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 def getDiscoItems(self, requestor, service, nodeIdentifier=""):
88e332cec47b plugin XEP-0084: "User Avatar" implementation:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 return []