fix: исправлены импорты и добавлен планировщик рассылки
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Some checks reported errors
continuous-integration/drone/push Build encountered an error
- Исправлены импорты: database → src.core.database, config → src.core.config - Заменены async for get_session() на async with async_session_maker() - Добавлен планировщик для пакетной рассылки сообщений (BATCH_SIZE=20, BATCH_DELAY=1.0s) - Исправлено использование is_registered вместо is_active для фильтрации пользователей - Реализована защита от блокировки Telegram при массовой рассылке Изменения: - src/handlers/chat_handlers.py: добавлен broadcast_message_with_scheduler - src/handlers/admin_chat_handlers.py: исправлены импорты и использование сессий
This commit is contained in:
137
docs/CHAT_QUICKSTART.md
Normal file
137
docs/CHAT_QUICKSTART.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# Быстрый старт: Система чата
|
||||||
|
|
||||||
|
## Что реализовано
|
||||||
|
|
||||||
|
✅ **Два режима работы:**
|
||||||
|
- Broadcast: сообщения рассылаются всем пользователям
|
||||||
|
- Forward: сообщения пересылаются в канал/группу
|
||||||
|
|
||||||
|
✅ **7 типов сообщений:** text, photo, video, document, animation, sticker, voice
|
||||||
|
|
||||||
|
✅ **Система банов:**
|
||||||
|
- Личные баны пользователей с причиной
|
||||||
|
- Глобальный бан (закрытие чата для всех кроме админов)
|
||||||
|
|
||||||
|
✅ **Модерация:** удаление сообщений с отслеживанием
|
||||||
|
|
||||||
|
## Быстрая настройка
|
||||||
|
|
||||||
|
### 1. Режим рассылки (broadcast)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Админ отправляет команду:
|
||||||
|
/chat_mode
|
||||||
|
# → Нажимает "📢 Рассылка всем"
|
||||||
|
|
||||||
|
# Готово! Теперь сообщения пользователей рассылаются друг другу
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Режим пересылки (forward)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Шаг 1: Создайте канал и добавьте бота как админа
|
||||||
|
|
||||||
|
# Шаг 2: Узнайте chat_id канала:
|
||||||
|
# - Напишите в канале сообщение
|
||||||
|
# - Перешлите его @userinfobot
|
||||||
|
# - Скопируйте chat_id (например: -1001234567890)
|
||||||
|
|
||||||
|
# Шаг 3: Установите канал
|
||||||
|
/set_forward -1001234567890
|
||||||
|
|
||||||
|
# Шаг 4: Переключите режим
|
||||||
|
/chat_mode
|
||||||
|
# → Нажимает "➡️ Пересылка в канал"
|
||||||
|
|
||||||
|
# Готово! Сообщения пользователей пересылаются в канал
|
||||||
|
```
|
||||||
|
|
||||||
|
## Команды модерации
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Забанить пользователя (ответ на сообщение)
|
||||||
|
/ban Причина бана
|
||||||
|
|
||||||
|
# Забанить по ID
|
||||||
|
/ban 123456789 Спам
|
||||||
|
|
||||||
|
# Разбанить
|
||||||
|
/unban # (ответ на сообщение)
|
||||||
|
/unban 123456789
|
||||||
|
|
||||||
|
# Список банов
|
||||||
|
/banlist
|
||||||
|
|
||||||
|
# Закрыть/открыть чат для всех
|
||||||
|
/global_ban
|
||||||
|
|
||||||
|
# Удалить сообщение из всех чатов
|
||||||
|
/delete_msg # (ответ на сообщение)
|
||||||
|
|
||||||
|
# Статистика чата
|
||||||
|
/chat_stats
|
||||||
|
```
|
||||||
|
|
||||||
|
## Структура БД
|
||||||
|
|
||||||
|
```
|
||||||
|
chat_settings (1 строка)
|
||||||
|
├── mode: 'broadcast' | 'forward'
|
||||||
|
├── forward_chat_id: ID канала (если forward)
|
||||||
|
└── global_ban: true/false
|
||||||
|
|
||||||
|
banned_users
|
||||||
|
├── telegram_id: ID забаненного
|
||||||
|
├── banned_by: кто забанил
|
||||||
|
├── reason: причина
|
||||||
|
└── is_active: активен ли бан
|
||||||
|
|
||||||
|
chat_messages
|
||||||
|
├── user_id: отправитель
|
||||||
|
├── message_type: тип сообщения
|
||||||
|
├── text: текст или caption
|
||||||
|
├── file_id: ID файла
|
||||||
|
├── forwarded_message_ids: {user_id: msg_id} (JSONB)
|
||||||
|
├── is_deleted: удалено ли
|
||||||
|
└── deleted_by: кто удалил
|
||||||
|
```
|
||||||
|
|
||||||
|
## Файлы
|
||||||
|
|
||||||
|
| Файл | Описание | Строк |
|
||||||
|
|------|----------|-------|
|
||||||
|
| `migrations/versions/005_add_chat_system.py` | Миграция БД | 108 |
|
||||||
|
| `src/core/models.py` | Модели ORM (+67) | - |
|
||||||
|
| `src/core/chat_services.py` | Сервисы | 267 |
|
||||||
|
| `src/handlers/chat_handlers.py` | Обработчики сообщений | 447 |
|
||||||
|
| `src/handlers/admin_chat_handlers.py` | Админ команды | 369 |
|
||||||
|
| `docs/CHAT_SYSTEM.md` | Полная документация | 390 |
|
||||||
|
|
||||||
|
## Следующие шаги
|
||||||
|
|
||||||
|
1. **Тестирование:**
|
||||||
|
- Проверить broadcast режим с разными типами сообщений
|
||||||
|
- Проверить forward режим с каналом
|
||||||
|
- Протестировать баны и разбаны
|
||||||
|
- Проверить удаление сообщений
|
||||||
|
|
||||||
|
2. **Опциональные улучшения:**
|
||||||
|
- Фильтрация контента (мат, спам)
|
||||||
|
- Лимиты сообщений (антиспам)
|
||||||
|
- Ответы на сообщения
|
||||||
|
- Реакции на сообщения
|
||||||
|
- История чата через команду
|
||||||
|
|
||||||
|
## Коммит
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --oneline -1
|
||||||
|
# b6c27b7 feat: добавлена система чата с модерацией
|
||||||
|
|
||||||
|
# Ветка: feature/chat-system
|
||||||
|
# Изменений: 7 файлов, 1592 строки добавлено
|
||||||
|
```
|
||||||
|
|
||||||
|
## Полная документация
|
||||||
|
|
||||||
|
Смотрите: [docs/CHAT_SYSTEM.md](./CHAT_SYSTEM.md)
|
||||||
@@ -10,8 +10,8 @@ from src.core.chat_services import (
|
|||||||
ChatMessageService
|
ChatMessageService
|
||||||
)
|
)
|
||||||
from src.core.services import UserService
|
from src.core.services import UserService
|
||||||
from database import get_session
|
from src.core.database import async_session_maker
|
||||||
from config import ADMIN_IDS
|
from src.core.config import ADMIN_IDS
|
||||||
|
|
||||||
|
|
||||||
router = Router(name='admin_chat_router')
|
router = Router(name='admin_chat_router')
|
||||||
@@ -40,7 +40,7 @@ async def cmd_chat_mode(message: Message):
|
|||||||
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
settings = await ChatSettingsService.get_or_create_settings(session)
|
settings = await ChatSettingsService.get_or_create_settings(session)
|
||||||
|
|
||||||
mode_text = "📢 Рассылка всем пользователям" if settings.mode == 'broadcast' else "➡️ Пересылка в канал"
|
mode_text = "📢 Рассылка всем пользователям" if settings.mode == 'broadcast' else "➡️ Пересылка в канал"
|
||||||
@@ -63,7 +63,7 @@ async def process_chat_mode(callback: CallbackQuery):
|
|||||||
|
|
||||||
mode = callback.data.split(":")[1]
|
mode = callback.data.split(":")[1]
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
settings = await ChatSettingsService.set_mode(session, mode)
|
settings = await ChatSettingsService.set_mode(session, mode)
|
||||||
|
|
||||||
mode_text = "📢 Рассылка всем пользователям" if mode == 'broadcast' else "➡️ Пересылка в канал"
|
mode_text = "📢 Рассылка всем пользователям" if mode == 'broadcast' else "➡️ Пересылка в канал"
|
||||||
@@ -100,7 +100,7 @@ async def cmd_set_forward(message: Message):
|
|||||||
|
|
||||||
chat_id = args[1].strip()
|
chat_id = args[1].strip()
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
settings = await ChatSettingsService.set_forward_chat(session, chat_id)
|
settings = await ChatSettingsService.set_forward_chat(session, chat_id)
|
||||||
|
|
||||||
await message.answer(
|
await message.answer(
|
||||||
@@ -118,7 +118,7 @@ async def cmd_global_ban(message: Message):
|
|||||||
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
settings = await ChatSettingsService.get_or_create_settings(session)
|
settings = await ChatSettingsService.get_or_create_settings(session)
|
||||||
|
|
||||||
# Переключаем состояние
|
# Переключаем состояние
|
||||||
@@ -169,7 +169,7 @@ async def cmd_ban(message: Message):
|
|||||||
await message.answer("❌ Неверный ID пользователя")
|
await message.answer("❌ Неверный ID пользователя")
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
# Получаем пользователя
|
# Получаем пользователя
|
||||||
user = await UserService.get_user_by_telegram_id(session, target_user_id)
|
user = await UserService.get_user_by_telegram_id(session, target_user_id)
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ async def cmd_unban(message: Message):
|
|||||||
await message.answer("❌ Неверный ID пользователя")
|
await message.answer("❌ Неверный ID пользователя")
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
# Разбаниваем
|
# Разбаниваем
|
||||||
success = await BanService.unban_user(session, target_user_id)
|
success = await BanService.unban_user(session, target_user_id)
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ async def cmd_banlist(message: Message):
|
|||||||
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
banned_users = await BanService.get_banned_users(session, active_only=True)
|
banned_users = await BanService.get_banned_users(session, active_only=True)
|
||||||
|
|
||||||
if not banned_users:
|
if not banned_users:
|
||||||
@@ -290,7 +290,7 @@ async def cmd_delete_message(message: Message):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
# Получаем админа
|
# Получаем админа
|
||||||
admin = await UserService.get_user_by_telegram_id(session, message.from_user.id)
|
admin = await UserService.get_user_by_telegram_id(session, message.from_user.id)
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ async def cmd_chat_stats(message: Message):
|
|||||||
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
await message.answer("❌ У вас нет прав для выполнения этой команды")
|
||||||
return
|
return
|
||||||
|
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
settings = await ChatSettingsService.get_or_create_settings(session)
|
settings = await ChatSettingsService.get_or_create_settings(session)
|
||||||
banned_users = await BanService.get_banned_users(session, active_only=True)
|
banned_users = await BanService.get_banned_users(session, active_only=True)
|
||||||
recent_messages = await ChatMessageService.get_recent_messages(session, limit=100)
|
recent_messages = await ChatMessageService.get_recent_messages(session, limit=100)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
from aiogram import Router, F
|
from aiogram import Router, F
|
||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
import asyncio
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
|
||||||
from src.core.chat_services import (
|
from src.core.chat_services import (
|
||||||
ChatSettingsService,
|
ChatSettingsService,
|
||||||
@@ -10,8 +12,8 @@ from src.core.chat_services import (
|
|||||||
BanService
|
BanService
|
||||||
)
|
)
|
||||||
from src.core.services import UserService
|
from src.core.services import UserService
|
||||||
from database import get_session
|
from src.core.database import async_session_maker
|
||||||
from config import ADMIN_IDS
|
from src.core.config import ADMIN_IDS
|
||||||
|
|
||||||
|
|
||||||
def is_admin(user_id: int) -> bool:
|
def is_admin(user_id: int) -> bool:
|
||||||
@@ -21,39 +23,75 @@ def is_admin(user_id: int) -> bool:
|
|||||||
|
|
||||||
router = Router(name='chat_router')
|
router = Router(name='chat_router')
|
||||||
|
|
||||||
|
# Настройки для планировщика рассылки
|
||||||
|
BATCH_SIZE = 20 # Количество сообщений в пакете
|
||||||
|
BATCH_DELAY = 1.0 # Задержка между пакетами в секундах
|
||||||
|
|
||||||
async def get_all_active_users(session: AsyncSession):
|
|
||||||
"""Получить всех активных пользователей для рассылки"""
|
async def get_all_active_users(session: AsyncSession) -> List:
|
||||||
|
"""Получить всех зарегистрированных пользователей для рассылки"""
|
||||||
users = await UserService.get_all_users(session)
|
users = await UserService.get_all_users(session)
|
||||||
return [u for u in users if u.is_active]
|
return [u for u in users if u.is_registered] # Используем is_registered вместо is_active
|
||||||
|
|
||||||
|
|
||||||
async def broadcast_message(message: Message, exclude_user_id: int = None):
|
async def broadcast_message_with_scheduler(message: Message, exclude_user_id: Optional[int] = None) -> tuple[Dict[str, int], int, int]:
|
||||||
"""Разослать сообщение всем пользователям"""
|
"""
|
||||||
async for session in get_session():
|
Разослать сообщение всем пользователям с планировщиком (пакетная отправка).
|
||||||
|
Возвращает: (forwarded_ids, success_count, fail_count)
|
||||||
|
"""
|
||||||
|
async with async_session_maker() as session:
|
||||||
users = await get_all_active_users(session)
|
users = await get_all_active_users(session)
|
||||||
|
|
||||||
|
if exclude_user_id:
|
||||||
|
users = [u for u in users if u.telegram_id != exclude_user_id]
|
||||||
|
|
||||||
|
forwarded_ids = {}
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
|
||||||
|
# Разбиваем на пакеты
|
||||||
|
for i in range(0, len(users), BATCH_SIZE):
|
||||||
|
batch = users[i:i + BATCH_SIZE]
|
||||||
|
|
||||||
forwarded_ids = {}
|
# Отправляем пакет
|
||||||
success_count = 0
|
tasks = []
|
||||||
fail_count = 0
|
for user in batch:
|
||||||
|
tasks.append(_send_message_to_user(message, user.telegram_id))
|
||||||
|
|
||||||
for user in users:
|
# Ждем завершения пакета
|
||||||
if exclude_user_id and user.telegram_id == exclude_user_id:
|
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||||
continue
|
|
||||||
|
# Обрабатываем результаты
|
||||||
try:
|
for user, result in zip(batch, results):
|
||||||
# Копируем сообщение пользователю
|
if isinstance(result, Exception):
|
||||||
sent_msg = await message.copy_to(user.telegram_id)
|
fail_count += 1
|
||||||
forwarded_ids[str(user.telegram_id)] = sent_msg.message_id
|
elif result is not None:
|
||||||
success_count += 1
|
forwarded_ids[str(user.telegram_id)] = result
|
||||||
except Exception as e:
|
success_count += 1
|
||||||
|
else:
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
print(f"Failed to send message to {user.telegram_id}: {e}")
|
|
||||||
|
|
||||||
return forwarded_ids, success_count, fail_count
|
# Задержка между пакетами (если есть еще пакеты)
|
||||||
|
if i + BATCH_SIZE < len(users):
|
||||||
|
await asyncio.sleep(BATCH_DELAY)
|
||||||
|
|
||||||
|
return forwarded_ids, success_count, fail_count
|
||||||
|
|
||||||
|
|
||||||
async def forward_to_channel(message: Message, channel_id: str):
|
async def _send_message_to_user(message: Message, user_telegram_id: int) -> Optional[int]:
|
||||||
|
"""
|
||||||
|
Отправить сообщение конкретному пользователю.
|
||||||
|
Возвращает message_id при успехе или None при ошибке.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
sent_msg = await message.copy_to(user_telegram_id)
|
||||||
|
return sent_msg.message_id
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to send message to {user_telegram_id}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def forward_to_channel(message: Message, channel_id: str) -> tuple[bool, Optional[int]]:
|
||||||
"""Переслать сообщение в канал/группу"""
|
"""Переслать сообщение в канал/группу"""
|
||||||
try:
|
try:
|
||||||
# Пересылаем сообщение в канал
|
# Пересылаем сообщение в канал
|
||||||
@@ -67,7 +105,7 @@ async def forward_to_channel(message: Message, channel_id: str):
|
|||||||
@router.message(F.text)
|
@router.message(F.text)
|
||||||
async def handle_text_message(message: Message):
|
async def handle_text_message(message: Message):
|
||||||
"""Обработчик текстовых сообщений"""
|
"""Обработчик текстовых сообщений"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
# Проверяем права на отправку
|
# Проверяем права на отправку
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
@@ -90,8 +128,8 @@ async def handle_text_message(message: Message):
|
|||||||
|
|
||||||
# Обрабатываем в зависимости от режима
|
# Обрабатываем в зависимости от режима
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
# Режим рассылки
|
# Режим рассылки с планировщиком
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
# Сохраняем сообщение в историю
|
# Сохраняем сообщение в историю
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
@@ -125,7 +163,7 @@ async def handle_text_message(message: Message):
|
|||||||
telegram_message_id=message.message_id,
|
telegram_message_id=message.message_id,
|
||||||
message_type='text',
|
message_type='text',
|
||||||
text=message.text,
|
text=message.text,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
|
|
||||||
await message.answer("✅ Сообщение переслано в канал")
|
await message.answer("✅ Сообщение переслано в канал")
|
||||||
@@ -136,10 +174,11 @@ async def handle_text_message(message: Message):
|
|||||||
@router.message(F.photo)
|
@router.message(F.photo)
|
||||||
async def handle_photo_message(message: Message):
|
async def handle_photo_message(message: Message):
|
||||||
"""Обработчик фото"""
|
"""Обработчик фото"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
message.from_user.id
|
message.from_user.id,
|
||||||
|
is_admin=is_admin(message.from_user.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not can_send:
|
if not can_send:
|
||||||
@@ -156,7 +195,7 @@ async def handle_photo_message(message: Message):
|
|||||||
photo = message.photo[-1]
|
photo = message.photo[-1]
|
||||||
|
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
session,
|
session,
|
||||||
@@ -182,7 +221,7 @@ async def handle_photo_message(message: Message):
|
|||||||
message_type='photo',
|
message_type='photo',
|
||||||
text=message.caption,
|
text=message.caption,
|
||||||
file_id=photo.file_id,
|
file_id=photo.file_id,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
await message.answer("✅ Фото переслано в канал")
|
await message.answer("✅ Фото переслано в канал")
|
||||||
|
|
||||||
@@ -190,10 +229,11 @@ async def handle_photo_message(message: Message):
|
|||||||
@router.message(F.video)
|
@router.message(F.video)
|
||||||
async def handle_video_message(message: Message):
|
async def handle_video_message(message: Message):
|
||||||
"""Обработчик видео"""
|
"""Обработчик видео"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
message.from_user.id
|
message.from_user.id,
|
||||||
|
is_admin=is_admin(message.from_user.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not can_send:
|
if not can_send:
|
||||||
@@ -207,7 +247,7 @@ async def handle_video_message(message: Message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
session,
|
session,
|
||||||
@@ -233,7 +273,7 @@ async def handle_video_message(message: Message):
|
|||||||
message_type='video',
|
message_type='video',
|
||||||
text=message.caption,
|
text=message.caption,
|
||||||
file_id=message.video.file_id,
|
file_id=message.video.file_id,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
await message.answer("✅ Видео переслано в канал")
|
await message.answer("✅ Видео переслано в канал")
|
||||||
|
|
||||||
@@ -241,10 +281,11 @@ async def handle_video_message(message: Message):
|
|||||||
@router.message(F.document)
|
@router.message(F.document)
|
||||||
async def handle_document_message(message: Message):
|
async def handle_document_message(message: Message):
|
||||||
"""Обработчик документов"""
|
"""Обработчик документов"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
message.from_user.id
|
message.from_user.id,
|
||||||
|
is_admin=is_admin(message.from_user.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not can_send:
|
if not can_send:
|
||||||
@@ -258,7 +299,7 @@ async def handle_document_message(message: Message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
session,
|
session,
|
||||||
@@ -284,7 +325,7 @@ async def handle_document_message(message: Message):
|
|||||||
message_type='document',
|
message_type='document',
|
||||||
text=message.caption,
|
text=message.caption,
|
||||||
file_id=message.document.file_id,
|
file_id=message.document.file_id,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
await message.answer("✅ Документ переслан в канал")
|
await message.answer("✅ Документ переслан в канал")
|
||||||
|
|
||||||
@@ -292,10 +333,11 @@ async def handle_document_message(message: Message):
|
|||||||
@router.message(F.animation)
|
@router.message(F.animation)
|
||||||
async def handle_animation_message(message: Message):
|
async def handle_animation_message(message: Message):
|
||||||
"""Обработчик GIF анимаций"""
|
"""Обработчик GIF анимаций"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
message.from_user.id
|
message.from_user.id,
|
||||||
|
is_admin=is_admin(message.from_user.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not can_send:
|
if not can_send:
|
||||||
@@ -309,7 +351,7 @@ async def handle_animation_message(message: Message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
session,
|
session,
|
||||||
@@ -335,7 +377,7 @@ async def handle_animation_message(message: Message):
|
|||||||
message_type='animation',
|
message_type='animation',
|
||||||
text=message.caption,
|
text=message.caption,
|
||||||
file_id=message.animation.file_id,
|
file_id=message.animation.file_id,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
await message.answer("✅ Анимация переслана в канал")
|
await message.answer("✅ Анимация переслана в канал")
|
||||||
|
|
||||||
@@ -343,10 +385,11 @@ async def handle_animation_message(message: Message):
|
|||||||
@router.message(F.sticker)
|
@router.message(F.sticker)
|
||||||
async def handle_sticker_message(message: Message):
|
async def handle_sticker_message(message: Message):
|
||||||
"""Обработчик стикеров"""
|
"""Обработчик стикеров"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
message.from_user.id
|
message.from_user.id,
|
||||||
|
is_admin=is_admin(message.from_user.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not can_send:
|
if not can_send:
|
||||||
@@ -360,7 +403,7 @@ async def handle_sticker_message(message: Message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
session,
|
session,
|
||||||
@@ -384,7 +427,7 @@ async def handle_sticker_message(message: Message):
|
|||||||
telegram_message_id=message.message_id,
|
telegram_message_id=message.message_id,
|
||||||
message_type='sticker',
|
message_type='sticker',
|
||||||
file_id=message.sticker.file_id,
|
file_id=message.sticker.file_id,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
await message.answer("✅ Стикер переслан в канал")
|
await message.answer("✅ Стикер переслан в канал")
|
||||||
|
|
||||||
@@ -392,10 +435,11 @@ async def handle_sticker_message(message: Message):
|
|||||||
@router.message(F.voice)
|
@router.message(F.voice)
|
||||||
async def handle_voice_message(message: Message):
|
async def handle_voice_message(message: Message):
|
||||||
"""Обработчик голосовых сообщений"""
|
"""Обработчик голосовых сообщений"""
|
||||||
async for session in get_session():
|
async with async_session_maker() as session:
|
||||||
can_send, reason = await ChatPermissionService.can_send_message(
|
can_send, reason = await ChatPermissionService.can_send_message(
|
||||||
session,
|
session,
|
||||||
message.from_user.id
|
message.from_user.id,
|
||||||
|
is_admin=is_admin(message.from_user.id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not can_send:
|
if not can_send:
|
||||||
@@ -409,7 +453,7 @@ async def handle_voice_message(message: Message):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if settings.mode == 'broadcast':
|
if settings.mode == 'broadcast':
|
||||||
forwarded_ids, success, fail = await broadcast_message(message, exclude_user_id=message.from_user.id)
|
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
|
||||||
|
|
||||||
await ChatMessageService.save_message(
|
await ChatMessageService.save_message(
|
||||||
session,
|
session,
|
||||||
@@ -433,6 +477,6 @@ async def handle_voice_message(message: Message):
|
|||||||
telegram_message_id=message.message_id,
|
telegram_message_id=message.message_id,
|
||||||
message_type='voice',
|
message_type='voice',
|
||||||
file_id=message.voice.file_id,
|
file_id=message.voice.file_id,
|
||||||
forwarded_ids={'channel': channel_msg_id}
|
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
|
||||||
)
|
)
|
||||||
await message.answer("✅ Голосовое сообщение переслано в канал")
|
await message.answer("✅ Голосовое сообщение переслано в канал")
|
||||||
|
|||||||
Reference in New Issue
Block a user