Fix Signal messages and replies

This commit is contained in:
2026-03-03 15:51:58 +00:00
parent 56c620473f
commit d6bd56dace
31 changed files with 3317 additions and 668 deletions

View File

@@ -1,5 +1,6 @@
import asyncio
import base64
import logging
import aiohttp
import orjson
@@ -7,6 +8,8 @@ import requests
from django.conf import settings
from rest_framework import status
log = logging.getLogger(__name__)
async def start_typing(uuid):
base = getattr(settings, "SIGNAL_HTTP_URL", "http://signal:8080").rstrip("/")
@@ -70,7 +73,7 @@ async def download_and_encode_base64(file_url, filename, content_type, session=N
return None
async def send_message_raw(recipient_uuid, text=None, attachments=None):
async def send_message_raw(recipient_uuid, text=None, attachments=None, metadata=None):
"""
Sends a message using the Signal REST API, ensuring attachment links are not included in the text body.
@@ -90,6 +93,7 @@ async def send_message_raw(recipient_uuid, text=None, attachments=None):
"number": settings.SIGNAL_NUMBER,
"base64_attachments": [],
}
meta = dict(metadata or {})
async def _attachment_to_base64(attachment, session):
row = dict(attachment or {})
@@ -132,15 +136,47 @@ async def send_message_raw(recipient_uuid, text=None, attachments=None):
if text:
data["message"] = text
async with aiohttp.ClientSession() as session:
async with session.post(url, json=data) as response:
response_text = await response.text()
response_status = response.status
quote_timestamp = int(meta.get("quote_timestamp") or 0)
quote_author = str(meta.get("quote_author") or "").strip()
quote_text = str(meta.get("quote_text") or "").strip()
has_quote = quote_timestamp > 0 and bool(quote_author)
if response_status == status.HTTP_201_CREATED:
ts = orjson.loads(response_text).get("timestamp", None)
return ts if ts else False
return False
payloads = [dict(data)]
if has_quote:
flat_quote_payload = dict(data)
flat_quote_payload["quote_timestamp"] = int(quote_timestamp)
flat_quote_payload["quote_author"] = quote_author
if quote_text:
flat_quote_payload["quote_message"] = quote_text
nested_quote_payload = dict(data)
nested_quote_payload["quote"] = {
"id": int(quote_timestamp),
"author": quote_author,
}
if quote_text:
nested_quote_payload["quote"]["text"] = quote_text
payloads = [flat_quote_payload, nested_quote_payload, dict(data)]
async with aiohttp.ClientSession() as session:
for index, payload in enumerate(payloads):
async with session.post(url, json=payload) as response:
response_text = await response.text()
response_status = response.status
if response_status == status.HTTP_201_CREATED:
ts = orjson.loads(response_text).get("timestamp", None)
return ts if ts else False
if index == len(payloads) - 1:
return False
if response_status not in {status.HTTP_400_BAD_REQUEST, status.HTTP_422_UNPROCESSABLE_ENTITY}:
return False
log.warning(
"signal send quote payload rejected (%s), trying fallback shape: %s",
response_status,
response_text[:200],
)
return False
async def send_reaction(