124 lines
3.7 KiB
Python
124 lines
3.7 KiB
Python
from dataclasses import dataclass
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.db import transaction
|
|
from django.db.models import Q
|
|
from django.utils import timezone
|
|
|
|
from notifications.cache import invalidate_unread_summary
|
|
from notifications.models import Notification
|
|
from notifications.realtime import send_notifications_read_all_event
|
|
from procurement.models import ProcurementItem, ProcurementRequest
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProcurementNotificationReadResult:
|
|
notification_ids: list[int]
|
|
count: int
|
|
|
|
|
|
class ProcurementNotificationReadService:
|
|
"""Use case for reading notifications related to a procurement request."""
|
|
|
|
procurement_verb_filter = Q(verb__startswith="procurement_") | Q(
|
|
verb__startswith="equipment_"
|
|
)
|
|
|
|
def mark_request_notifications_as_read(
|
|
self,
|
|
*,
|
|
user,
|
|
procurement_request: ProcurementRequest,
|
|
) -> ProcurementNotificationReadResult:
|
|
queryset = self._get_unread_queryset(
|
|
user_id=user.id,
|
|
procurement_request=procurement_request,
|
|
).exclude(verb="procurement_item_commented")
|
|
return self._mark_queryset_as_read(user_id=user.id, queryset=queryset)
|
|
|
|
def mark_item_comment_notifications_as_read(
|
|
self,
|
|
*,
|
|
user,
|
|
item: ProcurementItem,
|
|
) -> ProcurementNotificationReadResult:
|
|
item_id = item.id
|
|
queryset = Notification.objects.filter(
|
|
recipient_id=user.id,
|
|
unread=True,
|
|
deleted=False,
|
|
verb="procurement_item_commented",
|
|
).filter(Q(data__item_id=item_id) | Q(data__item_id=str(item_id)))
|
|
return self._mark_queryset_as_read(user_id=user.id, queryset=queryset)
|
|
|
|
def _mark_queryset_as_read(
|
|
self,
|
|
*,
|
|
user_id: int,
|
|
queryset,
|
|
) -> ProcurementNotificationReadResult:
|
|
notification_ids = list(queryset.values_list("id", flat=True))
|
|
|
|
if not notification_ids:
|
|
return ProcurementNotificationReadResult(
|
|
notification_ids=[],
|
|
count=0,
|
|
)
|
|
|
|
read_at = timezone.now()
|
|
count = Notification.objects.filter(
|
|
id__in=notification_ids,
|
|
).update(
|
|
unread=False,
|
|
timestamp_read=read_at,
|
|
)
|
|
|
|
invalidate_unread_summary(user_id)
|
|
|
|
def notify_after_commit():
|
|
invalidate_unread_summary(user_id)
|
|
send_notifications_read_all_event(user_id, notification_ids)
|
|
|
|
transaction.on_commit(notify_after_commit)
|
|
|
|
return ProcurementNotificationReadResult(
|
|
notification_ids=notification_ids,
|
|
count=count,
|
|
)
|
|
|
|
def _get_unread_queryset(
|
|
self,
|
|
*,
|
|
user_id: int,
|
|
procurement_request: ProcurementRequest,
|
|
):
|
|
request_content_type = ContentType.objects.get_for_model(
|
|
ProcurementRequest,
|
|
)
|
|
request_id = procurement_request.id
|
|
request_id_text = str(request_id)
|
|
|
|
request_filter = (
|
|
Q(data__request_id=request_id)
|
|
| Q(data__request_id=request_id_text)
|
|
| Q(
|
|
target_content_type=request_content_type,
|
|
target_object_id=request_id_text,
|
|
)
|
|
| Q(
|
|
action_object_content_type=request_content_type,
|
|
action_object_object_id=request_id_text,
|
|
)
|
|
)
|
|
|
|
return (
|
|
Notification.objects.filter(
|
|
recipient_id=user_id,
|
|
unread=True,
|
|
deleted=False,
|
|
)
|
|
.filter(self.procurement_verb_filter)
|
|
.filter(request_filter)
|
|
.distinct()
|
|
)
|