slidge 0.2.12__py3-none-any.whl → 0.3.0a0__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/__init__.py +5 -2
- slidge/command/adhoc.py +9 -3
- slidge/command/admin.py +16 -12
- slidge/command/base.py +16 -12
- slidge/command/chat_command.py +25 -16
- slidge/command/user.py +7 -8
- slidge/contact/contact.py +119 -209
- slidge/contact/roster.py +106 -105
- slidge/core/config.py +2 -43
- slidge/core/dispatcher/caps.py +9 -2
- slidge/core/dispatcher/disco.py +13 -3
- slidge/core/dispatcher/message/__init__.py +1 -1
- slidge/core/dispatcher/message/chat_state.py +17 -8
- slidge/core/dispatcher/message/marker.py +7 -5
- slidge/core/dispatcher/message/message.py +117 -92
- slidge/core/dispatcher/muc/__init__.py +1 -1
- slidge/core/dispatcher/muc/admin.py +4 -4
- slidge/core/dispatcher/muc/mam.py +10 -6
- slidge/core/dispatcher/muc/misc.py +4 -2
- slidge/core/dispatcher/muc/owner.py +5 -3
- slidge/core/dispatcher/muc/ping.py +3 -1
- slidge/core/dispatcher/presence.py +21 -15
- slidge/core/dispatcher/registration.py +20 -12
- slidge/core/dispatcher/search.py +7 -3
- slidge/core/dispatcher/session_dispatcher.py +13 -5
- slidge/core/dispatcher/util.py +37 -27
- slidge/core/dispatcher/vcard.py +7 -4
- slidge/core/gateway.py +168 -84
- slidge/core/mixins/__init__.py +1 -11
- slidge/core/mixins/attachment.py +163 -148
- slidge/core/mixins/avatar.py +100 -177
- slidge/core/mixins/db.py +50 -2
- slidge/core/mixins/message.py +19 -17
- slidge/core/mixins/message_maker.py +29 -15
- slidge/core/mixins/message_text.py +38 -30
- slidge/core/mixins/presence.py +91 -35
- slidge/core/pubsub.py +42 -47
- slidge/core/session.py +88 -57
- slidge/db/alembic/versions/0337c90c0b96_unify_legacy_xmpp_id_mappings.py +183 -0
- slidge/db/alembic/versions/4dbd23a3f868_new_avatar_store.py +56 -0
- slidge/db/alembic/versions/54ce3cde350c_use_hash_for_avatar_filenames.py +50 -0
- slidge/db/alembic/versions/58b98dacf819_refactor.py +118 -0
- slidge/db/alembic/versions/75a62b74b239_ditch_hats_table.py +74 -0
- slidge/db/avatar.py +150 -119
- slidge/db/meta.py +33 -22
- slidge/db/models.py +68 -117
- slidge/db/store.py +412 -1094
- slidge/group/archive.py +61 -54
- slidge/group/bookmarks.py +74 -55
- slidge/group/participant.py +135 -142
- slidge/group/room.py +315 -312
- slidge/main.py +28 -18
- slidge/migration.py +2 -12
- slidge/slixfix/__init__.py +20 -4
- slidge/slixfix/delivery_receipt.py +6 -4
- slidge/slixfix/link_preview/link_preview.py +1 -1
- slidge/slixfix/link_preview/stanza.py +1 -1
- slidge/slixfix/roster.py +5 -7
- slidge/slixfix/xep_0077/register.py +8 -8
- slidge/slixfix/xep_0077/stanza.py +7 -7
- slidge/slixfix/xep_0100/gateway.py +12 -13
- slidge/slixfix/xep_0153/vcard_avatar.py +1 -1
- slidge/slixfix/xep_0292/vcard4.py +1 -1
- slidge/util/archive_msg.py +11 -5
- slidge/util/conf.py +23 -20
- slidge/util/jid_escaping.py +1 -1
- slidge/{core/mixins → util}/lock.py +6 -6
- slidge/util/test.py +30 -29
- slidge/util/types.py +22 -18
- slidge/util/util.py +19 -22
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/METADATA +1 -1
- slidge-0.3.0a0.dist-info/RECORD +117 -0
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/WHEEL +1 -1
- slidge-0.2.12.dist-info/RECORD +0 -112
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/entry_points.txt +0 -0
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/licenses/LICENSE +0 -0
- {slidge-0.2.12.dist-info → slidge-0.3.0a0.dist-info}/top_level.txt +0 -0
slidge/core/mixins/attachment.py
CHANGED
@@ -11,7 +11,7 @@ from datetime import datetime
|
|
11
11
|
from itertools import chain
|
12
12
|
from mimetypes import guess_extension, guess_type
|
13
13
|
from pathlib import Path
|
14
|
-
from typing import
|
14
|
+
from typing import Collection, Optional, Sequence, Union
|
15
15
|
from urllib.parse import quote as urlquote
|
16
16
|
from uuid import uuid4
|
17
17
|
from xml.etree import ElementTree as ET
|
@@ -25,6 +25,7 @@ from slixmpp.plugins.xep_0363 import FileUploadError
|
|
25
25
|
from slixmpp.plugins.xep_0447.stanza import StatelessFileSharing
|
26
26
|
|
27
27
|
from ...db.avatar import avatar_cache
|
28
|
+
from ...db.models import Attachment
|
28
29
|
from ...util.types import (
|
29
30
|
LegacyAttachment,
|
30
31
|
LegacyMessageType,
|
@@ -37,9 +38,7 @@ from .message_text import TextMessageMixin
|
|
37
38
|
|
38
39
|
|
39
40
|
class AttachmentMixin(TextMessageMixin):
|
40
|
-
|
41
|
-
super().__init__(*a, **kw)
|
42
|
-
self.__store = self.xmpp.store.attachments
|
41
|
+
is_group: bool
|
43
42
|
|
44
43
|
async def __upload(
|
45
44
|
self,
|
@@ -137,28 +136,41 @@ class AttachmentMixin(TextMessageMixin):
|
|
137
136
|
|
138
137
|
return destination, uploaded_url
|
139
138
|
|
139
|
+
async def __valid_url(self, url: str) -> bool:
|
140
|
+
async with self.session.http.head(url) as r:
|
141
|
+
return r.status < 400
|
142
|
+
|
143
|
+
async def __get_stored(self, attachment: LegacyAttachment) -> Attachment:
|
144
|
+
if attachment.legacy_file_id is not None:
|
145
|
+
with self.xmpp.store.session() as orm:
|
146
|
+
stored = (
|
147
|
+
orm.query(Attachment)
|
148
|
+
.filter_by(legacy_file_id=str(attachment.legacy_file_id))
|
149
|
+
.one_or_none()
|
150
|
+
)
|
151
|
+
if stored is not None:
|
152
|
+
if not await self.__valid_url(stored.url):
|
153
|
+
stored.url = None # type:ignore
|
154
|
+
return stored
|
155
|
+
return Attachment(
|
156
|
+
user_account_id=None
|
157
|
+
if self.session is NotImplemented
|
158
|
+
else self.session.user_pk,
|
159
|
+
legacy_file_id=None
|
160
|
+
if attachment.legacy_file_id is None
|
161
|
+
else str(attachment.legacy_file_id),
|
162
|
+
url=attachment.url,
|
163
|
+
)
|
164
|
+
|
140
165
|
async def __get_url(
|
141
|
-
self,
|
142
|
-
file_path: Optional[Path] = None,
|
143
|
-
async_data_stream: Optional[AsyncIterator[bytes]] = None,
|
144
|
-
data_stream: Optional[IO[bytes]] = None,
|
145
|
-
data: Optional[bytes] = None,
|
146
|
-
file_url: Optional[str] = None,
|
147
|
-
file_name: Optional[str] = None,
|
148
|
-
content_type: Optional[str] = None,
|
149
|
-
legacy_file_id: Optional[Union[str, int]] = None,
|
166
|
+
self, attachment: LegacyAttachment, stored: Attachment
|
150
167
|
) -> tuple[bool, Optional[Path], str]:
|
151
|
-
if
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
else:
|
158
|
-
self.__store.remove(str(legacy_file_id))
|
159
|
-
|
160
|
-
if file_url and config.USE_ATTACHMENT_ORIGINAL_URLS:
|
161
|
-
return False, None, file_url
|
168
|
+
if attachment.url and config.USE_ATTACHMENT_ORIGINAL_URLS:
|
169
|
+
return False, None, attachment.url
|
170
|
+
|
171
|
+
file_name = attachment.name
|
172
|
+
content_type = attachment.content_type
|
173
|
+
file_path = attachment.path
|
162
174
|
|
163
175
|
if file_name and len(file_name) > config.ATTACHMENT_MAXIMUM_FILE_NAME_LENGTH:
|
164
176
|
log.debug("Trimming long filename: %s", file_name)
|
@@ -176,47 +188,48 @@ class AttachmentMixin(TextMessageMixin):
|
|
176
188
|
file_name += ext
|
177
189
|
temp_dir = Path(tempfile.mkdtemp())
|
178
190
|
file_path = temp_dir / file_name
|
179
|
-
if
|
180
|
-
async with self.session.http.get(
|
191
|
+
if attachment.url:
|
192
|
+
async with self.session.http.get(attachment.url) as r:
|
181
193
|
r.raise_for_status()
|
182
194
|
with file_path.open("wb") as f:
|
183
195
|
f.write(await r.read())
|
184
196
|
|
185
|
-
elif
|
186
|
-
data =
|
197
|
+
elif attachment.stream is not None:
|
198
|
+
data = attachment.stream.read()
|
187
199
|
if data is None:
|
188
200
|
raise RuntimeError
|
189
201
|
|
190
202
|
with file_path.open("wb") as f:
|
191
203
|
f.write(data)
|
192
|
-
elif
|
204
|
+
elif attachment.aio_stream is not None:
|
193
205
|
# TODO: patch slixmpp to allow this as data source for
|
194
206
|
# upload_file() so we don't even have to write anything
|
195
207
|
# to disk.
|
196
208
|
with file_path.open("wb") as f:
|
197
|
-
async for chunk in
|
209
|
+
async for chunk in attachment.aio_stream:
|
198
210
|
f.write(chunk)
|
199
|
-
elif data is not None:
|
211
|
+
elif attachment.data is not None:
|
200
212
|
with file_path.open("wb") as f:
|
201
|
-
f.write(data)
|
213
|
+
f.write(attachment.data)
|
202
214
|
|
203
215
|
is_temp = not bool(config.NO_UPLOAD_PATH)
|
204
216
|
else:
|
205
217
|
is_temp = False
|
206
218
|
|
219
|
+
assert isinstance(file_path, Path)
|
207
220
|
if config.FIX_FILENAME_SUFFIX_MIME_TYPE:
|
208
221
|
file_name = str(fix_suffix(file_path, content_type, file_name))
|
209
222
|
|
210
223
|
if config.NO_UPLOAD_PATH:
|
211
224
|
local_path, new_url = await self.__no_upload(
|
212
|
-
file_path, file_name, legacy_file_id
|
225
|
+
file_path, file_name, stored.legacy_file_id
|
213
226
|
)
|
214
227
|
new_url = (config.NO_UPLOAD_URL_PREFIX or "") + "/" + urlquote(new_url)
|
215
228
|
else:
|
216
229
|
local_path = file_path
|
217
230
|
new_url = await self.__upload(file_path, file_name, content_type)
|
218
|
-
if legacy_file_id and new_url is not None:
|
219
|
-
|
231
|
+
if stored.legacy_file_id and new_url is not None:
|
232
|
+
stored.url = new_url
|
220
233
|
|
221
234
|
return is_temp, local_path, new_url
|
222
235
|
|
@@ -225,13 +238,11 @@ class AttachmentMixin(TextMessageMixin):
|
|
225
238
|
msg: Message,
|
226
239
|
uploaded_url: str,
|
227
240
|
path: Optional[Path],
|
228
|
-
|
229
|
-
|
230
|
-
file_name: Optional[str] = None,
|
241
|
+
attachment: LegacyAttachment,
|
242
|
+
stored: Attachment,
|
231
243
|
) -> Thumbnail | None:
|
232
|
-
|
233
|
-
|
234
|
-
ref = self.xmpp["xep_0372"].stanza.Reference(xml=ET.fromstring(cache))
|
244
|
+
if stored.sims is not None:
|
245
|
+
ref = self.xmpp["xep_0372"].stanza.Reference(xml=ET.fromstring(stored.sims))
|
235
246
|
msg.append(ref)
|
236
247
|
if ref["sims"]["file"].get_plugin("thumbnail", check=True):
|
237
248
|
return ref["sims"]["file"]["thumbnail"]
|
@@ -242,12 +253,14 @@ class AttachmentMixin(TextMessageMixin):
|
|
242
253
|
return None
|
243
254
|
|
244
255
|
ref = self.xmpp["xep_0385"].get_sims(
|
245
|
-
path, [uploaded_url], content_type, caption
|
256
|
+
path, [uploaded_url], attachment.content_type, attachment.caption
|
246
257
|
)
|
247
|
-
if
|
248
|
-
ref["sims"]["file"]["name"] =
|
258
|
+
if attachment.name:
|
259
|
+
ref["sims"]["file"]["name"] = attachment.name
|
249
260
|
thumbnail = None
|
250
|
-
if content_type is not None and content_type.startswith(
|
261
|
+
if attachment.content_type is not None and attachment.content_type.startswith(
|
262
|
+
"image"
|
263
|
+
):
|
251
264
|
try:
|
252
265
|
h, x, y = await self.xmpp.loop.run_in_executor(
|
253
266
|
avatar_cache._thread_pool, get_thumbhash, path
|
@@ -261,8 +274,7 @@ class AttachmentMixin(TextMessageMixin):
|
|
261
274
|
thumbnail["media-type"] = "image/thumbhash"
|
262
275
|
thumbnail["uri"] = "data:image/thumbhash;base64," + urlquote(h)
|
263
276
|
|
264
|
-
|
265
|
-
|
277
|
+
stored.sims = str(ref)
|
266
278
|
msg.append(ref)
|
267
279
|
|
268
280
|
return thumbnail
|
@@ -272,26 +284,25 @@ class AttachmentMixin(TextMessageMixin):
|
|
272
284
|
msg: Message,
|
273
285
|
uploaded_url: str,
|
274
286
|
path: Optional[Path],
|
275
|
-
|
276
|
-
|
277
|
-
file_name: Optional[str] = None,
|
287
|
+
attachment: LegacyAttachment,
|
288
|
+
stored: Attachment,
|
278
289
|
thumbnail: Optional[Thumbnail] = None,
|
279
|
-
):
|
280
|
-
|
281
|
-
|
282
|
-
msg.append(StatelessFileSharing(xml=ET.fromstring(cache)))
|
290
|
+
) -> None:
|
291
|
+
if stored.sfs is not None:
|
292
|
+
msg.append(StatelessFileSharing(xml=ET.fromstring(stored.sfs)))
|
283
293
|
return
|
284
294
|
|
285
295
|
if not path:
|
286
296
|
return
|
287
297
|
|
288
|
-
sfs = self.xmpp["xep_0447"].get_sfs(
|
289
|
-
|
290
|
-
|
298
|
+
sfs = self.xmpp["xep_0447"].get_sfs(
|
299
|
+
path, [uploaded_url], attachment.content_type, attachment.caption
|
300
|
+
)
|
301
|
+
if attachment.name:
|
302
|
+
sfs["file"]["name"] = attachment.name
|
291
303
|
if thumbnail is not None:
|
292
304
|
sfs["file"].append(thumbnail)
|
293
|
-
|
294
|
-
|
305
|
+
stored.sfs = str(sfs)
|
295
306
|
msg.append(sfs)
|
296
307
|
|
297
308
|
def __send_url(
|
@@ -300,9 +311,9 @@ class AttachmentMixin(TextMessageMixin):
|
|
300
311
|
legacy_msg_id: LegacyMessageType,
|
301
312
|
uploaded_url: str,
|
302
313
|
caption: Optional[str] = None,
|
303
|
-
carbon=False,
|
314
|
+
carbon: bool = False,
|
304
315
|
when: Optional[datetime] = None,
|
305
|
-
correction=False,
|
316
|
+
correction: bool = False,
|
306
317
|
**kwargs,
|
307
318
|
) -> list[Message]:
|
308
319
|
msg["oob"]["url"] = uploaded_url
|
@@ -325,51 +336,21 @@ class AttachmentMixin(TextMessageMixin):
|
|
325
336
|
self._set_msg_id(msg, legacy_msg_id)
|
326
337
|
return [self._send(msg, carbon=carbon, **kwargs)]
|
327
338
|
|
328
|
-
|
339
|
+
def __get_base_message(
|
329
340
|
self,
|
330
|
-
file_path: Optional[Union[Path, str]] = None,
|
331
341
|
legacy_msg_id: Optional[LegacyMessageType] = None,
|
332
|
-
*,
|
333
|
-
async_data_stream: Optional[AsyncIterator[bytes]] = None,
|
334
|
-
data_stream: Optional[IO[bytes]] = None,
|
335
|
-
data: Optional[bytes] = None,
|
336
|
-
file_url: Optional[str] = None,
|
337
|
-
file_name: Optional[str] = None,
|
338
|
-
content_type: Optional[str] = None,
|
339
342
|
reply_to: Optional[MessageReference] = None,
|
340
343
|
when: Optional[datetime] = None,
|
341
|
-
caption: Optional[str] = None,
|
342
|
-
legacy_file_id: Optional[Union[str, int]] = None,
|
343
344
|
thread: Optional[LegacyThreadType] = None,
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
:param file_path: Path to the attachment
|
350
|
-
:param async_data_stream: Alternatively (and ideally) an AsyncIterator yielding bytes
|
351
|
-
:param data_stream: Alternatively, a stream of bytes (such as a File object)
|
352
|
-
:param data: Alternatively, a bytes object
|
353
|
-
:param file_url: Alternatively, a URL
|
354
|
-
:param file_name: How the file should be named.
|
355
|
-
:param content_type: MIME type, inferred from filename if not given
|
356
|
-
:param legacy_msg_id: If you want to be able to transport read markers from the gateway
|
357
|
-
user to the legacy network, specify this
|
358
|
-
:param reply_to: Quote another message (:xep:`0461`)
|
359
|
-
:param when: when the file was sent, for a "delay" tag (:xep:`0203`)
|
360
|
-
:param caption: an optional text that is linked to the file
|
361
|
-
:param legacy_file_id: A unique identifier for the file on the legacy network.
|
362
|
-
Plugins should try their best to provide it, to avoid duplicates.
|
363
|
-
:param thread:
|
364
|
-
"""
|
365
|
-
carbon = kwargs.pop("carbon", False)
|
366
|
-
mto = kwargs.pop("mto", None)
|
367
|
-
store_multi = kwargs.pop("store_multi", True)
|
368
|
-
correction = kwargs.get("correction", False)
|
345
|
+
carbon: bool = False,
|
346
|
+
correction: bool = False,
|
347
|
+
mto: Optional[JID] = None,
|
348
|
+
) -> Message:
|
369
349
|
if correction and (original_xmpp_id := self._legacy_to_xmpp(legacy_msg_id)):
|
370
|
-
|
371
|
-
self.
|
372
|
-
|
350
|
+
with self.xmpp.store.session() as orm:
|
351
|
+
xmpp_ids = self.xmpp.store.id_map.get_xmpp(
|
352
|
+
orm, self._recipient_pk(), str(legacy_msg_id), self.is_group
|
353
|
+
)
|
373
354
|
|
374
355
|
for xmpp_id in xmpp_ids:
|
375
356
|
if xmpp_id == original_xmpp_id:
|
@@ -386,7 +367,7 @@ class AttachmentMixin(TextMessageMixin):
|
|
386
367
|
else:
|
387
368
|
reply_to_for_attachment = reply_to
|
388
369
|
|
389
|
-
|
370
|
+
return self._make_message(
|
390
371
|
when=when,
|
391
372
|
reply_to=reply_to_for_attachment,
|
392
373
|
carbon=carbon,
|
@@ -394,43 +375,85 @@ class AttachmentMixin(TextMessageMixin):
|
|
394
375
|
thread=thread,
|
395
376
|
)
|
396
377
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
)
|
378
|
+
async def send_file(
|
379
|
+
self,
|
380
|
+
attachment: LegacyAttachment | Path | str,
|
381
|
+
legacy_msg_id: Optional[LegacyMessageType] = None,
|
382
|
+
*,
|
383
|
+
reply_to: Optional[MessageReference] = None,
|
384
|
+
when: Optional[datetime] = None,
|
385
|
+
thread: Optional[LegacyThreadType] = None,
|
386
|
+
**kwargs,
|
387
|
+
) -> tuple[Optional[str], list[Message]]:
|
388
|
+
"""
|
389
|
+
Send a single file from this :term:`XMPP Entity`.
|
410
390
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
391
|
+
:param attachment: The file to send.
|
392
|
+
Ideally, a :class:`.LegacyAttachment` with a unique ``legacy_file_id``
|
393
|
+
attribute set, to optimise potential future reuses.
|
394
|
+
It can also be:
|
395
|
+
- a :class:`pathlib.Path` instance to point to a local file, or
|
396
|
+
- a ``str``, representing a fetchable HTTP URL.
|
397
|
+
:param legacy_msg_id: If you want to be able to transport read markers from the gateway
|
398
|
+
user to the legacy network, specify this
|
399
|
+
:param reply_to: Quote another message (:xep:`0461`)
|
400
|
+
:param when: when the file was sent, for a "delay" tag (:xep:`0203`)
|
401
|
+
:param thread:
|
402
|
+
"""
|
403
|
+
store_multi = kwargs.pop("store_multi", True)
|
404
|
+
carbon = kwargs.pop("carbon", False)
|
405
|
+
mto = kwargs.pop("mto", None)
|
406
|
+
correction = kwargs.get("correction", False)
|
418
407
|
|
419
|
-
|
420
|
-
|
421
|
-
)
|
422
|
-
self.__set_sfs(
|
423
|
-
msg, new_url, local_path, content_type, caption, file_name, thumbnail
|
408
|
+
msg = self.__get_base_message(
|
409
|
+
legacy_msg_id, reply_to, when, thread, carbon, correction, mto
|
424
410
|
)
|
411
|
+
|
412
|
+
if isinstance(attachment, str):
|
413
|
+
attachment = LegacyAttachment(url=attachment)
|
414
|
+
elif isinstance(attachment, Path):
|
415
|
+
attachment = LegacyAttachment(path=attachment)
|
416
|
+
|
417
|
+
stored = await self.__get_stored(attachment)
|
418
|
+
|
419
|
+
if attachment.content_type is None and (
|
420
|
+
name := (attachment.name or attachment.url or attachment.path)
|
421
|
+
):
|
422
|
+
attachment.content_type, _ = guess_type(name)
|
423
|
+
|
424
|
+
if stored.url:
|
425
|
+
is_temp = False
|
426
|
+
local_path = None
|
427
|
+
new_url = stored.url
|
428
|
+
else:
|
429
|
+
is_temp, local_path, new_url = await self.__get_url(attachment, stored)
|
430
|
+
if new_url is None:
|
431
|
+
msg["body"] = (
|
432
|
+
"I tried to send a file, but something went wrong. "
|
433
|
+
"Tell your slidge admin to check the logs."
|
434
|
+
)
|
435
|
+
self._set_msg_id(msg, legacy_msg_id)
|
436
|
+
return None, [self._send(msg, **kwargs)]
|
437
|
+
|
438
|
+
stored.url = new_url
|
439
|
+
thumbnail = await self.__set_sims(msg, new_url, local_path, attachment, stored)
|
440
|
+
self.__set_sfs(msg, new_url, local_path, attachment, stored, thumbnail)
|
441
|
+
|
442
|
+
if self.session is not NotImplemented:
|
443
|
+
with self.xmpp.store.session(expire_on_commit=False) as orm:
|
444
|
+
orm.add(stored)
|
445
|
+
orm.commit()
|
446
|
+
|
425
447
|
if is_temp and isinstance(local_path, Path):
|
426
448
|
local_path.unlink()
|
427
449
|
local_path.parent.rmdir()
|
428
450
|
|
429
451
|
msgs = self.__send_url(
|
430
|
-
msg, legacy_msg_id, new_url, caption, carbon, when, **kwargs
|
452
|
+
msg, legacy_msg_id, new_url, attachment.caption, carbon, when, **kwargs
|
431
453
|
)
|
432
|
-
if
|
433
|
-
|
454
|
+
if self.session is not NotImplemented:
|
455
|
+
if store_multi:
|
456
|
+
self.__store_multi(legacy_msg_id, msgs)
|
434
457
|
return new_url, msgs
|
435
458
|
|
436
459
|
def __send_body(
|
@@ -463,18 +486,15 @@ class AttachmentMixin(TextMessageMixin):
|
|
463
486
|
reply_to: Optional[MessageReference] = None,
|
464
487
|
when: Optional[datetime] = None,
|
465
488
|
thread: Optional[LegacyThreadType] = None,
|
466
|
-
body_first=False,
|
467
|
-
correction=False,
|
489
|
+
body_first: bool = False,
|
490
|
+
correction: bool = False,
|
468
491
|
correction_event_id: Optional[LegacyMessageType] = None,
|
469
492
|
**kwargs,
|
470
|
-
):
|
493
|
+
) -> None:
|
471
494
|
# TODO: once the epic XEP-0385 vs XEP-0447 battle is over, pick
|
472
495
|
# one and stop sending several attachments this way
|
473
496
|
# we attach the legacy_message ID to the last message we send, because
|
474
497
|
# we don't want several messages with the same ID (especially for MUC MAM)
|
475
|
-
# TODO: refactor this so we limit the number of SQL calls, ie, if
|
476
|
-
# the legacy file ID is known, only fetch the row once, and if it
|
477
|
-
# is new, write it all in a single call
|
478
498
|
if not attachments and not body:
|
479
499
|
# ignoring empty message
|
480
500
|
return
|
@@ -500,18 +520,11 @@ class AttachmentMixin(TextMessageMixin):
|
|
500
520
|
else:
|
501
521
|
legacy = None
|
502
522
|
_url, msgs = await self.send_file(
|
503
|
-
|
504
|
-
|
505
|
-
file_url=attachment.url,
|
506
|
-
data_stream=attachment.stream,
|
507
|
-
data=attachment.data,
|
523
|
+
attachment,
|
524
|
+
legacy,
|
508
525
|
reply_to=reply_to,
|
509
526
|
when=when,
|
510
527
|
thread=thread,
|
511
|
-
file_name=attachment.name,
|
512
|
-
content_type=attachment.content_type,
|
513
|
-
legacy_file_id=attachment.legacy_file_id,
|
514
|
-
caption=attachment.caption,
|
515
528
|
store_multi=False,
|
516
529
|
**kwargs,
|
517
530
|
)
|
@@ -524,7 +537,7 @@ class AttachmentMixin(TextMessageMixin):
|
|
524
537
|
self,
|
525
538
|
legacy_msg_id: Optional[LegacyMessageType],
|
526
539
|
all_msgs: Sequence[Optional[Message]],
|
527
|
-
):
|
540
|
+
) -> None:
|
528
541
|
if legacy_msg_id is None:
|
529
542
|
return
|
530
543
|
ids = []
|
@@ -535,9 +548,11 @@ class AttachmentMixin(TextMessageMixin):
|
|
535
548
|
ids.append(stanza_id["id"])
|
536
549
|
else:
|
537
550
|
ids.append(msg.get_id())
|
538
|
-
self.xmpp.store.
|
539
|
-
self.
|
540
|
-
|
551
|
+
with self.xmpp.store.session() as orm:
|
552
|
+
self.xmpp.store.id_map.set_msg(
|
553
|
+
orm, self._recipient_pk(), str(legacy_msg_id), ids, self.is_group
|
554
|
+
)
|
555
|
+
orm.commit()
|
541
556
|
|
542
557
|
|
543
558
|
def get_thumbhash(path: Path) -> tuple[str, int, int]:
|