slidge 0.3.0a3__py3-none-any.whl → 0.3.0b2__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.
Files changed (44) hide show
  1. slidge/contact/contact.py +2 -2
  2. slidge/contact/roster.py +2 -0
  3. slidge/core/dispatcher/message/message.py +3 -1
  4. slidge/core/dispatcher/presence.py +5 -0
  5. slidge/core/gateway.py +1 -1
  6. slidge/core/mixins/attachment.py +31 -0
  7. slidge/core/mixins/avatar.py +8 -13
  8. slidge/core/session.py +7 -3
  9. slidge/db/alembic/versions/cef02a8b1451_initial_schema.py +361 -0
  10. slidge/group/participant.py +1 -1
  11. slidge/group/room.py +52 -53
  12. slidge/main.py +6 -4
  13. slidge/migration.py +14 -5
  14. slidge/util/conf.py +4 -1
  15. {slidge-0.3.0a3.dist-info → slidge-0.3.0b2.dist-info}/METADATA +1 -1
  16. {slidge-0.3.0a3.dist-info → slidge-0.3.0b2.dist-info}/RECORD +20 -43
  17. slidge/db/alembic/versions/0337c90c0b96_unify_legacy_xmpp_id_mappings.py +0 -183
  18. slidge/db/alembic/versions/04cf35e3cf85_add_participant_nickname_no_illegal.py +0 -33
  19. slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +0 -36
  20. slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +0 -85
  21. slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +0 -36
  22. slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +0 -37
  23. slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +0 -41
  24. slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +0 -52
  25. slidge/db/alembic/versions/3231d2c623bc_add_unique_contraint_for_attachment_.py +0 -33
  26. slidge/db/alembic/versions/45c24cc73c91_add_bob.py +0 -42
  27. slidge/db/alembic/versions/4dbd23a3f868_new_avatar_store.py +0 -105
  28. slidge/db/alembic/versions/54ce3cde350c_use_hash_for_avatar_filenames.py +0 -50
  29. slidge/db/alembic/versions/58b98dacf819_refactor.py +0 -118
  30. slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +0 -61
  31. slidge/db/alembic/versions/75a62b74b239_ditch_hats_table.py +0 -74
  32. slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +0 -48
  33. slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +0 -43
  34. slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +0 -139
  35. slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +0 -50
  36. slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +0 -79
  37. slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +0 -214
  38. slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +0 -52
  39. slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +0 -34
  40. slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +0 -26
  41. {slidge-0.3.0a3.dist-info → slidge-0.3.0b2.dist-info}/WHEEL +0 -0
  42. {slidge-0.3.0a3.dist-info → slidge-0.3.0b2.dist-info}/entry_points.txt +0 -0
  43. {slidge-0.3.0a3.dist-info → slidge-0.3.0b2.dist-info}/licenses/LICENSE +0 -0
  44. {slidge-0.3.0a3.dist-info → slidge-0.3.0b2.dist-info}/top_level.txt +0 -0
slidge/contact/contact.py CHANGED
@@ -95,7 +95,7 @@ class LegacyContact(
95
95
  super().__init__()
96
96
 
97
97
  @property
98
- def jid(self):
98
+ def jid(self): # type:ignore[override]
99
99
  jid = JID(self.stored.jid)
100
100
  jid.resource = self.RESOURCE
101
101
  return jid
@@ -298,7 +298,7 @@ class LegacyContact(
298
298
  )
299
299
  self.commit()
300
300
  for p in self.participants:
301
- p.nickname = n
301
+ p.nickname = n or str(self.legacy_id)
302
302
 
303
303
  def _post_avatar_update(self, cached_avatar) -> None:
304
304
  if self.is_friend and self.added_to_roster:
slidge/contact/roster.py CHANGED
@@ -95,6 +95,8 @@ class LegacyRoster(
95
95
  contact_jid = JID(contact_jid.bare)
96
96
  async with self.lock(("username", username)):
97
97
  legacy_id = await self.jid_username_to_legacy_id(username)
98
+ if legacy_id == self.user_legacy_id:
99
+ raise ContactIsUser
98
100
  if self.get_lock(("legacy_id", legacy_id)):
99
101
  self.log.debug("Already updating %s via by_legacy_id()", contact_jid)
100
102
  return await self.by_legacy_id(legacy_id)
@@ -415,7 +415,9 @@ class MessageContentMixin(DispatcherMixin):
415
415
  with self.xmpp.store.session() as orm:
416
416
  sticker = self.xmpp.store.bob.get_sticker(orm, cid)
417
417
  if sticker is None:
418
- await self.xmpp.plugin["xep_0231"].get_bob(from_, cid)
418
+ await self.xmpp.plugin["xep_0231"].get_bob(
419
+ from_, cid, ifrom=self.xmpp.boundjid
420
+ )
419
421
  with self.xmpp.store.session() as orm:
420
422
  sticker = self.xmpp.store.bob.get_sticker(orm, cid)
421
423
  assert sticker is not None
@@ -3,6 +3,7 @@ import logging
3
3
  from slixmpp import JID, Presence
4
4
  from slixmpp.exceptions import XMPPError
5
5
 
6
+ from ...contact.roster import ContactIsUser
6
7
  from ...util.util import merge_resources
7
8
  from ..session import BaseSession
8
9
  from .util import DispatcherMixin, exceptions_to_xmpp_errors
@@ -142,6 +143,10 @@ class PresenceHandlerMixin(DispatcherMixin):
142
143
  contact = await session.contacts.by_jid(pto)
143
144
  except XMPPError:
144
145
  contact = None
146
+ except ContactIsUser:
147
+ raise XMPPError(
148
+ "bad-request", "Actions with yourself are not supported."
149
+ )
145
150
  if contact is not None:
146
151
  await self.xmpp.pubsub.on_presence_available(p, contact)
147
152
  return
slidge/core/gateway.py CHANGED
@@ -472,7 +472,7 @@ class BaseGateway(
472
472
  )
473
473
 
474
474
  @property # type: ignore
475
- def jid(self):
475
+ def jid(self): # type:ignore[override]
476
476
  # Override to avoid slixmpp deprecation warnings.
477
477
  return self.boundjid
478
478
 
@@ -403,6 +403,37 @@ class AttachmentMixin(TextMessageMixin):
403
403
  :param when: when the file was sent, for a "delay" tag (:xep:`0203`)
404
404
  :param thread:
405
405
  """
406
+ coro = self.__send_file(
407
+ attachment,
408
+ legacy_msg_id,
409
+ reply_to=reply_to,
410
+ when=when,
411
+ thread=thread,
412
+ **kwargs,
413
+ )
414
+ if self.session is NotImplemented:
415
+ return await coro
416
+ elif not isinstance(attachment, LegacyAttachment):
417
+ return await coro
418
+ elif attachment.legacy_file_id is None:
419
+ return await coro
420
+ else:
421
+ # prevents race conditions where we download the same thing several time
422
+ # and end up attempting to insert it twice in the DB, raising an
423
+ # IntegrityError.
424
+ async with self.session.lock(("attachment", attachment.legacy_file_id)):
425
+ return await coro
426
+
427
+ async def __send_file(
428
+ self,
429
+ attachment: LegacyAttachment | Path | str,
430
+ legacy_msg_id: Optional[LegacyMessageType] = None,
431
+ *,
432
+ reply_to: Optional[MessageReference] = None,
433
+ when: Optional[datetime] = None,
434
+ thread: Optional[LegacyThreadType] = None,
435
+ **kwargs,
436
+ ) -> tuple[Optional[str], list[Message]]:
406
437
  store_multi = kwargs.pop("store_multi", True)
407
438
  carbon = kwargs.pop("carbon", False)
408
439
  mto = kwargs.pop("mto", None)
@@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Optional
4
4
 
5
5
  from PIL import UnidentifiedImageError
6
6
  from slixmpp import JID
7
- from sqlalchemy.exc import IntegrityError
8
7
  from sqlalchemy.orm.exc import DetachedInstanceError
9
8
 
10
9
  from ...db.avatar import CachedAvatar, avatar_cache
@@ -123,19 +122,15 @@ class AvatarMixin(UpdateInfoMixin):
123
122
  else:
124
123
  avatar.path.unlink()
125
124
 
126
- if cached_avatar is None:
127
- self.stored.avatar = None
128
- else:
129
- self.stored.avatar = cached_avatar.stored
130
- try:
131
- self.commit(merge=True)
132
- except IntegrityError as e:
133
- self.log.debug(
134
- "Hit integrity error, attempting to fix by refreshing participants"
135
- )
125
+ stored_avatar = None if cached_avatar is None else cached_avatar.stored
126
+ if not self._updating_info:
136
127
  with self.xmpp.store.session() as orm:
137
- orm.refresh(self.stored, ["participants"])
138
- self.commit(merge=True)
128
+ with orm.no_autoflush:
129
+ self.stored = orm.merge(self.stored)
130
+ orm.refresh(self.stored)
131
+
132
+ self.stored.avatar = stored_avatar
133
+ self.commit(merge=True)
139
134
 
140
135
  self._post_avatar_update(cached_avatar)
141
136
 
slidge/core/session.py CHANGED
@@ -24,6 +24,7 @@ from ..db.models import Contact, GatewayUser
24
24
  from ..group.bookmarks import LegacyBookmarks
25
25
  from ..group.room import LegacyMUC
26
26
  from ..util import ABCSubclassableOnceAtMost
27
+ from ..util.lock import NamedLockMixin
27
28
  from ..util.types import (
28
29
  LegacyGroupIdType,
29
30
  LegacyMessageType,
@@ -50,7 +51,9 @@ class CachedPresence(NamedTuple):
50
51
 
51
52
 
52
53
  class BaseSession(
53
- Generic[LegacyMessageType, RecipientType], metaclass=ABCSubclassableOnceAtMost
54
+ Generic[LegacyMessageType, RecipientType],
55
+ NamedLockMixin,
56
+ metaclass=ABCSubclassableOnceAtMost,
54
57
  ):
55
58
  """
56
59
  The session of a registered :term:`User`.
@@ -95,6 +98,7 @@ class BaseSession(
95
98
  _bookmarks_cls: Type[LegacyBookmarks]
96
99
 
97
100
  def __init__(self, user: GatewayUser) -> None:
101
+ super().__init__()
98
102
  self.user = user
99
103
  self.log = logging.getLogger(user.jid.bare)
100
104
 
@@ -129,8 +133,8 @@ class BaseSession(
129
133
  self.log.debug("Removing fut %s", fut)
130
134
  self.__tasks.remove(fut)
131
135
 
132
- def create_task(self, coro) -> asyncio.Task:
133
- task = self.xmpp.loop.create_task(coro)
136
+ def create_task(self, coro, name: str | None = None) -> asyncio.Task:
137
+ task = self.xmpp.loop.create_task(coro, name=name)
134
138
  self.__tasks.add(task)
135
139
  self.log.debug("Creating task %s", task)
136
140
  task.add_done_callback(lambda _: self.__remove_task(task))
@@ -0,0 +1,361 @@
1
+ """Initial schema
2
+
3
+ Revision ID: cef02a8b1451
4
+ Revises:
5
+ Create Date: 2025-08-28 12:48:16.890606
6
+
7
+ """
8
+
9
+ from typing import Sequence, Union
10
+
11
+ import sqlalchemy as sa
12
+ from alembic import op
13
+
14
+ import slidge
15
+
16
+ # revision identifiers, used by Alembic.
17
+ revision: str = "cef02a8b1451"
18
+ down_revision: Union[str, None] = None
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
+ op.create_table(
26
+ "avatar",
27
+ sa.Column("id", sa.Integer(), nullable=False),
28
+ sa.Column("hash", sa.String(), nullable=False),
29
+ sa.Column("height", sa.Integer(), nullable=False),
30
+ sa.Column("width", sa.Integer(), nullable=False),
31
+ sa.Column("legacy_id", sa.String(), nullable=True),
32
+ sa.Column("url", sa.String(), nullable=True),
33
+ sa.Column("etag", sa.String(), nullable=True),
34
+ sa.Column("last_modified", sa.String(), nullable=True),
35
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_avatar")),
36
+ sa.UniqueConstraint("hash", name=op.f("uq_avatar_hash")),
37
+ sa.UniqueConstraint("legacy_id", name=op.f("uq_avatar_legacy_id")),
38
+ )
39
+ op.create_table(
40
+ "bob",
41
+ sa.Column("id", sa.Integer(), nullable=False),
42
+ sa.Column("file_name", sa.String(), nullable=False),
43
+ sa.Column("sha_1", sa.String(), nullable=False),
44
+ sa.Column("sha_256", sa.String(), nullable=False),
45
+ sa.Column("sha_512", sa.String(), nullable=False),
46
+ sa.Column("content_type", sa.String(), nullable=False),
47
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_bob")),
48
+ sa.UniqueConstraint("sha_1", name=op.f("uq_bob_sha_1")),
49
+ sa.UniqueConstraint("sha_256", name=op.f("uq_bob_sha_256")),
50
+ sa.UniqueConstraint("sha_512", name=op.f("uq_bob_sha_512")),
51
+ )
52
+ op.create_table(
53
+ "user_account",
54
+ sa.Column("id", sa.Integer(), nullable=False),
55
+ sa.Column("jid", slidge.db.meta.JIDType(), nullable=False),
56
+ sa.Column(
57
+ "registration_date",
58
+ sa.DateTime(),
59
+ server_default=sa.text("(CURRENT_TIMESTAMP)"),
60
+ nullable=False,
61
+ ),
62
+ sa.Column(
63
+ "legacy_module_data", slidge.db.meta.JSONEncodedDict(), nullable=False
64
+ ),
65
+ sa.Column("preferences", slidge.db.meta.JSONEncodedDict(), nullable=False),
66
+ sa.Column("avatar_hash", sa.String(), nullable=True),
67
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_user_account")),
68
+ sa.UniqueConstraint("jid", name=op.f("uq_user_account_jid")),
69
+ )
70
+ op.create_table(
71
+ "attachment",
72
+ sa.Column("id", sa.Integer(), nullable=False),
73
+ sa.Column("user_account_id", sa.Integer(), nullable=False),
74
+ sa.Column("legacy_file_id", sa.String(), nullable=True),
75
+ sa.Column("url", sa.String(), nullable=False),
76
+ sa.Column("sims", sa.String(), nullable=True),
77
+ sa.Column("sfs", sa.String(), nullable=True),
78
+ sa.ForeignKeyConstraint(
79
+ ["user_account_id"],
80
+ ["user_account.id"],
81
+ name=op.f("fk_attachment_user_account_id_user_account"),
82
+ ),
83
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_attachment")),
84
+ sa.UniqueConstraint(
85
+ "user_account_id",
86
+ "legacy_file_id",
87
+ name=op.f("uq_attachment_user_account_id"),
88
+ ),
89
+ )
90
+ with op.batch_alter_table("attachment", schema=None) as batch_op:
91
+ batch_op.create_index(
92
+ batch_op.f("ix_attachment_legacy_file_id"), ["legacy_file_id"], unique=False
93
+ )
94
+ batch_op.create_index(batch_op.f("ix_attachment_url"), ["url"], unique=False)
95
+
96
+ op.create_table(
97
+ "contact",
98
+ sa.Column("id", sa.Integer(), nullable=False),
99
+ sa.Column("user_account_id", sa.Integer(), nullable=False),
100
+ sa.Column("legacy_id", sa.String(), nullable=False),
101
+ sa.Column("jid", slidge.db.meta.JIDType(), nullable=False),
102
+ sa.Column("avatar_id", sa.Integer(), nullable=True),
103
+ sa.Column("nick", sa.String(), nullable=True),
104
+ sa.Column("cached_presence", sa.Boolean(), nullable=False),
105
+ sa.Column("last_seen", sa.DateTime(), nullable=True),
106
+ sa.Column("ptype", sa.String(), nullable=True),
107
+ sa.Column("pstatus", sa.String(), nullable=True),
108
+ sa.Column("pshow", sa.String(), nullable=True),
109
+ sa.Column("caps_ver", sa.String(), nullable=True),
110
+ sa.Column("is_friend", sa.Boolean(), nullable=False),
111
+ sa.Column("added_to_roster", sa.Boolean(), nullable=False),
112
+ sa.Column("extra_attributes", slidge.db.meta.JSONEncodedDict(), nullable=True),
113
+ sa.Column("updated", sa.Boolean(), nullable=False),
114
+ sa.Column("vcard", sa.String(), nullable=True),
115
+ sa.Column("vcard_fetched", sa.Boolean(), nullable=False),
116
+ sa.Column(
117
+ "client_type",
118
+ sa.Enum(
119
+ "bot",
120
+ "console",
121
+ "game",
122
+ "handheld",
123
+ "pc",
124
+ "phone",
125
+ "sms",
126
+ "tablet",
127
+ "web",
128
+ native_enum=False,
129
+ ),
130
+ nullable=False,
131
+ ),
132
+ sa.ForeignKeyConstraint(
133
+ ["avatar_id"], ["avatar.id"], name=op.f("fk_contact_avatar_id_avatar")
134
+ ),
135
+ sa.ForeignKeyConstraint(
136
+ ["user_account_id"],
137
+ ["user_account.id"],
138
+ name=op.f("fk_contact_user_account_id_user_account"),
139
+ ),
140
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_contact")),
141
+ sa.UniqueConstraint(
142
+ "user_account_id", "jid", name=op.f("uq_contact_user_account_id")
143
+ ),
144
+ sa.UniqueConstraint(
145
+ "user_account_id", "legacy_id", name=op.f("uq_contact_user_account_id")
146
+ ),
147
+ )
148
+ op.create_table(
149
+ "room",
150
+ sa.Column("id", sa.Integer(), nullable=False),
151
+ sa.Column("user_account_id", sa.Integer(), nullable=False),
152
+ sa.Column("legacy_id", sa.String(), nullable=False),
153
+ sa.Column("jid", slidge.db.meta.JIDType(), nullable=False),
154
+ sa.Column("avatar_id", sa.Integer(), nullable=True),
155
+ sa.Column("name", sa.String(), nullable=True),
156
+ sa.Column("description", sa.String(), nullable=True),
157
+ sa.Column("subject", sa.String(), nullable=True),
158
+ sa.Column("subject_date", sa.DateTime(), nullable=True),
159
+ sa.Column("subject_setter", sa.String(), nullable=True),
160
+ sa.Column("n_participants", sa.Integer(), nullable=True),
161
+ sa.Column(
162
+ "muc_type",
163
+ sa.Enum("GROUP", "CHANNEL", "CHANNEL_NON_ANONYMOUS", name="muctype"),
164
+ nullable=False,
165
+ ),
166
+ sa.Column("user_nick", sa.String(), nullable=True),
167
+ sa.Column("user_resources", sa.String(), nullable=True),
168
+ sa.Column("participants_filled", sa.Boolean(), nullable=False),
169
+ sa.Column("history_filled", sa.Boolean(), nullable=False),
170
+ sa.Column("extra_attributes", slidge.db.meta.JSONEncodedDict(), nullable=True),
171
+ sa.Column("updated", sa.Boolean(), nullable=False),
172
+ sa.ForeignKeyConstraint(
173
+ ["avatar_id"], ["avatar.id"], name=op.f("fk_room_avatar_id_avatar")
174
+ ),
175
+ sa.ForeignKeyConstraint(
176
+ ["user_account_id"],
177
+ ["user_account.id"],
178
+ name=op.f("fk_room_user_account_id_user_account"),
179
+ ),
180
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_room")),
181
+ sa.UniqueConstraint(
182
+ "user_account_id", "jid", name="uq_room_user_account_id_jid"
183
+ ),
184
+ sa.UniqueConstraint(
185
+ "user_account_id", "legacy_id", name="uq_room_user_account_id_legacy_id"
186
+ ),
187
+ )
188
+ op.create_table(
189
+ "contact_sent",
190
+ sa.Column("id", sa.Integer(), nullable=False),
191
+ sa.Column("contact_id", sa.Integer(), nullable=False),
192
+ sa.Column("msg_id", sa.String(), nullable=False),
193
+ sa.ForeignKeyConstraint(
194
+ ["contact_id"],
195
+ ["contact.id"],
196
+ name=op.f("fk_contact_sent_contact_id_contact"),
197
+ ),
198
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_contact_sent")),
199
+ sa.UniqueConstraint(
200
+ "contact_id", "msg_id", name=op.f("uq_contact_sent_contact_id")
201
+ ),
202
+ )
203
+ op.create_table(
204
+ "direct_msg",
205
+ sa.Column("foreign_key", sa.Integer(), nullable=False),
206
+ sa.Column("id", sa.Integer(), nullable=False),
207
+ sa.Column("legacy_id", sa.String(), nullable=False),
208
+ sa.Column("xmpp_id", sa.String(), nullable=False),
209
+ sa.ForeignKeyConstraint(
210
+ ["foreign_key"],
211
+ ["contact.id"],
212
+ name=op.f("fk_direct_msg_foreign_key_contact"),
213
+ ),
214
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_direct_msg")),
215
+ )
216
+ with op.batch_alter_table("direct_msg", schema=None) as batch_op:
217
+ batch_op.create_index(
218
+ "ix_direct_msg_legacy_id", ["legacy_id", "foreign_key"], unique=False
219
+ )
220
+
221
+ op.create_table(
222
+ "direct_thread",
223
+ sa.Column("foreign_key", sa.Integer(), nullable=False),
224
+ sa.Column("id", sa.Integer(), nullable=False),
225
+ sa.Column("legacy_id", sa.String(), nullable=False),
226
+ sa.Column("xmpp_id", sa.String(), nullable=False),
227
+ sa.ForeignKeyConstraint(
228
+ ["foreign_key"],
229
+ ["contact.id"],
230
+ name=op.f("fk_direct_thread_foreign_key_contact"),
231
+ ),
232
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_direct_thread")),
233
+ )
234
+ with op.batch_alter_table("direct_thread", schema=None) as batch_op:
235
+ batch_op.create_index(
236
+ "ix_direct_direct_thread_id", ["legacy_id", "foreign_key"], unique=False
237
+ )
238
+
239
+ op.create_table(
240
+ "group_msg",
241
+ sa.Column("foreign_key", sa.Integer(), nullable=False),
242
+ sa.Column("id", sa.Integer(), nullable=False),
243
+ sa.Column("legacy_id", sa.String(), nullable=False),
244
+ sa.Column("xmpp_id", sa.String(), nullable=False),
245
+ sa.ForeignKeyConstraint(
246
+ ["foreign_key"], ["room.id"], name=op.f("fk_group_msg_foreign_key_room")
247
+ ),
248
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_group_msg")),
249
+ )
250
+ with op.batch_alter_table("group_msg", schema=None) as batch_op:
251
+ batch_op.create_index(
252
+ "ix_group_msg_legacy_id", ["legacy_id", "foreign_key"], unique=False
253
+ )
254
+
255
+ op.create_table(
256
+ "group_thread",
257
+ sa.Column("foreign_key", sa.Integer(), nullable=False),
258
+ sa.Column("id", sa.Integer(), nullable=False),
259
+ sa.Column("legacy_id", sa.String(), nullable=False),
260
+ sa.Column("xmpp_id", sa.String(), nullable=False),
261
+ sa.ForeignKeyConstraint(
262
+ ["foreign_key"], ["room.id"], name=op.f("fk_group_thread_foreign_key_room")
263
+ ),
264
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_group_thread")),
265
+ )
266
+ with op.batch_alter_table("group_thread", schema=None) as batch_op:
267
+ batch_op.create_index(
268
+ "ix_direct_group_thread_id", ["legacy_id", "foreign_key"], unique=False
269
+ )
270
+
271
+ op.create_table(
272
+ "mam",
273
+ sa.Column("id", sa.Integer(), nullable=False),
274
+ sa.Column("room_id", sa.Integer(), nullable=False),
275
+ sa.Column("stanza_id", sa.String(), nullable=False),
276
+ sa.Column("timestamp", sa.DateTime(), nullable=False),
277
+ sa.Column("author_jid", slidge.db.meta.JIDType(), nullable=False),
278
+ sa.Column(
279
+ "source",
280
+ sa.Enum("LIVE", "BACKFILL", name="archivedmessagesource"),
281
+ nullable=False,
282
+ ),
283
+ sa.Column("legacy_id", sa.String(), nullable=True),
284
+ sa.Column("stanza", sa.String(), nullable=False),
285
+ sa.ForeignKeyConstraint(
286
+ ["room_id"], ["room.id"], name=op.f("fk_mam_room_id_room")
287
+ ),
288
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_mam")),
289
+ sa.UniqueConstraint("room_id", "stanza_id", name=op.f("uq_mam_room_id")),
290
+ )
291
+ op.create_table(
292
+ "participant",
293
+ sa.Column("id", sa.Integer(), nullable=False),
294
+ sa.Column("room_id", sa.Integer(), nullable=False),
295
+ sa.Column("contact_id", sa.Integer(), nullable=True),
296
+ sa.Column("is_user", sa.Boolean(), nullable=False),
297
+ sa.Column(
298
+ "affiliation",
299
+ sa.Enum("outcast", "member", "admin", "owner", "none", native_enum=False),
300
+ nullable=False,
301
+ ),
302
+ sa.Column(
303
+ "role",
304
+ sa.Enum("moderator", "participant", "visitor", "none", native_enum=False),
305
+ nullable=False,
306
+ ),
307
+ sa.Column("presence_sent", sa.Boolean(), nullable=False),
308
+ sa.Column("resource", sa.String(), nullable=False),
309
+ sa.Column("nickname", sa.String(), nullable=False),
310
+ sa.Column("nickname_no_illegal", sa.String(), nullable=False),
311
+ sa.Column("hats", sa.JSON(), nullable=False),
312
+ sa.Column("extra_attributes", slidge.db.meta.JSONEncodedDict(), nullable=True),
313
+ sa.ForeignKeyConstraint(
314
+ ["contact_id"],
315
+ ["contact.id"],
316
+ name=op.f("fk_participant_contact_id_contact"),
317
+ ),
318
+ sa.ForeignKeyConstraint(
319
+ ["room_id"], ["room.id"], name=op.f("fk_participant_room_id_room")
320
+ ),
321
+ sa.PrimaryKeyConstraint("id", name=op.f("pk_participant")),
322
+ sa.UniqueConstraint(
323
+ "room_id", "contact_id", name=op.f("uq_participant_room_id")
324
+ ),
325
+ sa.UniqueConstraint("room_id", "resource", name=op.f("uq_participant_room_id")),
326
+ )
327
+ # ### end Alembic commands ###
328
+
329
+
330
+ def downgrade() -> None:
331
+ # ### commands auto generated by Alembic - please adjust! ###
332
+ op.drop_table("participant")
333
+ op.drop_table("mam")
334
+ with op.batch_alter_table("group_thread", schema=None) as batch_op:
335
+ batch_op.drop_index("ix_direct_group_thread_id")
336
+
337
+ op.drop_table("group_thread")
338
+ with op.batch_alter_table("group_msg", schema=None) as batch_op:
339
+ batch_op.drop_index("ix_group_msg_legacy_id")
340
+
341
+ op.drop_table("group_msg")
342
+ with op.batch_alter_table("direct_thread", schema=None) as batch_op:
343
+ batch_op.drop_index("ix_direct_direct_thread_id")
344
+
345
+ op.drop_table("direct_thread")
346
+ with op.batch_alter_table("direct_msg", schema=None) as batch_op:
347
+ batch_op.drop_index("ix_direct_msg_legacy_id")
348
+
349
+ op.drop_table("direct_msg")
350
+ op.drop_table("contact_sent")
351
+ op.drop_table("room")
352
+ op.drop_table("contact")
353
+ with op.batch_alter_table("attachment", schema=None) as batch_op:
354
+ batch_op.drop_index(batch_op.f("ix_attachment_url"))
355
+ batch_op.drop_index(batch_op.f("ix_attachment_legacy_file_id"))
356
+
357
+ op.drop_table("attachment")
358
+ op.drop_table("user_account")
359
+ op.drop_table("bob")
360
+ op.drop_table("avatar")
361
+ # ### end Alembic commands ###
@@ -302,7 +302,7 @@ class LegacyParticipant(
302
302
  return p
303
303
 
304
304
  @property
305
- def DISCO_NAME(self):
305
+ def DISCO_NAME(self): # type:ignore[override]
306
306
  return self.nickname
307
307
 
308
308
  def __send_presence_if_needed(