slidge 0.2.12__py3-none-any.whl → 0.3.0__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 (93) hide show
  1. slidge/__init__.py +5 -2
  2. slidge/command/adhoc.py +9 -3
  3. slidge/command/admin.py +16 -12
  4. slidge/command/base.py +16 -12
  5. slidge/command/chat_command.py +25 -16
  6. slidge/command/user.py +7 -8
  7. slidge/contact/contact.py +123 -210
  8. slidge/contact/roster.py +108 -105
  9. slidge/core/config.py +2 -43
  10. slidge/core/dispatcher/caps.py +9 -2
  11. slidge/core/dispatcher/disco.py +13 -3
  12. slidge/core/dispatcher/message/__init__.py +1 -1
  13. slidge/core/dispatcher/message/chat_state.py +17 -8
  14. slidge/core/dispatcher/message/marker.py +7 -5
  15. slidge/core/dispatcher/message/message.py +120 -93
  16. slidge/core/dispatcher/muc/__init__.py +1 -1
  17. slidge/core/dispatcher/muc/admin.py +4 -4
  18. slidge/core/dispatcher/muc/mam.py +10 -6
  19. slidge/core/dispatcher/muc/misc.py +4 -2
  20. slidge/core/dispatcher/muc/owner.py +5 -3
  21. slidge/core/dispatcher/muc/ping.py +3 -1
  22. slidge/core/dispatcher/presence.py +26 -15
  23. slidge/core/dispatcher/registration.py +20 -12
  24. slidge/core/dispatcher/search.py +7 -3
  25. slidge/core/dispatcher/session_dispatcher.py +13 -5
  26. slidge/core/dispatcher/util.py +37 -27
  27. slidge/core/dispatcher/vcard.py +7 -4
  28. slidge/core/gateway.py +177 -87
  29. slidge/core/mixins/__init__.py +1 -11
  30. slidge/core/mixins/attachment.py +200 -147
  31. slidge/core/mixins/avatar.py +105 -177
  32. slidge/core/mixins/base.py +3 -1
  33. slidge/core/mixins/db.py +50 -2
  34. slidge/core/mixins/disco.py +1 -1
  35. slidge/core/mixins/message.py +19 -17
  36. slidge/core/mixins/message_maker.py +29 -15
  37. slidge/core/mixins/message_text.py +67 -30
  38. slidge/core/mixins/presence.py +94 -37
  39. slidge/core/pubsub.py +42 -47
  40. slidge/core/session.py +95 -60
  41. slidge/db/alembic/versions/cef02a8b1451_initial_schema.py +361 -0
  42. slidge/db/avatar.py +150 -119
  43. slidge/db/meta.py +33 -22
  44. slidge/db/models.py +69 -117
  45. slidge/db/store.py +414 -1094
  46. slidge/group/archive.py +65 -55
  47. slidge/group/bookmarks.py +96 -59
  48. slidge/group/participant.py +150 -144
  49. slidge/group/room.py +345 -327
  50. slidge/main.py +34 -22
  51. slidge/migration.py +17 -29
  52. slidge/slixfix/__init__.py +20 -4
  53. slidge/slixfix/delivery_receipt.py +6 -4
  54. slidge/slixfix/link_preview/link_preview.py +1 -1
  55. slidge/slixfix/link_preview/stanza.py +1 -1
  56. slidge/slixfix/roster.py +5 -7
  57. slidge/slixfix/xep_0077/register.py +8 -8
  58. slidge/slixfix/xep_0077/stanza.py +7 -7
  59. slidge/slixfix/xep_0100/gateway.py +12 -13
  60. slidge/slixfix/xep_0153/vcard_avatar.py +1 -1
  61. slidge/slixfix/xep_0292/vcard4.py +12 -2
  62. slidge/util/archive_msg.py +11 -5
  63. slidge/util/conf.py +27 -21
  64. slidge/util/jid_escaping.py +1 -1
  65. slidge/{core/mixins → util}/lock.py +6 -6
  66. slidge/util/test.py +30 -29
  67. slidge/util/types.py +24 -18
  68. slidge/util/util.py +26 -22
  69. {slidge-0.2.12.dist-info → slidge-0.3.0.dist-info}/METADATA +1 -1
  70. slidge-0.3.0.dist-info/RECORD +95 -0
  71. {slidge-0.2.12.dist-info → slidge-0.3.0.dist-info}/WHEEL +1 -1
  72. slidge/db/alembic/versions/04cf35e3cf85_add_participant_nickname_no_illegal.py +0 -33
  73. slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +0 -36
  74. slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +0 -85
  75. slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +0 -36
  76. slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +0 -37
  77. slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +0 -41
  78. slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +0 -52
  79. slidge/db/alembic/versions/45c24cc73c91_add_bob.py +0 -42
  80. slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +0 -61
  81. slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +0 -48
  82. slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +0 -43
  83. slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +0 -139
  84. slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +0 -50
  85. slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +0 -79
  86. slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +0 -214
  87. slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +0 -52
  88. slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +0 -34
  89. slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +0 -26
  90. slidge-0.2.12.dist-info/RECORD +0 -112
  91. {slidge-0.2.12.dist-info → slidge-0.3.0.dist-info}/entry_points.txt +0 -0
  92. {slidge-0.2.12.dist-info → slidge-0.3.0.dist-info}/licenses/LICENSE +0 -0
  93. {slidge-0.2.12.dist-info → slidge-0.3.0.dist-info}/top_level.txt +0 -0
slidge/db/models.py CHANGED
@@ -6,24 +6,13 @@ from typing import Optional
6
6
  import sqlalchemy as sa
7
7
  from slixmpp import JID
8
8
  from slixmpp.types import MucAffiliation, MucRole
9
- from sqlalchemy import ForeignKey, Index, UniqueConstraint
10
- from sqlalchemy.orm import Mapped, mapped_column, relationship
9
+ from sqlalchemy import JSON, ForeignKey, Index, UniqueConstraint
10
+ from sqlalchemy.orm import Mapped, declared_attr, mapped_column, relationship
11
11
 
12
12
  from ..util.types import ClientType, MucType
13
13
  from .meta import Base, JSONSerializable, JSONSerializableTypes
14
14
 
15
15
 
16
- class XmppToLegacyEnum(IntEnum):
17
- """
18
- XMPP-client generated IDs, used in the XmppToLegacyIds table to keep track
19
- of corresponding legacy IDs
20
- """
21
-
22
- DM = 1
23
- GROUP_CHAT = 2
24
- THREAD = 3
25
-
26
-
27
16
  class ArchivedMessageSource(IntEnum):
28
17
  """
29
18
  Whether an archived message comes from ``LegacyMUC.backfill()`` or was received
@@ -63,16 +52,7 @@ class GatewayUser(Base):
63
52
  rooms: Mapped[list["Room"]] = relationship(
64
53
  back_populates="user", cascade="all, delete-orphan"
65
54
  )
66
- xmpp_to_legacy: Mapped[list["XmppToLegacyIds"]] = relationship(
67
- cascade="all, delete-orphan"
68
- )
69
55
  attachments: Mapped[list["Attachment"]] = relationship(cascade="all, delete-orphan")
70
- multi_legacy: Mapped[list["LegacyIdsMulti"]] = relationship(
71
- cascade="all, delete-orphan"
72
- )
73
- multi_xmpp: Mapped[list["XmppIdsMulti"]] = relationship(
74
- cascade="all, delete-orphan"
75
- )
76
56
 
77
57
  def __repr__(self) -> str:
78
58
  return f"User(id={self.id!r}, jid={self.jid!r})"
@@ -109,11 +89,12 @@ class Avatar(Base):
109
89
 
110
90
  id: Mapped[int] = mapped_column(primary_key=True)
111
91
 
112
- filename: Mapped[str] = mapped_column(unique=True)
113
92
  hash: Mapped[str] = mapped_column(unique=True)
114
93
  height: Mapped[int] = mapped_column()
115
94
  width: Mapped[int] = mapped_column()
116
95
 
96
+ legacy_id: Mapped[Optional[str]] = mapped_column(unique=True, nullable=True)
97
+
117
98
  # this is only used when avatars are available as HTTP URLs and do not
118
99
  # have a legacy_id
119
100
  url: Mapped[Optional[str]] = mapped_column(default=None)
@@ -137,13 +118,17 @@ class Contact(Base):
137
118
 
138
119
  id: Mapped[int] = mapped_column(primary_key=True)
139
120
  user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
140
- user: Mapped[GatewayUser] = relationship(back_populates="contacts")
121
+ user: Mapped[GatewayUser] = relationship(lazy=True, back_populates="contacts")
141
122
  legacy_id: Mapped[str] = mapped_column(nullable=False)
142
123
 
143
124
  jid: Mapped[JID] = mapped_column()
144
125
 
145
- avatar_id: Mapped[int] = mapped_column(ForeignKey("avatar.id"), nullable=True)
146
- avatar: Mapped[Avatar] = relationship(back_populates="contacts")
126
+ avatar_id: Mapped[Optional[int]] = mapped_column(
127
+ ForeignKey("avatar.id"), nullable=True
128
+ )
129
+ avatar: Mapped[Optional[Avatar]] = relationship(
130
+ lazy=False, back_populates="contacts"
131
+ )
147
132
 
148
133
  nick: Mapped[Optional[str]] = mapped_column(nullable=True)
149
134
 
@@ -170,10 +155,13 @@ class Contact(Base):
170
155
 
171
156
  participants: Mapped[list["Participant"]] = relationship(back_populates="contact")
172
157
 
173
- avatar_legacy_id: Mapped[Optional[str]] = mapped_column(nullable=True)
174
-
175
158
  client_type: Mapped[ClientType] = mapped_column(nullable=False, default="pc")
176
159
 
160
+ messages: Mapped[list["DirectMessages"]] = relationship(
161
+ cascade="all, delete-orphan"
162
+ )
163
+ threads: Mapped[list["DirectThreads"]] = relationship(cascade="all, delete-orphan")
164
+
177
165
 
178
166
  class ContactSent(Base):
179
167
  """
@@ -207,13 +195,15 @@ class Room(Base):
207
195
  __tablename__ = "room"
208
196
  id: Mapped[int] = mapped_column(primary_key=True)
209
197
  user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
210
- user: Mapped[GatewayUser] = relationship(back_populates="rooms")
198
+ user: Mapped[GatewayUser] = relationship(lazy=True, back_populates="rooms")
211
199
  legacy_id: Mapped[str] = mapped_column(nullable=False)
212
200
 
213
201
  jid: Mapped[JID] = mapped_column(nullable=False)
214
202
 
215
- avatar_id: Mapped[int] = mapped_column(ForeignKey("avatar.id"), nullable=True)
216
- avatar: Mapped[Avatar] = relationship(back_populates="rooms")
203
+ avatar_id: Mapped[Optional[int]] = mapped_column(
204
+ ForeignKey("avatar.id"), nullable=True
205
+ )
206
+ avatar: Mapped[Optional[Avatar]] = relationship(lazy=False, back_populates="rooms")
217
207
 
218
208
  name: Mapped[Optional[str]] = mapped_column(nullable=True)
219
209
  description: Mapped[Optional[str]] = mapped_column(nullable=True)
@@ -223,7 +213,7 @@ class Room(Base):
223
213
 
224
214
  n_participants: Mapped[Optional[int]] = mapped_column(default=None)
225
215
 
226
- muc_type: Mapped[Optional[MucType]] = mapped_column(default=MucType.GROUP)
216
+ muc_type: Mapped[MucType] = mapped_column(default=MucType.CHANNEL)
227
217
 
228
218
  user_nick: Mapped[Optional[str]] = mapped_column()
229
219
  user_resources: Mapped[Optional[str]] = mapped_column(nullable=True)
@@ -240,12 +230,13 @@ class Room(Base):
240
230
  cascade="all, delete-orphan",
241
231
  )
242
232
 
243
- avatar_legacy_id: Mapped[Optional[str]] = mapped_column(nullable=True)
244
-
245
233
  archive: Mapped[list["ArchivedMessage"]] = relationship(
246
234
  cascade="all, delete-orphan"
247
235
  )
248
236
 
237
+ messages: Mapped[list["GroupMessages"]] = relationship(cascade="all, delete-orphan")
238
+ threads: Mapped[list["GroupThreads"]] = relationship(cascade="all, delete-orphan")
239
+
249
240
 
250
241
  class ArchivedMessage(Base):
251
242
  """
@@ -267,23 +258,40 @@ class ArchivedMessage(Base):
267
258
  stanza: Mapped[str] = mapped_column(nullable=False)
268
259
 
269
260
 
270
- class XmppToLegacyIds(Base):
261
+ class _LegacyToXmppIdsBase:
271
262
  """
272
- XMPP-client generated IDs, and mapping to the corresponding legacy IDs
263
+ XMPP-client generated IDs, and mapping to the corresponding legacy IDs.
264
+
265
+ A single legacy ID can map to several XMPP ids.
273
266
  """
274
267
 
275
- __tablename__ = "xmpp_to_legacy_ids"
276
- __table_args__ = (
277
- Index("xmpp_legacy", "user_account_id", "xmpp_id", "legacy_id", unique=True),
278
- )
279
268
  id: Mapped[int] = mapped_column(primary_key=True)
280
- user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
281
- user: Mapped[GatewayUser] = relationship(back_populates="xmpp_to_legacy")
282
-
283
- xmpp_id: Mapped[str] = mapped_column(nullable=False)
284
269
  legacy_id: Mapped[str] = mapped_column(nullable=False)
270
+ xmpp_id: Mapped[str] = mapped_column(nullable=False)
271
+
272
+
273
+ class DirectMessages(_LegacyToXmppIdsBase, Base):
274
+ __tablename__ = "direct_msg"
275
+ __table_args__ = (Index("ix_direct_msg_legacy_id", "legacy_id", "foreign_key"),)
276
+ foreign_key: Mapped[int] = mapped_column(ForeignKey("contact.id"), nullable=False)
277
+
278
+
279
+ class GroupMessages(_LegacyToXmppIdsBase, Base):
280
+ __tablename__ = "group_msg"
281
+ __table_args__ = (Index("ix_group_msg_legacy_id", "legacy_id", "foreign_key"),)
282
+ foreign_key: Mapped[int] = mapped_column(ForeignKey("room.id"), nullable=False)
285
283
 
286
- type: Mapped[XmppToLegacyEnum] = mapped_column(nullable=False)
284
+
285
+ class DirectThreads(_LegacyToXmppIdsBase, Base):
286
+ __tablename__ = "direct_thread"
287
+ __table_args__ = (Index("ix_direct_direct_thread_id", "legacy_id", "foreign_key"),)
288
+ foreign_key: Mapped[int] = mapped_column(ForeignKey("contact.id"), nullable=False)
289
+
290
+
291
+ class GroupThreads(_LegacyToXmppIdsBase, Base):
292
+ __tablename__ = "group_thread"
293
+ __table_args__ = (Index("ix_direct_group_thread_id", "legacy_id", "foreign_key"),)
294
+ foreign_key: Mapped[int] = mapped_column(ForeignKey("room.id"), nullable=False)
287
295
 
288
296
 
289
297
  class Attachment(Base):
@@ -292,6 +300,7 @@ class Attachment(Base):
292
300
  """
293
301
 
294
302
  __tablename__ = "attachment"
303
+ __table_args__ = (UniqueConstraint("user_account_id", "legacy_file_id"),)
295
304
 
296
305
  id: Mapped[int] = mapped_column(primary_key=True)
297
306
  user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
@@ -303,81 +312,26 @@ class Attachment(Base):
303
312
  sfs: Mapped[Optional[str]] = mapped_column()
304
313
 
305
314
 
306
- class LegacyIdsMulti(Base):
307
- """
308
- Legacy messages with multiple attachments are split as several XMPP messages,
309
- this table and the next maps a single legacy ID to multiple XMPP IDs.
310
- """
311
-
312
- __tablename__ = "legacy_ids_multi"
313
- __table_args__ = (
314
- Index(
315
- "legacy_ids_multi_user_account_id_legacy_id",
316
- "user_account_id",
317
- "legacy_id",
318
- unique=True,
319
- ),
320
- )
321
- id: Mapped[int] = mapped_column(primary_key=True)
322
- user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
323
-
324
- legacy_id: Mapped[str] = mapped_column(nullable=False)
325
- xmpp_ids: Mapped[list["XmppIdsMulti"]] = relationship(
326
- back_populates="legacy_ids_multi", cascade="all, delete-orphan"
327
- )
328
-
329
-
330
- class XmppIdsMulti(Base):
331
- __tablename__ = "xmpp_ids_multi"
332
- __table_args__ = (
333
- Index(
334
- "legacy_ids_multi_user_account_id_xmpp_id",
335
- "user_account_id",
336
- "xmpp_id",
337
- unique=True,
338
- ),
339
- )
340
- id: Mapped[int] = mapped_column(primary_key=True)
341
- user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
342
-
343
- xmpp_id: Mapped[str] = mapped_column(nullable=False)
344
-
345
- legacy_ids_multi_id: Mapped[int] = mapped_column(ForeignKey("legacy_ids_multi.id"))
346
- legacy_ids_multi: Mapped[LegacyIdsMulti] = relationship(back_populates="xmpp_ids")
347
-
348
-
349
- participant_hats = sa.Table(
350
- "participant_hats",
351
- Base.metadata,
352
- sa.Column("participant_id", ForeignKey("participant.id"), primary_key=True),
353
- sa.Column("hat_id", ForeignKey("hat.id"), primary_key=True),
354
- )
355
-
356
-
357
- class Hat(Base):
358
- __tablename__ = "hat"
359
- __table_args__ = (UniqueConstraint("title", "uri"),)
360
-
361
- id: Mapped[int] = mapped_column(primary_key=True)
362
- title: Mapped[str] = mapped_column()
363
- uri: Mapped[str] = mapped_column()
364
- participants: Mapped[list["Participant"]] = relationship(
365
- secondary=participant_hats, back_populates="hats"
366
- )
367
-
368
-
369
315
  class Participant(Base):
370
316
  __tablename__ = "participant"
317
+ __table_args__ = (
318
+ UniqueConstraint("room_id", "resource"),
319
+ UniqueConstraint("room_id", "contact_id"),
320
+ )
371
321
 
372
322
  id: Mapped[int] = mapped_column(primary_key=True)
373
323
 
374
324
  room_id: Mapped[int] = mapped_column(ForeignKey("room.id"), nullable=False)
375
325
  room: Mapped[Room] = relationship(
376
- back_populates="participants", primaryjoin=Room.id == room_id
326
+ lazy=False, back_populates="participants", primaryjoin=Room.id == room_id
377
327
  )
378
328
 
379
- contact_id: Mapped[int] = mapped_column(ForeignKey("contact.id"), nullable=True)
380
- contact: Mapped[Contact] = relationship(lazy=False, back_populates="participants")
329
+ contact_id: Mapped[Optional[int]] = mapped_column(
330
+ ForeignKey("contact.id"), nullable=True
331
+ )
332
+ contact: Mapped[Optional[Contact]] = relationship(
333
+ lazy=False, back_populates="participants"
334
+ )
381
335
 
382
336
  is_user: Mapped[bool] = mapped_column(default=False)
383
337
 
@@ -386,13 +340,11 @@ class Participant(Base):
386
340
 
387
341
  presence_sent: Mapped[bool] = mapped_column(default=False)
388
342
 
389
- resource: Mapped[Optional[str]] = mapped_column(default=None)
390
- nickname: Mapped[str] = mapped_column(nullable=True, default=None)
391
- nickname_no_illegal: Mapped[str] = mapped_column(nullable=True, default=None)
343
+ resource: Mapped[str] = mapped_column(nullable=False)
344
+ nickname: Mapped[str] = mapped_column(nullable=False, default=None)
345
+ nickname_no_illegal: Mapped[str] = mapped_column(nullable=False, default=None)
392
346
 
393
- hats: Mapped[list["Hat"]] = relationship(
394
- secondary=participant_hats, back_populates="participants"
395
- )
347
+ hats: Mapped[list[tuple[str, str]]] = mapped_column(JSON, default=list)
396
348
 
397
349
  extra_attributes: Mapped[Optional[JSONSerializable]] = mapped_column(default=None)
398
350