slidge 0.1.2__py3-none-any.whl → 0.2.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. slidge/__init__.py +3 -5
  2. slidge/__main__.py +2 -197
  3. slidge/__version__.py +5 -0
  4. slidge/command/adhoc.py +40 -17
  5. slidge/command/admin.py +24 -12
  6. slidge/command/base.py +10 -8
  7. slidge/command/categories.py +13 -3
  8. slidge/command/chat_command.py +29 -2
  9. slidge/command/register.py +32 -16
  10. slidge/command/user.py +106 -13
  11. slidge/contact/contact.py +254 -50
  12. slidge/contact/roster.py +124 -53
  13. slidge/core/config.py +19 -13
  14. slidge/core/dispatcher/__init__.py +3 -0
  15. slidge/core/{gateway → dispatcher}/caps.py +12 -8
  16. slidge/core/{gateway → dispatcher}/disco.py +10 -18
  17. slidge/core/dispatcher/message/__init__.py +10 -0
  18. slidge/core/dispatcher/message/chat_state.py +40 -0
  19. slidge/core/dispatcher/message/marker.py +62 -0
  20. slidge/core/dispatcher/message/message.py +397 -0
  21. slidge/core/dispatcher/muc/__init__.py +12 -0
  22. slidge/core/dispatcher/muc/admin.py +98 -0
  23. slidge/core/{gateway → dispatcher/muc}/mam.py +25 -17
  24. slidge/core/dispatcher/muc/misc.py +121 -0
  25. slidge/core/dispatcher/muc/owner.py +96 -0
  26. slidge/core/{gateway → dispatcher/muc}/ping.py +11 -17
  27. slidge/core/dispatcher/presence.py +176 -0
  28. slidge/core/dispatcher/registration.py +85 -0
  29. slidge/core/{gateway → dispatcher}/search.py +9 -16
  30. slidge/core/dispatcher/session_dispatcher.py +84 -0
  31. slidge/core/dispatcher/util.py +174 -0
  32. slidge/core/{gateway/vcard_temp.py → dispatcher/vcard.py} +35 -19
  33. slidge/core/{gateway/base.py → gateway.py} +176 -153
  34. slidge/core/mixins/__init__.py +11 -1
  35. slidge/core/mixins/attachment.py +106 -67
  36. slidge/core/mixins/avatar.py +94 -25
  37. slidge/core/mixins/base.py +10 -4
  38. slidge/core/mixins/db.py +18 -0
  39. slidge/core/mixins/disco.py +0 -10
  40. slidge/core/mixins/lock.py +10 -8
  41. slidge/core/mixins/message.py +11 -195
  42. slidge/core/mixins/message_maker.py +17 -9
  43. slidge/core/mixins/message_text.py +211 -0
  44. slidge/core/mixins/presence.py +17 -4
  45. slidge/core/pubsub.py +114 -288
  46. slidge/core/session.py +101 -40
  47. slidge/db/__init__.py +4 -0
  48. slidge/db/alembic/__init__.py +0 -0
  49. slidge/db/alembic/env.py +64 -0
  50. slidge/db/alembic/old_user_store.py +183 -0
  51. slidge/db/alembic/script.py.mako +26 -0
  52. slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +36 -0
  53. slidge/db/alembic/versions/15b0bd83407a_remove_bogus_unique_constraints_on_room_.py +85 -0
  54. slidge/db/alembic/versions/2461390c0af2_store_contacts_caps_verstring_in_db.py +36 -0
  55. slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +37 -0
  56. slidge/db/alembic/versions/2b1f45ab7379_store_room_subject_setter_by_nickname.py +41 -0
  57. slidge/db/alembic/versions/3071e0fa69d4_add_contact_client_type.py +52 -0
  58. slidge/db/alembic/versions/45c24cc73c91_add_bob.py +42 -0
  59. slidge/db/alembic/versions/5bd48bfdffa2_lift_room_legacy_id_constraint.py +61 -0
  60. slidge/db/alembic/versions/82a4af84b679_add_muc_history_filled.py +48 -0
  61. slidge/db/alembic/versions/8b993243a536_add_vcard_content_to_contact_table.py +43 -0
  62. slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +139 -0
  63. slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +101 -0
  64. slidge/db/alembic/versions/abba1ae0edb3_store_avatar_legacy_id_in_the_contact_.py +79 -0
  65. slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +214 -0
  66. slidge/db/alembic/versions/b64b1a793483_add_source_and_legacy_id_for_archived_.py +52 -0
  67. slidge/db/alembic/versions/c4a8ec35a0e8_per_room_user_nick.py +34 -0
  68. slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +26 -0
  69. slidge/db/avatar.py +205 -0
  70. slidge/db/meta.py +72 -0
  71. slidge/db/models.py +405 -0
  72. slidge/db/store.py +1257 -0
  73. slidge/group/archive.py +58 -14
  74. slidge/group/bookmarks.py +89 -65
  75. slidge/group/participant.py +111 -44
  76. slidge/group/room.py +402 -213
  77. slidge/main.py +202 -0
  78. slidge/migration.py +45 -1
  79. slidge/slixfix/__init__.py +31 -1
  80. slidge/{core/gateway → slixfix}/delivery_receipt.py +1 -1
  81. slidge/slixfix/roster.py +13 -4
  82. slidge/slixfix/xep_0292/vcard4.py +1 -87
  83. slidge/util/archive_msg.py +2 -1
  84. slidge/util/db.py +4 -228
  85. slidge/util/test.py +91 -4
  86. slidge/util/types.py +39 -4
  87. slidge/util/util.py +45 -2
  88. {slidge-0.1.2.dist-info → slidge-0.2.0.dist-info}/METADATA +10 -5
  89. slidge-0.2.0.dist-info/RECORD +131 -0
  90. slidge-0.2.0.dist-info/entry_points.txt +3 -0
  91. slidge/core/cache.py +0 -183
  92. slidge/core/gateway/__init__.py +0 -3
  93. slidge/core/gateway/muc_admin.py +0 -35
  94. slidge/core/gateway/presence.py +0 -95
  95. slidge/core/gateway/registration.py +0 -53
  96. slidge/core/gateway/session_dispatcher.py +0 -795
  97. slidge/util/schema.sql +0 -126
  98. slidge/util/sql.py +0 -508
  99. slidge-0.1.2.dist-info/RECORD +0 -96
  100. slidge-0.1.2.dist-info/entry_points.txt +0 -3
  101. {slidge-0.1.2.dist-info → slidge-0.2.0.dist-info}/LICENSE +0 -0
  102. {slidge-0.1.2.dist-info → slidge-0.2.0.dist-info}/WHEEL +0 -0
@@ -1,23 +1,15 @@
1
1
  import logging
2
2
  import uuid
3
3
  import warnings
4
- from datetime import datetime
5
- from typing import TYPE_CHECKING, Iterable, Optional
4
+ from typing import TYPE_CHECKING, Optional
6
5
 
7
6
  from slixmpp import Iq, Message
8
7
 
9
8
  from ...slixfix.xep_0490.mds import PUBLISH_OPTIONS
10
- from ...util.types import (
11
- ChatState,
12
- LegacyMessageType,
13
- LegacyThreadType,
14
- LinkPreview,
15
- Marker,
16
- MessageReference,
17
- ProcessingHint,
18
- )
9
+ from ...util.types import ChatState, LegacyMessageType, Marker
19
10
  from .attachment import AttachmentMixin
20
11
  from .message_maker import MessageMaker
12
+ from .message_text import TextMessageMixin
21
13
 
22
14
  if TYPE_CHECKING:
23
15
  from ...group import LegacyMUC
@@ -111,7 +103,7 @@ class MarkerMixin(MessageMaker):
111
103
  self.xmpp.delivery_receipt.make_ack(
112
104
  self._legacy_to_xmpp(legacy_msg_id),
113
105
  mfrom=self.jid,
114
- mto=self.user.jid,
106
+ mto=self.user_jid,
115
107
  )
116
108
  )
117
109
  self._send(
@@ -144,7 +136,7 @@ class MarkerMixin(MessageMaker):
144
136
  # We'll see if we need to implement that later
145
137
  return
146
138
  xmpp_msg_id = self._legacy_to_xmpp(legacy_msg_id)
147
- iq = Iq(sto=self.user.bare_jid, sfrom=self.user.bare_jid, stype="set")
139
+ iq = Iq(sto=self.user_jid.bare, sfrom=self.user_jid.bare, stype="set")
148
140
  iq["pubsub"]["publish"]["node"] = self.xmpp["xep_0490"].stanza.NS
149
141
  iq["pubsub"]["publish"]["item"]["id"] = muc_jid
150
142
  displayed = self.xmpp["xep_0490"].stanza.Displayed()
@@ -158,195 +150,19 @@ class MarkerMixin(MessageMaker):
158
150
  self.session.log.debug("Could not MDS mark", exc_info=e)
159
151
 
160
152
 
161
- class ContentMessageMixin(AttachmentMixin):
162
- def __default_hints(self, hints: Optional[Iterable[ProcessingHint]] = None):
163
- if hints is not None:
164
- return hints
165
- elif self.mtype == "chat":
166
- return {"markable", "store"}
167
- elif self.mtype == "groupchat":
168
- return {"markable"}
169
-
170
- def __replace_id(self, legacy_msg_id: LegacyMessageType):
171
- if self.mtype == "groupchat":
172
- return self.session.muc_sent_msg_ids.get(
173
- legacy_msg_id
174
- ) or self._legacy_to_xmpp(legacy_msg_id)
175
- else:
176
- return self._legacy_to_xmpp(legacy_msg_id)
177
-
178
- def send_text(
179
- self,
180
- body: str,
181
- legacy_msg_id: Optional[LegacyMessageType] = None,
182
- *,
183
- when: Optional[datetime] = None,
184
- reply_to: Optional[MessageReference] = None,
185
- thread: Optional[LegacyThreadType] = None,
186
- hints: Optional[Iterable[ProcessingHint]] = None,
187
- carbon=False,
188
- archive_only=False,
189
- correction=False,
190
- correction_event_id: Optional[LegacyMessageType] = None,
191
- link_previews: Optional[list[LinkPreview]] = None,
192
- **send_kwargs,
193
- ):
194
- """
195
- Send a text message from this :term:`XMPP Entity`.
196
-
197
- :param body: Content of the message
198
- :param legacy_msg_id: If you want to be able to transport read markers from the gateway
199
- user to the legacy network, specify this
200
- :param when: when the message was sent, for a "delay" tag (:xep:`0203`)
201
- :param reply_to: Quote another message (:xep:`0461`)
202
- :param hints:
203
- :param thread:
204
- :param carbon: (only used if called on a :class:`LegacyContact`)
205
- Set this to ``True`` if this is actually a message sent **to** the
206
- :class:`LegacyContact` by the :term:`User`.
207
- Use this to synchronize outgoing history for legacy official apps.
208
- :param correction: whether this message is a correction or not
209
- :param correction_event_id: in the case where an ID is associated with the legacy
210
- 'correction event', specify it here to use it on the XMPP side. If not specified,
211
- a random ID will be used.
212
- :param link_previews: A little of sender (or server, or gateway)-generated
213
- previews of URLs linked in the body.
214
- :param archive_only: (only in groups) Do not send this message to user,
215
- but store it in the archive. Meant to be used during ``MUC.backfill()``
216
- """
217
- if carbon:
218
- if not correction and legacy_msg_id in self.session.sent:
219
- log.warning(
220
- "Carbon message for a message an XMPP has sent? This is a bug! %s",
221
- legacy_msg_id,
222
- )
223
- return
224
- self.session.sent[legacy_msg_id] = self.session.legacy_to_xmpp_msg_id(
225
- legacy_msg_id
226
- )
227
- hints = self.__default_hints(hints)
228
- msg = self._make_message(
229
- mbody=body,
230
- legacy_msg_id=correction_event_id if correction else legacy_msg_id,
231
- when=when,
232
- reply_to=reply_to,
233
- hints=hints or (),
234
- carbon=carbon,
235
- thread=thread,
236
- link_previews=link_previews,
237
- )
238
- if correction:
239
- msg["replace"]["id"] = self.__replace_id(legacy_msg_id)
240
- return self._send(msg, archive_only=archive_only, carbon=carbon, **send_kwargs)
241
-
242
- def correct(
243
- self,
244
- legacy_msg_id: LegacyMessageType,
245
- new_text: str,
246
- *,
247
- when: Optional[datetime] = None,
248
- reply_to: Optional[MessageReference] = None,
249
- thread: Optional[LegacyThreadType] = None,
250
- hints: Optional[Iterable[ProcessingHint]] = None,
251
- carbon=False,
252
- archive_only=False,
253
- correction_event_id: Optional[LegacyMessageType] = None,
254
- link_previews: Optional[list[LinkPreview]] = None,
255
- **send_kwargs,
256
- ):
257
- """
258
- Modify a message that was previously sent by this :term:`XMPP Entity`.
259
-
260
- Uses last message correction (:xep:`0308`)
261
-
262
- :param new_text: New content of the message
263
- :param legacy_msg_id: The legacy message ID of the message to correct
264
- :param when: when the message was sent, for a "delay" tag (:xep:`0203`)
265
- :param reply_to: Quote another message (:xep:`0461`)
266
- :param hints:
267
- :param thread:
268
- :param carbon: (only in 1:1) Reflect a message sent to this ``Contact`` by the user.
269
- Use this to synchronize outgoing history for legacy official apps.
270
- :param archive_only: (only in groups) Do not send this message to user,
271
- but store it in the archive. Meant to be used during ``MUC.backfill()``
272
- :param correction_event_id: in the case where an ID is associated with the legacy
273
- 'correction event', specify it here to use it on the XMPP side. If not specified,
274
- a random ID will be used.
275
- :param link_previews: A little of sender (or server, or gateway)-generated
276
- previews of URLs linked in the body.
277
- """
278
- self.send_text(
279
- new_text,
280
- legacy_msg_id,
281
- when=when,
282
- reply_to=reply_to,
283
- hints=hints,
284
- carbon=carbon,
285
- thread=thread,
286
- correction=True,
287
- archive_only=archive_only,
288
- correction_event_id=correction_event_id,
289
- link_previews=link_previews,
290
- **send_kwargs,
291
- )
292
-
293
- def react(
294
- self,
295
- legacy_msg_id: LegacyMessageType,
296
- emojis: Iterable[str] = (),
297
- thread: Optional[LegacyThreadType] = None,
298
- **kwargs,
299
- ):
300
- """
301
- Send a reaction (:xep:`0444`) from this :term:`XMPP Entity`.
302
-
303
- :param legacy_msg_id: The message which the reaction refers to.
304
- :param emojis: An iterable of emojis used as reactions
305
- :param thread:
306
- """
307
- msg = self._make_message(
308
- hints={"store"}, carbon=kwargs.get("carbon"), thread=thread
309
- )
310
- xmpp_id = kwargs.pop("xmpp_id", None)
311
- if not xmpp_id:
312
- xmpp_id = self._legacy_to_xmpp(legacy_msg_id)
313
- self.xmpp["xep_0444"].set_reactions(msg, to_id=xmpp_id, reactions=emojis)
314
- self._send(msg, **kwargs)
315
-
316
- def retract(
317
- self,
318
- legacy_msg_id: LegacyMessageType,
319
- thread: Optional[LegacyThreadType] = None,
320
- **kwargs,
321
- ):
322
- """
323
- Send a message retraction (:XEP:`0424`) from this :term:`XMPP Entity`.
324
-
325
- :param legacy_msg_id: Legacy ID of the message to delete
326
- :param thread:
327
- """
328
- msg = self._make_message(
329
- state=None,
330
- hints={"store"},
331
- mbody=f"/me retracted the message {legacy_msg_id}",
332
- carbon=kwargs.get("carbon"),
333
- thread=thread,
334
- )
335
- msg.enable("fallback")
336
- # namespace version mismatch between slidge and slixmpp, update me later
337
- msg["fallback"]["for"] = self.xmpp["xep_0424"].namespace[:-1] + "1"
338
- msg["retract"]["id"] = msg["replace"]["id"] = self.__replace_id(legacy_msg_id)
339
- self._send(msg, **kwargs)
153
+ class ContentMessageMixin(AttachmentMixin, TextMessageMixin):
154
+ pass
340
155
 
341
156
 
342
157
  class CarbonMessageMixin(ContentMessageMixin, MarkerMixin):
343
158
  def _privileged_send(self, msg: Message):
344
159
  i = msg.get_id()
345
- if not i:
346
- i = str(uuid.uuid4())
160
+ if i:
161
+ self.session.ignore_messages.add(i)
162
+ else:
163
+ i = "slidge-carbon-" + str(uuid.uuid4())
347
164
  msg.set_id(i)
348
165
  msg.del_origin_id()
349
- self.session.ignore_messages.add(i)
350
166
  try:
351
167
  self.xmpp["xep_0356"].send_privileged_message(msg)
352
168
  except PermissionError:
@@ -7,8 +7,8 @@ from uuid import uuid4
7
7
  from slixmpp import Message
8
8
  from slixmpp.types import MessageTypes
9
9
 
10
+ from ...db.models import GatewayUser
10
11
  from ...slixfix.link_preview.stanza import LinkPreview as LinkPreviewStanza
11
- from ...util.db import GatewayUser
12
12
  from ...util.types import (
13
13
  ChatState,
14
14
  LegacyMessageType,
@@ -60,8 +60,9 @@ class MessageMaker(BaseSender):
60
60
  msg["body"] = body
61
61
  state = "active"
62
62
  if thread:
63
- known_threads = self.session.threads.inverse # type:ignore
64
- msg["thread"] = known_threads.get(thread) or str(thread)
63
+ msg["thread"] = self.xmpp.store.sent.get_legacy_thread(
64
+ self.user_pk, str(thread)
65
+ ) or str(thread)
65
66
  if state:
66
67
  msg["chat_state"] = state
67
68
  for hint in hints:
@@ -88,9 +89,9 @@ class MessageMaker(BaseSender):
88
89
  msg["stanza_id"]["by"] = self.muc.jid # type: ignore
89
90
 
90
91
  def _legacy_to_xmpp(self, legacy_id: LegacyMessageType):
91
- return self.session.sent.get(legacy_id) or self.session.legacy_to_xmpp_msg_id(
92
- legacy_id
93
- )
92
+ return self.xmpp.store.sent.get_xmpp_id(
93
+ self.session.user_pk, str(legacy_id)
94
+ ) or self.session.legacy_to_xmpp_msg_id(legacy_id)
94
95
 
95
96
  def _add_delay(self, msg: Message, when: Optional[datetime]):
96
97
  if when:
@@ -110,16 +111,23 @@ class MessageMaker(BaseSender):
110
111
  muc = getattr(self, "muc", None)
111
112
 
112
113
  if entity := reply_to.author:
113
- if isinstance(entity, GatewayUser):
114
+ if entity == "user" or isinstance(entity, GatewayUser):
115
+ if isinstance(entity, GatewayUser):
116
+ warnings.warn(
117
+ "Using a GatewayUser as the author of a "
118
+ "MessageReference is deprecated. Use the string 'user' "
119
+ "instead.",
120
+ DeprecationWarning,
121
+ )
114
122
  if muc:
115
123
  jid = copy(muc.jid)
116
124
  jid.resource = fallback_nick = muc.user_nick
117
125
  msg["reply"]["to"] = jid
118
126
  else:
119
- msg["reply"]["to"] = entity.jid
127
+ msg["reply"]["to"] = self.session.user_jid
120
128
  # TODO: here we should use preferably use the PEP nick of the user
121
129
  # (but it doesn't matter much)
122
- fallback_nick = entity.jid.local
130
+ fallback_nick = self.session.user_jid.local
123
131
  else:
124
132
  if muc:
125
133
  if hasattr(entity, "muc"):
@@ -0,0 +1,211 @@
1
+ import logging
2
+ from datetime import datetime
3
+ from typing import Iterable, Optional
4
+
5
+ from ...util.types import (
6
+ LegacyMessageType,
7
+ LegacyThreadType,
8
+ LinkPreview,
9
+ MessageReference,
10
+ ProcessingHint,
11
+ )
12
+ from .message_maker import MessageMaker
13
+
14
+
15
+ class TextMessageMixin(MessageMaker):
16
+ def __default_hints(self, hints: Optional[Iterable[ProcessingHint]] = None):
17
+ if hints is not None:
18
+ return hints
19
+ elif self.mtype == "chat":
20
+ return {"markable", "store"}
21
+ elif self.mtype == "groupchat":
22
+ return {"markable"}
23
+
24
+ def _replace_id(self, legacy_msg_id: LegacyMessageType):
25
+ if self.mtype == "groupchat":
26
+ return self.xmpp.store.sent.get_group_xmpp_id(
27
+ self.session.user_pk, str(legacy_msg_id)
28
+ ) or self._legacy_to_xmpp(legacy_msg_id)
29
+ else:
30
+ return self._legacy_to_xmpp(legacy_msg_id)
31
+
32
+ def send_text(
33
+ self,
34
+ body: str,
35
+ legacy_msg_id: Optional[LegacyMessageType] = None,
36
+ *,
37
+ when: Optional[datetime] = None,
38
+ reply_to: Optional[MessageReference] = None,
39
+ thread: Optional[LegacyThreadType] = None,
40
+ hints: Optional[Iterable[ProcessingHint]] = None,
41
+ carbon=False,
42
+ archive_only=False,
43
+ correction=False,
44
+ correction_event_id: Optional[LegacyMessageType] = None,
45
+ link_previews: Optional[list[LinkPreview]] = None,
46
+ **send_kwargs,
47
+ ):
48
+ """
49
+ Send a text message from this :term:`XMPP Entity`.
50
+
51
+ :param body: Content of the message
52
+ :param legacy_msg_id: If you want to be able to transport read markers from the gateway
53
+ user to the legacy network, specify this
54
+ :param when: when the message was sent, for a "delay" tag (:xep:`0203`)
55
+ :param reply_to: Quote another message (:xep:`0461`)
56
+ :param hints:
57
+ :param thread:
58
+ :param carbon: (only used if called on a :class:`LegacyContact`)
59
+ Set this to ``True`` if this is actually a message sent **to** the
60
+ :class:`LegacyContact` by the :term:`User`.
61
+ Use this to synchronize outgoing history for legacy official apps.
62
+ :param correction: whether this message is a correction or not
63
+ :param correction_event_id: in the case where an ID is associated with the legacy
64
+ 'correction event', specify it here to use it on the XMPP side. If not specified,
65
+ a random ID will be used.
66
+ :param link_previews: A little of sender (or server, or gateway)-generated
67
+ previews of URLs linked in the body.
68
+ :param archive_only: (only in groups) Do not send this message to user,
69
+ but store it in the archive. Meant to be used during ``MUC.backfill()``
70
+ """
71
+ if carbon and not hasattr(self, "muc"):
72
+ if not correction and self.xmpp.store.sent.was_sent_by_user(
73
+ self.session.user_pk, str(legacy_msg_id)
74
+ ):
75
+ log.warning(
76
+ "Carbon message for a message an XMPP has sent? This is a bug! %s",
77
+ legacy_msg_id,
78
+ )
79
+ return
80
+ if hasattr(self, "muc") and not self.is_user: # type:ignore
81
+ log.warning(
82
+ "send_text() called with carbon=True on a participant who is not the user",
83
+ legacy_msg_id,
84
+ )
85
+ self.xmpp.store.sent.set_message(
86
+ self.session.user_pk,
87
+ str(legacy_msg_id),
88
+ self.session.legacy_to_xmpp_msg_id(legacy_msg_id),
89
+ )
90
+ hints = self.__default_hints(hints)
91
+ msg = self._make_message(
92
+ mbody=body,
93
+ legacy_msg_id=correction_event_id if correction else legacy_msg_id,
94
+ when=when,
95
+ reply_to=reply_to,
96
+ hints=hints or (),
97
+ carbon=carbon,
98
+ thread=thread,
99
+ link_previews=link_previews,
100
+ )
101
+ if correction:
102
+ msg["replace"]["id"] = self._replace_id(legacy_msg_id)
103
+ return self._send(
104
+ msg,
105
+ archive_only=archive_only,
106
+ carbon=carbon,
107
+ legacy_msg_id=legacy_msg_id,
108
+ **send_kwargs,
109
+ )
110
+
111
+ def correct(
112
+ self,
113
+ legacy_msg_id: LegacyMessageType,
114
+ new_text: str,
115
+ *,
116
+ when: Optional[datetime] = None,
117
+ reply_to: Optional[MessageReference] = None,
118
+ thread: Optional[LegacyThreadType] = None,
119
+ hints: Optional[Iterable[ProcessingHint]] = None,
120
+ carbon=False,
121
+ archive_only=False,
122
+ correction_event_id: Optional[LegacyMessageType] = None,
123
+ link_previews: Optional[list[LinkPreview]] = None,
124
+ **send_kwargs,
125
+ ):
126
+ """
127
+ Modify a message that was previously sent by this :term:`XMPP Entity`.
128
+
129
+ Uses last message correction (:xep:`0308`)
130
+
131
+ :param new_text: New content of the message
132
+ :param legacy_msg_id: The legacy message ID of the message to correct
133
+ :param when: when the message was sent, for a "delay" tag (:xep:`0203`)
134
+ :param reply_to: Quote another message (:xep:`0461`)
135
+ :param hints:
136
+ :param thread:
137
+ :param carbon: (only in 1:1) Reflect a message sent to this ``Contact`` by the user.
138
+ Use this to synchronize outgoing history for legacy official apps.
139
+ :param archive_only: (only in groups) Do not send this message to user,
140
+ but store it in the archive. Meant to be used during ``MUC.backfill()``
141
+ :param correction_event_id: in the case where an ID is associated with the legacy
142
+ 'correction event', specify it here to use it on the XMPP side. If not specified,
143
+ a random ID will be used.
144
+ :param link_previews: A little of sender (or server, or gateway)-generated
145
+ previews of URLs linked in the body.
146
+ """
147
+ self.send_text(
148
+ new_text,
149
+ legacy_msg_id,
150
+ when=when,
151
+ reply_to=reply_to,
152
+ hints=hints,
153
+ carbon=carbon,
154
+ thread=thread,
155
+ correction=True,
156
+ archive_only=archive_only,
157
+ correction_event_id=correction_event_id,
158
+ link_previews=link_previews,
159
+ **send_kwargs,
160
+ )
161
+
162
+ def react(
163
+ self,
164
+ legacy_msg_id: LegacyMessageType,
165
+ emojis: Iterable[str] = (),
166
+ thread: Optional[LegacyThreadType] = None,
167
+ **kwargs,
168
+ ):
169
+ """
170
+ Send a reaction (:xep:`0444`) from this :term:`XMPP Entity`.
171
+
172
+ :param legacy_msg_id: The message which the reaction refers to.
173
+ :param emojis: An iterable of emojis used as reactions
174
+ :param thread:
175
+ """
176
+ msg = self._make_message(
177
+ hints={"store"}, carbon=kwargs.get("carbon"), thread=thread
178
+ )
179
+ xmpp_id = kwargs.pop("xmpp_id", None)
180
+ if not xmpp_id:
181
+ xmpp_id = self._legacy_to_xmpp(legacy_msg_id)
182
+ self.xmpp["xep_0444"].set_reactions(msg, to_id=xmpp_id, reactions=emojis)
183
+ self._send(msg, **kwargs)
184
+
185
+ def retract(
186
+ self,
187
+ legacy_msg_id: LegacyMessageType,
188
+ thread: Optional[LegacyThreadType] = None,
189
+ **kwargs,
190
+ ):
191
+ """
192
+ Send a message retraction (:XEP:`0424`) from this :term:`XMPP Entity`.
193
+
194
+ :param legacy_msg_id: Legacy ID of the message to delete
195
+ :param thread:
196
+ """
197
+ msg = self._make_message(
198
+ state=None,
199
+ hints={"store"},
200
+ mbody=f"/me retracted the message {legacy_msg_id}",
201
+ carbon=kwargs.get("carbon"),
202
+ thread=thread,
203
+ )
204
+ msg.enable("fallback")
205
+ # namespace version mismatch between slidge and slixmpp, update me later
206
+ msg["fallback"]["for"] = self.xmpp["xep_0424"].namespace[:-1] + "1"
207
+ msg["retract"]["id"] = msg["replace"]["id"] = self._replace_id(legacy_msg_id)
208
+ self._send(msg, **kwargs)
209
+
210
+
211
+ log = logging.getLogger(__name__)
@@ -5,7 +5,7 @@ from typing import Optional
5
5
 
6
6
  from slixmpp.types import PresenceShows, PresenceTypes
7
7
 
8
- from ...util.sql import CachedPresence, db
8
+ from ...util.types import CachedPresence
9
9
  from .. import config
10
10
  from .base import BaseSender
11
11
 
@@ -19,20 +19,32 @@ _FRIEND_REQUEST_PRESENCES = {"subscribe", "unsubscribe", "subscribed", "unsubscr
19
19
 
20
20
  class PresenceMixin(BaseSender):
21
21
  _ONLY_SEND_PRESENCE_CHANGES = False
22
+ contact_pk: Optional[int] = None
22
23
 
23
24
  def __init__(self, *a, **k):
24
25
  super().__init__(*a, **k)
26
+ # FIXME: this should not be an attribute of this mixin to allow garbage
27
+ # collection of instances
25
28
  self.__update_last_seen_fallback_task: Optional[Task] = None
29
+ # this is only used when a presence is set during Contact.update_info(),
30
+ # when the contact does not have a DB primary key yet, and is written
31
+ # to DB at the end of update_info()
32
+ self.cached_presence: Optional[CachedPresence] = None
26
33
 
27
34
  async def __update_last_seen_fallback(self):
28
35
  await sleep(3600 * 7)
29
36
  self.send_last_presence(force=True, no_cache_online=False)
30
37
 
31
38
  def _get_last_presence(self) -> Optional[CachedPresence]:
32
- return db.presence_get(self.jid, self.user)
39
+ if self.contact_pk is None:
40
+ return None
41
+ return self.xmpp.store.contacts.get_presence(self.contact_pk)
33
42
 
34
43
  def _store_last_presence(self, new: CachedPresence):
35
- return db.presence_store(self.jid, new, self.user)
44
+ if self.contact_pk is None:
45
+ self.cached_presence = new
46
+ return
47
+ self.xmpp.store.contacts.set_presence(self.contact_pk, new)
36
48
 
37
49
  def _make_presence(
38
50
  self,
@@ -55,7 +67,8 @@ class PresenceMixin(BaseSender):
55
67
  )
56
68
  if old != new:
57
69
  if hasattr(self, "muc") and ptype == "unavailable":
58
- db.presence_delete(self.jid, self.user)
70
+ if self.contact_pk is not None:
71
+ self.xmpp.store.contacts.reset_presence(self.contact_pk)
59
72
  else:
60
73
  self._store_last_presence(new)
61
74
  if old and not force and self._ONLY_SEND_PRESENCE_CHANGES: