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/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
|
+
)
|