diff --git a/app/database.py b/app/database.py index 9b47797..a3ec77a 100644 --- a/app/database.py +++ b/app/database.py @@ -197,12 +197,16 @@ class Database: return cursor.rowcount > 0 def hard_delete_contact(self, public_key: str) -> bool: - """Permanently delete a contact from the database.""" + """Permanently delete a contact from the database. + + Also clears ignored/blocked rows that reference this contact + via FK without ON DELETE CASCADE. + """ + pk = public_key.lower() with self._connect() as conn: - cursor = conn.execute( - "DELETE FROM contacts WHERE public_key = ?", - (public_key.lower(),) - ) + conn.execute("DELETE FROM ignored_contacts WHERE public_key = ?", (pk,)) + conn.execute("DELETE FROM blocked_contacts WHERE public_key = ?", (pk,)) + cursor = conn.execute("DELETE FROM contacts WHERE public_key = ?", (pk,)) return cursor.rowcount > 0 def downgrade_stale_device_contacts(self, active_device_keys: set) -> int: diff --git a/app/schema.sql b/app/schema.sql index e4f5e50..d4203b1 100644 --- a/app/schema.sql +++ b/app/schema.sql @@ -152,13 +152,13 @@ CREATE TABLE IF NOT EXISTS read_status ( -- Ignored contacts (adverts cached but not pending/auto-added) CREATE TABLE IF NOT EXISTS ignored_contacts ( - public_key TEXT PRIMARY KEY REFERENCES contacts(public_key), + public_key TEXT PRIMARY KEY REFERENCES contacts(public_key) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) ); -- Blocked contacts (ignored + messages hidden from display) CREATE TABLE IF NOT EXISTS blocked_contacts ( - public_key TEXT PRIMARY KEY REFERENCES contacts(public_key), + public_key TEXT PRIMARY KEY REFERENCES contacts(public_key) ON DELETE CASCADE, created_at TEXT NOT NULL DEFAULT (datetime('now')) );