From 54a7805a90db814b3ac11bc60ac3b82de5ee747a Mon Sep 17 00:00:00 2001 From: Typosaurus Date: Thu, 23 Jul 2026 01:31:16 +0000 Subject: [PATCH] ticket #85 attempt 1 --- devplacepy/database/schema.py | 21 +++++++++++++ devplacepy/services/messaging/persist.py | 40 ++++++++++++++++++------ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/devplacepy/database/schema.py b/devplacepy/database/schema.py index b9b043b5..289c928f 100644 --- a/devplacepy/database/schema.py +++ b/devplacepy/database/schema.py @@ -30,6 +30,26 @@ def migrate_bug_tables_to_issue_tables() -> None: logger.info("Dropped table %s after migration", source_name) +def _add_message_unique_index() -> None: + if "messages" not in db.tables: + return + with db: + db.query( + """ + DELETE FROM messages WHERE id NOT IN ( + SELECT MIN(id) FROM messages GROUP BY sender_uid, receiver_uid, content + ) + """ + ) + _index( + db, + "messages", + "idx_messages_unique_sender_receiver_content", + ["sender_uid", "receiver_uid", "content"], + unique=True, + ) + + def init_db(): tables = db.tables _index(db, "users", "idx_users_username", ["username"]) @@ -131,6 +151,7 @@ def init_db(): "idx_messages_conversation_rev", ["receiver_uid", "sender_uid"], ) + _add_message_unique_index() _index(db, "notifications", "idx_notifications_user", ["user_uid"]) _index(db, "notifications", "idx_notifications_user_read", ["user_uid", "read"]) _index(db, "push_registration", "idx_push_registration_user", ["user_uid"]) diff --git a/devplacepy/services/messaging/persist.py b/devplacepy/services/messaging/persist.py index 1d8726a4..ecbcb828 100644 --- a/devplacepy/services/messaging/persist.py +++ b/devplacepy/services/messaging/persist.py @@ -18,6 +18,8 @@ from devplacepy.utils import ( track_action, ) from devplacepy.services.audit import record as audit +from sqlalchemy.exc import IntegrityError + from devplacepy.services.correction import schedule_correction from devplacepy.services.ai_modifier import schedule_modification @@ -110,16 +112,36 @@ def persist_message( messages_table = get_table("messages") msg_uid = generate_uid() created_at = datetime.now(timezone.utc).isoformat() - messages_table.insert( - { - "uid": msg_uid, - "sender_uid": sender_uid, - "receiver_uid": receiver_uid, - "content": content, - "read": False, - "created_at": created_at, + + try: + messages_table.insert( + { + "uid": msg_uid, + "sender_uid": sender_uid, + "receiver_uid": receiver_uid, + "content": content, + "read": False, + "created_at": created_at, + } + ) + except IntegrityError: + existing = messages_table.find_one( + sender_uid=sender_uid, receiver_uid=receiver_uid, content=content + ) + if not existing: + raise + logger.debug( + "Dedup via unique constraint for message (uid %s)", existing["uid"] + ) + _content_cache[content_hash] = (time.time(), existing["uid"]) + return { + "uid": existing["uid"], + "sender_uid": existing["sender_uid"], + "receiver_uid": existing["receiver_uid"], + "content": existing["content"], + "read": existing.get("read", False), + "created_at": existing["created_at"], } - ) link_attachments(attachment_uids, "message", msg_uid) schedule_correction(sender, "messages", msg_uid, request)