Corp/backend/tasks/realtime.py
2026-07-06 13:47:03 +03:00

127 lines
3.4 KiB
Python

import logging
from collections.abc import Iterable
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Q
from employees.models import Department, EmployeeDepartment, RoleAssignment
from .models import TaskBoard
logger = logging.getLogger(__name__)
def get_task_board_recipient_ids(board: TaskBoard) -> set[int]:
if not board or not board.pk:
return set()
User = get_user_model()
admin_q = Q(is_staff=True) | Q(is_superuser=True)
if not board.members.exists() and not board.departments.exists():
return set(
User.objects.filter(is_active=True)
.values_list("id", flat=True)
)
department_ids = list(board.departments.values_list("id", flat=True))
recipient_ids = {board.created_by_id}
recipient_ids.update(board.members.values_list("id", flat=True))
if department_ids:
recipient_ids.update(
EmployeeDepartment.objects.filter(
department_id__in=department_ids,
is_active=True,
employee__is_active=True,
).values_list("employee_id", flat=True)
)
recipient_ids.update(
Department.objects.filter(
id__in=department_ids,
head__is_active=True,
).values_list("head_id", flat=True)
)
recipient_ids.update(
RoleAssignment.objects.filter(
role__department_id__in=department_ids,
is_active=True,
employee__is_active=True,
).values_list("employee_id", flat=True)
)
recipient_ids.update(
User.objects.filter(is_active=True)
.filter(admin_q)
.values_list("id", flat=True)
)
return set(
User.objects.filter(
id__in={user_id for user_id in recipient_ids if user_id},
is_active=True,
).values_list("id", flat=True)
)
def send_task_board_update(
board: TaskBoard | None,
event: str,
model: str,
object_id: int | None = None,
*,
recipient_ids: Iterable[int] | None = None,
board_id: int | None = None,
extra: dict | None = None,
) -> None:
resolved_board_id = board_id or getattr(board, "id", None)
if not resolved_board_id:
return
recipients = set(
recipient_ids
or (
get_task_board_recipient_ids(board)
if board and board.pk
else set()
)
)
if not recipients:
return
payload = {
"board_id": resolved_board_id,
"event": event,
"model": model,
"object_id": object_id,
}
if extra:
payload.update(extra)
def _send() -> None:
channel_layer = get_channel_layer()
if channel_layer is None:
return
message = {
"type": "task_board_update",
"event": event,
"data": payload,
}
for user_id in recipients:
try:
async_to_sync(channel_layer.group_send)(
f"user_{user_id}",
message,
)
except Exception:
logger.exception(
"Failed to send task board update to user %s",
user_id,
)
transaction.on_commit(_send)