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/session.py
CHANGED
@@ -18,11 +18,10 @@ from slixmpp.types import PresenceShows
|
|
18
18
|
|
19
19
|
from ..command import SearchResult
|
20
20
|
from ..contact import LegacyContact, LegacyRoster
|
21
|
+
from ..db.models import GatewayUser
|
21
22
|
from ..group.bookmarks import LegacyBookmarks
|
22
23
|
from ..group.room import LegacyMUC
|
23
24
|
from ..util import ABCSubclassableOnceAtMost
|
24
|
-
from ..util.db import GatewayUser, user_store
|
25
|
-
from ..util.sql import SQLBiDict
|
26
25
|
from ..util.types import (
|
27
26
|
LegacyGroupIdType,
|
28
27
|
LegacyMessageType,
|
@@ -92,16 +91,10 @@ class BaseSession(
|
|
92
91
|
"""
|
93
92
|
|
94
93
|
def __init__(self, user: GatewayUser):
|
95
|
-
self.log = logging.getLogger(user.
|
94
|
+
self.log = logging.getLogger(user.jid.bare)
|
96
95
|
|
97
|
-
self.
|
98
|
-
self.
|
99
|
-
"session_message_sent", "legacy_id", "xmpp_id", self.user
|
100
|
-
)
|
101
|
-
# message ids (*not* stanza-ids), needed for last msg correction
|
102
|
-
self.muc_sent_msg_ids = SQLBiDict[LegacyMessageType, str](
|
103
|
-
"session_message_sent_muc", "legacy_id", "xmpp_id", self.user
|
104
|
-
)
|
96
|
+
self.user_jid = user.jid
|
97
|
+
self.user_pk = user.id
|
105
98
|
|
106
99
|
self.ignore_messages = set[str]()
|
107
100
|
|
@@ -115,26 +108,26 @@ class BaseSession(
|
|
115
108
|
|
116
109
|
self.http = self.xmpp.http
|
117
110
|
|
118
|
-
self.threads = SQLBiDict[str, LegacyThreadType]( # type:ignore
|
119
|
-
"session_thread_sent_muc", "legacy_id", "xmpp_id", self.user
|
120
|
-
)
|
121
111
|
self.thread_creation_lock = asyncio.Lock()
|
122
112
|
|
123
113
|
self.__cached_presence: Optional[CachedPresence] = None
|
124
114
|
|
125
|
-
self.avatar_hash: Optional[str] = None
|
126
|
-
|
127
115
|
self.__tasks = set[asyncio.Task]()
|
128
116
|
|
117
|
+
@property
|
118
|
+
def user(self) -> GatewayUser:
|
119
|
+
return self.xmpp.store.users.get(self.user_jid) # type:ignore
|
120
|
+
|
129
121
|
def __remove_task(self, fut):
|
130
122
|
self.log.debug("Removing fut %s", fut)
|
131
123
|
self.__tasks.remove(fut)
|
132
124
|
|
133
|
-
def create_task(self, coro) ->
|
125
|
+
def create_task(self, coro) -> asyncio.Task:
|
134
126
|
task = self.xmpp.loop.create_task(coro)
|
135
127
|
self.__tasks.add(task)
|
136
128
|
self.log.debug("Creating task %s", task)
|
137
129
|
task.add_done_callback(lambda _: self.__remove_task(task))
|
130
|
+
return task
|
138
131
|
|
139
132
|
def cancel_all_tasks(self):
|
140
133
|
for task in self.__tasks:
|
@@ -488,6 +481,17 @@ class BaseSession(
|
|
488
481
|
"""
|
489
482
|
await muc.on_set_affiliation(contact, "member", reason, None)
|
490
483
|
|
484
|
+
async def on_leave_group(self, muc: LegacyMUC):
|
485
|
+
"""
|
486
|
+
Triggered when the user leaves a group via the dedicated slidge command
|
487
|
+
or the :xep:`0077` ``<remove />`` mechanism.
|
488
|
+
|
489
|
+
This should be interpreted as definitely leaving the group.
|
490
|
+
|
491
|
+
:param muc: The group to leave
|
492
|
+
"""
|
493
|
+
raise NotImplementedError
|
494
|
+
|
491
495
|
def __reset_ready(self):
|
492
496
|
self.ready = self.xmpp.loop.create_future()
|
493
497
|
|
@@ -507,7 +511,7 @@ class BaseSession(
|
|
507
511
|
self.ready.set_result(True)
|
508
512
|
|
509
513
|
def __repr__(self):
|
510
|
-
return f"<Session of {self.
|
514
|
+
return f"<Session of {self.user_jid}>"
|
511
515
|
|
512
516
|
def shutdown(self) -> asyncio.Task:
|
513
517
|
for c in self.contacts:
|
@@ -571,9 +575,9 @@ class BaseSession(
|
|
571
575
|
log.debug("user not found", stack_info=True)
|
572
576
|
raise XMPPError(text="User not found", condition="subscription-required")
|
573
577
|
|
574
|
-
session = _sessions.get(user)
|
578
|
+
session = _sessions.get(user.jid.bare)
|
575
579
|
if session is None:
|
576
|
-
_sessions[user] = session = cls(user)
|
580
|
+
_sessions[user.jid.bare] = session = cls(user)
|
577
581
|
return session
|
578
582
|
|
579
583
|
@classmethod
|
@@ -590,7 +594,7 @@ class BaseSession(
|
|
590
594
|
# :param s:
|
591
595
|
# :return:
|
592
596
|
# """
|
593
|
-
return cls.
|
597
|
+
return cls.from_jid(s.get_from())
|
594
598
|
|
595
599
|
@classmethod
|
596
600
|
def from_jid(cls, jid: JID) -> "BaseSession":
|
@@ -602,7 +606,11 @@ class BaseSession(
|
|
602
606
|
# :param jid:
|
603
607
|
# :return:
|
604
608
|
# """
|
605
|
-
|
609
|
+
session = _sessions.get(jid.bare)
|
610
|
+
if session is not None:
|
611
|
+
return session
|
612
|
+
user = cls.xmpp.store.users.get(jid)
|
613
|
+
return cls._from_user_or_none(user)
|
606
614
|
|
607
615
|
@classmethod
|
608
616
|
async def kill_by_jid(cls, jid: JID):
|
@@ -615,16 +623,21 @@ class BaseSession(
|
|
615
623
|
# :return:
|
616
624
|
# """
|
617
625
|
log.debug("Killing session of %s", jid)
|
618
|
-
for
|
619
|
-
if
|
626
|
+
for user_jid, session in _sessions.items():
|
627
|
+
if user_jid == jid.bare:
|
620
628
|
break
|
621
629
|
else:
|
622
630
|
log.debug("Did not find a session for %s", jid)
|
623
631
|
return
|
624
632
|
for c in session.contacts:
|
625
633
|
c.unsubscribe()
|
634
|
+
user = cls.xmpp.store.users.get(jid)
|
635
|
+
if user is None:
|
636
|
+
log.warning("User not found during unregistration")
|
637
|
+
return
|
626
638
|
await cls.xmpp.unregister(user)
|
627
|
-
|
639
|
+
cls.xmpp.store.users.delete(user.jid)
|
640
|
+
del _sessions[user.jid.bare]
|
628
641
|
del user
|
629
642
|
del session
|
630
643
|
|
@@ -649,7 +662,7 @@ class BaseSession(
|
|
649
662
|
"""
|
650
663
|
self.__cached_presence = CachedPresence(status, show, kwargs)
|
651
664
|
self.xmpp.send_presence(
|
652
|
-
pto=self.
|
665
|
+
pto=self.user_jid.bare, pstatus=status, pshow=show, **kwargs
|
653
666
|
)
|
654
667
|
|
655
668
|
def send_cached_presence(self, to: JID):
|
@@ -671,7 +684,7 @@ class BaseSession(
|
|
671
684
|
|
672
685
|
:param text: A text
|
673
686
|
"""
|
674
|
-
self.xmpp.send_text(text, mto=self.
|
687
|
+
self.xmpp.send_text(text, mto=self.user_jid, **msg_kwargs)
|
675
688
|
|
676
689
|
def send_gateway_invite(
|
677
690
|
self,
|
@@ -686,7 +699,7 @@ class BaseSession(
|
|
686
699
|
:param reason:
|
687
700
|
:param password:
|
688
701
|
"""
|
689
|
-
self.xmpp.invite_to(muc, reason=reason, password=password, mto=self.
|
702
|
+
self.xmpp.invite_to(muc, reason=reason, password=password, mto=self.user_jid)
|
690
703
|
|
691
704
|
async def input(self, text: str, **msg_kwargs):
|
692
705
|
"""
|
@@ -698,7 +711,7 @@ class BaseSession(
|
|
698
711
|
:param msg_kwargs: Extra attributes
|
699
712
|
:return:
|
700
713
|
"""
|
701
|
-
return await self.xmpp.input(self.
|
714
|
+
return await self.xmpp.input(self.user_jid, text, **msg_kwargs)
|
702
715
|
|
703
716
|
async def send_qr(self, text: str):
|
704
717
|
"""
|
@@ -707,7 +720,7 @@ class BaseSession(
|
|
707
720
|
|
708
721
|
:param text: Text to encode as a QR code
|
709
722
|
"""
|
710
|
-
await self.xmpp.send_qr(text, mto=self.
|
723
|
+
await self.xmpp.send_qr(text, mto=self.user_jid)
|
711
724
|
|
712
725
|
def re_login(self):
|
713
726
|
# Logout then re-login
|
@@ -718,8 +731,8 @@ class BaseSession(
|
|
718
731
|
async def get_contact_or_group_or_participant(self, jid: JID):
|
719
732
|
if jid.bare in (contacts := self.contacts.known_contacts(only_friends=False)):
|
720
733
|
return contacts[jid.bare]
|
721
|
-
if
|
722
|
-
return await self.__get_muc_or_participant(
|
734
|
+
if (muc := self.bookmarks.by_jid_only_if_exists(JID(jid.bare))) is not None:
|
735
|
+
return await self.__get_muc_or_participant(muc, jid)
|
723
736
|
else:
|
724
737
|
muc = None
|
725
738
|
|
@@ -763,6 +776,25 @@ class BaseSession(
|
|
763
776
|
"Legacy session is not fully initialized, retry later",
|
764
777
|
)
|
765
778
|
|
779
|
+
def legacy_module_data_update(self, data: dict):
|
780
|
+
with self.xmpp.store.session():
|
781
|
+
user = self.user
|
782
|
+
user.legacy_module_data.update(data)
|
783
|
+
self.xmpp.store.users.update(user)
|
784
|
+
|
785
|
+
def legacy_module_data_set(self, data: dict):
|
786
|
+
with self.xmpp.store.session():
|
787
|
+
user = self.user
|
788
|
+
user.legacy_module_data = data
|
789
|
+
self.xmpp.store.users.update(user)
|
790
|
+
|
791
|
+
def legacy_module_data_clear(self):
|
792
|
+
with self.xmpp.store.session():
|
793
|
+
user = self.user
|
794
|
+
user.legacy_module_data.clear()
|
795
|
+
self.xmpp.store.users.update(user)
|
796
|
+
|
766
797
|
|
767
|
-
|
798
|
+
# keys = user.jid.bare
|
799
|
+
_sessions: dict[str, BaseSession] = {}
|
768
800
|
log = logging.getLogger(__name__)
|
slidge/db/__init__.py
ADDED
slidge/db/alembic/env.py
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
from alembic import context
|
2
|
+
|
3
|
+
from slidge import global_config
|
4
|
+
from slidge.db.meta import Base, get_engine
|
5
|
+
|
6
|
+
config = context.config
|
7
|
+
|
8
|
+
target_metadata = Base.metadata
|
9
|
+
|
10
|
+
|
11
|
+
def run_migrations_offline() -> None:
|
12
|
+
"""Run migrations in 'offline' mode.
|
13
|
+
|
14
|
+
This configures the context with just a URL
|
15
|
+
and not an Engine, though an Engine is acceptable
|
16
|
+
here as well. By skipping the Engine creation
|
17
|
+
we don't even need a DBAPI to be available.
|
18
|
+
|
19
|
+
Calls to context.execute() here emit the given string to the
|
20
|
+
script output.
|
21
|
+
|
22
|
+
"""
|
23
|
+
url = config.get_main_option("sqlalchemy.url")
|
24
|
+
context.configure(
|
25
|
+
url=url,
|
26
|
+
target_metadata=target_metadata,
|
27
|
+
literal_binds=True,
|
28
|
+
dialect_opts={"paramstyle": "named"},
|
29
|
+
render_as_batch=True,
|
30
|
+
)
|
31
|
+
|
32
|
+
with context.begin_transaction():
|
33
|
+
context.run_migrations()
|
34
|
+
|
35
|
+
|
36
|
+
def run_migrations_online() -> None:
|
37
|
+
"""Run migrations in 'online' mode.
|
38
|
+
|
39
|
+
In this scenario we need to create an Engine
|
40
|
+
and associate a connection with the context.
|
41
|
+
|
42
|
+
"""
|
43
|
+
try:
|
44
|
+
# in prod
|
45
|
+
connectable = get_engine(global_config.DB_URL)
|
46
|
+
except AttributeError:
|
47
|
+
# during dev, to generate migrations
|
48
|
+
connectable = get_engine("sqlite+pysqlite:///dev/slidge.sqlite")
|
49
|
+
|
50
|
+
with connectable.connect() as connection:
|
51
|
+
context.configure(
|
52
|
+
connection=connection,
|
53
|
+
target_metadata=target_metadata,
|
54
|
+
render_as_batch=True,
|
55
|
+
)
|
56
|
+
|
57
|
+
with context.begin_transaction():
|
58
|
+
context.run_migrations()
|
59
|
+
|
60
|
+
|
61
|
+
if context.is_offline_mode():
|
62
|
+
run_migrations_offline()
|
63
|
+
else:
|
64
|
+
run_migrations_online()
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"""${message}
|
2
|
+
|
3
|
+
Revision ID: ${up_revision}
|
4
|
+
Revises: ${down_revision | comma,n}
|
5
|
+
Create Date: ${create_date}
|
6
|
+
|
7
|
+
"""
|
8
|
+
from typing import Sequence, Union
|
9
|
+
|
10
|
+
from alembic import op
|
11
|
+
import sqlalchemy as sa
|
12
|
+
${imports if imports else ""}
|
13
|
+
|
14
|
+
# revision identifiers, used by Alembic.
|
15
|
+
revision: str = ${repr(up_revision)}
|
16
|
+
down_revision: Union[str, None] = ${repr(down_revision)}
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
18
|
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
19
|
+
|
20
|
+
|
21
|
+
def upgrade() -> None:
|
22
|
+
${upgrades if upgrades else "pass"}
|
23
|
+
|
24
|
+
|
25
|
+
def downgrade() -> None:
|
26
|
+
${downgrades if downgrades else "pass"}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
"""Add n_participants attributes to Room
|
2
|
+
|
3
|
+
Should have been part of another commit, but I messed up some rebase
|
4
|
+
|
5
|
+
Revision ID: 09f27f098baa
|
6
|
+
Revises: 29f5280c61aa
|
7
|
+
Create Date: 2024-07-11 10:54:21.155871
|
8
|
+
|
9
|
+
"""
|
10
|
+
|
11
|
+
from typing import Sequence, Union
|
12
|
+
|
13
|
+
import sqlalchemy as sa
|
14
|
+
from alembic import op
|
15
|
+
|
16
|
+
# revision identifiers, used by Alembic.
|
17
|
+
revision: str = "09f27f098baa"
|
18
|
+
down_revision: Union[str, None] = "29f5280c61aa"
|
19
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
20
|
+
depends_on: Union[str, Sequence[str], None] = None
|
21
|
+
|
22
|
+
|
23
|
+
def upgrade() -> None:
|
24
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
25
|
+
with op.batch_alter_table("room", schema=None) as batch_op:
|
26
|
+
batch_op.add_column(sa.Column("n_participants", sa.Integer(), nullable=True))
|
27
|
+
|
28
|
+
# ### end Alembic commands ###
|
29
|
+
|
30
|
+
|
31
|
+
def downgrade() -> None:
|
32
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
33
|
+
with op.batch_alter_table("room", schema=None) as batch_op:
|
34
|
+
batch_op.drop_column("n_participants")
|
35
|
+
|
36
|
+
# ### end Alembic commands ###
|
@@ -0,0 +1,37 @@
|
|
1
|
+
"""Store subject setter in Room
|
2
|
+
|
3
|
+
Revision ID: 29f5280c61aa
|
4
|
+
Revises: 8d2ced764698
|
5
|
+
Create Date: 2024-07-10 13:09:25.181594
|
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 = "29f5280c61aa"
|
16
|
+
down_revision: Union[str, None] = "8d2ced764698"
|
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("room", schema=None) as batch_op:
|
23
|
+
batch_op.add_column(sa.Column("subject_setter_id", sa.Integer(), nullable=True))
|
24
|
+
# we give this constraint a name a workaround for
|
25
|
+
# https://github.com/sqlalchemy/alembic/issues/1195
|
26
|
+
batch_op.create_foreign_key(
|
27
|
+
"subject_setter_id_foreign_key",
|
28
|
+
"participant",
|
29
|
+
["subject_setter_id"],
|
30
|
+
["id"],
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
def downgrade() -> None:
|
35
|
+
with op.batch_alter_table("room", schema=None) as batch_op:
|
36
|
+
batch_op.drop_constraint("subject_setter_id_foreign_key", type_="foreignkey")
|
37
|
+
batch_op.drop_column("subject_setter_id")
|
@@ -0,0 +1,133 @@
|
|
1
|
+
"""Rely on DB to store contacts, rooms and participants
|
2
|
+
|
3
|
+
Revision ID: 8d2ced764698
|
4
|
+
Revises: b33993e87db3
|
5
|
+
Create Date: 2024-07-08 14:39:47.022088
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Sequence, Union
|
10
|
+
|
11
|
+
import sqlalchemy as sa
|
12
|
+
from alembic import op
|
13
|
+
|
14
|
+
import slidge.db.meta
|
15
|
+
|
16
|
+
# revision identifiers, used by Alembic.
|
17
|
+
revision: str = "8d2ced764698"
|
18
|
+
down_revision: Union[str, None] = "b33993e87db3"
|
19
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
20
|
+
depends_on: Union[str, Sequence[str], None] = None
|
21
|
+
|
22
|
+
|
23
|
+
def upgrade() -> None:
|
24
|
+
op.create_table(
|
25
|
+
"hat",
|
26
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
27
|
+
sa.Column("title", sa.String(), nullable=False),
|
28
|
+
sa.Column("uri", sa.String(), nullable=False),
|
29
|
+
sa.PrimaryKeyConstraint("id"),
|
30
|
+
sa.UniqueConstraint("title", "uri"),
|
31
|
+
)
|
32
|
+
op.create_table(
|
33
|
+
"contact_sent",
|
34
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
35
|
+
sa.Column("contact_id", sa.Integer(), nullable=False),
|
36
|
+
sa.Column("msg_id", sa.String(), nullable=False),
|
37
|
+
sa.ForeignKeyConstraint(
|
38
|
+
["contact_id"],
|
39
|
+
["contact.id"],
|
40
|
+
),
|
41
|
+
sa.PrimaryKeyConstraint("id"),
|
42
|
+
sa.UniqueConstraint("contact_id", "msg_id"),
|
43
|
+
)
|
44
|
+
op.create_table(
|
45
|
+
"participant",
|
46
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
47
|
+
sa.Column("room_id", sa.Integer(), nullable=False),
|
48
|
+
sa.Column("contact_id", sa.Integer(), nullable=True),
|
49
|
+
sa.Column("is_user", sa.Boolean(), nullable=False),
|
50
|
+
sa.Column(
|
51
|
+
"affiliation",
|
52
|
+
sa.Enum("outcast", "member", "admin", "owner", "none", native_enum=False),
|
53
|
+
nullable=False,
|
54
|
+
),
|
55
|
+
sa.Column(
|
56
|
+
"role",
|
57
|
+
sa.Enum("moderator", "participant", "visitor", "none", native_enum=False),
|
58
|
+
nullable=False,
|
59
|
+
),
|
60
|
+
sa.Column("presence_sent", sa.Boolean(), nullable=False),
|
61
|
+
sa.Column("resource", sa.String(), nullable=True),
|
62
|
+
sa.Column("nickname", sa.String(), nullable=True),
|
63
|
+
sa.Column("extra_attributes", slidge.db.meta.JSONEncodedDict(), nullable=True),
|
64
|
+
sa.ForeignKeyConstraint(
|
65
|
+
["contact_id"],
|
66
|
+
["contact.id"],
|
67
|
+
),
|
68
|
+
sa.ForeignKeyConstraint(
|
69
|
+
["room_id"],
|
70
|
+
["room.id"],
|
71
|
+
),
|
72
|
+
sa.PrimaryKeyConstraint("id"),
|
73
|
+
)
|
74
|
+
op.create_table(
|
75
|
+
"participant_hats",
|
76
|
+
sa.Column("participant_id", sa.Integer(), nullable=False),
|
77
|
+
sa.Column("hat_id", sa.Integer(), nullable=False),
|
78
|
+
sa.ForeignKeyConstraint(
|
79
|
+
["hat_id"],
|
80
|
+
["hat.id"],
|
81
|
+
),
|
82
|
+
sa.ForeignKeyConstraint(
|
83
|
+
["participant_id"],
|
84
|
+
["participant.id"],
|
85
|
+
),
|
86
|
+
sa.PrimaryKeyConstraint("participant_id", "hat_id"),
|
87
|
+
)
|
88
|
+
op.add_column("contact", sa.Column("is_friend", sa.Boolean(), nullable=False))
|
89
|
+
op.add_column("contact", sa.Column("added_to_roster", sa.Boolean(), nullable=False))
|
90
|
+
op.add_column(
|
91
|
+
"contact",
|
92
|
+
sa.Column("extra_attributes", slidge.db.meta.JSONEncodedDict(), nullable=True),
|
93
|
+
)
|
94
|
+
op.add_column("contact", sa.Column("updated", sa.Boolean(), nullable=False))
|
95
|
+
op.add_column("room", sa.Column("description", sa.String(), nullable=True))
|
96
|
+
op.add_column("room", sa.Column("subject", sa.String(), nullable=True))
|
97
|
+
op.add_column("room", sa.Column("subject_date", sa.DateTime(), nullable=True))
|
98
|
+
op.add_column(
|
99
|
+
"room",
|
100
|
+
sa.Column(
|
101
|
+
"muc_type",
|
102
|
+
sa.Enum("GROUP", "CHANNEL", "CHANNEL_NON_ANONYMOUS", name="muctype"),
|
103
|
+
nullable=True,
|
104
|
+
),
|
105
|
+
)
|
106
|
+
op.add_column("room", sa.Column("user_resources", sa.String(), nullable=True))
|
107
|
+
op.add_column(
|
108
|
+
"room", sa.Column("participants_filled", sa.Boolean(), nullable=False)
|
109
|
+
)
|
110
|
+
op.add_column(
|
111
|
+
"room",
|
112
|
+
sa.Column("extra_attributes", slidge.db.meta.JSONEncodedDict(), nullable=True),
|
113
|
+
)
|
114
|
+
op.add_column("room", sa.Column("updated", sa.Boolean(), nullable=False))
|
115
|
+
|
116
|
+
|
117
|
+
def downgrade() -> None:
|
118
|
+
op.drop_column("room", "updated")
|
119
|
+
op.drop_column("room", "extra_attributes")
|
120
|
+
op.drop_column("room", "participants_filled")
|
121
|
+
op.drop_column("room", "user_resources")
|
122
|
+
op.drop_column("room", "muc_type")
|
123
|
+
op.drop_column("room", "subject_date")
|
124
|
+
op.drop_column("room", "subject")
|
125
|
+
op.drop_column("room", "description")
|
126
|
+
op.drop_column("contact", "updated")
|
127
|
+
op.drop_column("contact", "extra_attributes")
|
128
|
+
op.drop_column("contact", "added_to_roster")
|
129
|
+
op.drop_column("contact", "is_friend")
|
130
|
+
op.drop_table("participant_hats")
|
131
|
+
op.drop_table("participant")
|
132
|
+
op.drop_table("contact_sent")
|
133
|
+
op.drop_table("hat")
|
@@ -0,0 +1,76 @@
|
|
1
|
+
"""DB Creation
|
2
|
+
|
3
|
+
Including a migration from the user_store shelf
|
4
|
+
|
5
|
+
Revision ID: aa9d82a7f6ef
|
6
|
+
Revises:
|
7
|
+
Create Date: 2024-04-17 20:57:01.357041
|
8
|
+
|
9
|
+
"""
|
10
|
+
|
11
|
+
import logging
|
12
|
+
from typing import Sequence, Union
|
13
|
+
|
14
|
+
import sqlalchemy as sa
|
15
|
+
from alembic import op
|
16
|
+
|
17
|
+
import slidge.db.meta
|
18
|
+
|
19
|
+
# revision identifiers, used by Alembic.
|
20
|
+
revision: str = "aa9d82a7f6ef"
|
21
|
+
down_revision: Union[str, None] = None
|
22
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
23
|
+
depends_on: Union[str, Sequence[str], None] = None
|
24
|
+
|
25
|
+
|
26
|
+
def upgrade() -> None:
|
27
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
28
|
+
accounts = op.create_table(
|
29
|
+
"user_account",
|
30
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
31
|
+
sa.Column("jid", slidge.db.meta.JIDType(), nullable=False),
|
32
|
+
sa.Column(
|
33
|
+
"registration_date",
|
34
|
+
sa.DateTime(),
|
35
|
+
server_default=sa.text("(CURRENT_TIMESTAMP)"),
|
36
|
+
nullable=False,
|
37
|
+
),
|
38
|
+
sa.Column(
|
39
|
+
"legacy_module_data", slidge.db.meta.JSONEncodedDict(), nullable=False
|
40
|
+
),
|
41
|
+
sa.Column("preferences", slidge.db.meta.JSONEncodedDict(), nullable=False),
|
42
|
+
sa.PrimaryKeyConstraint("id"),
|
43
|
+
sa.UniqueConstraint("jid"),
|
44
|
+
)
|
45
|
+
# ### end Alembic commands ###
|
46
|
+
migrate_from_shelf(accounts)
|
47
|
+
|
48
|
+
|
49
|
+
def downgrade() -> None:
|
50
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
51
|
+
op.drop_table("user_account")
|
52
|
+
# ### end Alembic commands ###
|
53
|
+
|
54
|
+
|
55
|
+
def migrate_from_shelf(accounts: sa.Table) -> None:
|
56
|
+
try:
|
57
|
+
from slidge.util.db import user_store
|
58
|
+
except ImportError:
|
59
|
+
return
|
60
|
+
try:
|
61
|
+
users = list(user_store.get_all())
|
62
|
+
except AttributeError:
|
63
|
+
return
|
64
|
+
logging.info("Migrating %s users from the deprecated user_store shelf", len(users))
|
65
|
+
op.bulk_insert(
|
66
|
+
accounts,
|
67
|
+
[
|
68
|
+
{
|
69
|
+
"jid": user.jid,
|
70
|
+
"registration_date": user.registration_date,
|
71
|
+
"legacy_module_data": user.registration_form,
|
72
|
+
"preferences": {},
|
73
|
+
}
|
74
|
+
for user in users
|
75
|
+
],
|
76
|
+
)
|