Corp/backend/docs/guides/COMMENTS_USAGE.md
lizerk 6ddd3f69ba feat(communications): Добавить тип 'comments', пометить 'department' как legacy
BREAKING CHANGE: Тип 'department' помечен как deprecated.

Изменения:
- Добавлен новый тип чата 'comments' для систем комментариев
- Тип 'department' перемещен в конец списка и помечен как [Legacy]
- Обновлен help_text: рекомендуется использовать 'group' + context_object
- Обновлен __str__() для обработки типа 'comments'
- Создана миграция 0036_add_comments_type_deprecate_department

Универсальность:
- 'comments' + context_object работает с любыми моделями
- Треды, реакции, вложения доступны из коробки
- Real-time обновления через WebSocket
- Автоматические уведомления при упоминаниях и ответах

Рекомендации:
- Для проектно-специфичных чатов используй type='group' + context_object
- Department: type='group' + context_object=department + flags={'is_department': True}
- Comments: type='comments' + context_object=any_model

Документация:
- Создан docs/guides/COMMENTS_USAGE.md с примерами
- Описаны все возможности системы комментариев
- Примеры API, WebSocket, миграции с legacy типов
2026-03-11 17:06:06 +03:00

9.5 KiB
Raw Blame History

Использование Communications для комментариев

Новый тип чата: comments

С версии migrations/0036 добавлен специальный тип чата "comments" для систем комментариев.

Быстрый старт

1. Создание чата комментариев

from django.contrib.contenttypes.models import ContentType
from communications.models import Chat, Message

# Привязать комментарии к любому объекту
document = Document.objects.get(id=123)

comments_chat = Chat.objects.create(
    type='comments',
    name=f'Комментарии: {document.title}',
    context_object=document,  # GenericFK - работает с ЛЮБОЙ моделью
    created_by=request.user,
    flags={'allow_replies': True, 'allow_reactions': True}
)

2. Добавление комментария

# Простой комментарий
comment = Message.objects.create(
    chat=comments_chat,
    author=request.user,
    content="Отличный документ!"
)

# Комментарий с вложениями
comment = Message.objects.create(
    chat=comments_chat,
    author=request.user,
    content="См. прикрепленный файл",
    has_attachments=True
)
MessageAttachment.objects.create(
    message=comment,
    file=uploaded_file,
    file_type='file',
    file_name='report.pdf',
    file_size=12345
)

3. Вложенные комментарии (треды)

# Ответ на комментарий
reply = Message.objects.create(
    chat=comments_chat,
    author=another_user,
    content="Согласен!",
    reply_to=comment,  # Прямой ответ
    thread_root=comment  # Корень треда
)

# Получить все ответы на комментарий
replies = comment.direct_replies.filter(is_deleted=False)

# Получить весь тред
thread = Message.objects.filter(
    thread_root=comment,
    is_deleted=False
).order_by('created_at')

4. Редактирование и удаление

# Редактировать комментарий
from django.utils import timezone

comment.content = "Отличный документ! (обновлено)"
comment.is_edited = True
comment.edited_at = timezone.now()
comment.save()

# Мягкое удаление
comment.is_deleted = True
comment.deleted_at = timezone.now()
comment.deleted_by = request.user
comment.save()

5. Реакции (эмодзи)

from communications.models import MessageReaction

# Добавить реакцию
MessageReaction.objects.create(
    message=comment,
    user=request.user,
    emoji='👍'
)

# Получить сводку по реакциям
reactions_summary = comment.get_reactions_summary()
# {
#     '👍': {'count': 3, 'users': [1, 2, 3], 'user_names': ['User1', ...]},
#     '❤️': {'count': 1, 'users': [4], 'user_names': ['User4']}
# }

6. Уведомления (автоматические)

Модуль автоматически отправляет уведомления при:

  • Упоминаниях: @username в тексте комментария
  • Ответах: reply_to на чужой комментарий
  • Новых комментариях: всем участникам чата (кроме автора)
# Упомянуть пользователя
comment = Message.objects.create(
    chat=comments_chat,
    author=request.user,
    content="@john.doe посмотри этот документ"
)
# → john.doe получит уведомление автоматически

7. Real-time обновления через WebSocket

// Frontend: подключение к WebSocket
const ws = new WebSocket('ws://localhost:8000/ws/realtime/');

// Подписаться на комментарии
ws.send(JSON.stringify({
    type: 'chat.subscribe',
    chat_id: commentsChat.id
}));

// Получать обновления в реальном времени
ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    if (data.type === 'chat.message') {
        // Новый комментарий → обновить UI
        addCommentToUI(data.message);
    }
};

API эндпоинты

Получить список комментариев

GET /api/v1/communications/chats/{chat_id}/messages/?page=1&page_size=20

Response:
{
    "count": 42,
    "next": "...",
    "results": [
        {
            "id": 123,
            "author": {...},
            "content": "Отличный документ!",
            "created_at": "2026-03-11T15:30:00Z",
            "is_edited": false,
            "reply_to": null,
            "thread_root": null,
            "reactions_summary": {
                "👍": {"count": 3, "users": [1,2,3]}
            },
            "attachments": [...]
        }
    ]
}

Создать комментарий

POST /api/v1/communications/chats/{chat_id}/messages/

{
    "content": "Отличный документ!",
    "reply_to": 123  // опционально
}

Редактировать комментарий

PATCH /api/v1/communications/messages/{message_id}/

{
    "content": "Отличный документ! (обновлено)"
}

Удалить комментарий

DELETE /api/v1/communications/messages/{message_id}/

Добавить реакцию

POST /api/v1/communications/messages/{message_id}/react/

{
    "emoji": "👍"
}

Преимущества использования Communications для комментариев

✅ Треды - вложенные комментарии "из коробки"
✅ Реакции - эмодзи-реакции на комментарии
✅ Вложения - картинки, файлы, видео
✅ Редактирование - с историей изменений
✅ Упоминания - @username с автоматическими уведомлениями
✅ Real-time - WebSocket обновления
✅ Универсальность - GenericFK работает с любыми моделями
✅ Оптимизация - денормализованные счетчики, prefetch

Миграция с "department" на универсальные типы

❌ Старый подход (проектно-специфичный)

# Чат отдела (жестко привязан к EUSRR)
chat = Chat.objects.create(
    type='department',  # DEPRECATED!
    department=department_instance
)

✅ Новый подход (универсальный)

# Используй type='group' + context_object
chat = Chat.objects.create(
    type='group',  # Универсальный тип
    name=f'Чат отдела: {department.name}',
    context_object=department,  # GenericFK
    flags={'is_department_chat': True}
)

# Или для комментариев к объектам отдела
chat = Chat.objects.create(
    type='comments',
    name=f'Обсуждение: {department.name}',
    context_object=department
)

Настройка участников через callback

Для проектно-специфичной логики участников используй callback:

# settings.py
COMMUNICATIONS_PARTICIPANT_RESOLVER = 'myproject.utils.get_chat_participants'

# myproject/utils.py
def get_chat_participants(chat):
    """
    Кастомная логика определения участников.
    
    Возвращает QuerySet пользователей или None для fallback.
    """
    if chat.type == 'comments':
        # Комментарии видят только те, кто имеет доступ к объекту
        if hasattr(chat.context_object, 'get_allowed_users'):
            return chat.context_object.get_allowed_users()
    
    # Для department используй GenericFK
    if chat.flags.get('is_department_chat'):
        from employees.models import EmployeeDepartment
        dept = chat.context_object
        user_ids = EmployeeDepartment.objects.filter(
            department=dept,
            is_active=True
        ).values_list('employee_id', flat=True)
        return User.objects.filter(id__in=user_ids)
    
    return None  # Fallback к стандартной логике

Примеры использования

Комментарии к документу

document = Document.objects.get(id=123)
chat = Chat.objects.create(
    type='comments',
    name=f'Комментарии: {document.title}',
    context_object=document,
    flags={'allow_anonymous': False}
)

Комментарии к задаче

task = Task.objects.get(id=456)
chat = Chat.objects.create(
    type='comments',
    name=f'Обсуждение: {task.title}',
    context_object=task,
    flags={'notify_assignee': True}
)

Комментарии к посту в соцсети

post = Post.objects.get(id=789)
chat = Chat.objects.create(
    type='comments',
    name='Comments',
    context_object=post,
    flags={'allow_public_comments': True, 'moderation_enabled': True}
)

См. также