slidge 0.2.12__py3-none-any.whl → 0.3.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 +5 -2
- slidge/command/adhoc.py +9 -3
- slidge/command/admin.py +16 -12
- slidge/command/base.py +16 -12
- slidge/command/chat_command.py +25 -16
- slidge/command/user.py +7 -8
- slidge/contact/contact.py +119 -209
- slidge/contact/roster.py +106 -105
- slidge/core/config.py +2 -43
- slidge/core/dispatcher/caps.py +9 -2
- slidge/core/dispatcher/disco.py +13 -3
- slidge/core/dispatcher/message/__init__.py +1 -1
- slidge/core/dispatcher/message/chat_state.py +17 -8
- slidge/core/dispatcher/message/marker.py +7 -5
- slidge/core/dispatcher/message/message.py +117 -92
- slidge/core/dispatcher/muc/__init__.py +1 -1
- slidge/core/dispatcher/muc/admin.py +4 -4
- slidge/core/dispatcher/muc/mam.py +10 -6
- slidge/core/dispatcher/muc/misc.py +4 -2
- slidge/core/dispatcher/muc/owner.py +5 -3
- slidge/core/dispatcher/muc/ping.py +3 -1
- slidge/core/dispatcher/presence.py +21 -15
- slidge/core/dispatcher/registration.py +20 -12
- slidge/core/dispatcher/search.py +7 -3
- slidge/core/dispatcher/session_dispatcher.py +13 -5
- slidge/core/dispatcher/util.py +37 -27
- slidge/core/dispatcher/vcard.py +7 -4
- slidge/core/gateway.py +168 -84
- slidge/core/mixins/__init__.py +1 -11
- slidge/core/mixins/attachment.py +163 -148
- slidge/core/mixins/avatar.py +100 -177
- slidge/core/mixins/db.py +50 -2
- slidge/core/mixins/message.py +19 -17
- slidge/core/mixins/message_maker.py +29 -15
- slidge/core/mixins/message_text.py +38 -30
- slidge/core/mixins/presence.py +91 -35
- slidge/core/pubsub.py +42 -47
- slidge/core/session.py +88 -57
- slidge/db/alembic/versions/0337c90c0b96_unify_legacy_xmpp_id_mappings.py +183 -0
- slidge/db/alembic/versions/4dbd23a3f868_new_avatar_store.py +56 -0
- slidge/db/alembic/versions/54ce3cde350c_use_hash_for_avatar_filenames.py +50 -0
- slidge/db/alembic/versions/58b98dacf819_refactor.py +118 -0
- slidge/db/alembic/versions/75a62b74b239_ditch_hats_table.py +74 -0
- slidge/db/avatar.py +150 -119
- slidge/db/meta.py +33 -22
- slidge/db/models.py +68 -117
- slidge/db/store.py +412 -1094
- slidge/group/archive.py +61 -54
- slidge/group/bookmarks.py +74 -55
- slidge/group/participant.py +135 -142
- slidge/group/room.py +315 -312
- slidge/main.py +28 -18
- slidge/migration.py +2 -12
- slidge/slixfix/__init__.py +20 -4
- slidge/slixfix/delivery_receipt.py +6 -4
- slidge/slixfix/link_preview/link_preview.py +1 -1
- slidge/slixfix/link_preview/stanza.py +1 -1
- slidge/slixfix/roster.py +5 -7
- slidge/slixfix/xep_0077/register.py +8 -8
- slidge/slixfix/xep_0077/stanza.py +7 -7
- slidge/slixfix/xep_0100/gateway.py +12 -13
- slidge/slixfix/xep_0153/vcard_avatar.py +1 -1
- slidge/slixfix/xep_0292/vcard4.py +1 -1
- slidge/util/archive_msg.py +11 -5
- slidge/util/conf.py +23 -20
- slidge/util/jid_escaping.py +1 -1
- slidge/{core/mixins → util}/lock.py +6 -6
- slidge/util/test.py +30 -29
- slidge/util/types.py +22 -18
- slidge/util/util.py +19 -22
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/METADATA +1 -1
- slidge-0.3.0a0.dist-info/RECORD +117 -0
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/WHEEL +1 -1
- slidge-0.2.12.dist-info/RECORD +0 -112
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/entry_points.txt +0 -0
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/licenses/LICENSE +0 -0
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/top_level.txt +0 -0
slidge/core/session.py
CHANGED
@@ -7,18 +7,20 @@ from typing import (
|
|
7
7
|
Iterable,
|
8
8
|
NamedTuple,
|
9
9
|
Optional,
|
10
|
+
Type,
|
10
11
|
Union,
|
11
12
|
cast,
|
12
13
|
)
|
13
14
|
|
14
15
|
import aiohttp
|
16
|
+
import sqlalchemy as sa
|
15
17
|
from slixmpp import JID, Message
|
16
18
|
from slixmpp.exceptions import XMPPError
|
17
19
|
from slixmpp.types import PresenceShows
|
18
20
|
|
19
21
|
from ..command import SearchResult
|
20
22
|
from ..contact import LegacyContact, LegacyRoster
|
21
|
-
from ..db.models import GatewayUser
|
23
|
+
from ..db.models import Contact, GatewayUser
|
22
24
|
from ..group.bookmarks import LegacyBookmarks
|
23
25
|
from ..group.room import LegacyMUC
|
24
26
|
from ..util import ABCSubclassableOnceAtMost
|
@@ -89,22 +91,21 @@ class BaseSession(
|
|
89
91
|
This can be used to implement voting in polls in a hacky way.
|
90
92
|
"""
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
+
_roster_cls: Type[LegacyRoster]
|
95
|
+
_bookmarks_cls: Type[LegacyBookmarks]
|
94
96
|
|
95
|
-
|
96
|
-
self.
|
97
|
+
def __init__(self, user: GatewayUser) -> None:
|
98
|
+
self.user = user
|
99
|
+
self.log = logging.getLogger(user.jid.bare)
|
97
100
|
|
98
101
|
self.ignore_messages = set[str]()
|
99
102
|
|
100
|
-
self.contacts
|
103
|
+
self.contacts = self._roster_cls(self)
|
101
104
|
self.is_logging_in = False
|
102
105
|
self._logged = False
|
103
106
|
self.__reset_ready()
|
104
107
|
|
105
|
-
self.bookmarks
|
106
|
-
self
|
107
|
-
)
|
108
|
+
self.bookmarks = self._bookmarks_cls(self)
|
108
109
|
|
109
110
|
self.thread_creation_lock = asyncio.Lock()
|
110
111
|
|
@@ -113,14 +114,18 @@ class BaseSession(
|
|
113
114
|
self.__tasks = set[asyncio.Task]()
|
114
115
|
|
115
116
|
@property
|
116
|
-
def
|
117
|
-
return self.
|
117
|
+
def user_jid(self) -> JID:
|
118
|
+
return self.user.jid
|
119
|
+
|
120
|
+
@property
|
121
|
+
def user_pk(self) -> int:
|
122
|
+
return self.user.id
|
118
123
|
|
119
124
|
@property
|
120
125
|
def http(self) -> aiohttp.ClientSession:
|
121
126
|
return self.xmpp.http
|
122
127
|
|
123
|
-
def __remove_task(self, fut):
|
128
|
+
def __remove_task(self, fut) -> None:
|
124
129
|
self.log.debug("Removing fut %s", fut)
|
125
130
|
self.__tasks.remove(fut)
|
126
131
|
|
@@ -131,7 +136,7 @@ class BaseSession(
|
|
131
136
|
task.add_done_callback(lambda _: self.__remove_task(task))
|
132
137
|
return task
|
133
138
|
|
134
|
-
def cancel_all_tasks(self):
|
139
|
+
def cancel_all_tasks(self) -> None:
|
135
140
|
for task in self.__tasks:
|
136
141
|
task.cancel()
|
137
142
|
|
@@ -148,7 +153,7 @@ class BaseSession(
|
|
148
153
|
"""
|
149
154
|
raise NotImplementedError
|
150
155
|
|
151
|
-
async def logout(self):
|
156
|
+
async def logout(self) -> None:
|
152
157
|
"""
|
153
158
|
Logs out the gateway user from the legacy network.
|
154
159
|
|
@@ -304,6 +309,17 @@ class BaseSession(
|
|
304
309
|
|
305
310
|
paused = deprecated("BaseSession.paused", on_paused)
|
306
311
|
|
312
|
+
async def on_gone(
|
313
|
+
self, chat: RecipientType, thread: Optional[LegacyThreadType] = None
|
314
|
+
):
|
315
|
+
"""
|
316
|
+
Triggered when the user is "gone" in a legacy chat (:xep:`0085`)
|
317
|
+
|
318
|
+
:param chat: See :meth:`.BaseSession.on_text`
|
319
|
+
:param thread:
|
320
|
+
"""
|
321
|
+
raise NotImplementedError
|
322
|
+
|
307
323
|
async def on_displayed(
|
308
324
|
self,
|
309
325
|
chat: RecipientType,
|
@@ -493,7 +509,7 @@ class BaseSession(
|
|
493
509
|
|
494
510
|
async def on_invitation(
|
495
511
|
self, contact: LegacyContact, muc: LegacyMUC, reason: Optional[str]
|
496
|
-
):
|
512
|
+
) -> None:
|
497
513
|
"""
|
498
514
|
Triggered when the user invites a :term:`Contact` to a legacy MUC via
|
499
515
|
:xep:`0249`.
|
@@ -519,7 +535,7 @@ class BaseSession(
|
|
519
535
|
"""
|
520
536
|
raise NotImplementedError
|
521
537
|
|
522
|
-
def __reset_ready(self):
|
538
|
+
def __reset_ready(self) -> None:
|
523
539
|
self.ready = self.xmpp.loop.create_future()
|
524
540
|
|
525
541
|
@property
|
@@ -527,7 +543,7 @@ class BaseSession(
|
|
527
543
|
return self._logged
|
528
544
|
|
529
545
|
@logged.setter
|
530
|
-
def logged(self, v: bool):
|
546
|
+
def logged(self, v: bool) -> None:
|
531
547
|
self.is_logging_in = False
|
532
548
|
self._logged = v
|
533
549
|
if self.ready.done():
|
@@ -539,19 +555,34 @@ class BaseSession(
|
|
539
555
|
if v:
|
540
556
|
self.ready.set_result(True)
|
541
557
|
|
542
|
-
def __repr__(self):
|
558
|
+
def __repr__(self) -> str:
|
543
559
|
return f"<Session of {self.user_jid}>"
|
544
560
|
|
545
|
-
def shutdown(self, logout=True) -> asyncio.Task:
|
561
|
+
def shutdown(self, logout: bool = True) -> asyncio.Task:
|
546
562
|
for m in self.bookmarks:
|
547
563
|
m.shutdown()
|
548
|
-
|
549
|
-
|
564
|
+
with self.xmpp.store.session() as orm:
|
565
|
+
for jid in orm.execute(
|
566
|
+
sa.select(Contact.jid).filter_by(user=self.user, is_friend=True)
|
567
|
+
).scalars():
|
568
|
+
pres = self.xmpp.make_presence(
|
569
|
+
pfrom=jid,
|
570
|
+
pto=self.user_jid,
|
571
|
+
ptype="unavailable",
|
572
|
+
pstatus="Gateway has shut down.",
|
573
|
+
)
|
574
|
+
pres.send()
|
550
575
|
if logout:
|
551
|
-
return self.xmpp.loop.create_task(self.
|
576
|
+
return self.xmpp.loop.create_task(self.__logout())
|
552
577
|
else:
|
553
578
|
return self.xmpp.loop.create_task(noop_coro())
|
554
579
|
|
580
|
+
async def __logout(self) -> None:
|
581
|
+
try:
|
582
|
+
await self.logout()
|
583
|
+
except NotImplementedError:
|
584
|
+
pass
|
585
|
+
|
555
586
|
@staticmethod
|
556
587
|
def legacy_to_xmpp_msg_id(legacy_msg_id: LegacyMessageType) -> str:
|
557
588
|
"""
|
@@ -604,7 +635,7 @@ class BaseSession(
|
|
604
635
|
@classmethod
|
605
636
|
def _from_user_or_none(cls, user):
|
606
637
|
if user is None:
|
607
|
-
log.debug("user not found"
|
638
|
+
log.debug("user not found")
|
608
639
|
raise XMPPError(text="User not found", condition="subscription-required")
|
609
640
|
|
610
641
|
session = _sessions.get(user.jid.bare)
|
@@ -641,11 +672,12 @@ class BaseSession(
|
|
641
672
|
session = _sessions.get(jid.bare)
|
642
673
|
if session is not None:
|
643
674
|
return session
|
644
|
-
|
675
|
+
with cls.xmpp.store.session() as orm:
|
676
|
+
user = orm.query(GatewayUser).filter_by(jid=jid.bare).one_or_none()
|
645
677
|
return cls._from_user_or_none(user)
|
646
678
|
|
647
679
|
@classmethod
|
648
|
-
async def kill_by_jid(cls, jid: JID):
|
680
|
+
async def kill_by_jid(cls, jid: JID) -> None:
|
649
681
|
# """
|
650
682
|
# Terminate a user session.
|
651
683
|
#
|
@@ -665,17 +697,19 @@ class BaseSession(
|
|
665
697
|
c.unsubscribe()
|
666
698
|
for m in session.bookmarks:
|
667
699
|
m.shutdown()
|
668
|
-
|
669
|
-
|
700
|
+
|
701
|
+
try:
|
702
|
+
session = _sessions.pop(jid.bare)
|
703
|
+
except KeyError:
|
670
704
|
log.warning("User not found during unregistration")
|
671
705
|
return
|
672
|
-
await cls.xmpp.unregister(user)
|
673
|
-
cls.xmpp.store.users.delete(user.jid)
|
674
|
-
del _sessions[user.jid.bare]
|
675
|
-
del user
|
676
|
-
del session
|
677
706
|
|
678
|
-
|
707
|
+
with cls.xmpp.store.session() as orm:
|
708
|
+
await cls.xmpp.unregister(session.user)
|
709
|
+
orm.delete(session.user)
|
710
|
+
orm.commit()
|
711
|
+
|
712
|
+
def __ack(self, msg: Message) -> None:
|
679
713
|
if not self.xmpp.PROPER_RECEIPTS:
|
680
714
|
self.xmpp.delivery_receipt.ack(msg)
|
681
715
|
|
@@ -684,7 +718,7 @@ class BaseSession(
|
|
684
718
|
status: Optional[str] = None,
|
685
719
|
show=Optional[PresenceShows],
|
686
720
|
**kwargs,
|
687
|
-
):
|
721
|
+
) -> None:
|
688
722
|
"""
|
689
723
|
Send a presence from the gateway to the user.
|
690
724
|
|
@@ -699,7 +733,7 @@ class BaseSession(
|
|
699
733
|
pto=self.user_jid.bare, pstatus=status, pshow=show, **kwargs
|
700
734
|
)
|
701
735
|
|
702
|
-
def send_cached_presence(self, to: JID):
|
736
|
+
def send_cached_presence(self, to: JID) -> None:
|
703
737
|
if not self.__cached_presence:
|
704
738
|
self.xmpp.send_presence(pto=to, ptype="unavailable")
|
705
739
|
return
|
@@ -710,7 +744,7 @@ class BaseSession(
|
|
710
744
|
**self.__cached_presence.kwargs,
|
711
745
|
)
|
712
746
|
|
713
|
-
def send_gateway_message(self, text: str, **msg_kwargs):
|
747
|
+
def send_gateway_message(self, text: str, **msg_kwargs) -> None:
|
714
748
|
"""
|
715
749
|
Send a message from the gateway component to the user.
|
716
750
|
|
@@ -725,7 +759,7 @@ class BaseSession(
|
|
725
759
|
muc: LegacyMUC,
|
726
760
|
reason: Optional[str] = None,
|
727
761
|
password: Optional[str] = None,
|
728
|
-
):
|
762
|
+
) -> None:
|
729
763
|
"""
|
730
764
|
Send an invitation to join a MUC, emanating from the gateway component.
|
731
765
|
|
@@ -747,7 +781,7 @@ class BaseSession(
|
|
747
781
|
"""
|
748
782
|
return await self.xmpp.input(self.user_jid, text, **msg_kwargs)
|
749
783
|
|
750
|
-
async def send_qr(self, text: str):
|
784
|
+
async def send_qr(self, text: str) -> None:
|
751
785
|
"""
|
752
786
|
Sends a QR code generated from 'text' via HTTP Upload and send the URL to
|
753
787
|
``self.user``
|
@@ -756,13 +790,13 @@ class BaseSession(
|
|
756
790
|
"""
|
757
791
|
await self.xmpp.send_qr(text, mto=self.user_jid)
|
758
792
|
|
759
|
-
def re_login(self):
|
793
|
+
def re_login(self) -> None:
|
760
794
|
# Logout then re-login
|
761
795
|
#
|
762
796
|
# No reason to override this
|
763
797
|
self.xmpp.re_login(self)
|
764
798
|
|
765
|
-
async def get_contact_or_group_or_participant(self, jid: JID, create=True):
|
799
|
+
async def get_contact_or_group_or_participant(self, jid: JID, create: bool = True):
|
766
800
|
if (contact := self.contacts.by_jid_only_if_exists(jid)) is not None:
|
767
801
|
return contact
|
768
802
|
if (muc := self.bookmarks.by_jid_only_if_exists(JID(jid.bare))) is not None:
|
@@ -813,23 +847,20 @@ class BaseSession(
|
|
813
847
|
"Legacy session is not fully initialized, retry later",
|
814
848
|
)
|
815
849
|
|
816
|
-
def legacy_module_data_update(self, data: dict):
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
user = self.user
|
831
|
-
user.legacy_module_data.clear()
|
832
|
-
self.xmpp.store.users.update(user)
|
850
|
+
def legacy_module_data_update(self, data: dict) -> None:
|
851
|
+
user = self.user
|
852
|
+
user.legacy_module_data.update(data)
|
853
|
+
self.xmpp.store.users.update(user)
|
854
|
+
|
855
|
+
def legacy_module_data_set(self, data: dict) -> None:
|
856
|
+
user = self.user
|
857
|
+
user.legacy_module_data = data
|
858
|
+
self.xmpp.store.users.update(user)
|
859
|
+
|
860
|
+
def legacy_module_data_clear(self) -> None:
|
861
|
+
user = self.user
|
862
|
+
user.legacy_module_data.clear()
|
863
|
+
self.xmpp.store.users.update(user)
|
833
864
|
|
834
865
|
|
835
866
|
# keys = user.jid.bare
|
@@ -0,0 +1,183 @@
|
|
1
|
+
"""Unify legacy/XMPP id mappings
|
2
|
+
|
3
|
+
Revision ID: 0337c90c0b96
|
4
|
+
Revises: 58b98dacf819
|
5
|
+
Create Date: 2025-04-25 20:22:47.612652
|
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 = "0337c90c0b96"
|
16
|
+
down_revision: Union[str, None] = "58b98dacf819"
|
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
|
+
op.create_table(
|
24
|
+
"direct_msg",
|
25
|
+
sa.Column("foreign_key", sa.Integer(), nullable=False),
|
26
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
27
|
+
sa.Column("legacy_id", sa.String(), nullable=False),
|
28
|
+
sa.Column("xmpp_id", sa.String(), nullable=False),
|
29
|
+
sa.ForeignKeyConstraint(
|
30
|
+
["foreign_key"],
|
31
|
+
["contact.id"],
|
32
|
+
name=op.f("fk_direct_msg_foreign_key_contact"),
|
33
|
+
),
|
34
|
+
sa.PrimaryKeyConstraint("id", name=op.f("pk_direct_msg")),
|
35
|
+
)
|
36
|
+
with op.batch_alter_table("direct_msg", schema=None) as batch_op:
|
37
|
+
batch_op.create_index(
|
38
|
+
"ix_direct_msg_legacy_id", ["legacy_id", "foreign_key"], unique=False
|
39
|
+
)
|
40
|
+
|
41
|
+
op.create_table(
|
42
|
+
"direct_thread",
|
43
|
+
sa.Column("foreign_key", sa.Integer(), nullable=False),
|
44
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
45
|
+
sa.Column("legacy_id", sa.String(), nullable=False),
|
46
|
+
sa.Column("xmpp_id", sa.String(), nullable=False),
|
47
|
+
sa.ForeignKeyConstraint(
|
48
|
+
["foreign_key"],
|
49
|
+
["contact.id"],
|
50
|
+
name=op.f("fk_direct_thread_foreign_key_contact"),
|
51
|
+
),
|
52
|
+
sa.PrimaryKeyConstraint("id", name=op.f("pk_direct_thread")),
|
53
|
+
)
|
54
|
+
with op.batch_alter_table("direct_thread", schema=None) as batch_op:
|
55
|
+
batch_op.create_index(
|
56
|
+
"ix_direct_direct_thread_id", ["legacy_id", "foreign_key"], unique=False
|
57
|
+
)
|
58
|
+
|
59
|
+
op.create_table(
|
60
|
+
"group_msg",
|
61
|
+
sa.Column("foreign_key", sa.Integer(), nullable=False),
|
62
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
63
|
+
sa.Column("legacy_id", sa.String(), nullable=False),
|
64
|
+
sa.Column("xmpp_id", sa.String(), nullable=False),
|
65
|
+
sa.ForeignKeyConstraint(
|
66
|
+
["foreign_key"], ["room.id"], name=op.f("fk_group_msg_foreign_key_room")
|
67
|
+
),
|
68
|
+
sa.PrimaryKeyConstraint("id", name=op.f("pk_group_msg")),
|
69
|
+
)
|
70
|
+
with op.batch_alter_table("group_msg", schema=None) as batch_op:
|
71
|
+
batch_op.create_index(
|
72
|
+
"ix_group_msg_legacy_id", ["legacy_id", "foreign_key"], unique=False
|
73
|
+
)
|
74
|
+
|
75
|
+
op.create_table(
|
76
|
+
"group_thread",
|
77
|
+
sa.Column("foreign_key", sa.Integer(), nullable=False),
|
78
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
79
|
+
sa.Column("legacy_id", sa.String(), nullable=False),
|
80
|
+
sa.Column("xmpp_id", sa.String(), nullable=False),
|
81
|
+
sa.ForeignKeyConstraint(
|
82
|
+
["foreign_key"], ["room.id"], name=op.f("fk_group_thread_foreign_key_room")
|
83
|
+
),
|
84
|
+
sa.PrimaryKeyConstraint("id", name=op.f("pk_group_thread")),
|
85
|
+
)
|
86
|
+
with op.batch_alter_table("group_thread", schema=None) as batch_op:
|
87
|
+
batch_op.create_index(
|
88
|
+
"ix_direct_group_thread_id", ["legacy_id", "foreign_key"], unique=False
|
89
|
+
)
|
90
|
+
|
91
|
+
with op.batch_alter_table("xmpp_ids_multi", schema=None) as batch_op:
|
92
|
+
batch_op.drop_index("legacy_ids_multi_user_account_id_xmpp_id")
|
93
|
+
|
94
|
+
op.drop_table("xmpp_ids_multi")
|
95
|
+
with op.batch_alter_table("xmpp_to_legacy_ids", schema=None) as batch_op:
|
96
|
+
batch_op.drop_index("xmpp_legacy")
|
97
|
+
|
98
|
+
op.drop_table("xmpp_to_legacy_ids")
|
99
|
+
with op.batch_alter_table("legacy_ids_multi", schema=None) as batch_op:
|
100
|
+
batch_op.drop_index("legacy_ids_multi_user_account_id_legacy_id")
|
101
|
+
|
102
|
+
op.drop_table("legacy_ids_multi")
|
103
|
+
# ### end Alembic commands ###
|
104
|
+
|
105
|
+
|
106
|
+
def downgrade() -> None:
|
107
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
108
|
+
op.create_table(
|
109
|
+
"legacy_ids_multi",
|
110
|
+
sa.Column("id", sa.INTEGER(), nullable=False),
|
111
|
+
sa.Column("user_account_id", sa.INTEGER(), nullable=False),
|
112
|
+
sa.Column("legacy_id", sa.VARCHAR(), nullable=False),
|
113
|
+
sa.ForeignKeyConstraint(
|
114
|
+
["user_account_id"],
|
115
|
+
["user_account.id"],
|
116
|
+
),
|
117
|
+
sa.PrimaryKeyConstraint("id"),
|
118
|
+
)
|
119
|
+
with op.batch_alter_table("legacy_ids_multi", schema=None) as batch_op:
|
120
|
+
batch_op.create_index(
|
121
|
+
"legacy_ids_multi_user_account_id_legacy_id",
|
122
|
+
["user_account_id", "legacy_id"],
|
123
|
+
unique=1,
|
124
|
+
)
|
125
|
+
|
126
|
+
op.create_table(
|
127
|
+
"xmpp_to_legacy_ids",
|
128
|
+
sa.Column("id", sa.INTEGER(), nullable=False),
|
129
|
+
sa.Column("user_account_id", sa.INTEGER(), nullable=False),
|
130
|
+
sa.Column("xmpp_id", sa.VARCHAR(), nullable=False),
|
131
|
+
sa.Column("legacy_id", sa.VARCHAR(), nullable=False),
|
132
|
+
sa.Column("type", sa.VARCHAR(length=10), nullable=False),
|
133
|
+
sa.ForeignKeyConstraint(
|
134
|
+
["user_account_id"],
|
135
|
+
["user_account.id"],
|
136
|
+
),
|
137
|
+
sa.PrimaryKeyConstraint("id"),
|
138
|
+
)
|
139
|
+
with op.batch_alter_table("xmpp_to_legacy_ids", schema=None) as batch_op:
|
140
|
+
batch_op.create_index(
|
141
|
+
"xmpp_legacy", ["user_account_id", "xmpp_id", "legacy_id"], unique=1
|
142
|
+
)
|
143
|
+
|
144
|
+
op.create_table(
|
145
|
+
"xmpp_ids_multi",
|
146
|
+
sa.Column("id", sa.INTEGER(), nullable=False),
|
147
|
+
sa.Column("user_account_id", sa.INTEGER(), nullable=False),
|
148
|
+
sa.Column("xmpp_id", sa.VARCHAR(), nullable=False),
|
149
|
+
sa.Column("legacy_ids_multi_id", sa.INTEGER(), nullable=False),
|
150
|
+
sa.ForeignKeyConstraint(
|
151
|
+
["legacy_ids_multi_id"],
|
152
|
+
["legacy_ids_multi.id"],
|
153
|
+
),
|
154
|
+
sa.ForeignKeyConstraint(
|
155
|
+
["user_account_id"],
|
156
|
+
["user_account.id"],
|
157
|
+
),
|
158
|
+
sa.PrimaryKeyConstraint("id"),
|
159
|
+
)
|
160
|
+
with op.batch_alter_table("xmpp_ids_multi", schema=None) as batch_op:
|
161
|
+
batch_op.create_index(
|
162
|
+
"legacy_ids_multi_user_account_id_xmpp_id",
|
163
|
+
["user_account_id", "xmpp_id"],
|
164
|
+
unique=1,
|
165
|
+
)
|
166
|
+
|
167
|
+
with op.batch_alter_table("group_thread", schema=None) as batch_op:
|
168
|
+
batch_op.drop_index("ix_direct_group_thread_id")
|
169
|
+
|
170
|
+
op.drop_table("group_thread")
|
171
|
+
with op.batch_alter_table("group_msg", schema=None) as batch_op:
|
172
|
+
batch_op.drop_index("ix_group_msg_legacy_id")
|
173
|
+
|
174
|
+
op.drop_table("group_msg")
|
175
|
+
with op.batch_alter_table("direct_thread", schema=None) as batch_op:
|
176
|
+
batch_op.drop_index("ix_direct_direct_thread_id")
|
177
|
+
|
178
|
+
op.drop_table("direct_thread")
|
179
|
+
with op.batch_alter_table("direct_msg", schema=None) as batch_op:
|
180
|
+
batch_op.drop_index("ix_direct_msg_legacy_id")
|
181
|
+
|
182
|
+
op.drop_table("direct_msg")
|
183
|
+
# ### end Alembic commands ###
|
@@ -0,0 +1,56 @@
|
|
1
|
+
"""New avatar store
|
2
|
+
|
3
|
+
Revision ID: 4dbd23a3f868
|
4
|
+
Revises: 04cf35e3cf85
|
5
|
+
Create Date: 2025-04-14 21:57:49.030430
|
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 = "4dbd23a3f868"
|
16
|
+
down_revision: Union[str, None] = "04cf35e3cf85"
|
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
|
+
with op.batch_alter_table("avatar", schema=None) as batch_op:
|
23
|
+
batch_op.add_column(sa.Column("legacy_id", sa.String(), nullable=True))
|
24
|
+
batch_op.create_unique_constraint("avatar_unique_legacy_id", ["legacy_id"])
|
25
|
+
|
26
|
+
batch_op.execute("""
|
27
|
+
UPDATE avatar
|
28
|
+
SET legacy_id = contact.avatar_legacy_id
|
29
|
+
FROM contact
|
30
|
+
WHERE avatar.id = contact.avatar_id
|
31
|
+
""")
|
32
|
+
|
33
|
+
batch_op.execute("""
|
34
|
+
UPDATE avatar
|
35
|
+
SET legacy_id = room.avatar_legacy_id
|
36
|
+
FROM room
|
37
|
+
WHERE avatar.id = room.avatar_id
|
38
|
+
""")
|
39
|
+
|
40
|
+
with op.batch_alter_table("contact", schema=None) as batch_op:
|
41
|
+
batch_op.drop_column("avatar_legacy_id")
|
42
|
+
|
43
|
+
with op.batch_alter_table("room", schema=None) as batch_op:
|
44
|
+
batch_op.drop_column("avatar_legacy_id")
|
45
|
+
|
46
|
+
|
47
|
+
def downgrade() -> None:
|
48
|
+
with op.batch_alter_table("room", schema=None) as batch_op:
|
49
|
+
batch_op.add_column(sa.Column("avatar_legacy_id", sa.VARCHAR(), nullable=True))
|
50
|
+
|
51
|
+
with op.batch_alter_table("contact", schema=None) as batch_op:
|
52
|
+
batch_op.add_column(sa.Column("avatar_legacy_id", sa.VARCHAR(), nullable=True))
|
53
|
+
|
54
|
+
with op.batch_alter_table("avatar", schema=None) as batch_op:
|
55
|
+
batch_op.drop_constraint("avatar_unique_legacy_id", type_="unique")
|
56
|
+
batch_op.drop_column("legacy_id")
|
@@ -0,0 +1,50 @@
|
|
1
|
+
"""Use hash for avatar filenames
|
2
|
+
|
3
|
+
Revision ID: 54ce3cde350c
|
4
|
+
Revises: 4dbd23a3f868
|
5
|
+
Create Date: 2025-04-14 23:52:38.520744
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
from pathlib import Path
|
10
|
+
from typing import Sequence, Union
|
11
|
+
|
12
|
+
import sqlalchemy as sa
|
13
|
+
from alembic import op
|
14
|
+
|
15
|
+
# revision identifiers, used by Alembic.
|
16
|
+
revision: str = "54ce3cde350c"
|
17
|
+
down_revision: Union[str, None] = "4dbd23a3f868"
|
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
|
+
from slidge.core import config
|
24
|
+
|
25
|
+
try:
|
26
|
+
avatars_root = config.HOME_DIR / "slidge_avatars_v3"
|
27
|
+
except AttributeError:
|
28
|
+
avatars_root = Path(".")
|
29
|
+
|
30
|
+
connection = op.get_bind()
|
31
|
+
avatars = connection.execute(sa.text("SELECT id, filename, hash FROM avatar"))
|
32
|
+
for avatar in avatars:
|
33
|
+
filename = avatar[1]
|
34
|
+
hash_value = avatar[2]
|
35
|
+
if filename and hash_value:
|
36
|
+
old_file_path = avatars_root / filename
|
37
|
+
new_file_path = (avatars_root / hash_value).with_suffix(".png")
|
38
|
+
if old_file_path.exists():
|
39
|
+
old_file_path.rename(new_file_path)
|
40
|
+
|
41
|
+
with op.batch_alter_table("avatar", schema=None) as batch_op:
|
42
|
+
batch_op.drop_column("filename")
|
43
|
+
|
44
|
+
|
45
|
+
def downgrade() -> None:
|
46
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
47
|
+
with op.batch_alter_table("avatar", schema=None) as batch_op:
|
48
|
+
batch_op.add_column(sa.Column("filename", sa.VARCHAR(), nullable=False))
|
49
|
+
|
50
|
+
# ### end Alembic commands ###
|