diff --git a/app/repository/contacts.py b/app/repository/contacts.py index 0250725..8ca2d9b 100644 --- a/app/repository/contacts.py +++ b/app/repository/contacts.py @@ -395,11 +395,11 @@ class ContactRepository: @staticmethod async def delete(public_key: str) -> None: normalized = public_key.lower() + # contact_name_history and contact_advert_paths cascade via FK, but + # messages has no FK to contacts — clean up DMs explicitly. await db.conn.execute( - "DELETE FROM contact_name_history WHERE public_key = ?", (normalized,) - ) - await db.conn.execute( - "DELETE FROM contact_advert_paths WHERE public_key = ?", (normalized,) + "DELETE FROM messages WHERE type = 'PRIV' AND conversation_key = ?", + (normalized,), ) await db.conn.execute("DELETE FROM contacts WHERE public_key = ?", (normalized,)) await db.conn.commit() diff --git a/tests/test_contacts_router.py b/tests/test_contacts_router.py index b2a0e5a..2161ab1 100644 --- a/tests/test_contacts_router.py +++ b/tests/test_contacts_router.py @@ -363,6 +363,34 @@ class TestDeleteContactCascade: assert len(await ContactNameHistoryRepository.get_history(KEY_A)) == 0 assert len(await ContactAdvertPathRepository.get_recent_for_contact(KEY_A)) == 0 + @pytest.mark.asyncio + async def test_delete_removes_direct_messages(self, test_db, client): + await _insert_contact(KEY_A, "Alice") + + # Create a DM for this contact + await MessageRepository.create( + msg_type="PRIV", + conversation_key=KEY_A, + text="hello", + sender_timestamp=1000, + received_at=1000, + ) + msgs = await MessageRepository.get_all(msg_type="PRIV", conversation_key=KEY_A) + assert len(msgs) == 1 + + with patch("app.routers.contacts.radio_manager") as mock_rm: + mock_rm.is_connected = False + mock_rm.meshcore = None + mock_rm.radio_operation = _noop_radio_operation() + + response = await client.delete(f"/api/contacts/{KEY_A}") + + assert response.status_code == 200 + + # DMs for the deleted contact should be gone + msgs = await MessageRepository.get_all(msg_type="PRIV", conversation_key=KEY_A) + assert len(msgs) == 0 + class TestMarkRead: """Test POST /api/contacts/{public_key}/mark-read."""