slidge 0.2.0a2__tar.gz → 0.2.0a3__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {slidge-0.2.0a2 → slidge-0.2.0a3}/PKG-INFO +1 -1
- {slidge-0.2.0a2 → slidge-0.2.0a3}/pyproject.toml +1 -1
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/__version__.py +1 -1
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/contact/contact.py +24 -1
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/base.py +0 -2
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/session_dispatcher.py +19 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/vcard_temp.py +2 -2
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/pubsub.py +11 -9
- slidge-0.2.0a3/slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +44 -0
- slidge-0.2.0a3/slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +43 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +13 -1
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/meta.py +7 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/models.py +12 -2
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/store.py +12 -1
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/main.py +0 -4
- slidge-0.2.0a3/slidge/py.typed +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/roster.py +4 -2
- slidge-0.2.0a3/slidge/slixfix/xep_0292/vcard4.py +14 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/util/test.py +1 -1
- slidge-0.2.0a2/slidge/slixfix/xep_0292/vcard4.py +0 -103
- {slidge-0.2.0a2 → slidge-0.2.0a3}/LICENSE +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/README.md +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/__main__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/adhoc.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/admin.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/base.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/categories.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/chat_command.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/register.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/command/user.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/contact/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/contact/roster.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/config.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/caps.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/delivery_receipt.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/disco.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/mam.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/muc_admin.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/ping.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/presence.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/registration.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/gateway/search.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/attachment.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/avatar.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/base.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/db.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/disco.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/lock.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/message.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/message_maker.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/presence.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/mixins/recipient.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/core/session.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/__init__.py +0 -0
- /slidge-0.2.0a2/slidge/py.typed → /slidge-0.2.0a3/slidge/db/alembic/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/env.py +0 -0
- /slidge-0.2.0a2/slidge/util/db.py → /slidge-0.2.0a3/slidge/db/alembic/old_user_store.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/script.py.mako +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/avatar.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/group/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/group/archive.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/group/bookmarks.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/group/participant.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/group/room.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/migration.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/link_preview/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/link_preview/link_preview.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/link_preview/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0077/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0077/register.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0077/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0100/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0100/gateway.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0100/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0153/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0153/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0153/vcard_avatar.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0264/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0264/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0264/thumbnail.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0292/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0313/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0313/mam.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0313/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0317/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0317/hats.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0317/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0356_old/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0356_old/privilege.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0356_old/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0424/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0424/retraction.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0424/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0490/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0490/mds.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/slixfix/xep_0490/stanza.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/util/__init__.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/util/archive_msg.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/util/conf.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/util/types.py +0 -0
- {slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/util/util.py +0 -0
@@ -3,6 +3,7 @@ import logging
|
|
3
3
|
import warnings
|
4
4
|
from datetime import date
|
5
5
|
from typing import TYPE_CHECKING, Generic, Iterable, Optional, Self, Union
|
6
|
+
from xml.etree import ElementTree as ET
|
6
7
|
|
7
8
|
from slixmpp import JID, Message, Presence
|
8
9
|
from slixmpp.exceptions import IqError
|
@@ -125,6 +126,16 @@ class LegacyContact(
|
|
125
126
|
self._is_friend: bool = False
|
126
127
|
self._added_to_roster = False
|
127
128
|
self._caps_ver: str | None = None
|
129
|
+
self._vcard_fetched = False
|
130
|
+
self._vcard: str | None = None
|
131
|
+
|
132
|
+
async def get_vcard(self) -> VCard4 | None:
|
133
|
+
if not self._vcard_fetched:
|
134
|
+
await self.fetch_vcard()
|
135
|
+
if self._vcard is None:
|
136
|
+
return None
|
137
|
+
|
138
|
+
return VCard4(xml=ET.fromstring(self._vcard))
|
128
139
|
|
129
140
|
@property
|
130
141
|
def is_friend(self):
|
@@ -373,7 +384,17 @@ class LegacyContact(
|
|
373
384
|
elif country:
|
374
385
|
vcard.add_address(country, locality)
|
375
386
|
|
376
|
-
self.
|
387
|
+
self._vcard = str(vcard)
|
388
|
+
self._vcard_fetched = True
|
389
|
+
self.session.create_task(
|
390
|
+
self.xmpp.pubsub.broadcast_vcard_event(self.jid, self.user_jid, vcard)
|
391
|
+
)
|
392
|
+
|
393
|
+
if self._updating_info:
|
394
|
+
return
|
395
|
+
|
396
|
+
assert self.contact_pk is not None
|
397
|
+
self.xmpp.store.contacts.set_vcard(self.contact_pk, self._vcard)
|
377
398
|
|
378
399
|
def get_roster_item(self):
|
379
400
|
item = {
|
@@ -584,6 +605,8 @@ class LegacyContact(
|
|
584
605
|
contact._caps_ver = stored.caps_ver
|
585
606
|
contact._set_logger_name()
|
586
607
|
contact._set_avatar_from_store(stored)
|
608
|
+
contact._vcard = stored.vcard
|
609
|
+
contact._vcard_fetched = stored.vcard_fetched
|
587
610
|
return contact
|
588
611
|
|
589
612
|
|
@@ -36,7 +36,6 @@ from ...command.register import RegistrationType
|
|
36
36
|
from ...db import GatewayUser, SlidgeStore
|
37
37
|
from ...db.avatar import avatar_cache
|
38
38
|
from ...slixfix.roster import RosterBackend
|
39
|
-
from ...slixfix.xep_0292.vcard4 import VCard4Provider
|
40
39
|
from ...util import ABCSubclassableOnceAtMost
|
41
40
|
from ...util.types import AvatarType, MessageOrPresenceTypeVar
|
42
41
|
from ...util.util import timeit
|
@@ -331,7 +330,6 @@ class BaseGateway(
|
|
331
330
|
|
332
331
|
self.register_plugin("pubsub", {"component_name": self.COMPONENT_NAME})
|
333
332
|
self.pubsub: PubSubComponent = self["pubsub"]
|
334
|
-
self.vcard: VCard4Provider = self["xep_0292_provider"]
|
335
333
|
self.delivery_receipt: DeliveryReceipt = DeliveryReceipt(self)
|
336
334
|
|
337
335
|
# with this we receive user avatar updates
|
@@ -68,6 +68,13 @@ class SessionDispatcher:
|
|
68
68
|
_exceptions_to_xmpp_errors(self.on_ibr_remove), # type: ignore
|
69
69
|
)
|
70
70
|
)
|
71
|
+
self.xmpp.register_handler(
|
72
|
+
CoroutineCallback(
|
73
|
+
"get_vcard",
|
74
|
+
StanzaPath("iq@type=get/vcard"),
|
75
|
+
_exceptions_to_xmpp_errors(self.on_get_vcard), # type:ignore
|
76
|
+
)
|
77
|
+
)
|
71
78
|
|
72
79
|
for event in (
|
73
80
|
"legacy_message",
|
@@ -778,6 +785,18 @@ class SessionDispatcher:
|
|
778
785
|
|
779
786
|
raise XMPPError("feature-not-implemented")
|
780
787
|
|
788
|
+
async def on_get_vcard(self, iq: Iq):
|
789
|
+
session = await self.__get_session(iq)
|
790
|
+
session.raise_if_not_logged()
|
791
|
+
contact = await session.contacts.by_jid(iq.get_to())
|
792
|
+
vcard = await contact.get_vcard()
|
793
|
+
reply = iq.reply()
|
794
|
+
if vcard:
|
795
|
+
reply.append(vcard)
|
796
|
+
else:
|
797
|
+
reply.enable("vcard")
|
798
|
+
reply.send()
|
799
|
+
|
781
800
|
def _xmpp_msg_id_to_legacy(self, session: "BaseSession", xmpp_id: str):
|
782
801
|
sent = self.xmpp.store.sent.get_legacy_id(session.user_pk, xmpp_id)
|
783
802
|
if sent is not None:
|
@@ -79,14 +79,14 @@ class VCardTemp:
|
|
79
79
|
elif not (contact := entity.contact):
|
80
80
|
raise XMPPError("item-not-found", "This participant has no contact")
|
81
81
|
else:
|
82
|
-
vcard = await
|
82
|
+
vcard = await contact.get_vcard()
|
83
83
|
avatar = contact.get_avatar()
|
84
84
|
type_ = "image/png"
|
85
85
|
else:
|
86
86
|
avatar = entity.get_avatar()
|
87
87
|
type_ = "image/png"
|
88
88
|
if isinstance(entity, LegacyContact):
|
89
|
-
vcard = await
|
89
|
+
vcard = await entity.get_vcard()
|
90
90
|
else:
|
91
91
|
vcard = None
|
92
92
|
v = self.xmpp.plugin["xep_0054"].make_vcard()
|
@@ -135,6 +135,7 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
135
135
|
|
136
136
|
to = p.get_to()
|
137
137
|
|
138
|
+
contact = None
|
138
139
|
# we don't want to push anything for contacts that are not in the user's roster
|
139
140
|
if to != self.xmpp.boundjid.bare:
|
140
141
|
session = self.xmpp.get_session_from_stanza(p)
|
@@ -186,17 +187,19 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
186
187
|
else:
|
187
188
|
await self.__broadcast(data=pep_nick.nick, from_=p.get_to(), to=from_)
|
188
189
|
|
189
|
-
if VCARD4_NAMESPACE + "+notify" in features:
|
190
|
-
await self.broadcast_vcard_event(
|
190
|
+
if contact is not None and VCARD4_NAMESPACE + "+notify" in features:
|
191
|
+
await self.broadcast_vcard_event(
|
192
|
+
p.get_to(), from_, await contact.get_vcard()
|
193
|
+
)
|
191
194
|
|
192
|
-
async def broadcast_vcard_event(self, from_, to):
|
195
|
+
async def broadcast_vcard_event(self, from_: JID, to: JID, vcard: VCard4 | None):
|
193
196
|
item = Item()
|
194
197
|
item.namespace = VCARD4_NAMESPACE
|
195
198
|
item["id"] = "current"
|
196
|
-
vcard: VCard4 = await self.xmpp["xep_0292_provider"].get_vcard(from_, to)
|
199
|
+
# vcard: VCard4 = await self.xmpp["xep_0292_provider"].get_vcard(from_, to)
|
197
200
|
# The vcard content should NOT be in this event according to the spec:
|
198
201
|
# https://xmpp.org/extensions/xep-0292.html#sect-idm45669698174224
|
199
|
-
# but movim expects it to be here, and I guess
|
202
|
+
# but movim expects it to be here, and I guess it does not hurt
|
200
203
|
|
201
204
|
log.debug("Broadcast vcard4 event: %s", vcard)
|
202
205
|
await self.__broadcast(
|
@@ -268,10 +271,9 @@ class PubSubComponent(NamedLockMixin, BasePlugin):
|
|
268
271
|
# this is not the proper way that clients should retrieve VCards, but
|
269
272
|
# gajim does it this way.
|
270
273
|
# https://xmpp.org/extensions/xep-0292.html#sect-idm45669698174224
|
271
|
-
|
272
|
-
|
273
|
-
)
|
274
|
-
log.debug("VCARD: %s -- %s -- %s", iq.get_to().bare, iq.get_from().bare, vcard)
|
274
|
+
session = self.xmpp.get_session_from_stanza(iq)
|
275
|
+
contact = await session.contacts.by_jid(iq.get_to())
|
276
|
+
vcard = await contact.get_vcard()
|
275
277
|
if vcard is None:
|
276
278
|
raise XMPPError("item-not-found")
|
277
279
|
self._reply_with_payload(iq, vcard, "current", VCARD4_NAMESPACE)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""Lift room legacy ID constraint
|
2
|
+
|
3
|
+
Revision ID: 5bd48bfdffa2
|
4
|
+
Revises: b64b1a793483
|
5
|
+
Create Date: 2024-07-24 10:29:23.467851
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Sequence, Union
|
10
|
+
|
11
|
+
from alembic import op
|
12
|
+
|
13
|
+
from slidge.db.models import Room
|
14
|
+
|
15
|
+
# revision identifiers, used by Alembic.
|
16
|
+
revision: str = "5bd48bfdffa2"
|
17
|
+
down_revision: Union[str, None] = "b64b1a793483"
|
18
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
19
|
+
depends_on: Union[str, Sequence[str], None] = None
|
20
|
+
|
21
|
+
|
22
|
+
def upgrade() -> None:
|
23
|
+
with op.batch_alter_table(
|
24
|
+
"room",
|
25
|
+
schema=None,
|
26
|
+
# without copy_from, the newly created table keeps the constraints
|
27
|
+
# we actually want to ditch.
|
28
|
+
copy_from=Room.__table__, # type:ignore
|
29
|
+
) as batch_op:
|
30
|
+
batch_op.create_unique_constraint(
|
31
|
+
"uq_room_user_account_id_jid", ["user_account_id", "jid"]
|
32
|
+
)
|
33
|
+
batch_op.create_unique_constraint(
|
34
|
+
"uq_room_user_account_id_legacy_id", ["user_account_id", "legacy_id"]
|
35
|
+
)
|
36
|
+
|
37
|
+
|
38
|
+
def downgrade() -> None:
|
39
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
40
|
+
with op.batch_alter_table("room", schema=None) as batch_op:
|
41
|
+
batch_op.drop_constraint("uq_room_user_account_id_legacy_id", type_="unique")
|
42
|
+
batch_op.drop_constraint("uq_room_user_account_id_jid", type_="unique")
|
43
|
+
|
44
|
+
# ### end Alembic commands ###
|
@@ -0,0 +1,43 @@
|
|
1
|
+
"""Add vcard content to contact table
|
2
|
+
|
3
|
+
Revision ID: 8b993243a536
|
4
|
+
Revises: 5bd48bfdffa2
|
5
|
+
Create Date: 2024-07-24 07:02:47.770894
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Sequence, Union
|
10
|
+
|
11
|
+
import sqlalchemy as sa
|
12
|
+
from alembic import op
|
13
|
+
|
14
|
+
# revision identifiers, used by Alembic.
|
15
|
+
revision: str = "8b993243a536"
|
16
|
+
down_revision: Union[str, None] = "5bd48bfdffa2"
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
19
|
+
|
20
|
+
|
21
|
+
def upgrade() -> None:
|
22
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
23
|
+
with op.batch_alter_table("contact", schema=None) as batch_op:
|
24
|
+
batch_op.add_column(sa.Column("vcard", sa.String(), nullable=True))
|
25
|
+
batch_op.add_column(
|
26
|
+
sa.Column(
|
27
|
+
"vcard_fetched",
|
28
|
+
sa.Boolean(),
|
29
|
+
nullable=False,
|
30
|
+
server_default=sa.sql.true(),
|
31
|
+
)
|
32
|
+
)
|
33
|
+
|
34
|
+
# ### end Alembic commands ###
|
35
|
+
|
36
|
+
|
37
|
+
def downgrade() -> None:
|
38
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
39
|
+
with op.batch_alter_table("contact", schema=None) as batch_op:
|
40
|
+
batch_op.drop_column("vcard_fetched")
|
41
|
+
batch_op.drop_column("vcard")
|
42
|
+
|
43
|
+
# ### end Alembic commands ###
|
@@ -58,10 +58,19 @@ def downgrade() -> None:
|
|
58
58
|
|
59
59
|
|
60
60
|
def migrate_from_shelf(accounts: sa.Table) -> None:
|
61
|
+
from slidge import global_config
|
62
|
+
|
63
|
+
db_file = global_config.HOME_DIR / "slidge.db"
|
64
|
+
if not db_file.exists():
|
65
|
+
return
|
66
|
+
|
61
67
|
try:
|
62
|
-
from slidge.
|
68
|
+
from slidge.db.alembic.old_user_store import user_store
|
63
69
|
except ImportError:
|
64
70
|
return
|
71
|
+
|
72
|
+
user_store.set_file(db_file, global_config.SECRET_KEY)
|
73
|
+
|
65
74
|
try:
|
66
75
|
users = list(user_store.get_all())
|
67
76
|
except AttributeError:
|
@@ -83,3 +92,6 @@ def migrate_from_shelf(accounts: sa.Table) -> None:
|
|
83
92
|
for user in users
|
84
93
|
],
|
85
94
|
)
|
95
|
+
|
96
|
+
user_store.close()
|
97
|
+
db_file.unlink()
|
@@ -58,6 +58,13 @@ JSONSerializable = dict[str, JSONSerializableTypes]
|
|
58
58
|
|
59
59
|
class Base(sa.orm.DeclarativeBase):
|
60
60
|
type_annotation_map = {JSONSerializable: JSONEncodedDict, JID: JIDType}
|
61
|
+
naming_convention = {
|
62
|
+
"ix": "ix_%(column_0_label)s",
|
63
|
+
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
64
|
+
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
|
65
|
+
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
66
|
+
"pk": "pk_%(table_name)s",
|
67
|
+
}
|
61
68
|
|
62
69
|
|
63
70
|
def get_engine(path: str) -> sa.Engine:
|
@@ -166,6 +166,9 @@ class Contact(Base):
|
|
166
166
|
)
|
167
167
|
updated: Mapped[bool] = mapped_column(default=False)
|
168
168
|
|
169
|
+
vcard: Mapped[Optional[str]] = mapped_column()
|
170
|
+
vcard_fetched: Mapped[bool] = mapped_column(default=False)
|
171
|
+
|
169
172
|
participants: Mapped[list["Participant"]] = relationship(back_populates="contact")
|
170
173
|
|
171
174
|
|
@@ -191,13 +194,20 @@ class Room(Base):
|
|
191
194
|
Legacy room
|
192
195
|
"""
|
193
196
|
|
197
|
+
__table_args__ = (
|
198
|
+
UniqueConstraint(
|
199
|
+
"user_account_id", "legacy_id", name="uq_room_user_account_id_legacy_id"
|
200
|
+
),
|
201
|
+
UniqueConstraint("user_account_id", "jid", name="uq_room_user_account_id_jid"),
|
202
|
+
)
|
203
|
+
|
194
204
|
__tablename__ = "room"
|
195
205
|
id: Mapped[int] = mapped_column(primary_key=True)
|
196
206
|
user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
|
197
207
|
user: Mapped[GatewayUser] = relationship(back_populates="rooms")
|
198
|
-
legacy_id: Mapped[str] = mapped_column(
|
208
|
+
legacy_id: Mapped[str] = mapped_column(nullable=False)
|
199
209
|
|
200
|
-
jid: Mapped[JID] = mapped_column(
|
210
|
+
jid: Mapped[JID] = mapped_column(nullable=False)
|
201
211
|
|
202
212
|
avatar_id: Mapped[int] = mapped_column(ForeignKey("avatar.id"), nullable=True)
|
203
213
|
avatar: Mapped[Avatar] = relationship(back_populates="rooms")
|
@@ -380,11 +380,22 @@ class ContactStore(UpdatedMixin):
|
|
380
380
|
row.updated = True
|
381
381
|
row.extra_attributes = contact.serialize_extra_attributes()
|
382
382
|
row.caps_ver = contact._caps_ver
|
383
|
+
row.vcard = contact._vcard
|
384
|
+
row.vcard_fetched = contact._vcard_fetched
|
383
385
|
session.add(row)
|
384
386
|
if commit:
|
385
387
|
session.commit()
|
386
388
|
return row.id
|
387
389
|
|
390
|
+
def set_vcard(self, contact_pk: int, vcard: str | None) -> None:
|
391
|
+
with self.session() as session:
|
392
|
+
session.execute(
|
393
|
+
update(Contact)
|
394
|
+
.where(Contact.id == contact_pk)
|
395
|
+
.values(vcard=vcard, vcard_fetched=True)
|
396
|
+
)
|
397
|
+
session.commit()
|
398
|
+
|
388
399
|
def add_to_sent(self, contact_pk: int, msg_id: str) -> None:
|
389
400
|
with self.session() as session:
|
390
401
|
new = ContactSent(contact_id=contact_pk, msg_id=msg_id)
|
@@ -660,7 +671,7 @@ class MultiStore(EngineMixin):
|
|
660
671
|
if existing is not None:
|
661
672
|
if fail:
|
662
673
|
raise
|
663
|
-
log.
|
674
|
+
log.debug("Resetting multi for %s", legacy_msg_id)
|
664
675
|
session.execute(
|
665
676
|
delete(LegacyIdsMulti)
|
666
677
|
.where(LegacyIdsMulti.user_account_id == user_pk)
|
@@ -32,7 +32,6 @@ from slidge.db.avatar import avatar_cache
|
|
32
32
|
from slidge.db.meta import get_engine
|
33
33
|
from slidge.migration import migrate
|
34
34
|
from slidge.util.conf import ConfigModule
|
35
|
-
from slidge.util.db import user_store
|
36
35
|
|
37
36
|
|
38
37
|
class MainConfig(ConfigModule):
|
@@ -114,9 +113,6 @@ def configure():
|
|
114
113
|
logging.info("Creating directory '%s'", h)
|
115
114
|
h.mkdir()
|
116
115
|
|
117
|
-
db_file = config.HOME_DIR / "slidge.db"
|
118
|
-
user_store.set_file(db_file, args.secret_key)
|
119
|
-
|
120
116
|
config.UPLOAD_REQUESTER = config.UPLOAD_REQUESTER or config.JID.bare
|
121
117
|
|
122
118
|
return unknown_argv
|
File without changes
|
@@ -1,9 +1,8 @@
|
|
1
|
+
import logging
|
1
2
|
from typing import TYPE_CHECKING
|
2
3
|
|
3
4
|
from slixmpp import JID
|
4
5
|
|
5
|
-
from ..util.db import log
|
6
|
-
|
7
6
|
if TYPE_CHECKING:
|
8
7
|
from .. import BaseGateway
|
9
8
|
|
@@ -65,3 +64,6 @@ class RosterBackend:
|
|
65
64
|
"whitelisted": False,
|
66
65
|
"subscription": "none",
|
67
66
|
}
|
67
|
+
|
68
|
+
|
69
|
+
log = logging.getLogger(__name__)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from slixmpp.plugins.base import BasePlugin, register_plugin
|
2
|
+
from slixmpp.plugins.xep_0292.stanza import NS
|
3
|
+
|
4
|
+
|
5
|
+
class VCard4Provider(BasePlugin):
|
6
|
+
name = "xep_0292_provider"
|
7
|
+
description = "VCard4 Provider"
|
8
|
+
dependencies = {"xep_0030"}
|
9
|
+
|
10
|
+
def plugin_init(self):
|
11
|
+
self.xmpp.plugin["xep_0030"].add_feature(NS)
|
12
|
+
|
13
|
+
|
14
|
+
register_plugin(VCard4Provider)
|
@@ -287,7 +287,7 @@ class SlidgeTest(SlixTestPlus):
|
|
287
287
|
stanza = self.next_sent()
|
288
288
|
assert "yup" in stanza["status"].lower(), stanza
|
289
289
|
|
290
|
-
self.romeo = BaseSession.get_self_or_unique_subclass().from_jid(
|
290
|
+
self.romeo: BaseSession = BaseSession.get_self_or_unique_subclass().from_jid(
|
291
291
|
JID("romeo@montague.lit")
|
292
292
|
)
|
293
293
|
self.juliet: LegacyContact = self.run_coro(
|
@@ -1,103 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from typing import TYPE_CHECKING, NamedTuple, Optional
|
3
|
-
|
4
|
-
from slixmpp import JID, CoroutineCallback, Iq, StanzaPath
|
5
|
-
from slixmpp.plugins.base import BasePlugin, register_plugin
|
6
|
-
from slixmpp.plugins.xep_0292.stanza import NS, VCard4
|
7
|
-
from slixmpp.types import JidStr
|
8
|
-
|
9
|
-
from slidge.contact import LegacyContact
|
10
|
-
|
11
|
-
if TYPE_CHECKING:
|
12
|
-
from slidge.core.gateway import BaseGateway
|
13
|
-
|
14
|
-
|
15
|
-
class StoredVCard(NamedTuple):
|
16
|
-
content: VCard4
|
17
|
-
authorized_jids: set[JidStr]
|
18
|
-
|
19
|
-
|
20
|
-
class VCard4Provider(BasePlugin):
|
21
|
-
xmpp: "BaseGateway"
|
22
|
-
|
23
|
-
name = "xep_0292_provider"
|
24
|
-
description = "VCard4 Provider"
|
25
|
-
dependencies = {"xep_0030"}
|
26
|
-
|
27
|
-
def __init__(self, *a, **k):
|
28
|
-
super(VCard4Provider, self).__init__(*a, **k)
|
29
|
-
# TODO: store that in DB and not in RAM
|
30
|
-
self._vcards = dict[JidStr, StoredVCard]()
|
31
|
-
|
32
|
-
def plugin_init(self):
|
33
|
-
self.xmpp.register_handler(
|
34
|
-
CoroutineCallback(
|
35
|
-
"get_vcard",
|
36
|
-
StanzaPath(f"iq@type=get/vcard"),
|
37
|
-
self.handle_vcard_get, # type:ignore
|
38
|
-
)
|
39
|
-
)
|
40
|
-
|
41
|
-
self.xmpp.plugin["xep_0030"].add_feature(NS)
|
42
|
-
|
43
|
-
def _get_cached_vcard(self, jid: JidStr, requested_by: JidStr) -> Optional[VCard4]:
|
44
|
-
vcard = self._vcards.get(JID(jid).bare)
|
45
|
-
if vcard:
|
46
|
-
if auth := vcard.authorized_jids:
|
47
|
-
if JID(requested_by).bare in auth:
|
48
|
-
return vcard.content
|
49
|
-
else:
|
50
|
-
return vcard.content
|
51
|
-
return None
|
52
|
-
|
53
|
-
async def get_vcard(self, jid: JidStr, requested_by: JidStr) -> Optional[VCard4]:
|
54
|
-
if vcard := self._get_cached_vcard(jid, requested_by):
|
55
|
-
log.debug("Found a cached vcard")
|
56
|
-
return vcard
|
57
|
-
if not hasattr(self.xmpp, "get_session_from_jid"):
|
58
|
-
return None
|
59
|
-
jid = JID(jid)
|
60
|
-
if not jid.local:
|
61
|
-
return None
|
62
|
-
requested_by = JID(requested_by)
|
63
|
-
session = self.xmpp.get_session_from_jid(requested_by)
|
64
|
-
if session is None:
|
65
|
-
return
|
66
|
-
entity = await session.get_contact_or_group_or_participant(jid)
|
67
|
-
if isinstance(entity, LegacyContact):
|
68
|
-
log.debug("Fetching vcard")
|
69
|
-
await entity.fetch_vcard()
|
70
|
-
return self._get_cached_vcard(jid, requested_by)
|
71
|
-
return None
|
72
|
-
|
73
|
-
async def handle_vcard_get(self, iq: Iq):
|
74
|
-
r = iq.reply()
|
75
|
-
if vcard := await self.get_vcard(iq.get_to().bare, iq.get_from().bare):
|
76
|
-
r.append(vcard)
|
77
|
-
else:
|
78
|
-
r.enable("vcard")
|
79
|
-
r.send()
|
80
|
-
|
81
|
-
def set_vcard(
|
82
|
-
self,
|
83
|
-
jid: JidStr,
|
84
|
-
vcard: VCard4,
|
85
|
-
/,
|
86
|
-
authorized_jids: Optional[set[JidStr]] = None,
|
87
|
-
):
|
88
|
-
cache = self._vcards.get(jid)
|
89
|
-
new = StoredVCard(
|
90
|
-
vcard, authorized_jids if authorized_jids is not None else set()
|
91
|
-
)
|
92
|
-
self._vcards[jid] = new
|
93
|
-
if cache == new:
|
94
|
-
return
|
95
|
-
if self.xmpp["pubsub"] and authorized_jids:
|
96
|
-
for to in authorized_jids:
|
97
|
-
self.xmpp.loop.create_task(
|
98
|
-
self.xmpp["pubsub"].broadcast_vcard_event(jid, to)
|
99
|
-
)
|
100
|
-
|
101
|
-
|
102
|
-
register_plugin(VCard4Provider)
|
103
|
-
log = logging.getLogger(__name__)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{slidge-0.2.0a2 → slidge-0.2.0a3}/slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|