slidge 0.3.0b2__py3-none-any.whl → 0.3.0b4__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/core/gateway.py CHANGED
@@ -172,6 +172,13 @@ class BaseGateway(
172
172
  required=True,
173
173
  type="boolean",
174
174
  ),
175
+ FormField(
176
+ var="reaction_fallback",
177
+ label="Receive fallback messages for reactions (for legacy XMPP clients)",
178
+ value="false",
179
+ required=True,
180
+ type="boolean",
181
+ ),
175
182
  ]
176
183
 
177
184
  ROSTER_GROUP: str = "slidge"
@@ -303,6 +303,10 @@ class AttachmentMixin(TextMessageMixin):
303
303
  )
304
304
  if attachment.name:
305
305
  sfs["file"]["name"] = attachment.name
306
+ if attachment.disposition:
307
+ sfs["disposition"] = attachment.disposition
308
+ else:
309
+ del sfs["disposition"]
306
310
  if thumbnail is not None:
307
311
  sfs["file"].append(thumbnail)
308
312
  stored.sfs = str(sfs)
@@ -19,7 +19,7 @@ class Base:
19
19
  xmpp: "BaseGateway" = NotImplemented
20
20
 
21
21
  jid: JID = NotImplemented
22
- name: str = NotImplemented
22
+ name: str | None = NotImplemented
23
23
 
24
24
  @property
25
25
  def user_jid(self):
@@ -31,6 +31,8 @@ class Base:
31
31
 
32
32
 
33
33
  class BaseSender(Base):
34
+ is_participant = False
35
+
34
36
  def _send(
35
37
  self, stanza: MessageOrPresenceTypeVar, **send_kwargs
36
38
  ) -> MessageOrPresenceTypeVar:
@@ -13,7 +13,7 @@ class BaseDiscoMixin(Base):
13
13
  DISCO_NAME: str = NotImplemented
14
14
  DISCO_LANG = None
15
15
 
16
- def _get_disco_name(self):
16
+ def _get_disco_name(self) -> str | None:
17
17
  if self.DISCO_NAME is NotImplemented:
18
18
  return self.xmpp.COMPONENT_NAME
19
19
  return self.DISCO_NAME or self.xmpp.COMPONENT_NAME
@@ -2,6 +2,9 @@ import logging
2
2
  from datetime import datetime
3
3
  from typing import Iterable, Optional
4
4
 
5
+ from slixmpp import Message
6
+
7
+ from ...util.archive_msg import HistoryMessage
5
8
  from ...util.types import (
6
9
  LegacyMessageType,
7
10
  LegacyThreadType,
@@ -9,6 +12,7 @@ from ...util.types import (
9
12
  MessageReference,
10
13
  ProcessingHint,
11
14
  )
15
+ from ...util.util import add_quote_prefix
12
16
  from .message_maker import MessageMaker
13
17
 
14
18
 
@@ -188,8 +192,33 @@ class TextMessageMixin(MessageMaker):
188
192
  if not xmpp_id:
189
193
  xmpp_id = self._legacy_to_xmpp(legacy_msg_id)
190
194
  self.xmpp["xep_0444"].set_reactions(msg, to_id=xmpp_id, reactions=emojis)
195
+ self.__add_reaction_fallback(msg, legacy_msg_id, emojis)
191
196
  self._send(msg, **kwargs)
192
197
 
198
+ def __add_reaction_fallback(
199
+ self,
200
+ msg: Message,
201
+ legacy_msg_id: LegacyMessageType,
202
+ emojis: Iterable[str] = (),
203
+ ) -> None:
204
+ if not self.session.user.preferences.get("reaction_fallback", False):
205
+ return
206
+ msg["fallback"]["for"] = self.xmpp.plugin["xep_0444"].namespace
207
+ msg["fallback"].enable("body")
208
+ msg["body"] = " ".join(emojis)
209
+ if not self.is_participant:
210
+ return
211
+ with self.xmpp.store.session() as orm:
212
+ archived = self.xmpp.store.mam.get_by_legacy_id(
213
+ orm, self.muc.stored.id, str(legacy_msg_id)
214
+ )
215
+ if archived is None:
216
+ return
217
+ history_msg = HistoryMessage(archived.stanza)
218
+ msg["body"] = (
219
+ add_quote_prefix(history_msg.stanza["body"]) + "\n" + msg["body"]
220
+ )
221
+
193
222
  def retract(
194
223
  self,
195
224
  legacy_msg_id: LegacyMessageType,
@@ -62,8 +62,9 @@ class PresenceMixin(BaseSender, DBMixin):
62
62
  try:
63
63
  return self.stored.contact
64
64
  except DetachedInstanceError:
65
- self.merge()
66
- return self.stored.contact
65
+ with self.xmpp.store.session() as orm:
66
+ orm.add(self.stored)
67
+ return self.stored.contact
67
68
 
68
69
  @property
69
70
  def __contact_pk(self) -> int | None:
slidge/db/store.py CHANGED
@@ -478,7 +478,7 @@ class ParticipantStore:
478
478
 
479
479
  @staticmethod
480
480
  def get_all(
481
- session, room_pk: int, user_included: bool = True
481
+ session: Session, room_pk: int, user_included: bool = True
482
482
  ) -> Iterator[Participant]:
483
483
  query = select(Participant).where(Participant.room_id == room_pk)
484
484
  if not user_included:
slidge/group/archive.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import uuid
3
+ import warnings
3
4
  from copy import copy
4
5
  from datetime import datetime, timezone
5
6
  from typing import TYPE_CHECKING, Collection, Optional
@@ -48,7 +49,9 @@ class MessageArchive:
48
49
  elif participant.is_system:
49
50
  new_msg["muc"]["jid"] = participant.muc.jid
50
51
  else:
51
- log.warning("No real JID for participant in this group")
52
+ warnings.warn(
53
+ f"No real JID for participant '{participant.nickname}' in '{self.room.name}'"
54
+ )
52
55
  new_msg["muc"]["jid"] = (
53
56
  f"{uuid.uuid4()}@{participant.xmpp.boundjid.bare}"
54
57
  )
slidge/group/bookmarks.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import abc
2
2
  import logging
3
- from typing import TYPE_CHECKING, Generic, Iterator, Optional, Type
3
+ from typing import TYPE_CHECKING, Generic, Iterator, Literal, Optional, Type, overload
4
4
 
5
5
  from slixmpp import JID
6
6
  from slixmpp.exceptions import XMPPError
@@ -119,13 +119,31 @@ class LegacyBookmarks(
119
119
  return self.from_store(stored)
120
120
  return None
121
121
 
122
- async def by_legacy_id(self, legacy_id: LegacyGroupIdType) -> LegacyMUCType:
122
+ @overload
123
+ async def by_legacy_id(self, legacy_id: LegacyGroupIdType) -> "LegacyMUCType": ...
124
+
125
+ @overload
126
+ async def by_legacy_id(
127
+ self, legacy_id: LegacyGroupIdType, create: Literal[False]
128
+ ) -> "LegacyMUCType | None": ...
129
+
130
+ @overload
131
+ async def by_legacy_id(
132
+ self, legacy_id: LegacyGroupIdType, create: Literal[True]
133
+ ) -> "LegacyMUCType": ...
134
+
135
+ async def by_legacy_id(
136
+ self, legacy_id: LegacyGroupIdType, create: bool = False
137
+ ) -> LegacyMUCType | None:
123
138
  async with self.lock(("legacy_id", legacy_id)):
124
139
  local = await self.legacy_id_to_jid_local_part(legacy_id)
125
140
  jid = JID(f"{local}@{self.xmpp.boundjid}")
126
141
  if self.get_lock(("bare", jid.bare)):
127
142
  self.session.log.debug("Already updating %s via by_jid()", jid)
128
- return await self.by_jid(jid)
143
+ if create:
144
+ return await self.by_jid(jid)
145
+ else:
146
+ return self.by_jid_only_if_exists(jid)
129
147
 
130
148
  with self.xmpp.store.session() as orm:
131
149
  stored = (
@@ -140,7 +158,7 @@ class LegacyBookmarks(
140
158
  stored = Room(
141
159
  user_account_id=self.session.user_pk,
142
160
  jid=jid,
143
- legacy_id=legacy_id,
161
+ legacy_id=str(legacy_id),
144
162
  )
145
163
  return await self.__update_if_needed(stored)
146
164
 
@@ -6,8 +6,8 @@ from copy import copy
6
6
  from datetime import datetime
7
7
  from functools import cached_property
8
8
  from typing import TYPE_CHECKING, Any, Optional, Union
9
+ from xml.etree import ElementTree as ET
9
10
 
10
- import sqlalchemy as sa
11
11
  from slixmpp import JID, InvalidJID, Message, Presence
12
12
  from slixmpp.plugins.xep_0045.stanza import MUCAdminItem
13
13
  from slixmpp.types import MessageTypes, OptJid
@@ -51,6 +51,8 @@ class LegacyParticipant(
51
51
  A legacy participant of a legacy group chat.
52
52
  """
53
53
 
54
+ is_participant = True
55
+
54
56
  mtype: MessageTypes = "groupchat"
55
57
  _can_send_carbon = False
56
58
  USE_STANZA_ID = True
@@ -93,6 +95,13 @@ class LegacyParticipant(
93
95
  self.merge()
94
96
  return self.stored.is_user
95
97
 
98
+ @is_user.setter
99
+ def is_user(self, is_user: bool) -> None:
100
+ with self.xmpp.store.session(expire_on_commit=True) as orm:
101
+ orm.add(self.stored)
102
+ self.stored.is_user = is_user
103
+ orm.commit()
104
+
96
105
  @property
97
106
  def jid(self) -> JID:
98
107
  jid = JID(self.muc.jid)
@@ -510,7 +519,11 @@ class LegacyParticipant(
510
519
  if when is not None:
511
520
  msg["delay"].set_stamp(when)
512
521
  msg["delay"]["from"] = self.muc.jid
513
- msg["subject"] = subject or str(self.muc.name)
522
+ if subject:
523
+ msg["subject"] = subject
524
+ else:
525
+ # may be simplified if slixmpp lets it do it more easily some day
526
+ msg.xml.append(ET.Element(f"{{{msg.namespace}}}subject"))
514
527
  self._send(msg, full_jid)
515
528
 
516
529
 
slidge/group/room.py CHANGED
@@ -7,7 +7,16 @@ from asyncio import Lock
7
7
  from contextlib import asynccontextmanager
8
8
  from copy import copy
9
9
  from datetime import datetime, timedelta, timezone
10
- from typing import TYPE_CHECKING, AsyncIterator, Generic, Optional, Type, Union
10
+ from typing import (
11
+ TYPE_CHECKING,
12
+ AsyncIterator,
13
+ Generic,
14
+ Literal,
15
+ Optional,
16
+ Type,
17
+ Union,
18
+ overload,
19
+ )
11
20
  from uuid import uuid4
12
21
 
13
22
  import sqlalchemy as sa
@@ -325,16 +334,15 @@ class LegacyMUC(
325
334
  self.stored.history_filled = True
326
335
  self.commit(merge=True)
327
336
 
328
- @property
329
- def DISCO_NAME(self) -> str: # type:ignore
330
- return self.name or "unnamed-room"
337
+ def _get_disco_name(self) -> str | None:
338
+ return self.name
331
339
 
332
340
  @property
333
- def name(self) -> str:
334
- return self.stored.name or "unnamed-room"
341
+ def name(self) -> str | None:
342
+ return self.stored.name
335
343
 
336
344
  @name.setter
337
- def name(self, n: str) -> None:
345
+ def name(self, n: str | None) -> None:
338
346
  if self.name == n:
339
347
  return
340
348
  self.stored.name = n
@@ -423,8 +431,8 @@ class LegacyMUC(
423
431
  yield
424
432
 
425
433
  @property
426
- def subject(self):
427
- return self.stored.subject
434
+ def subject(self) -> str:
435
+ return self.stored.subject or ""
428
436
 
429
437
  @subject.setter
430
438
  def subject(self, s: str) -> None:
@@ -644,7 +652,7 @@ class LegacyMUC(
644
652
  orm.refresh(self.stored, ["participants"])
645
653
  if not user_participant.is_user:
646
654
  self.log.warning("is_user flag not set participant on user_participant")
647
- user_participant.is_user = True # type:ignore
655
+ user_participant.is_user = True
648
656
  user_participant.send_initial_presence(
649
657
  user_full_jid,
650
658
  presence_id=join_presence["id"],
@@ -672,8 +680,12 @@ class LegacyMUC(
672
680
  maxstanzas=maxstanzas,
673
681
  since=since,
674
682
  )
683
+ if self.HAS_SUBJECT:
684
+ subject = self.subject or ""
685
+ else:
686
+ subject = self.description or self.name or ""
675
687
  self.__get_subject_setter_participant().set_room_subject(
676
- self.subject if self.HAS_SUBJECT else (self.description or self.name),
688
+ subject,
677
689
  user_full_jid,
678
690
  self.subject_date,
679
691
  )
@@ -764,9 +776,24 @@ class LegacyMUC(
764
776
  """
765
777
  return self._participant_cls(self, Participant(), is_system=True)
766
778
 
779
+ @overload
767
780
  async def get_participant_by_contact(
768
781
  self, c: "LegacyContact"
769
- ) -> "LegacyParticipantType":
782
+ ) -> "LegacyParticipantType": ...
783
+
784
+ @overload
785
+ async def get_participant_by_contact(
786
+ self, c: "LegacyContact", create: Literal[False]
787
+ ) -> "LegacyParticipantType | None": ...
788
+
789
+ @overload
790
+ async def get_participant_by_contact(
791
+ self, c: "LegacyContact", create: Literal[True]
792
+ ) -> "LegacyParticipantType": ...
793
+
794
+ async def get_participant_by_contact(
795
+ self, c: "LegacyContact", create: bool = True
796
+ ) -> "LegacyParticipantType | None":
770
797
  """
771
798
  Get a non-anonymous participant.
772
799
 
@@ -774,6 +801,7 @@ class LegacyMUC(
774
801
  that the Contact jid is associated to this participant
775
802
 
776
803
  :param c: The :class:`.LegacyContact` instance corresponding to this contact
804
+ :param create: Creates the participant if it does not exist.
777
805
  :return:
778
806
  """
779
807
  await self.session.contacts.ready
@@ -785,7 +813,10 @@ class LegacyMUC(
785
813
  .filter_by(contact=c.stored, room=self.stored)
786
814
  .one_or_none()
787
815
  )
788
- if stored is not None:
816
+ if stored is None:
817
+ if not create:
818
+ return None
819
+ else:
789
820
  return self.participant_from_store(stored=stored, contact=c)
790
821
 
791
822
  nickname = c.name or unescape_node(c.jid.node)
slidge/migration.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import logging
2
- import shutil
3
2
  import sys
4
3
  import traceback
5
4
  from pathlib import Path
@@ -7,15 +6,6 @@ from pathlib import Path
7
6
  from alembic import command
8
7
  from alembic.config import Config
9
8
 
10
- from .core import config
11
-
12
-
13
- def remove_avatar_cache_v1() -> None:
14
- old_dir = config.HOME_DIR / "slidge_avatars"
15
- if old_dir.exists():
16
- log.info("Avatar cache dir v1 found, clearing it.")
17
- shutil.rmtree(old_dir)
18
-
19
9
 
20
10
  def get_alembic_cfg() -> Config:
21
11
  alembic_cfg = Config()
@@ -28,7 +18,6 @@ def get_alembic_cfg() -> Config:
28
18
 
29
19
 
30
20
  def migrate() -> None:
31
- remove_avatar_cache_v1()
32
21
  try:
33
22
  command.upgrade(get_alembic_cfg(), "head")
34
23
  except Exception as e:
slidge/util/types.py CHANGED
@@ -72,6 +72,7 @@ MucRole = Literal["visitor", "participant", "moderator", "none"]
72
72
  ClientType = Literal[
73
73
  "bot", "console", "game", "handheld", "pc", "phone", "sms", "tablet", "web"
74
74
  ]
75
+ AttachmentDisposition = Literal["attachment", "inline"]
75
76
 
76
77
 
77
78
  @dataclass
@@ -115,6 +116,7 @@ class LegacyAttachment:
115
116
  legacy_file_id: Optional[Union[str, int]] = None
116
117
  url: Optional[str] = None
117
118
  caption: Optional[str] = None
119
+ disposition: Optional[AttachmentDisposition] = None
118
120
  """
119
121
  A caption for this specific image. For a global caption for a list of attachments,
120
122
  use the ``body`` parameter of :meth:`.AttachmentMixin.send_files`
slidge/util/util.py CHANGED
@@ -324,3 +324,10 @@ def strip_leading_emoji(text: str) -> str:
324
324
 
325
325
  async def noop_coro() -> None:
326
326
  pass
327
+
328
+
329
+ def add_quote_prefix(text: str):
330
+ """
331
+ Return multi-line text with leading quote marks (i.e. the ">" character).
332
+ """
333
+ return "\n".join(("> " + x).strip() for x in text.split("\n")).strip()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slidge
3
- Version: 0.3.0b2
3
+ Version: 0.3.0b4
4
4
  Summary: XMPP bridging framework
5
5
  Author-email: Nicolas Cedilnik <nicoco@nicoco.fr>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -1,7 +1,7 @@
1
1
  slidge/__init__.py,sha256=OWGOMz8wl6I6XNUT9ipE9IFD-OinS8zQGGn4U_z3IWw,1835
2
2
  slidge/__main__.py,sha256=ydjUklOoavS4YlGfjRX_8BQN2DaSbaXPMi47RkOgcFI,37
3
3
  slidge/main.py,sha256=bUdAau6TorsPpDRBPfzvUolHlXF5K-BY9aJdSmNUcyw,7109
4
- slidge/migration.py,sha256=Y_PJ9ahHwcgwP1gnGByIiUJSxTu2DYFpmNiPdOpVgoQ,1545
4
+ slidge/migration.py,sha256=b0Bi1D6QObpBhwZy33LvtYy3ObIx56pUdxgLfoQglh4,1271
5
5
  slidge/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  slidge/command/__init__.py,sha256=UYf1mjCYbZ5G7PIgaFTWSQRAzEJkQ6dTH8Fu_e_XnO0,613
7
7
  slidge/command/adhoc.py,sha256=NCHammJdl30eHniiYukYQZKp1IeI-5qv5u9NncLNSNM,10760
@@ -16,7 +16,7 @@ slidge/contact/contact.py,sha256=AZSpBInijGXn5hP_eJQhdyCOcUnzM62h65ZliyFZWhg,194
16
16
  slidge/contact/roster.py,sha256=uZ3iCl8oa7kEpIptUVa9p1k51bSvbuQq1pUGnf_zru8,9791
17
17
  slidge/core/__init__.py,sha256=RG7Jj5JCJERjhqJ31lOLYV-7bH_oblClQD1KF9LsTXo,68
18
18
  slidge/core/config.py,sha256=1HxHQ5BOnYghi8V5KbCQ6sUsNnXzAZAIoFA5PrMqH4E,6060
19
- slidge/core/gateway.py,sha256=0nuWlig6K4urNowoEKCVkSvEVH46BhR70A52fH6O4AE,40956
19
+ slidge/core/gateway.py,sha256=5GImsd1b7KKcwIZcNSWgVieezrnp5dJCv7IlmOvWkRc,41192
20
20
  slidge/core/pubsub.py,sha256=-YK49tEdz_SLM3O8Y9zvu3p5KYhxgNpqbsD57rOIdNI,12141
21
21
  slidge/core/session.py,sha256=Rji81tCEVI5zpKtKpMIuclKvDR0XuHZRki8ivIhtNnQ,29500
22
22
  slidge/core/dispatcher/__init__.py,sha256=1EXcjXietUKlxEqdrCWCV3xZ3q_DSsjHoqWrPMbtYao,84
@@ -39,30 +39,30 @@ slidge/core/dispatcher/muc/misc.py,sha256=FYo5FdmzksEuUCfCLLOOm8_8plXtZFQP8IzvzV
39
39
  slidge/core/dispatcher/muc/owner.py,sha256=dDAxpRaA8H_NJQNIyBNixck2oG4GHZeEQqPhKd7MmDQ,3359
40
40
  slidge/core/dispatcher/muc/ping.py,sha256=EgKKS9AvMnW-vINGcoGbtk6NdbN9A7zVaGfT5T7F6YE,1699
41
41
  slidge/core/mixins/__init__.py,sha256=Zea39CCwjJU5XfHwcYPEZ9Sin8z1BZxoV68G2RwC3nE,386
42
- slidge/core/mixins/attachment.py,sha256=f_8SZGyEAK00fzpwUWyIocPzdkSl5awPihR6_GCgdDo,21766
42
+ slidge/core/mixins/attachment.py,sha256=6c1gZNydVZHgHB-_PjBLbT_9ntBSNG0AWqlv9Cgcku8,21906
43
43
  slidge/core/mixins/avatar.py,sha256=0E0mQxdTUcJQrYXlBkYqkNl4bYuga4cIC1s4XA2rED8,5559
44
- slidge/core/mixins/base.py,sha256=MOd-pas38_52VawQVlxWtBtmTKC6My9G0ZaCeQxOJbs,748
44
+ slidge/core/mixins/base.py,sha256=getXMptzJwIc4fEbeMoJCSKcC3awi8UbKnx5FVCthjc,783
45
45
  slidge/core/mixins/db.py,sha256=a6idm-FgHWfDK-MJZWy5AkkBlyY8JmwOB8xAFmm0E9g,1934
46
- slidge/core/mixins/disco.py,sha256=jk3Z1B6zTuisHv8VKNRJodIo0ee5btYHh2ZrlflPj_Q,3670
46
+ slidge/core/mixins/disco.py,sha256=mrYhWO9qpnLMAVtKKqwbDh6CNOH2dPNERpyfmWzZGg8,3684
47
47
  slidge/core/mixins/message.py,sha256=xk4bgiJF9ATe-rgtH4sHU8hUwecBF4KjGIujm90mbXQ,8014
48
48
  slidge/core/mixins/message_maker.py,sha256=d9lMurnWCr7Y-pyyUkLoQYykb6lCCZuBNKFOe2hcY3A,6552
49
- slidge/core/mixins/message_text.py,sha256=UUbY-hdsMEUHe3b2h2Rwkaic43iDiaaUoEmuyw6FezY,8564
50
- slidge/core/mixins/presence.py,sha256=YPGdAPyVocjV7UJgIGupgf-arKJUYni67b3I7ajsKJE,9697
49
+ slidge/core/mixins/message_text.py,sha256=-hlGDzQ9dya-ZCPBe3v7UrpBetQa36N3YIACRxBt8Yc,9632
50
+ slidge/core/mixins/presence.py,sha256=ijIxjX38DtvPuiBkoxduHp0TBPHSjKLi03rDZvlquEY,9768
51
51
  slidge/core/mixins/recipient.py,sha256=b0uFnpym-hOFgYxGjXT1xQcZ4YRbDSBftPcNWLzSwEI,1336
52
52
  slidge/db/__init__.py,sha256=EBDH1JSEhgqYcli2Bw11CRC749wJk8AOucgBzmhDSvU,105
53
53
  slidge/db/avatar.py,sha256=MXFd1oe0eL5CCUYbc5CpsIcbio3cY3xVoKt39RAoj9I,8240
54
54
  slidge/db/meta.py,sha256=NtjGWcqPfG7uPfwR_cC6_23zyo8ftqgKX8CbP9IBq6U,2185
55
55
  slidge/db/models.py,sha256=8z5bbaEINfU1Qx12iyHu4zRD9s3PwC6oUOz-PyBoqYg,12841
56
- slidge/db/store.py,sha256=shgBqGutbAeMD6T3sqH7Qo4IKs9TWwjwfH5-NDpj-kY,19399
56
+ slidge/db/store.py,sha256=ZksmZlFaTia7eWy_trALc_iTEkk2x7CIlEQeYkHW21g,19408
57
57
  slidge/db/alembic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  slidge/db/alembic/env.py,sha256=hsBlRNs0zF5diSHGRSa8Fi3qRVQDA2rJdR41AEIdvxc,1642
59
59
  slidge/db/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
60
60
  slidge/db/alembic/versions/cef02a8b1451_initial_schema.py,sha256=D1K-flfTM9Vkk0YFzg6HbmoDyEb2u5c751aXk2YzVVg,14881
61
61
  slidge/group/__init__.py,sha256=yFt7cHqeaKIMN6f9ZyhhspOcJJvBtLedGv-iICG7lto,258
62
- slidge/group/archive.py,sha256=DKwyde15-Op2rXuQBvdSmFcAKhUyWuorpEFcRSmDHec,5956
63
- slidge/group/bookmarks.py,sha256=UWrUjZMWlDmwKFRuNEqxZSx4cvXFib4AP_l388ApJa8,7086
64
- slidge/group/participant.py,sha256=eMwUgbEtxGjWMmIqUfS8uSKlaStitZ3D68M_RixQeso,17676
65
- slidge/group/room.py,sha256=_KP0jIh9f9k0yDRWCe7BsZBQesfm1lwbHpN9WYRKuzc,48391
62
+ slidge/group/archive.py,sha256=aBcklo24UbpzIC8o7DrjaMb0zYzNlLbqoAHKOiltMAQ,6046
63
+ slidge/group/bookmarks.py,sha256=eiXtlgirE59dBi1BT1349wCrGuHDkCoak1phCepzkqI,7653
64
+ slidge/group/participant.py,sha256=mR_SJKA3WEONHdopZz2GtKuC8Srx9-V0-REhPxdZ_Gc,18118
65
+ slidge/group/room.py,sha256=3CiwiTYx0R6Ud5lP6otD6QEjwU3ZicUHKf3gJPmrUBo,49098
66
66
  slidge/slixfix/__init__.py,sha256=LvaYZQYjr4l_45AYYpod1dB3MUaZye18vKF-4H8Bm20,4758
67
67
  slidge/slixfix/delivery_receipt.py,sha256=JmogxsiXYEbTmCM4fvC5wkQs0jBsaJtKl4j_B_18riE,1415
68
68
  slidge/slixfix/roster.py,sha256=DjjHQqCsKsPChUxV7S0Pm4IAgjfrwgm5tcTdJi3N_gY,1670
@@ -85,11 +85,11 @@ slidge/util/conf.py,sha256=Wv-xr1fQfz6jDCBpj2e5Nm-igMpdIjsYsVfoY8grJoo,7380
85
85
  slidge/util/jid_escaping.py,sha256=QJ2Yj_j1gTmiO9g2r187iVCu7kia_O5ABhRiLAO2TG4,1073
86
86
  slidge/util/lock.py,sha256=ZnUi3LGiz271-YeYKo9JzxovJCoSwlP9P65pNyHIO9o,1029
87
87
  slidge/util/test.py,sha256=_E6er2BtQlpyzTUmp4u8C9KhBYzbLrmTwSVgxGObKHU,13988
88
- slidge/util/types.py,sha256=xJ84ZvaUOU_VVJSjEMysgNSl05k0_O9YKbyW-JUrsMI,5635
89
- slidge/util/util.py,sha256=4hihLCl4SsB5S14TT3bP8tDPP_Zg9rYbSfLdLB9-G_Q,9332
90
- slidge-0.3.0b2.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
91
- slidge-0.3.0b2.dist-info/METADATA,sha256=_O_tp1b_KiJA94aoQQG0e0Nbg37mt-P7BFJY6Gn0xcg,5056
92
- slidge-0.3.0b2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
93
- slidge-0.3.0b2.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
94
- slidge-0.3.0b2.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
95
- slidge-0.3.0b2.dist-info/RECORD,,
88
+ slidge/util/types.py,sha256=nilphTeJU3yb0MSqb86tZeWXis495oDvHSDDBs0hn_4,5747
89
+ slidge/util/util.py,sha256=PBdHtcRIQi6Dy-yHASS_xiRGQ4Pv4i6QSSZAAELPnmQ,9536
90
+ slidge-0.3.0b4.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
91
+ slidge-0.3.0b4.dist-info/METADATA,sha256=JT5D6Cw0DTljYUdK527OLNco4wD2OddL70PjRJMsaH0,5056
92
+ slidge-0.3.0b4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
93
+ slidge-0.3.0b4.dist-info/entry_points.txt,sha256=py3_x834fFJ2TEzPd18Wt2DnysdAfuVqJ5zzBrXbAZs,44
94
+ slidge-0.3.0b4.dist-info/top_level.txt,sha256=2LRjDYHaGZ5ieCMF8xy58JIiabRMzX-MGMbCZwfE17c,7
95
+ slidge-0.3.0b4.dist-info/RECORD,,