Add sender_key to outgoing and make unread counts respect block list

This commit is contained in:
Jack Kingsman
2026-03-05 10:43:16 -08:00
parent 01a5dc8d93
commit 7715732e69
5 changed files with 244 additions and 8 deletions
+143 -1
View File
@@ -4,7 +4,12 @@ import time
import pytest
from app.repository import AppSettingsRepository, MessageRepository
from app.repository import (
AppSettingsRepository,
ChannelRepository,
ContactRepository,
MessageRepository,
)
from app.routers.settings import (
BlockKeyRequest,
BlockNameRequest,
@@ -168,3 +173,140 @@ class TestMessageBlockFiltering:
assert "blocked dm" not in texts
assert "normal dm" in texts
assert "outgoing to blocked" in texts
class TestUnreadCountsBlockFiltering:
"""Unread counts should exclude messages from blocked keys/names."""
@pytest.mark.asyncio
async def test_unread_counts_exclude_blocked_key_dms(self, test_db):
"""Blocked key DMs should not contribute to unread counts."""
blocked_key = "aa" * 32
normal_key = "bb" * 32
now = int(time.time())
# Set up contacts with last_read_at in the past
await ContactRepository.upsert({"public_key": blocked_key, "name": "Blocked"})
await ContactRepository.upsert({"public_key": normal_key, "name": "Normal"})
# Incoming DMs
await MessageRepository.create(
msg_type="PRIV",
text="blocked msg",
received_at=now,
conversation_key=blocked_key,
sender_timestamp=now,
)
await MessageRepository.create(
msg_type="PRIV",
text="normal msg",
received_at=now + 1,
conversation_key=normal_key,
sender_timestamp=now + 1,
)
result = await MessageRepository.get_unread_counts(
blocked_keys=[blocked_key],
)
assert f"contact-{blocked_key}" not in result["counts"]
assert result["counts"][f"contact-{normal_key}"] == 1
@pytest.mark.asyncio
async def test_unread_counts_exclude_blocked_key_channel_msgs(self, test_db):
"""Blocked key channel messages should not contribute to unread counts."""
blocked_key = "aa" * 32
normal_key = "bb" * 32
chan_key = "CC" * 16
now = int(time.time())
await ChannelRepository.upsert(key=chan_key, name="#test")
await ChannelRepository.update_last_read_at(chan_key, 0)
await MessageRepository.create(
msg_type="CHAN",
text="Blocked: spam",
received_at=now,
conversation_key=chan_key,
sender_timestamp=now,
sender_name="Blocked",
sender_key=blocked_key,
)
await MessageRepository.create(
msg_type="CHAN",
text="Normal: hi",
received_at=now + 1,
conversation_key=chan_key,
sender_timestamp=now + 1,
sender_name="Normal",
sender_key=normal_key,
)
result = await MessageRepository.get_unread_counts(
blocked_keys=[blocked_key],
)
assert result["counts"][f"channel-{chan_key}"] == 1
@pytest.mark.asyncio
async def test_unread_counts_exclude_blocked_name_channel_msgs(self, test_db):
"""Blocked name channel messages should not contribute to unread counts."""
chan_key = "DD" * 16
now = int(time.time())
await ChannelRepository.upsert(key=chan_key, name="#test2")
await ChannelRepository.update_last_read_at(chan_key, 0)
await MessageRepository.create(
msg_type="CHAN",
text="Spammer: buy stuff",
received_at=now,
conversation_key=chan_key,
sender_timestamp=now,
sender_name="Spammer",
sender_key="ee" * 32,
)
await MessageRepository.create(
msg_type="CHAN",
text="Friend: hello",
received_at=now + 1,
conversation_key=chan_key,
sender_timestamp=now + 1,
sender_name="Friend",
sender_key="ff" * 32,
)
result = await MessageRepository.get_unread_counts(
blocked_names=["Spammer"],
)
assert result["counts"][f"channel-{chan_key}"] == 1
@pytest.mark.asyncio
async def test_unread_counts_no_block_lists_returns_all(self, test_db):
"""Without block lists, all messages count toward unreads."""
blocked_key = "aa" * 32
chan_key = "CC" * 16
now = int(time.time())
await ContactRepository.upsert({"public_key": blocked_key, "name": "Someone"})
await ChannelRepository.upsert(key=chan_key, name="#all")
await ChannelRepository.update_last_read_at(chan_key, 0)
await MessageRepository.create(
msg_type="PRIV",
text="dm",
received_at=now,
conversation_key=blocked_key,
sender_timestamp=now,
)
await MessageRepository.create(
msg_type="CHAN",
text="Someone: hi",
received_at=now + 1,
conversation_key=chan_key,
sender_timestamp=now + 1,
sender_name="Someone",
sender_key=blocked_key,
)
result = await MessageRepository.get_unread_counts()
assert result["counts"][f"contact-{blocked_key}"] == 1
assert result["counts"][f"channel-{chan_key}"] == 1
+38
View File
@@ -259,6 +259,44 @@ class TestOutgoingChannelBotTrigger:
assert message.id is not None
assert message.acked == 0
@pytest.mark.asyncio
async def test_send_channel_msg_includes_sender_key(self, test_db):
"""Outgoing channel message includes our public key as sender_key."""
our_pubkey = "ab" * 32
mc = _make_mc(name="MyNode")
mc.self_info["public_key"] = our_pubkey
chan_key = "ee" * 16
await ChannelRepository.upsert(key=chan_key, name="#test")
broadcasts = []
def capture_broadcast(event_type, data):
broadcasts.append({"type": event_type, "data": data})
with (
patch("app.routers.messages.require_connected", return_value=mc),
patch.object(radio_manager, "_meshcore", mc),
patch("app.decoder.calculate_channel_hash", return_value="abcd"),
patch("app.bot.run_bot_for_message", new=AsyncMock()),
patch("app.routers.messages.broadcast_event", side_effect=capture_broadcast),
):
request = SendChannelMessageRequest(channel_key=chan_key, text="hello")
message = await send_channel_message(request)
# Response message includes sender_key
assert message.sender_key == our_pubkey
assert message.sender_name == "MyNode"
# Broadcast also includes sender_key
msg_broadcasts = [b for b in broadcasts if b["type"] == "message"]
assert len(msg_broadcasts) == 1
assert msg_broadcasts[0]["data"]["sender_key"] == our_pubkey
# DB row also has sender_key
db_msg = await MessageRepository.get_by_id(message.id)
assert db_msg is not None
assert db_msg.sender_key == our_pubkey
class TestResendChannelMessage:
"""Test the user-triggered resend endpoint."""