slidge 0.1.2__py3-none-any.whl → 0.2.0a0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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__)
|