Corp/backend/communications/context_processors.py
igor_nadein 8a083f6f67 fix: Исправлена система автоотметки прочитанных сообщений
- Удалено поле last_read_at из ChatReadState, используется только last_read_message FK
- Исправлена логика автоотметки: отмечается последнее ЗАГРУЖЕННОЕ сообщение, а не последнее в чате
- Убран вызов chat.mark_read() при WebSocket open_chat (отмечал последнее в чате вместо загруженного)
- Добавлен signal для мониторинга изменений ChatReadState
- Исправлена логика скролла: убран автоскролл при дозагрузке вниз
- Добавлена проверка разрывов при WebSocket сообщениях (предотвращает пропуск сообщений)
- Реализована автоотметка WebSocket сообщений (только если пользователь внизу)
- Асимметричная загрузка: 24 контекста + 6 новых сообщений
- Добавлен ScrollableMessageList компонент для корректной работы скролла
- Миграции: 0028 (удаление last_read_at), 0029 (индекс на last_read_message)
2026-02-25 20:29:00 +03:00

50 lines
1.6 KiB
Python

import datetime
from django.db import models
from django.db.models import Count, F, Q, Subquery, Value
from django.db.models.functions import Coalesce
from django.utils import timezone
from .models import Chat, ChatReadState, Message
def chat_unread_total(request):
"""
Считает общее количество непрочитанных сообщений пользователя.
Использует last_read_message_id (Telegram-style) вместо last_read_at.
"""
if not request.user.is_authenticated:
return {"chat_unread_total": 0}
user = request.user
# last_read_message_id для каждого чата текущего юзера
last_read_msg_sq = ChatReadState.objects.filter(
chat=models.OuterRef("pk"), user=user
).values("last_read_message_id")[:1]
# доступные юзеру чаты
deps = getattr(user, "departments", None)
deps_qs = deps.all() if deps is not None else []
chats_qs = (
Chat.objects.filter(
Q(type="global")
| Q(type="private", participants=user)
| Q(type="department", department__in=deps_qs)
)
.distinct()
.annotate(last_read_msg_id=Coalesce(Subquery(last_read_msg_sq), Value(0)))
.annotate(
unread=Count(
"messages",
filter=Q(messages__id__gt=F("last_read_msg_id"))
& ~Q(messages__author=user),
distinct=True,
)
)
)
total = chats_qs.aggregate(total=models.Sum("unread"))["total"] or 0
return {"chat_unread_total": total}