slidge 0.2.0a2__py3-none-any.whl → 0.2.0a4__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -58,10 +58,19 @@ def downgrade() -> None:
58
58
 
59
59
 
60
60
  def migrate_from_shelf(accounts: sa.Table) -> None:
61
+ from slidge import global_config
62
+
63
+ db_file = global_config.HOME_DIR / "slidge.db"
64
+ if not db_file.exists():
65
+ return
66
+
61
67
  try:
62
- from slidge.util.db import user_store
68
+ from slidge.db.alembic.old_user_store import user_store
63
69
  except ImportError:
64
70
  return
71
+
72
+ user_store.set_file(db_file, global_config.SECRET_KEY)
73
+
65
74
  try:
66
75
  users = list(user_store.get_all())
67
76
  except AttributeError:
@@ -83,3 +92,6 @@ def migrate_from_shelf(accounts: sa.Table) -> None:
83
92
  for user in users
84
93
  ],
85
94
  )
95
+
96
+ user_store.close()
97
+ db_file.unlink()
slidge/db/avatar.py CHANGED
@@ -206,6 +206,11 @@ class AvatarCache:
206
206
  stored = orm.execute(select(Avatar).where(Avatar.hash == hash_)).scalar()
207
207
 
208
208
  if stored is not None:
209
+ if unique_id is not None:
210
+ log.warning("Updating 'unique' IDs of a known avatar.")
211
+ stored.legacy_id = str(unique_id)
212
+ orm.add(stored)
213
+ orm.commit()
209
214
  return CachedAvatar.from_store(stored, self.dir)
210
215
 
211
216
  stored = Avatar(
slidge/db/meta.py CHANGED
@@ -58,6 +58,13 @@ JSONSerializable = dict[str, JSONSerializableTypes]
58
58
 
59
59
  class Base(sa.orm.DeclarativeBase):
60
60
  type_annotation_map = {JSONSerializable: JSONEncodedDict, JID: JIDType}
61
+ naming_convention = {
62
+ "ix": "ix_%(column_0_label)s",
63
+ "uq": "uq_%(table_name)s_%(column_0_name)s",
64
+ "ck": "ck_%(table_name)s_`%(constraint_name)s`",
65
+ "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
66
+ "pk": "pk_%(table_name)s",
67
+ }
61
68
 
62
69
 
63
70
  def get_engine(path: str) -> sa.Engine:
slidge/db/models.py CHANGED
@@ -166,6 +166,9 @@ class Contact(Base):
166
166
  )
167
167
  updated: Mapped[bool] = mapped_column(default=False)
168
168
 
169
+ vcard: Mapped[Optional[str]] = mapped_column()
170
+ vcard_fetched: Mapped[bool] = mapped_column(default=False)
171
+
169
172
  participants: Mapped[list["Participant"]] = relationship(back_populates="contact")
170
173
 
171
174
 
@@ -191,13 +194,20 @@ class Room(Base):
191
194
  Legacy room
192
195
  """
193
196
 
197
+ __table_args__ = (
198
+ UniqueConstraint(
199
+ "user_account_id", "legacy_id", name="uq_room_user_account_id_legacy_id"
200
+ ),
201
+ UniqueConstraint("user_account_id", "jid", name="uq_room_user_account_id_jid"),
202
+ )
203
+
194
204
  __tablename__ = "room"
195
205
  id: Mapped[int] = mapped_column(primary_key=True)
196
206
  user_account_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
197
207
  user: Mapped[GatewayUser] = relationship(back_populates="rooms")
198
- legacy_id: Mapped[str] = mapped_column(unique=True, nullable=False)
208
+ legacy_id: Mapped[str] = mapped_column(nullable=False)
199
209
 
200
- jid: Mapped[JID] = mapped_column(unique=True)
210
+ jid: Mapped[JID] = mapped_column(nullable=False)
201
211
 
202
212
  avatar_id: Mapped[int] = mapped_column(ForeignKey("avatar.id"), nullable=True)
203
213
  avatar: Mapped[Avatar] = relationship(back_populates="rooms")
slidge/db/store.py CHANGED
@@ -162,12 +162,20 @@ class AvatarStore(EngineMixin):
162
162
  class SentStore(EngineMixin):
163
163
  def set_message(self, user_pk: int, legacy_id: str, xmpp_id: str) -> None:
164
164
  with self.session() as session:
165
- msg = XmppToLegacyIds(
166
- user_account_id=user_pk,
167
- legacy_id=legacy_id,
168
- xmpp_id=xmpp_id,
169
- type=XmppToLegacyEnum.DM,
165
+ msg = (
166
+ session.query(XmppToLegacyIds)
167
+ .filter(XmppToLegacyIds.user_account_id == user_pk)
168
+ .filter(XmppToLegacyIds.legacy_id == legacy_id)
169
+ .filter(XmppToLegacyIds.xmpp_id == xmpp_id)
170
+ .scalar()
170
171
  )
172
+ if msg is None:
173
+ msg = XmppToLegacyIds(user_account_id=user_pk)
174
+ else:
175
+ log.debug("Resetting a DM from sent store")
176
+ msg.legacy_id = legacy_id
177
+ msg.xmpp_id = xmpp_id
178
+ msg.type = XmppToLegacyEnum.DM
171
179
  session.add(msg)
172
180
  session.commit()
173
181
 
@@ -380,11 +388,22 @@ class ContactStore(UpdatedMixin):
380
388
  row.updated = True
381
389
  row.extra_attributes = contact.serialize_extra_attributes()
382
390
  row.caps_ver = contact._caps_ver
391
+ row.vcard = contact._vcard
392
+ row.vcard_fetched = contact._vcard_fetched
383
393
  session.add(row)
384
394
  if commit:
385
395
  session.commit()
386
396
  return row.id
387
397
 
398
+ def set_vcard(self, contact_pk: int, vcard: str | None) -> None:
399
+ with self.session() as session:
400
+ session.execute(
401
+ update(Contact)
402
+ .where(Contact.id == contact_pk)
403
+ .values(vcard=vcard, vcard_fetched=True)
404
+ )
405
+ session.commit()
406
+
388
407
  def add_to_sent(self, contact_pk: int, msg_id: str) -> None:
389
408
  with self.session() as session:
390
409
  new = ContactSent(contact_id=contact_pk, msg_id=msg_id)
@@ -614,6 +633,7 @@ class MAMStore(EngineMixin):
614
633
  with self.session() as session:
615
634
  after_timestamp = (
616
635
  session.query(ArchivedMessage.timestamp)
636
+ .filter(ArchivedMessage.room_id == room_pk)
617
637
  .filter(ArchivedMessage.legacy_id == after_id)
618
638
  .scalar()
619
639
  )
@@ -660,7 +680,7 @@ class MultiStore(EngineMixin):
660
680
  if existing is not None:
661
681
  if fail:
662
682
  raise
663
- log.warning("Resetting multi for %s", legacy_msg_id)
683
+ log.debug("Resetting multi for %s", legacy_msg_id)
664
684
  session.execute(
665
685
  delete(LegacyIdsMulti)
666
686
  .where(LegacyIdsMulti.user_account_id == user_pk)
@@ -767,7 +787,10 @@ class RoomStore(UpdatedMixin):
767
787
  with self.session() as session:
768
788
  session.execute(
769
789
  update(Room).values(
770
- subject_setter=None, user_resources=None, history_filled=False
790
+ subject_setter=None,
791
+ user_resources=None,
792
+ history_filled=False,
793
+ participants_filled=False,
771
794
  )
772
795
  )
773
796
  session.commit()
@@ -879,6 +902,13 @@ class RoomStore(UpdatedMixin):
879
902
  )
880
903
  session.commit()
881
904
 
905
+ def update_user_nick(self, room_pk, nick: str) -> None:
906
+ with self.session() as session:
907
+ session.execute(
908
+ update(Room).where(Room.id == room_pk).values(user_nick=nick)
909
+ )
910
+ session.commit()
911
+
882
912
  def delete(self, room_pk: int) -> None:
883
913
  with self.session() as session:
884
914
  session.execute(delete(Room).where(Room.id == room_pk))
slidge/group/bookmarks.py CHANGED
@@ -8,6 +8,7 @@ from slixmpp.jid import _unescape_node
8
8
 
9
9
  from ..contact.roster import ESCAPE_TABLE
10
10
  from ..core.mixins.lock import NamedLockMixin
11
+ from ..db.models import Room
11
12
  from ..util import SubclassableOnce
12
13
  from ..util.types import LegacyGroupIdType, LegacyMUCType
13
14
  from .archive import MessageArchive
@@ -57,29 +58,6 @@ class LegacyBookmarks(
57
58
  def __repr__(self):
58
59
  return f"<Bookmarks of {self.user_jid}>"
59
60
 
60
- async def __finish_init_muc(self, legacy_id: LegacyGroupIdType, jid: JID):
61
- with self.__store.session():
62
- stored = self.__store.get_by_legacy_id(self.session.user_pk, str(legacy_id))
63
- if stored is not None:
64
- if stored.updated:
65
- return self._muc_class.from_store(self.session, stored)
66
- muc = self._muc_class(self.session, legacy_id=legacy_id, jid=jid)
67
- muc.pk = stored.id
68
- else:
69
- muc = self._muc_class(self.session, legacy_id=legacy_id, jid=jid)
70
-
71
- try:
72
- with muc.updating_info():
73
- await muc.avatar_wrap_update_info()
74
- except Exception as e:
75
- raise XMPPError("internal-server-error", str(e))
76
- if not muc.user_nick:
77
- muc.user_nick = self._user_nick
78
- self.log.debug("MUC created: %r", muc)
79
- muc.pk = self.__store.update(muc)
80
- muc.archive = MessageArchive(muc.pk, self.xmpp.store.mam)
81
- return muc
82
-
83
61
  async def legacy_id_to_jid_local_part(self, legacy_id: LegacyGroupIdType):
84
62
  return await self.legacy_id_to_jid_username(legacy_id)
85
63
 
@@ -110,24 +88,16 @@ class LegacyBookmarks(
110
88
  async def by_jid(self, jid: JID) -> LegacyMUCType:
111
89
  if jid.resource:
112
90
  jid = JID(jid.bare)
113
- bare = jid.bare
114
- async with self.lock(("bare", bare)):
115
- assert isinstance(jid.username, str)
116
- legacy_id = await self.jid_local_part_to_legacy_id(jid.username)
91
+ async with self.lock(("bare", jid.bare)):
92
+ assert isinstance(jid.local, str)
93
+ legacy_id = await self.jid_local_part_to_legacy_id(jid.local)
117
94
  if self.get_lock(("legacy_id", legacy_id)):
118
95
  self.log.debug("Not instantiating %s after all", jid)
119
96
  return await self.by_legacy_id(legacy_id)
120
97
 
121
98
  with self.__store.session():
122
99
  stored = self.__store.get_by_jid(self.session.user_pk, jid)
123
- if stored is not None and stored.updated:
124
- return self._muc_class.from_store(self.session, stored)
125
-
126
- self.log.debug("Attempting to instantiate a new MUC for JID %s", jid)
127
- local_part = jid.node
128
-
129
- self.log.debug("%r is group %r", local_part, legacy_id)
130
- return await self.__finish_init_muc(legacy_id, JID(bare))
100
+ return await self.__update_muc(stored, legacy_id, jid)
131
101
 
132
102
  def by_jid_only_if_exists(self, jid: JID) -> Optional[LegacyMUCType]:
133
103
  with self.__store.session():
@@ -138,22 +108,39 @@ class LegacyBookmarks(
138
108
 
139
109
  async def by_legacy_id(self, legacy_id: LegacyGroupIdType) -> LegacyMUCType:
140
110
  async with self.lock(("legacy_id", legacy_id)):
141
- with self.__store.session():
142
- stored = self.__store.get_by_legacy_id(
143
- self.session.user_pk, str(legacy_id)
144
- )
145
- if stored is not None and stored.updated:
146
- return self._muc_class.from_store(self.session, stored)
147
- self.log.debug("Create new MUC instance for legacy ID %s", legacy_id)
148
111
  local = await self.legacy_id_to_jid_local_part(legacy_id)
149
- bare = f"{local}@{self.xmpp.boundjid}"
150
- jid = JID(bare)
151
- if self.get_lock(("bare", bare)):
112
+ jid = JID(f"{local}@{self.xmpp.boundjid}")
113
+ if self.get_lock(("bare", jid.bare)):
152
114
  self.log.debug("Not instantiating %s after all", legacy_id)
153
115
  return await self.by_jid(jid)
154
- muc = await self.__finish_init_muc(legacy_id, jid)
155
116
 
156
- return muc
117
+ with self.__store.session():
118
+ stored = self.__store.get_by_legacy_id(
119
+ self.session.user_pk, str(legacy_id)
120
+ )
121
+ return await self.__update_muc(stored, legacy_id, jid)
122
+
123
+ async def __update_muc(
124
+ self, stored: Room | None, legacy_id: LegacyGroupIdType, jid: JID
125
+ ):
126
+ if stored is None:
127
+ muc = self._muc_class(self.session, legacy_id=legacy_id, jid=jid)
128
+ else:
129
+ muc = self._muc_class.from_store(self.session, stored)
130
+ if stored.updated:
131
+ return muc
132
+
133
+ try:
134
+ with muc.updating_info():
135
+ await muc.avatar_wrap_update_info()
136
+ except Exception as e:
137
+ raise XMPPError("internal-server-error", str(e))
138
+ if not muc.user_nick:
139
+ muc.user_nick = self._user_nick
140
+ self.log.debug("MUC created: %r", muc)
141
+ muc.pk = self.__store.update(muc)
142
+ muc.archive = MessageArchive(muc.pk, self.xmpp.store.mam)
143
+ return muc
157
144
 
158
145
  @abc.abstractmethod
159
146
  async def fill(self):
@@ -450,13 +450,21 @@ class LegacyParticipant(
450
450
  return super().get_disco_info()
451
451
 
452
452
  def moderate(self, legacy_msg_id: LegacyMessageType, reason: Optional[str] = None):
453
- m = self.muc.get_system_participant()._make_message()
454
- m["apply_to"]["id"] = self._legacy_to_xmpp(legacy_msg_id)
455
- m["apply_to"]["moderated"].enable("retract")
456
- m["apply_to"]["moderated"]["by"] = self.jid
457
- if reason:
458
- m["apply_to"]["moderated"]["reason"] = reason
459
- self._send(m)
453
+ xmpp_id = self._legacy_to_xmpp(legacy_msg_id)
454
+ multi = self.xmpp.store.multi.get_xmpp_ids(self.session.user_pk, xmpp_id)
455
+ if multi is None:
456
+ msg_ids = [xmpp_id]
457
+ else:
458
+ msg_ids = multi + [xmpp_id]
459
+
460
+ for i in msg_ids:
461
+ m = self.muc.get_system_participant()._make_message()
462
+ m["apply_to"]["id"] = i
463
+ m["apply_to"]["moderated"].enable("retract")
464
+ m["apply_to"]["moderated"]["by"] = self.jid
465
+ if reason:
466
+ m["apply_to"]["moderated"]["reason"] = reason
467
+ self._send(m)
460
468
 
461
469
  def set_room_subject(
462
470
  self,
slidge/group/room.py CHANGED
@@ -206,6 +206,8 @@ class LegacyMUC(
206
206
  @user_nick.setter
207
207
  def user_nick(self, nick: str):
208
208
  self._user_nick = nick
209
+ if not self._updating_info:
210
+ self.__store.update_user_nick(self.pk, nick)
209
211
 
210
212
  def add_user_resource(self, resource: str) -> None:
211
213
  self._user_resources.add(resource)
@@ -1195,7 +1197,7 @@ class LegacyMUC(
1195
1197
  )
1196
1198
  muc.pk = stored.id
1197
1199
  muc.type = stored.muc_type # type: ignore
1198
- muc.user_nick = stored.user_nick
1200
+ muc._user_nick = stored.user_nick
1199
1201
  if stored.name:
1200
1202
  muc.DISCO_NAME = stored.name
1201
1203
  if stored.description:
slidge/main.py CHANGED
@@ -32,7 +32,6 @@ from slidge.db.avatar import avatar_cache
32
32
  from slidge.db.meta import get_engine
33
33
  from slidge.migration import migrate
34
34
  from slidge.util.conf import ConfigModule
35
- from slidge.util.db import user_store
36
35
 
37
36
 
38
37
  class MainConfig(ConfigModule):
@@ -114,9 +113,6 @@ def configure():
114
113
  logging.info("Creating directory '%s'", h)
115
114
  h.mkdir()
116
115
 
117
- db_file = config.HOME_DIR / "slidge.db"
118
- user_store.set_file(db_file, args.secret_key)
119
-
120
116
  config.UPLOAD_REQUESTER = config.UPLOAD_REQUESTER or config.JID.bare
121
117
 
122
118
  return unknown_argv
slidge/slixfix/roster.py CHANGED
@@ -1,9 +1,8 @@
1
+ import logging
1
2
  from typing import TYPE_CHECKING
2
3
 
3
4
  from slixmpp import JID
4
5
 
5
- from ..util.db import log
6
-
7
6
  if TYPE_CHECKING:
8
7
  from .. import BaseGateway
9
8
 
@@ -65,3 +64,6 @@ class RosterBackend:
65
64
  "whitelisted": False,
66
65
  "subscription": "none",
67
66
  }
67
+
68
+
69
+ log = logging.getLogger(__name__)
@@ -1,103 +1,14 @@
1
- import logging
2
- from typing import TYPE_CHECKING, NamedTuple, Optional
3
-
4
- from slixmpp import JID, CoroutineCallback, Iq, StanzaPath
5
1
  from slixmpp.plugins.base import BasePlugin, register_plugin
6
- from slixmpp.plugins.xep_0292.stanza import NS, VCard4
7
- from slixmpp.types import JidStr
8
-
9
- from slidge.contact import LegacyContact
10
-
11
- if TYPE_CHECKING:
12
- from slidge.core.gateway import BaseGateway
13
-
14
-
15
- class StoredVCard(NamedTuple):
16
- content: VCard4
17
- authorized_jids: set[JidStr]
2
+ from slixmpp.plugins.xep_0292.stanza import NS
18
3
 
19
4
 
20
5
  class VCard4Provider(BasePlugin):
21
- xmpp: "BaseGateway"
22
-
23
6
  name = "xep_0292_provider"
24
7
  description = "VCard4 Provider"
25
8
  dependencies = {"xep_0030"}
26
9
 
27
- def __init__(self, *a, **k):
28
- super(VCard4Provider, self).__init__(*a, **k)
29
- # TODO: store that in DB and not in RAM
30
- self._vcards = dict[JidStr, StoredVCard]()
31
-
32
10
  def plugin_init(self):
33
- self.xmpp.register_handler(
34
- CoroutineCallback(
35
- "get_vcard",
36
- StanzaPath(f"iq@type=get/vcard"),
37
- self.handle_vcard_get, # type:ignore
38
- )
39
- )
40
-
41
11
  self.xmpp.plugin["xep_0030"].add_feature(NS)
42
12
 
43
- def _get_cached_vcard(self, jid: JidStr, requested_by: JidStr) -> Optional[VCard4]:
44
- vcard = self._vcards.get(JID(jid).bare)
45
- if vcard:
46
- if auth := vcard.authorized_jids:
47
- if JID(requested_by).bare in auth:
48
- return vcard.content
49
- else:
50
- return vcard.content
51
- return None
52
-
53
- async def get_vcard(self, jid: JidStr, requested_by: JidStr) -> Optional[VCard4]:
54
- if vcard := self._get_cached_vcard(jid, requested_by):
55
- log.debug("Found a cached vcard")
56
- return vcard
57
- if not hasattr(self.xmpp, "get_session_from_jid"):
58
- return None
59
- jid = JID(jid)
60
- if not jid.local:
61
- return None
62
- requested_by = JID(requested_by)
63
- session = self.xmpp.get_session_from_jid(requested_by)
64
- if session is None:
65
- return
66
- entity = await session.get_contact_or_group_or_participant(jid)
67
- if isinstance(entity, LegacyContact):
68
- log.debug("Fetching vcard")
69
- await entity.fetch_vcard()
70
- return self._get_cached_vcard(jid, requested_by)
71
- return None
72
-
73
- async def handle_vcard_get(self, iq: Iq):
74
- r = iq.reply()
75
- if vcard := await self.get_vcard(iq.get_to().bare, iq.get_from().bare):
76
- r.append(vcard)
77
- else:
78
- r.enable("vcard")
79
- r.send()
80
-
81
- def set_vcard(
82
- self,
83
- jid: JidStr,
84
- vcard: VCard4,
85
- /,
86
- authorized_jids: Optional[set[JidStr]] = None,
87
- ):
88
- cache = self._vcards.get(jid)
89
- new = StoredVCard(
90
- vcard, authorized_jids if authorized_jids is not None else set()
91
- )
92
- self._vcards[jid] = new
93
- if cache == new:
94
- return
95
- if self.xmpp["pubsub"] and authorized_jids:
96
- for to in authorized_jids:
97
- self.xmpp.loop.create_task(
98
- self.xmpp["pubsub"].broadcast_vcard_event(jid, to)
99
- )
100
-
101
13
 
102
14
  register_plugin(VCard4Provider)
103
- log = logging.getLogger(__name__)
slidge/util/db.py CHANGED
@@ -1,183 +1,5 @@
1
- """
2
- This module covers a backend for storing user data persistently and managing a
3
- pseudo-roster for the gateway component.
4
- """
1
+ # here to allow migration of the user store from v0.1
2
+ # since it relies on shelf, which relies on pickle, we need to keep objects
3
+ # importable where they were when the shelf was written
5
4
 
6
- import dataclasses
7
- import datetime
8
- import logging
9
- import os.path
10
- import shelve
11
- from io import BytesIO
12
- from os import PathLike
13
- from typing import Iterable, Optional, Union
14
-
15
- from pickle_secure import Pickler, Unpickler
16
- from slixmpp import JID, Iq, Message, Presence
17
-
18
-
19
- # noinspection PyUnresolvedReferences
20
- class EncryptedShelf(shelve.DbfilenameShelf):
21
- cache: dict
22
- dict: dict
23
- writeback: bool
24
- keyencoding: str
25
- _protocol: int
26
-
27
- def __init__(
28
- self, filename: PathLike, key: str, flag="c", protocol=None, writeback=False
29
- ):
30
- super().__init__(str(filename), flag, protocol, writeback)
31
- self.secret_key = key
32
-
33
- def __getitem__(self, key):
34
- try:
35
- value = self.cache[key]
36
- except KeyError:
37
- f = BytesIO(self.dict[key.encode(self.keyencoding)])
38
- value = Unpickler(f, key=self.secret_key).load() # type:ignore
39
- if self.writeback:
40
- self.cache[key] = value
41
- return value
42
-
43
- def __setitem__(self, key, value):
44
- if self.writeback:
45
- self.cache[key] = value
46
- f = BytesIO()
47
- p = Pickler(f, self._protocol, key=self.secret_key) # type:ignore
48
- p.dump(value)
49
- self.dict[key.encode(self.keyencoding)] = f.getvalue()
50
-
51
-
52
- @dataclasses.dataclass
53
- class GatewayUser:
54
- """
55
- A gateway user
56
- """
57
-
58
- bare_jid: str
59
- """Bare JID of the user"""
60
- registration_form: dict[str, Optional[str]]
61
- """Content of the registration form, as a dict"""
62
- plugin_data: Optional[dict] = None
63
- registration_date: Optional[datetime.datetime] = None
64
-
65
- def __hash__(self):
66
- return hash(self.bare_jid)
67
-
68
- def __repr__(self):
69
- return f"<User {self.bare_jid}>"
70
-
71
- def __post_init__(self):
72
- if self.registration_date is None:
73
- self.registration_date = datetime.datetime.now()
74
-
75
- @property
76
- def jid(self) -> JID:
77
- """
78
- The user's (bare) JID
79
-
80
- :return:
81
- """
82
- return JID(self.bare_jid)
83
-
84
- def get(self, field: str, default: str = "") -> Optional[str]:
85
- # """
86
- # Get fields from the registration form (required to comply with slixmpp backend protocol)
87
- #
88
- # :param field: Name of the field
89
- # :param default: Default value to return if the field is not present
90
- #
91
- # :return: Value of the field
92
- # """
93
- return self.registration_form.get(field, default)
94
-
95
-
96
- class UserStore:
97
- """
98
- Basic user store implementation using shelve from the python standard library
99
-
100
- Set_file must be called before it is usable
101
- """
102
-
103
- def __init__(self):
104
- self._users: shelve.Shelf[GatewayUser] = None # type: ignore
105
-
106
- def set_file(self, filename: PathLike, secret_key: Optional[str] = None):
107
- """
108
- Set the file to use to store user data
109
-
110
- :param filename: Path to the shelf file
111
- :param secret_key: Secret key to store files encrypted on disk
112
- """
113
- if self._users is not None:
114
- raise RuntimeError("Shelf file already set!")
115
- if os.path.exists(filename):
116
- log.info("Using existing slidge DB: %s", filename)
117
- else:
118
- log.info("Creating a new slidge DB: %s", filename)
119
- if secret_key:
120
- self._users = EncryptedShelf(filename, key=secret_key)
121
- else:
122
- self._users = shelve.open(str(filename))
123
- log.info("Registered users in the DB: %s", list(self._users.keys()))
124
-
125
- def get_all(self) -> Iterable[GatewayUser]:
126
- """
127
- Get all users in the store
128
-
129
- :return: An iterable of GatewayUsers
130
- """
131
- return self._users.values()
132
-
133
- def commit(self, user: GatewayUser):
134
- self._users[user.jid.bare] = user
135
- self._users.sync()
136
-
137
- def get(self, _gateway_jid, _node, ifrom: JID, iq) -> Optional[GatewayUser]:
138
- """
139
- Get a user from the store
140
-
141
- NB: there is no reason to call this, it is used by SliXMPP internal API
142
-
143
- :param _gateway_jid:
144
- :param _node:
145
- :param ifrom:
146
- :param iq:
147
- :return:
148
- """
149
- if ifrom is None: # bug in SliXMPP's XEP_0100 plugin
150
- ifrom = iq["from"]
151
- log.debug("Getting user %s", ifrom.bare)
152
- return self._users.get(ifrom.bare)
153
-
154
- def get_by_jid(self, jid: JID) -> Optional[GatewayUser]:
155
- """
156
- Convenience function to get a user from their JID.
157
-
158
- :param jid: JID of the gateway user
159
- :return:
160
- """
161
- return self._users.get(jid.bare)
162
-
163
- def get_by_stanza(self, s: Union[Presence, Message, Iq]) -> Optional[GatewayUser]:
164
- """
165
- Convenience function to get a user from a stanza they sent.
166
-
167
- :param s: A stanza sent by the gateway user
168
- :return:
169
- """
170
- return self.get_by_jid(s.get_from())
171
-
172
- def close(self):
173
- self._users.sync()
174
- self._users.close()
175
-
176
-
177
- user_store = UserStore()
178
- """
179
- A persistent store for slidge users. Not public, but I didn't find how to hide
180
- it from the docs!
181
- """
182
-
183
- log = logging.getLogger(__name__)
5
+ from ..db.alembic.old_user_store import * # noqa:F403
slidge/util/test.py CHANGED
@@ -287,7 +287,7 @@ class SlidgeTest(SlixTestPlus):
287
287
  stanza = self.next_sent()
288
288
  assert "yup" in stanza["status"].lower(), stanza
289
289
 
290
- self.romeo = BaseSession.get_self_or_unique_subclass().from_jid(
290
+ self.romeo: BaseSession = BaseSession.get_self_or_unique_subclass().from_jid(
291
291
  JID("romeo@montague.lit")
292
292
  )
293
293
  self.juliet: LegacyContact = self.run_coro(