Fix Signal messages and replies
This commit is contained in:
223
core/tests/test_signal_reply_send.py
Normal file
223
core/tests/test_signal_reply_send.py
Normal file
@@ -0,0 +1,223 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from unittest.mock import AsyncMock, patch
|
||||
from unittest.mock import Mock
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from django.conf import settings
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
|
||||
from core.clients import transport
|
||||
from core.clients.signal import SignalClient
|
||||
from core.models import ChatSession, Message, Person, PersonIdentifier, User
|
||||
from core.views.compose import _build_signal_reply_metadata
|
||||
|
||||
|
||||
class SignalReplyMetadataTests(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
username="signal-reply-meta-user",
|
||||
email="signal-reply-meta@example.com",
|
||||
password="x",
|
||||
)
|
||||
self.person = Person.objects.create(user=self.user, name="Signal Reply")
|
||||
self.identifier = PersonIdentifier.objects.create(
|
||||
user=self.user,
|
||||
person=self.person,
|
||||
service="signal",
|
||||
identifier="+15550001000",
|
||||
)
|
||||
self.session = ChatSession.objects.create(
|
||||
user=self.user,
|
||||
identifier=self.identifier,
|
||||
)
|
||||
|
||||
def test_build_signal_reply_metadata_uses_signal_source(self):
|
||||
incoming = Message.objects.create(
|
||||
user=self.user,
|
||||
session=self.session,
|
||||
sender_uuid="+15550001000",
|
||||
text="quoted body",
|
||||
ts=1772538353497,
|
||||
source_service="signal",
|
||||
source_message_id="1772538353497",
|
||||
source_chat_id="+15550001000",
|
||||
)
|
||||
payload = _build_signal_reply_metadata(incoming, "+15550001000")
|
||||
self.assertEqual(1772538353497, payload.get("quote_timestamp"))
|
||||
self.assertEqual("+15550001000", payload.get("quote_author"))
|
||||
self.assertEqual("quoted body", payload.get("quote_text"))
|
||||
|
||||
def test_build_signal_reply_metadata_uses_chat_number_when_sender_is_uuid(self):
|
||||
incoming = Message.objects.create(
|
||||
user=self.user,
|
||||
session=self.session,
|
||||
sender_uuid="756078fd-d447-426d-a620-581a86d64f51",
|
||||
text="quoted body",
|
||||
ts=1772538353497,
|
||||
source_service="signal",
|
||||
source_message_id="1772538353497",
|
||||
source_chat_id="+15550001000",
|
||||
)
|
||||
payload = _build_signal_reply_metadata(incoming, "+15550001000")
|
||||
self.assertEqual("+15550001000", payload.get("quote_author"))
|
||||
|
||||
def test_build_signal_reply_metadata_uses_local_sender_for_own_messages(self):
|
||||
outgoing = Message.objects.create(
|
||||
user=self.user,
|
||||
session=self.session,
|
||||
sender_uuid="",
|
||||
custom_author="USER",
|
||||
text="my previous message",
|
||||
ts=1772538353900,
|
||||
source_service="web",
|
||||
source_message_id="1772538353900",
|
||||
source_chat_id="+15550001000",
|
||||
)
|
||||
payload = _build_signal_reply_metadata(outgoing, "+15550001000")
|
||||
expected_author = str(getattr(settings, "SIGNAL_NUMBER", "") or "").strip()
|
||||
if expected_author:
|
||||
self.assertEqual(expected_author, payload.get("quote_author"))
|
||||
else:
|
||||
self.assertEqual("+15550001000", payload.get("quote_author"))
|
||||
|
||||
|
||||
class SignalTransportSendTests(TestCase):
|
||||
def test_transport_passes_reply_metadata_to_signal_api(self):
|
||||
with patch(
|
||||
"core.clients.transport.prepare_outbound_attachments",
|
||||
new=AsyncMock(return_value=[]),
|
||||
), patch(
|
||||
"core.clients.transport.signalapi.send_message_raw",
|
||||
new=AsyncMock(return_value=1772538354000),
|
||||
) as mocked_send:
|
||||
result = async_to_sync(transport.send_message_raw)(
|
||||
"signal",
|
||||
"+15550001000",
|
||||
text="reply payload",
|
||||
attachments=[],
|
||||
metadata={
|
||||
"quote_timestamp": 1772538353497,
|
||||
"quote_author": "+15550001000",
|
||||
"quote_text": "quoted body",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(1772538354000, result)
|
||||
mocked_send.assert_awaited_once_with(
|
||||
"+15550001000",
|
||||
"reply payload",
|
||||
[],
|
||||
metadata={
|
||||
"quote_timestamp": 1772538353497,
|
||||
"quote_author": "+15550001000",
|
||||
"quote_text": "quoted body",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class SignalInboundReplyLinkTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
username="signal-inbound-user",
|
||||
email="signal-inbound@example.com",
|
||||
password="x",
|
||||
)
|
||||
self.person = Person.objects.create(user=self.user, name="Signal Inbound")
|
||||
self.identifier = PersonIdentifier.objects.create(
|
||||
user=self.user,
|
||||
person=self.person,
|
||||
service="signal",
|
||||
identifier="+15550002000",
|
||||
)
|
||||
self.session = ChatSession.objects.create(
|
||||
user=self.user,
|
||||
identifier=self.identifier,
|
||||
)
|
||||
self.anchor = Message.objects.create(
|
||||
user=self.user,
|
||||
session=self.session,
|
||||
sender_uuid="+15550002000",
|
||||
text="anchor inbound",
|
||||
ts=1772545458187,
|
||||
source_service="signal",
|
||||
source_message_id="1772545458187",
|
||||
source_chat_id="+15550002000",
|
||||
)
|
||||
|
||||
def test_process_raw_inbound_event_links_signal_reply(self):
|
||||
fake_ur = Mock()
|
||||
fake_ur.message_received = AsyncMock(return_value=None)
|
||||
client = SignalClient.__new__(SignalClient)
|
||||
client.service = "signal"
|
||||
client.ur = fake_ur
|
||||
client.log = Mock()
|
||||
client.client = Mock()
|
||||
client.client.bot_uuid = ""
|
||||
client.client.phone_number = ""
|
||||
client._resolve_signal_identifiers = AsyncMock(return_value=[self.identifier])
|
||||
client._auto_link_single_user_signal_identifier = AsyncMock(return_value=[])
|
||||
|
||||
payload = {
|
||||
"envelope": {
|
||||
"sourceNumber": "+15550002000",
|
||||
"sourceUuid": "756078fd-d447-426d-a620-581a86d64f51",
|
||||
"timestamp": 1772545462051,
|
||||
"dataMessage": {
|
||||
"message": "reply inbound s3",
|
||||
"quote": {
|
||||
"targetSentTimestamp": 1772545458187,
|
||||
"authorNumber": "+15550002000",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
async_to_sync(client._process_raw_inbound_event)(json.dumps(payload))
|
||||
|
||||
created = Message.objects.filter(
|
||||
user=self.user,
|
||||
session=self.session,
|
||||
text="reply inbound s3",
|
||||
).order_by("-ts").first()
|
||||
self.assertIsNotNone(created)
|
||||
self.assertEqual(self.anchor.id, created.reply_to_id)
|
||||
self.assertEqual("1772545458187", created.reply_source_message_id)
|
||||
|
||||
def test_process_raw_inbound_event_applies_reaction(self):
|
||||
fake_ur = Mock()
|
||||
fake_ur.message_received = AsyncMock(return_value=None)
|
||||
fake_ur.xmpp = Mock()
|
||||
fake_ur.xmpp.client = Mock()
|
||||
fake_ur.xmpp.client.apply_external_reaction = AsyncMock(return_value=None)
|
||||
client = SignalClient.__new__(SignalClient)
|
||||
client.service = "signal"
|
||||
client.ur = fake_ur
|
||||
client.log = Mock()
|
||||
client.client = Mock()
|
||||
client.client.bot_uuid = ""
|
||||
client.client.phone_number = ""
|
||||
client._resolve_signal_identifiers = AsyncMock(return_value=[self.identifier])
|
||||
client._auto_link_single_user_signal_identifier = AsyncMock(return_value=[])
|
||||
|
||||
payload = {
|
||||
"envelope": {
|
||||
"sourceNumber": "+15550002000",
|
||||
"sourceUuid": "756078fd-d447-426d-a620-581a86d64f51",
|
||||
"timestamp": 1772545463000,
|
||||
"dataMessage": {
|
||||
"reaction": {
|
||||
"emoji": "❤️",
|
||||
"targetSentTimestamp": 1772545458187,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
async_to_sync(client._process_raw_inbound_event)(json.dumps(payload))
|
||||
|
||||
self.anchor.refresh_from_db()
|
||||
reactions = list((self.anchor.receipt_payload or {}).get("reactions") or [])
|
||||
self.assertTrue(
|
||||
any(str(row.get("emoji") or "") == "❤️" for row in reactions),
|
||||
"Expected Signal heart reaction to be applied to anchor receipt payload.",
|
||||
)
|
||||
Reference in New Issue
Block a user