Files
new_lottery_bot/docs/CHAT_SYSTEM.md
Andrew K. Choi b6c27b7b70
Some checks reported errors
continuous-integration/drone/push Build encountered an error
feat: добавлена система чата с модерацией
Реализована полнофункциональная система чата с двумя режимами работы:

## Режимы работы:
- Broadcast: рассылка сообщений всем пользователям
- Forward: пересылка сообщений в указанную группу/канал

## Функционал:
- Поддержка всех типов сообщений: text, photo, video, document, animation, sticker, voice
- Система банов: личные баны пользователей и глобальный бан чата
- Модерация: удаление сообщений с отслеживанием в БД
- История сообщений с сохранением ID пересланных сообщений

## Структура БД (миграция 005):
- chat_settings: настройки чата (режим, ID канала, глобальный бан)
- banned_users: история банов с причинами и информацией о модераторе
- chat_messages: история сообщений с типами, файлами и картой доставки (JSONB)

## Сервисы:
- ChatSettingsService: управление настройками чата
- BanService: управление банами пользователей
- ChatMessageService: работа с историей сообщений
- ChatPermissionService: проверка прав на отправку сообщений

## Обработчики:
- chat_handlers.py: обработка сообщений пользователей (7 типов контента)
- admin_chat_handlers.py: админские команды управления чатом

## Админские команды:
- /chat_mode - переключение режима (broadcast/forward)
- /set_forward <chat_id> - установка ID канала для пересылки
- /ban <user_id> [причина] - бан пользователя
- /unban <user_id> - разбан пользователя
- /banlist - список забаненных
- /global_ban - включение/выключение глобального бана
- /delete_msg - удаление сообщения (ответ на сообщение)
- /chat_stats - статистика чата

## Документация:
- docs/CHAT_SYSTEM.md: полное описание системы с примерами использования

Изменено файлов: 7 (2 modified, 5 new)
- main.py: подключены chat_router и admin_chat_router
- src/core/models.py: добавлены модели ChatSettings, BannedUser, ChatMessage
- migrations/versions/005_add_chat_system.py: миграция создания таблиц
- src/core/chat_services.py: сервисный слой для чата (267 строк)
- src/handlers/chat_handlers.py: обработчики сообщений (447 строк)
- src/handlers/admin_chat_handlers.py: админские команды (369 строк)
- docs/CHAT_SYSTEM.md: документация (390 строк)
2025-11-16 14:25:09 +09:00

15 KiB
Raw Blame History

Система чата пользователей

Описание

Система чата позволяет пользователям общаться между собой через бота с двумя режимами работы:

  • Broadcast (Рассылка) - сообщения пользователей рассылаются всем остальным пользователям
  • Forward (Пересылка) - сообщения пользователей пересылаются в указанную группу/канал

Режимы работы

Режим Broadcast (Рассылка всем)

В этом режиме сообщения от одного пользователя автоматически рассылаются всем остальным активным пользователям бота.

Особенности:

  • Отправитель не получает копию своего сообщения
  • Сообщение доставляется только активным пользователям (is_active=True)
  • В базу сохраняется статистика доставки (кому доставлено, кому нет)
  • ID отправленных сообщений сохраняются в forwarded_message_ids (JSONB)

Пример работы:

  1. Пользователь А отправляет фото с текстом "Привет всем!"
  2. Бот копирует это сообщение пользователям B, C, D...
  3. В базу сохраняется: {telegram_id_B: msg_id_1, telegram_id_C: msg_id_2, ...}
  4. Пользователю А показывается статистика: " Сообщение разослано! 📤 Доставлено: 15, Не доставлено: 2"

Режим Forward (Пересылка в канал)

В этом режиме сообщения от пользователей пересылаются в указанную группу или канал.

Особенности:

  • Бот должен быть администратором канала/группы с правом публикации
  • Сохраняется оригинальное авторство сообщения (пересылка, а не копия)
  • ID канала хранится в chat_settings.forward_chat_id
  • В базу сохраняется ID сообщения в канале

Пример работы:

  1. Пользователь отправляет видео
  2. Бот пересылает это видео в канал (сохраняя имя отправителя)
  3. В базу сохраняется: {channel: message_id_in_channel}
  4. Пользователю показывается: " Сообщение переслано в канал"

Поддерживаемые типы сообщений

Система поддерживает все основные типы контента:

Тип Поле message_type Поле file_id Описание
Текст text NULL Обычное текстовое сообщение
Фото photo file_id Изображение (сохраняется самое большое)
Видео video file_id Видео файл
Документ document file_id Файл любого типа
GIF animation file_id Анимированное изображение
Стикер sticker file_id Стикер из набора
Голосовое voice file_id Голосовое сообщение

Примечание: Для всех типов кроме text и sticker может быть указан caption (подпись), который сохраняется в поле text.

Система банов

Личный бан пользователя

Администратор может забанить конкретного пользователя:

/ban 123456789 Спам в чате
/ban (ответ на сообщение) Нарушение правил

Эффекты:

  • Пользователь не может отправлять сообщения
  • При попытке отправки получает: " Вы заблокированы и не можете отправлять сообщения"
  • Запись добавляется в таблицу banned_users с is_active=true

Разблокировка:

/unban 123456789
/unban (ответ на сообщение)

Глобальный бан чата

Администратор может временно закрыть весь чат:

/global_ban

Эффекты:

  • Все пользователи (кроме админов) не могут писать
  • При попытке отправки: " Чат временно закрыт администратором"
  • Флаг chat_settings.global_ban устанавливается в true

Открытие чата:

/global_ban  (повторно - переключение)

Модерация сообщений

Удаление сообщений

Администратор может удалить сообщение из всех чатов:

/delete_msg (ответ на сообщение)

Процесс:

  1. Сообщение помечается как удаленное в БД (is_deleted=true)
  2. Сохраняется кто удалил (deleted_by) и когда (deleted_at)
  3. Бот пытается удалить сообщение у всех пользователей, используя forwarded_message_ids
  4. Показывается статистика: " Удалено у 12 пользователей"

Важно: Удаление возможно только если сообщение было сохранено в БД и есть forwarded_message_ids.

Админские команды

/chat_mode

Переключение режима работы чата.

Интерфейс: Inline-клавиатура с выбором режима.

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

/chat_mode
→ Показывается меню выбора режима
→ Нажимаем "📢 Рассылка всем"
→ Режим изменен

/set_forward <chat_id>

Установить ID канала/группы для пересылки.

Как узнать chat_id:

  1. Добавьте бота в канал/группу
  2. Напишите любое сообщение в канале
  3. Перешлите его боту @userinfobot
  4. Он покажет chat_id (например: -1001234567890)

Пример:

/set_forward -1001234567890
→ ID канала для пересылки установлен!

/ban <user_id> [причина]

Забанить пользователя.

Способы использования:

  1. Ответить на сообщение: /ban Спам
  2. Указать ID: /ban 123456789 Нарушение правил

/unban <user_id>

Разбанить пользователя.

Способы использования:

  1. Ответить на сообщение: /unban
  2. Указать ID: /unban 123456789

/banlist

Показать список всех забаненных пользователей.

Формат вывода:

🚫 Забаненные пользователи

👤 Иван Иванов (123456789)
🔨 Забанил: Админ
📝 Причина: Спам
📅 Дата: 15.01.2025 14:30

👤 Петр Петров (987654321)
🔨 Забанил: Админ
📅 Дата: 14.01.2025 12:00

/global_ban

Включить/выключить глобальный бан чата (переключатель).

Статусы:

  • 🔇 Включен - только админы могут писать
  • 🔊 Выключен - все могут писать

/delete_msg

Удалить сообщение (ответ на сообщение).

Требует: Ответить на сообщение, которое нужно удалить.

/chat_stats

Показать статистику чата.

Информация:

  • Текущий режим работы
  • Статус глобального бана
  • Количество забаненных пользователей
  • Количество сообщений за последнее время
  • ID канала (если установлен)

База данных

Таблица chat_settings

Одна строка с глобальными настройками чата:

id = 1 (всегда)
mode = 'broadcast' | 'forward'
forward_chat_id = '-1001234567890' (для режима forward)
global_ban = true | false

Таблица banned_users

История банов пользователей:

id - уникальный ID бана
user_id - FK на users.id
telegram_id - Telegram ID пользователя
banned_by - FK на users.id (кто забанил)
reason - текстовая причина (nullable)
banned_at - timestamp бана
is_active - true/false (активен ли бан)

Примечание: При разбане is_active меняется на false, но запись не удаляется (история).

Таблица chat_messages

История всех отправленных сообщений:

id - уникальный ID сообщения
user_id - FK на users.id (отправитель)
telegram_message_id - ID сообщения в Telegram
message_type - text/photo/video/document/animation/sticker/voice
text - текст или caption (nullable)
file_id - file_id медиа (nullable)
forwarded_message_ids - JSONB с картой доставки
is_deleted - помечено ли как удаленное
deleted_by - FK на users.id (кто удалил, nullable)
deleted_at - timestamp удаления (nullable)
created_at - timestamp отправки

Формат forwarded_message_ids:

// Режим broadcast:
{
  "123456789": 12345,  // telegram_id: message_id
  "987654321": 12346,
  "555555555": 12347
}

// Режим forward:
{
  "channel": 54321  // ключ "channel", значение - ID сообщения в канале
}

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

Настройка режима broadcast

  1. Админ: /chat_mode → выбирает "📢 Рассылка всем"
  2. Пользователь А пишет: "Привет всем!"
  3. Пользователи B, C, D получают это сообщение
  4. Пользователь А видит: " Сообщение разослано! 📤 Доставлено: 3"

Настройка режима forward

  1. Админ создает канал и добавляет бота как админа
  2. Админ узнает chat_id канала (например: -1001234567890)
  3. Админ: /set_forward -1001234567890
  4. Админ: /chat_mode → выбирает "➡️ Пересылка в канал"
  5. Пользователь пишет сообщение → оно появляется в канале

Бан пользователя за спам

  1. Пользователь отправляет спам
  2. Админ отвечает на его сообщение: /ban Спам в чате
  3. Пользователь забанен, попытки отправить сообщение блокируются
  4. Админ: /banlist - видит список банов
  5. Админ: /unban (ответ на сообщение) - разбан

Временное закрытие чата

  1. Админ: /global_ban
  2. Все пользователи видят: " Чат временно закрыт администратором"
  3. Только админы могут писать
  4. Админ: /global_ban (повторно) - чат открыт

Удаление неприемлемого контента

  1. Пользователь отправил неприемлемое фото
  2. Фото разослано всем (режим broadcast)
  3. Админ отвечает на это сообщение: /delete_msg
  4. Бот удаляет фото у всех пользователей, кому оно было отправлено
  5. В БД сообщение помечается как удаленное

Технические детали

Порядок подключения роутеров

dp.include_router(registration_router)     # Первым
dp.include_router(admin_account_router)    
dp.include_router(admin_chat_router)       # До chat_router!
dp.include_router(redraw_router)
dp.include_router(account_router)
dp.include_router(chat_router)             # ПОСЛЕДНИМ (ловит все сообщения)
dp.include_router(router)
dp.include_router(admin_router)

Важно: chat_router должен быть последним, так как он ловит ВСЕ типы сообщений (text, photo, video и т.д.). Если поставить его раньше, он будет перехватывать команды и сообщения, предназначенные для других обработчиков.

Проверка прав

can_send, reason = await ChatPermissionService.can_send_message(
    session,
    telegram_id=user.telegram_id,
    is_admin=is_admin(user.telegram_id)
)

Логика проверки:

  1. Если пользователь админ → всегда can_send=True
  2. Если включен global_ban → can_send=False
  3. Если пользователь забанен → can_send=False
  4. Иначе → can_send=True

Миграция 005

При запуске миграции создаются 3 таблицы и вставляется начальная запись:

INSERT INTO chat_settings (id, mode, global_ban) 
VALUES (1, 'broadcast', false);

Эта запись будет использоваться всегда (единственная строка в таблице).

Возможные улучшения

  1. Фильтрация контента - автоматическая проверка на мат, спам, ссылки
  2. Лимиты - ограничение количества сообщений в минуту/час
  3. Ответы на сообщения - возможность отвечать на конкретное сообщение пользователя
  4. Редактирование - изменение отправленных сообщений
  5. Реакции - лайки/дизлайки на сообщения
  6. Каналы - разделение чата на темы/каналы
  7. История - просмотр истории сообщений через команду
  8. Поиск - поиск по истории сообщений