From 32a20a33ee6cb12ea5e45200254585f96a65089e Mon Sep 17 00:00:00 2001 From: lizerk Date: Thu, 16 Apr 2026 12:55:04 +0300 Subject: [PATCH] fix: narrow department chat comment notifications --- .../communications/notifications/handlers.py | 17 ++----- .../employees/test_department_discussion.py | 49 ++++++++++++++++++- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/backend/communications/notifications/handlers.py b/backend/communications/notifications/handlers.py index dfc66ddc..25cf2db0 100644 --- a/backend/communications/notifications/handlers.py +++ b/backend/communications/notifications/handlers.py @@ -219,7 +219,8 @@ def _notify_comment(message): Уведомляет: 1. Автора объекта (Post/Document/Request) - 2. Других участников обсуждения (кто оставлял комментарии) + 2. Для Department: сотрудников отдела и role-only участников отдела + 3. Автора parent comment, если это reply Args: message: Экземпляр модели Message (в чате type='comments') @@ -298,17 +299,9 @@ def _notify_comment(message): if object_author and object_author.id != author.id: recipient_ids.add(object_author.id) - # 2. Уведомляем всех, кто участвовал в обсуждении - from ..models import Message - previous_commenters = Message.objects.filter( - chat=chat, - is_deleted=False - ).exclude( - author_id=author.id - ).values_list('author_id', flat=True).distinct() - - if previous_commenters: - recipient_ids.update(previous_commenters) + # 2. Reply notification for comments is opt-in by explicit reply target. + if message.reply_to and message.reply_to.author_id != author.id: + recipient_ids.add(message.reply_to.author_id) recipient_ids.discard(author.id) if not recipient_ids: diff --git a/backend/tests/api/v1/employees/test_department_discussion.py b/backend/tests/api/v1/employees/test_department_discussion.py index 7ffa37aa..b398ce3a 100644 --- a/backend/tests/api/v1/employees/test_department_discussion.py +++ b/backend/tests/api/v1/employees/test_department_discussion.py @@ -181,7 +181,7 @@ def test_any_active_user_can_send_message_to_department_comments_chat( assert chat.flags.get("show_in_messages") is True -def test_department_comment_notifications_keep_chat_routing_and_include_role_only( +def test_department_comment_notifications_only_include_department_and_role_only( monkeypatch, ): department = Department.objects.create(name="Backoffice") @@ -229,7 +229,7 @@ def test_department_comment_notifications_keep_chat_routing_and_include_role_onl recipient_ids = {payload["recipient"].id for payload in sent_notifications} assert role_only.id in recipient_ids - assert previous_commenter.id in recipient_ids + assert previous_commenter.id not in recipient_ids assert member.id not in recipient_ids assert sent_notifications for payload in sent_notifications: @@ -237,6 +237,51 @@ def test_department_comment_notifications_keep_chat_routing_and_include_role_onl assert payload["data"]["chat_id"] == message.chat_id +def test_department_comment_reply_notifies_reply_target_outside_department( + monkeypatch, +): + department = Department.objects.create(name="Operations") + member = make_user("member@example.com") + outsider = make_user("outsider@example.com") + + EmployeeDepartment.objects.create( + employee=member, + department=department, + is_active=True, + ) + + first_comment = create_comment( + department, + author=outsider, + content="Вопрос от сотрудника вне отдела", + ) + + sent_notifications = [] + + def capture_notification(**kwargs): + sent_notifications.append(kwargs) + + monkeypatch.setattr( + "communications.notifications.handlers._send_notification", + capture_notification, + ) + + reply = create_comment( + department, + author=member, + content="Ответ сотруднику", + reply_to=first_comment, + ) + + recipient_ids = {payload["recipient"].id for payload in sent_notifications} + + assert outsider.id in recipient_ids + assert member.id not in recipient_ids + for payload in sent_notifications: + assert payload["action_url"] == f"/messages/{reply.chat_id}" + assert payload["data"]["chat_id"] == reply.chat_id + + def test_department_chat_visible_in_messages_list_but_generic_comments_hidden( api_client: APIClient, ):