47 lines
1.6 KiB
Python
47 lines
1.6 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.models import ChatReadState, Message
|
|
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
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
|