Corp/backend/communications/services/message_deletion.py
2026-09-07 19:43:48 +03:00

61 lines
2.2 KiB
Python

from __future__ import annotations
from django.db import transaction
from django.db.models import F, Q
from django.utils import timezone
from communications.mentions import mentioned_user_ids
from communications.models import ChatReadState, Message
from notifications.push_lifecycle import delete_message_notifications
def soft_delete_message(
message: Message,
*,
deleted_by,
replacement_content: str | None = None,
) -> bool:
"""Soft-delete a message and remove it from cached unread counters."""
with transaction.atomic():
locked_message = Message.objects.select_for_update().get(pk=message.pk)
if locked_message.is_deleted:
return False
unread_states = ChatReadState.objects.filter(
chat_id=locked_message.chat_id,
unread_count__gt=0,
).exclude(user_id=locked_message.author_id)
unread_states = unread_states.filter(
Q(last_read_message_id__isnull=True)
| Q(last_read_message_id__lt=locked_message.id)
)
unread_states.update(unread_count=F("unread_count") - 1)
mention_recipient_ids = mentioned_user_ids(locked_message.mentions)
if mention_recipient_ids:
unread_states.filter(
user_id__in=mention_recipient_ids,
unread_mention_count__gt=0,
).update(unread_mention_count=F("unread_mention_count") - 1)
locked_message.is_deleted = True
locked_message.deleted_at = timezone.now()
locked_message.deleted_by = deleted_by
update_fields = ["is_deleted", "deleted_at", "deleted_by"]
if replacement_content is not None:
locked_message.content = replacement_content
update_fields.append("content")
locked_message.save(update_fields=update_fields)
delete_message_notifications(
chat_id=locked_message.chat_id,
message_id=locked_message.id,
)
message.is_deleted = locked_message.is_deleted
message.deleted_at = locked_message.deleted_at
message.deleted_by = locked_message.deleted_by
if replacement_content is not None:
message.content = replacement_content
return True