slidge 0.1.2__py3-none-any.whl → 0.2.0a0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- slidge/__init__.py +3 -5
- slidge/__main__.py +2 -196
- slidge/__version__.py +5 -0
- slidge/command/adhoc.py +8 -1
- slidge/command/admin.py +5 -6
- slidge/command/base.py +1 -2
- slidge/command/register.py +32 -16
- slidge/command/user.py +85 -5
- slidge/contact/contact.py +93 -31
- slidge/contact/roster.py +54 -39
- slidge/core/config.py +13 -7
- slidge/core/gateway/base.py +139 -34
- slidge/core/gateway/disco.py +2 -4
- slidge/core/gateway/mam.py +1 -4
- slidge/core/gateway/ping.py +2 -3
- slidge/core/gateway/presence.py +1 -1
- slidge/core/gateway/registration.py +32 -21
- slidge/core/gateway/search.py +3 -5
- slidge/core/gateway/session_dispatcher.py +109 -51
- slidge/core/gateway/vcard_temp.py +6 -4
- slidge/core/mixins/__init__.py +11 -1
- slidge/core/mixins/attachment.py +15 -10
- slidge/core/mixins/avatar.py +66 -18
- slidge/core/mixins/base.py +8 -2
- slidge/core/mixins/message.py +11 -7
- slidge/core/mixins/message_maker.py +17 -9
- slidge/core/mixins/presence.py +14 -4
- slidge/core/pubsub.py +54 -212
- slidge/core/session.py +65 -33
- slidge/db/__init__.py +4 -0
- slidge/db/alembic/env.py +64 -0
- slidge/db/alembic/script.py.mako +26 -0
- slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +36 -0
- slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +37 -0
- slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +133 -0
- slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +76 -0
- slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +214 -0
- slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +26 -0
- slidge/db/avatar.py +224 -0
- slidge/db/meta.py +65 -0
- slidge/db/models.py +365 -0
- slidge/db/store.py +976 -0
- slidge/group/archive.py +13 -14
- slidge/group/bookmarks.py +59 -56
- slidge/group/participant.py +81 -29
- slidge/group/room.py +242 -142
- slidge/main.py +201 -0
- slidge/migration.py +30 -0
- slidge/slixfix/__init__.py +35 -2
- slidge/slixfix/roster.py +11 -4
- slidge/slixfix/xep_0292/vcard4.py +1 -0
- slidge/util/db.py +1 -47
- slidge/util/test.py +21 -4
- slidge/util/types.py +24 -4
- {slidge-0.1.2.dist-info → slidge-0.2.0a0.dist-info}/METADATA +3 -1
- slidge-0.2.0a0.dist-info/RECORD +108 -0
- slidge/core/cache.py +0 -183
- slidge/util/schema.sql +0 -126
- slidge/util/sql.py +0 -508
- slidge-0.1.2.dist-info/RECORD +0 -96
- {slidge-0.1.2.dist-info → slidge-0.2.0a0.dist-info}/LICENSE +0 -0
- {slidge-0.1.2.dist-info → slidge-0.2.0a0.dist-info}/WHEEL +0 -0
- {slidge-0.1.2.dist-info → slidge-0.2.0a0.dist-info}/entry_points.txt +0 -0
slidge/core/mixins/message.py
CHANGED
@@ -111,7 +111,7 @@ class MarkerMixin(MessageMaker):
|
|
111
111
|
self.xmpp.delivery_receipt.make_ack(
|
112
112
|
self._legacy_to_xmpp(legacy_msg_id),
|
113
113
|
mfrom=self.jid,
|
114
|
-
mto=self.
|
114
|
+
mto=self.user_jid,
|
115
115
|
)
|
116
116
|
)
|
117
117
|
self._send(
|
@@ -144,7 +144,7 @@ class MarkerMixin(MessageMaker):
|
|
144
144
|
# We'll see if we need to implement that later
|
145
145
|
return
|
146
146
|
xmpp_msg_id = self._legacy_to_xmpp(legacy_msg_id)
|
147
|
-
iq = Iq(sto=self.
|
147
|
+
iq = Iq(sto=self.user_jid.bare, sfrom=self.user_jid.bare, stype="set")
|
148
148
|
iq["pubsub"]["publish"]["node"] = self.xmpp["xep_0490"].stanza.NS
|
149
149
|
iq["pubsub"]["publish"]["item"]["id"] = muc_jid
|
150
150
|
displayed = self.xmpp["xep_0490"].stanza.Displayed()
|
@@ -169,8 +169,8 @@ class ContentMessageMixin(AttachmentMixin):
|
|
169
169
|
|
170
170
|
def __replace_id(self, legacy_msg_id: LegacyMessageType):
|
171
171
|
if self.mtype == "groupchat":
|
172
|
-
return self.
|
173
|
-
legacy_msg_id
|
172
|
+
return self.xmpp.store.sent.get_group_xmpp_id(
|
173
|
+
self.session.user_pk, str(legacy_msg_id)
|
174
174
|
) or self._legacy_to_xmpp(legacy_msg_id)
|
175
175
|
else:
|
176
176
|
return self._legacy_to_xmpp(legacy_msg_id)
|
@@ -215,14 +215,18 @@ class ContentMessageMixin(AttachmentMixin):
|
|
215
215
|
but store it in the archive. Meant to be used during ``MUC.backfill()``
|
216
216
|
"""
|
217
217
|
if carbon:
|
218
|
-
if not correction and
|
218
|
+
if not correction and self.xmpp.store.sent.was_sent_by_user(
|
219
|
+
self.session.user_pk, str(legacy_msg_id)
|
220
|
+
):
|
219
221
|
log.warning(
|
220
222
|
"Carbon message for a message an XMPP has sent? This is a bug! %s",
|
221
223
|
legacy_msg_id,
|
222
224
|
)
|
223
225
|
return
|
224
|
-
self.
|
225
|
-
|
226
|
+
self.xmpp.store.sent.set_message(
|
227
|
+
self.session.user_pk,
|
228
|
+
str(legacy_msg_id),
|
229
|
+
self.session.legacy_to_xmpp_msg_id(legacy_msg_id),
|
226
230
|
)
|
227
231
|
hints = self.__default_hints(hints)
|
228
232
|
msg = self._make_message(
|
@@ -7,8 +7,8 @@ from uuid import uuid4
|
|
7
7
|
from slixmpp import Message
|
8
8
|
from slixmpp.types import MessageTypes
|
9
9
|
|
10
|
+
from ...db.models import GatewayUser
|
10
11
|
from ...slixfix.link_preview.stanza import LinkPreview as LinkPreviewStanza
|
11
|
-
from ...util.db import GatewayUser
|
12
12
|
from ...util.types import (
|
13
13
|
ChatState,
|
14
14
|
LegacyMessageType,
|
@@ -60,8 +60,9 @@ class MessageMaker(BaseSender):
|
|
60
60
|
msg["body"] = body
|
61
61
|
state = "active"
|
62
62
|
if thread:
|
63
|
-
|
64
|
-
|
63
|
+
msg["thread"] = self.xmpp.store.sent.get_legacy_thread(
|
64
|
+
self.user_pk, str(thread)
|
65
|
+
) or str(thread)
|
65
66
|
if state:
|
66
67
|
msg["chat_state"] = state
|
67
68
|
for hint in hints:
|
@@ -88,9 +89,9 @@ class MessageMaker(BaseSender):
|
|
88
89
|
msg["stanza_id"]["by"] = self.muc.jid # type: ignore
|
89
90
|
|
90
91
|
def _legacy_to_xmpp(self, legacy_id: LegacyMessageType):
|
91
|
-
return self.
|
92
|
-
legacy_id
|
93
|
-
)
|
92
|
+
return self.xmpp.store.sent.get_xmpp_id(
|
93
|
+
self.session.user_pk, str(legacy_id)
|
94
|
+
) or self.session.legacy_to_xmpp_msg_id(legacy_id)
|
94
95
|
|
95
96
|
def _add_delay(self, msg: Message, when: Optional[datetime]):
|
96
97
|
if when:
|
@@ -110,16 +111,23 @@ class MessageMaker(BaseSender):
|
|
110
111
|
muc = getattr(self, "muc", None)
|
111
112
|
|
112
113
|
if entity := reply_to.author:
|
113
|
-
if isinstance(entity, GatewayUser):
|
114
|
+
if entity == "user" or isinstance(entity, GatewayUser):
|
115
|
+
if isinstance(entity, GatewayUser):
|
116
|
+
warnings.warn(
|
117
|
+
"Using a GatewayUser as the author of a "
|
118
|
+
"MessageReference is deprecated. Use the string 'user' "
|
119
|
+
"instead.",
|
120
|
+
DeprecationWarning,
|
121
|
+
)
|
114
122
|
if muc:
|
115
123
|
jid = copy(muc.jid)
|
116
124
|
jid.resource = fallback_nick = muc.user_nick
|
117
125
|
msg["reply"]["to"] = jid
|
118
126
|
else:
|
119
|
-
msg["reply"]["to"] =
|
127
|
+
msg["reply"]["to"] = self.session.user_jid
|
120
128
|
# TODO: here we should use preferably use the PEP nick of the user
|
121
129
|
# (but it doesn't matter much)
|
122
|
-
fallback_nick =
|
130
|
+
fallback_nick = self.session.user_jid.local
|
123
131
|
else:
|
124
132
|
if muc:
|
125
133
|
if hasattr(entity, "muc"):
|
slidge/core/mixins/presence.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Optional
|
|
5
5
|
|
6
6
|
from slixmpp.types import PresenceShows, PresenceTypes
|
7
7
|
|
8
|
-
from ...util.
|
8
|
+
from ...util.types import CachedPresence
|
9
9
|
from .. import config
|
10
10
|
from .base import BaseSender
|
11
11
|
|
@@ -19,9 +19,12 @@ _FRIEND_REQUEST_PRESENCES = {"subscribe", "unsubscribe", "subscribed", "unsubscr
|
|
19
19
|
|
20
20
|
class PresenceMixin(BaseSender):
|
21
21
|
_ONLY_SEND_PRESENCE_CHANGES = False
|
22
|
+
contact_pk: Optional[int]
|
22
23
|
|
23
24
|
def __init__(self, *a, **k):
|
24
25
|
super().__init__(*a, **k)
|
26
|
+
# FIXME: this should not be an attribute of this mixin to allow garbage
|
27
|
+
# collection of instances
|
25
28
|
self.__update_last_seen_fallback_task: Optional[Task] = None
|
26
29
|
|
27
30
|
async def __update_last_seen_fallback(self):
|
@@ -29,10 +32,16 @@ class PresenceMixin(BaseSender):
|
|
29
32
|
self.send_last_presence(force=True, no_cache_online=False)
|
30
33
|
|
31
34
|
def _get_last_presence(self) -> Optional[CachedPresence]:
|
32
|
-
|
35
|
+
# TODO: use contact PK instead of JID
|
36
|
+
if self.contact_pk is None:
|
37
|
+
return None
|
38
|
+
return self.xmpp.store.contacts.get_presence(self.contact_pk)
|
33
39
|
|
34
40
|
def _store_last_presence(self, new: CachedPresence):
|
35
|
-
|
41
|
+
# TODO: use contact PK instead of JID
|
42
|
+
if self.contact_pk is None:
|
43
|
+
return
|
44
|
+
self.xmpp.store.contacts.set_presence(self.contact_pk, new)
|
36
45
|
|
37
46
|
def _make_presence(
|
38
47
|
self,
|
@@ -55,7 +64,8 @@ class PresenceMixin(BaseSender):
|
|
55
64
|
)
|
56
65
|
if old != new:
|
57
66
|
if hasattr(self, "muc") and ptype == "unavailable":
|
58
|
-
|
67
|
+
if self.contact_pk is not None:
|
68
|
+
self.xmpp.store.contacts.reset_presence(self.contact_pk)
|
59
69
|
else:
|
60
70
|
self._store_last_presence(new)
|
61
71
|
if old and not force and self._ONLY_SEND_PRESENCE_CHANGES:
|
slidge/core/pubsub.py
CHANGED
@@ -1,12 +1,8 @@
|
|
1
|
-
import hashlib
|
2
|
-
import io
|
3
1
|
import logging
|
4
2
|
from copy import copy
|
5
3
|
from pathlib import Path
|
6
|
-
from typing import TYPE_CHECKING, Optional,
|
4
|
+
from typing import TYPE_CHECKING, Optional, Union
|
7
5
|
|
8
|
-
from PIL import Image, UnidentifiedImageError
|
9
|
-
from PIL.Image import Image as PILImage
|
10
6
|
from slixmpp import (
|
11
7
|
JID,
|
12
8
|
CoroutineCallback,
|
@@ -26,10 +22,8 @@ from slixmpp.types import JidStr, OptJidStr
|
|
26
22
|
|
27
23
|
from ..contact.contact import LegacyContact
|
28
24
|
from ..contact.roster import ContactIsUser
|
29
|
-
from ..
|
30
|
-
from ..
|
31
|
-
from ..util.types import AvatarType, LegacyFileIdType, PepItemType
|
32
|
-
from .cache import CachedAvatar, avatar_cache
|
25
|
+
from ..db.avatar import CachedAvatar, avatar_cache
|
26
|
+
from ..db.store import ContactStore, SlidgeStore
|
33
27
|
from .mixins.lock import NamedLockMixin
|
34
28
|
|
35
29
|
if TYPE_CHECKING:
|
@@ -39,19 +33,15 @@ VCARD4_NAMESPACE = "urn:xmpp:vcard4"
|
|
39
33
|
|
40
34
|
|
41
35
|
class PepItem:
|
42
|
-
|
43
|
-
def from_db(jid: JID, user: Optional[GatewayUser] = None) -> Optional["PepItem"]:
|
44
|
-
raise NotImplementedError
|
45
|
-
|
46
|
-
def to_db(self, jid: JID, user: Optional[GatewayUser] = None):
|
47
|
-
raise NotImplementedError
|
36
|
+
pass
|
48
37
|
|
49
38
|
|
50
39
|
class PepAvatar(PepItem):
|
51
|
-
|
40
|
+
store: SlidgeStore
|
41
|
+
|
42
|
+
def __init__(self):
|
52
43
|
self.metadata: Optional[AvatarMetadata] = None
|
53
44
|
self.id: Optional[str] = None
|
54
|
-
self.jid = jid
|
55
45
|
self._avatar_data_path: Optional[Path] = None
|
56
46
|
|
57
47
|
@property
|
@@ -62,63 +52,7 @@ class PepAvatar(PepItem):
|
|
62
52
|
data.set_value(self._avatar_data_path.read_bytes())
|
63
53
|
return data
|
64
54
|
|
65
|
-
|
66
|
-
def _sha(b: bytes):
|
67
|
-
return hashlib.sha1(b).hexdigest()
|
68
|
-
|
69
|
-
def _get_weak_unique_id(self, avatar: AvatarType):
|
70
|
-
if isinstance(avatar, str):
|
71
|
-
return avatar # url
|
72
|
-
elif isinstance(avatar, bytes):
|
73
|
-
return self._sha(avatar)
|
74
|
-
elif isinstance(avatar, Path):
|
75
|
-
return self._sha(avatar.read_bytes())
|
76
|
-
|
77
|
-
@staticmethod
|
78
|
-
async def _get_image(avatar: AvatarType) -> PILImage:
|
79
|
-
if isinstance(avatar, str):
|
80
|
-
# async with aiohttp.ClientSession() as session:
|
81
|
-
async with avatar_cache.http.get(avatar) as response:
|
82
|
-
return Image.open(io.BytesIO(await response.read()))
|
83
|
-
elif isinstance(avatar, bytes):
|
84
|
-
return Image.open(io.BytesIO(avatar))
|
85
|
-
elif isinstance(avatar, Path):
|
86
|
-
return Image.open(avatar)
|
87
|
-
else:
|
88
|
-
raise TypeError("Avatar must be bytes, a Path or a str (URL)", avatar)
|
89
|
-
|
90
|
-
async def set_avatar(
|
91
|
-
self, avatar: AvatarType, unique_id: Optional[LegacyFileIdType] = None
|
92
|
-
):
|
93
|
-
if unique_id is None:
|
94
|
-
if isinstance(avatar, str):
|
95
|
-
await self._set_avatar_from_url_alone(avatar)
|
96
|
-
return
|
97
|
-
unique_id = self._get_weak_unique_id(avatar)
|
98
|
-
|
99
|
-
await self._set_avatar_from_unique_id(avatar, unique_id)
|
100
|
-
|
101
|
-
async def _set_avatar_from_unique_id(
|
102
|
-
self, avatar: AvatarType, unique_id: LegacyFileIdType
|
103
|
-
):
|
104
|
-
cached_avatar = avatar_cache.get(unique_id)
|
105
|
-
if cached_avatar:
|
106
|
-
# this shouldn't be necessary but here to re-use avatars downloaded
|
107
|
-
# before the change introducing the JID to unique ID mapping
|
108
|
-
avatar_cache.store_jid(self.jid, unique_id)
|
109
|
-
else:
|
110
|
-
img = await self._get_image(avatar)
|
111
|
-
cached_avatar = await avatar_cache.convert_and_store(
|
112
|
-
img, unique_id, self.jid
|
113
|
-
)
|
114
|
-
|
115
|
-
self._set_avatar_from_cache(cached_avatar)
|
116
|
-
|
117
|
-
async def _set_avatar_from_url_alone(self, url: str):
|
118
|
-
cached_avatar = await avatar_cache.get_avatar_from_url_alone(url, self.jid)
|
119
|
-
self._set_avatar_from_cache(cached_avatar)
|
120
|
-
|
121
|
-
def _set_avatar_from_cache(self, cached_avatar: CachedAvatar):
|
55
|
+
def set_avatar_from_cache(self, cached_avatar: CachedAvatar):
|
122
56
|
metadata = AvatarMetadata()
|
123
57
|
self.id = cached_avatar.hash
|
124
58
|
metadata.add_info(
|
@@ -131,31 +65,10 @@ class PepAvatar(PepItem):
|
|
131
65
|
self.metadata = metadata
|
132
66
|
self._avatar_data_path = cached_avatar.path
|
133
67
|
|
134
|
-
@staticmethod
|
135
|
-
def from_db(jid: JID, user: Optional[GatewayUser] = None) -> Optional["PepAvatar"]:
|
136
|
-
cached_id = db.avatar_get(jid)
|
137
|
-
if cached_id is None:
|
138
|
-
return None
|
139
|
-
item = PepAvatar(jid)
|
140
|
-
cached_avatar = avatar_cache.get(cached_id)
|
141
|
-
if cached_avatar is None:
|
142
|
-
raise XMPPError("internal-server-error")
|
143
|
-
item._set_avatar_from_cache(cached_avatar)
|
144
|
-
return item
|
145
|
-
|
146
|
-
def to_db(self, jid: JID, user=None):
|
147
|
-
cached_id = avatar_cache.get_cached_id_for(jid)
|
148
|
-
if cached_id is None:
|
149
|
-
log.warning("Could not store avatar for %s", jid)
|
150
|
-
return
|
151
|
-
db.avatar_store(jid, cached_id)
|
152
|
-
|
153
|
-
@staticmethod
|
154
|
-
def remove_from_db(jid: JID):
|
155
|
-
db.avatar_delete(jid)
|
156
|
-
|
157
68
|
|
158
69
|
class PepNick(PepItem):
|
70
|
+
contact_store: ContactStore
|
71
|
+
|
159
72
|
def __init__(self, nick: Optional[str] = None):
|
160
73
|
nickname = UserNick()
|
161
74
|
if nick is not None:
|
@@ -163,20 +76,6 @@ class PepNick(PepItem):
|
|
163
76
|
self.nick = nickname
|
164
77
|
self.__nick_str = nick
|
165
78
|
|
166
|
-
@staticmethod
|
167
|
-
def from_db(jid: JID, user: Optional[GatewayUser] = None) -> Optional["PepNick"]:
|
168
|
-
if user is None:
|
169
|
-
raise XMPPError("not-allowed")
|
170
|
-
nick = db.nick_get(jid, user)
|
171
|
-
if nick is None:
|
172
|
-
return None
|
173
|
-
return PepNick(nick)
|
174
|
-
|
175
|
-
def to_db(self, jid: JID, user: Optional[GatewayUser] = None):
|
176
|
-
if user is None:
|
177
|
-
raise XMPPError("not-allowed")
|
178
|
-
db.nick_store(jid, str(self.__nick_str), user)
|
179
|
-
|
180
79
|
|
181
80
|
class PubSubComponent(NamedLockMixin, BasePlugin):
|
182
81
|
xmpp: "BaseGateway"
|
@@ -186,7 +85,6 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
186
85
|
dependencies = {
|
187
86
|
"xep_0030",
|
188
87
|
"xep_0060",
|
189
|
-
# "xep_0084",
|
190
88
|
"xep_0115",
|
191
89
|
"xep_0163",
|
192
90
|
}
|
@@ -276,7 +174,7 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
276
174
|
else:
|
277
175
|
if pep_avatar.metadata is None:
|
278
176
|
raise XMPPError("internal-server-error", "Avatar but no metadata?")
|
279
|
-
await self.
|
177
|
+
await self.broadcast(
|
280
178
|
data=pep_avatar.metadata,
|
281
179
|
from_=p.get_to(),
|
282
180
|
to=from_,
|
@@ -288,7 +186,7 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
288
186
|
except XMPPError:
|
289
187
|
pass
|
290
188
|
else:
|
291
|
-
await self.
|
189
|
+
await self.broadcast(data=pep_nick.nick, from_=p.get_to(), to=from_)
|
292
190
|
|
293
191
|
if VCARD4_NAMESPACE + "+notify" in features:
|
294
192
|
await self.broadcast_vcard_event(p.get_to(), to=from_)
|
@@ -303,7 +201,7 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
303
201
|
# but movim expects it to be here, and I guess
|
304
202
|
|
305
203
|
log.debug("Broadcast vcard4 event: %s", vcard)
|
306
|
-
await self.
|
204
|
+
await self.broadcast(
|
307
205
|
data=vcard,
|
308
206
|
from_=JID(from_).bare,
|
309
207
|
to=to,
|
@@ -311,26 +209,34 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
311
209
|
node=VCARD4_NAMESPACE,
|
312
210
|
)
|
313
211
|
|
314
|
-
async def _get_authorized_item(
|
315
|
-
self, cls: Type[PepItemType], stanza: Union[Iq, Presence]
|
316
|
-
) -> PepItemType:
|
317
|
-
sto = stanza.get_to()
|
318
|
-
user = user_store.get_by_jid(stanza.get_from())
|
319
|
-
item = cls.from_db(sto, user)
|
320
|
-
if item is None:
|
321
|
-
raise XMPPError("item-not-found")
|
322
|
-
|
323
|
-
if sto != self.xmpp.boundjid.bare:
|
324
|
-
session = self.xmpp.get_session_from_stanza(stanza)
|
325
|
-
await session.contacts.by_jid(sto)
|
326
|
-
|
327
|
-
return item # type:ignore
|
328
|
-
|
329
212
|
async def _get_authorized_avatar(self, stanza: Union[Iq, Presence]) -> PepAvatar:
|
330
|
-
|
213
|
+
if stanza.get_to() == self.xmpp.boundjid.bare:
|
214
|
+
item = PepAvatar()
|
215
|
+
item.set_avatar_from_cache(avatar_cache.get_by_pk(self.xmpp.avatar_pk))
|
216
|
+
return item
|
217
|
+
|
218
|
+
session = self.xmpp.get_session_from_stanza(stanza)
|
219
|
+
entity = await session.get_contact_or_group_or_participant(stanza.get_to())
|
220
|
+
|
221
|
+
item = PepAvatar()
|
222
|
+
avatar_id = entity.avatar_id
|
223
|
+
if avatar_id is not None:
|
224
|
+
stored = avatar_cache.get(str(avatar_id))
|
225
|
+
assert stored is not None
|
226
|
+
item.set_avatar_from_cache(stored)
|
227
|
+
return item
|
331
228
|
|
332
229
|
async def _get_authorized_nick(self, stanza: Union[Iq, Presence]) -> PepNick:
|
333
|
-
|
230
|
+
if stanza.get_to() == self.xmpp.boundjid.bare:
|
231
|
+
return PepNick(self.xmpp.COMPONENT_NAME)
|
232
|
+
|
233
|
+
session = self.xmpp.get_session_from_stanza(stanza)
|
234
|
+
entity = await session.contacts.by_jid(stanza.get_to())
|
235
|
+
|
236
|
+
if entity.name is not None:
|
237
|
+
return PepNick(entity.name)
|
238
|
+
else:
|
239
|
+
return PepNick()
|
334
240
|
|
335
241
|
async def _get_avatar_data(self, iq: Iq):
|
336
242
|
pep_avatar = await self._get_authorized_avatar(iq)
|
@@ -372,10 +278,6 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
372
278
|
raise XMPPError("item-not-found")
|
373
279
|
self._reply_with_payload(iq, vcard, "current", VCARD4_NAMESPACE)
|
374
280
|
|
375
|
-
@staticmethod
|
376
|
-
def get_avatar(jid: JID):
|
377
|
-
return PepAvatar.from_db(jid)
|
378
|
-
|
379
281
|
@staticmethod
|
380
282
|
def _reply_with_payload(
|
381
283
|
iq: Iq,
|
@@ -394,7 +296,7 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
394
296
|
result["pubsub"]["items"].append(item)
|
395
297
|
result.send()
|
396
298
|
|
397
|
-
async def
|
299
|
+
async def broadcast(self, data, from_: JidStr, to: OptJidStr = None, **kwargs):
|
398
300
|
from_ = JID(from_)
|
399
301
|
if from_ != self.xmpp.boundjid.bare and to is not None:
|
400
302
|
to = JID(to)
|
@@ -428,97 +330,37 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
428
330
|
msg.append(event)
|
429
331
|
|
430
332
|
if to is None:
|
431
|
-
for u in
|
333
|
+
for u in self.xmpp.store.users.get_all():
|
432
334
|
new_msg = copy(msg)
|
433
|
-
new_msg.set_to(u.
|
335
|
+
new_msg.set_to(u.jid.bare)
|
434
336
|
new_msg.send()
|
435
337
|
else:
|
436
338
|
msg.set_to(to)
|
437
339
|
msg.send()
|
438
340
|
|
439
|
-
async def
|
440
|
-
self,
|
441
|
-
|
442
|
-
avatar: Optional[AvatarType] = None,
|
443
|
-
broadcast_to: OptJidStr = None,
|
444
|
-
unique_id=None,
|
445
|
-
broadcast=True,
|
446
|
-
):
|
447
|
-
jid = JID(jid)
|
448
|
-
if avatar is None:
|
449
|
-
PepAvatar.remove_from_db(jid)
|
450
|
-
await self._broadcast(AvatarMetadata(), jid, broadcast_to)
|
451
|
-
avatar_cache.delete_jid(jid)
|
452
|
-
else:
|
453
|
-
pep_avatar = PepAvatar(jid)
|
454
|
-
try:
|
455
|
-
await pep_avatar.set_avatar(avatar, unique_id)
|
456
|
-
except (UnidentifiedImageError, FileNotFoundError) as e:
|
457
|
-
log.warning("Failed to set avatar for %s: %r", self, e)
|
458
|
-
return
|
459
|
-
pep_avatar.to_db(jid)
|
460
|
-
if pep_avatar.metadata is None:
|
461
|
-
raise RuntimeError
|
462
|
-
if not broadcast:
|
463
|
-
return
|
464
|
-
await self._broadcast(
|
465
|
-
pep_avatar.metadata,
|
466
|
-
jid,
|
467
|
-
broadcast_to,
|
468
|
-
id=pep_avatar.metadata["info"]["id"],
|
469
|
-
)
|
470
|
-
|
471
|
-
async def set_avatar_from_cache(
|
472
|
-
self, jid: JID, send_empty: bool, broadcast_to: OptJidStr = None, broadcast=True
|
473
|
-
):
|
474
|
-
uid = avatar_cache.get_cached_id_for(jid)
|
475
|
-
if uid is None:
|
476
|
-
if not send_empty:
|
477
|
-
return
|
478
|
-
self.xmpp.loop.create_task(
|
479
|
-
self.set_avatar(jid, None, broadcast_to, uid, broadcast)
|
480
|
-
)
|
481
|
-
return
|
482
|
-
cached_avatar = avatar_cache.get(str(uid))
|
341
|
+
async def broadcast_avatar(
|
342
|
+
self, from_: JidStr, to: JidStr, cached_avatar: Optional[CachedAvatar]
|
343
|
+
) -> None:
|
483
344
|
if cached_avatar is None:
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
345
|
+
await self.broadcast(AvatarMetadata(), from_, to)
|
346
|
+
else:
|
347
|
+
pep_avatar = PepAvatar()
|
348
|
+
pep_avatar.set_avatar_from_cache(cached_avatar)
|
349
|
+
assert pep_avatar.metadata is not None
|
350
|
+
await self.broadcast(
|
351
|
+
pep_avatar.metadata, from_, to, id=pep_avatar.metadata["info"]["id"]
|
489
352
|
)
|
490
|
-
return
|
491
|
-
self.xmpp.loop.create_task(
|
492
|
-
self.set_avatar(jid, cached_avatar.path, broadcast_to, uid, broadcast)
|
493
|
-
)
|
494
353
|
|
495
|
-
def
|
354
|
+
def broadcast_nick(
|
496
355
|
self,
|
497
|
-
|
356
|
+
user_jid: JID,
|
498
357
|
jid: JidStr,
|
499
358
|
nick: Optional[str] = None,
|
500
359
|
):
|
501
360
|
jid = JID(jid)
|
502
361
|
nickname = PepNick(nick)
|
503
|
-
nickname.to_db(jid, user)
|
504
362
|
log.debug("New nickname: %s", nickname.nick)
|
505
|
-
self.xmpp.loop.create_task(self.
|
506
|
-
|
507
|
-
async def broadcast_all(self, from_: JID, to: JID):
|
508
|
-
"""
|
509
|
-
Force push avatar and nick for a stored JID.
|
510
|
-
"""
|
511
|
-
a = PepAvatar.from_db(from_)
|
512
|
-
if a:
|
513
|
-
if a.metadata:
|
514
|
-
await self._broadcast(
|
515
|
-
a.metadata, from_, to, id=a.metadata["info"]["id"]
|
516
|
-
)
|
517
|
-
else:
|
518
|
-
log.warning("No metadata associated to this cached avatar?!")
|
519
|
-
n = PepNick.from_db(from_, user_store.get_by_jid(to))
|
520
|
-
if n:
|
521
|
-
await self._broadcast(n.nick, from_, to)
|
363
|
+
self.xmpp.loop.create_task(self.broadcast(nickname.nick, jid, user_jid.bare))
|
522
364
|
|
523
365
|
|
524
366
|
log = logging.getLogger(__name__)
|