Corp/backend/notifications/push_lifecycle.py

113 lines
3.4 KiB
Python

"""Synchronize stored and native browser notifications with chat events."""
from collections import defaultdict
from django.db import transaction
from django.utils import timezone
from notifications.cache import invalidate_unread_summary
from notifications.models import Notification
from notifications.realtime import send_notifications_deleted_event
def queue_push_control(
*,
user_id: int,
action: str,
scope: dict,
replacement_notification_id: int | None = None,
) -> None:
def enqueue():
from notifications.tasks import send_push_control
send_push_control.delay(
user_id,
action,
scope,
replacement_notification_id,
)
transaction.on_commit(enqueue)
def dismiss_chat_push(*, user_id: int, chat_id: int) -> None:
queue_push_control(
user_id=user_id,
action="dismiss_chat",
scope={"chat_id": chat_id},
)
def dismiss_notifications_push(*, user_id: int, notification_ids) -> None:
normalized_ids = [int(notification_id) for notification_id in notification_ids]
if not normalized_ids:
return
queue_push_control(
user_id=user_id,
action="dismiss_notifications",
scope={"notification_ids": normalized_ids},
)
def delete_message_notifications(*, chat_id: int, message_id: int) -> None:
notifications = list(
Notification.objects.filter(
deleted=False,
data__chat_id=chat_id,
data__message_id=message_id,
).values("id", "recipient_id")
)
if not notifications:
return
notification_ids = [item["id"] for item in notifications]
Notification.objects.filter(id__in=notification_ids).update(
deleted=True,
unread=False,
timestamp_read=timezone.now(),
)
notifications_by_recipient = defaultdict(list)
for item in notifications:
notifications_by_recipient[item["recipient_id"]].append(item["id"])
for recipient_id, recipient_notification_ids in notifications_by_recipient.items():
invalidate_unread_summary(recipient_id)
send_notifications_deleted_event(
recipient_id,
recipient_notification_ids,
)
queue_push_control(
user_id=recipient_id,
action="dismiss_message",
scope={"chat_id": chat_id, "message_id": message_id},
)
def replace_message_notifications(message) -> None:
notifications = list(
Notification.objects.filter(
deleted=False,
data__chat_id=message.chat_id,
data__message_id=message.id,
)
)
if not notifications:
return
description = (message.content or "").strip()
if len(description) > 150:
description = description[:147] + "..."
grouped = defaultdict(list)
for notification in notifications:
notification.description = description
grouped[notification.recipient_id].append(notification)
Notification.objects.bulk_update(notifications, ["description"])
for recipient_id, recipient_notifications in grouped.items():
latest = max(recipient_notifications, key=lambda item: item.id)
queue_push_control(
user_id=recipient_id,
action="replace_message",
scope={"chat_id": message.chat_id, "message_id": message.id},
replacement_notification_id=latest.id,
)