feature/chat-system #2

Merged
trevor merged 28 commits from feature/chat-system into master 2025-11-17 06:05:49 +00:00
33 changed files with 11415 additions and 401 deletions
Showing only changes of commit 9e07b768f5 - Show all commits

View File

@@ -104,43 +104,39 @@ async def forward_to_channel(message: Message, channel_id: str) -> tuple[bool, O
@router.message(F.text)
async def handle_text_message(message: Message):
"""
Обработчик текстовых сообщений - глобальный чат (broadcast всем)
Сообщения автоматически рассылаются всем пользователям, кроме:
- Команд (начинаются с /)
- Паттернов счетов для админов (обрабатываются в account_handlers)
"""
# 1. Проверяем является ли это командой
"""Обработчик текстовых сообщений"""
# Проверяем является ли это командой
if message.text and message.text.startswith('/'):
# Список известных команд
user_commands = ['/my_code', '/my_accounts', '/chat']
# Список команд, которые НЕ нужно пересылать
# (Базовые команды /start, /help уже обработаны раньше в main.py)
user_commands = ['/my_code', '/my_accounts']
admin_commands = [
'/add_account', '/remove_account', '/verify_winner', '/winner_status', '/user_info',
'/check_unclaimed', '/redraw', '/admin', '/delete',
'/check_unclaimed', '/redraw',
'/chat_mode', '/set_forward', '/global_ban', '/ban', '/unban', '/banlist', '/delete_msg', '/chat_stats'
]
# Извлекаем команду (первое слово)
command = message.text.split()[0] if message.text else ''
# Если это известная команда - пропускаем (будет обработана другими обработчиками)
if command in user_commands or command in admin_commands:
# Если это пользовательская команда - пропускаем, она будет обработана другими обработчиками
if command in user_commands:
return
# Неизвестная команда - тоже не рассылаем
# Если это админская команда
if command in admin_commands:
# Проверяем права админа
if not is_admin(message.from_user.id):
await message.answer("У вас нет прав для выполнения этой команды")
return
# Если админ - команда будет обработана другими обработчиками, пропускаем пересылку
return
# Если неизвестная команда - тоже не пересылаем
return
# 2. Для админов - проверяем на паттерн счетов
if is_admin(message.from_user.id):
from ..utils.account_utils import parse_accounts_from_message
accounts = parse_accounts_from_message(message.text)
if accounts:
# Это сообщение с счетами - пропускаем, обработает account_handlers
return
# 3. Проверяем права на отправку в чат
async with async_session_maker() as session:
# Проверяем права на отправку
can_send, reason = await ChatPermissionService.can_send_message(
session,
message.from_user.id,
@@ -151,35 +147,63 @@ async def handle_text_message(message: Message):
await message.answer(f"{reason}")
return
# Получаем настройки чата
settings = await ChatSettingsService.get_or_create_settings(session)
# Получаем пользователя
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("Вы не зарегистрированы. Используйте /start")
await message.answer("Пользователь не найден")
return
# 4. Рассылаем сообщение всем (broadcast)
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
# Сохраняем сообщение в историю
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='text',
text=message.text,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Сообщение разослано!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
# Обрабатываем в зависимости от режима
if settings.mode == 'broadcast':
# Режим рассылки с планировщиком
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
# Сохраняем сообщение в историю
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='text',
text=message.text,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Сообщение разослано!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
elif settings.mode == 'forward':
# Режим пересылки в канал
if not settings.forward_chat_id:
await message.answer("❌ Канал для пересылки не настроен")
return
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
# Сохраняем сообщение в историю
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='text',
text=message.text,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Сообщение переслано в канал")
else:
await message.answer("Не удалось переслать сообщение")
@router.message(F.photo)
async def handle_photo_message(message: Message):
"""Обработчик фото - глобальный чат (broadcast всем)"""
"""Обработчик фото"""
async with async_session_maker() as session:
can_send, reason = await ChatPermissionService.can_send_message(
session,
@@ -191,38 +215,50 @@ async def handle_photo_message(message: Message):
await message.answer(f"{reason}")
return
settings = await ChatSettingsService.get_or_create_settings(session)
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("❌ Вы не зарегистрированы. Используйте /start")
return
# Получаем file_id самого большого фото
photo = message.photo[-1]
# Рассылаем всем
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='photo',
text=message.caption,
file_id=photo.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Фото разослано!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
if settings.mode == 'broadcast':
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='photo',
text=message.caption,
file_id=photo.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(f"✅ Фото разослано: {success} получателей")
elif settings.mode == 'forward':
if settings.forward_chat_id:
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='photo',
text=message.caption,
file_id=photo.file_id,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Фото переслано в канал")
@router.message(F.video)
async def handle_video_message(message: Message):
"""Обработчик видео - глобальный чат (broadcast всем)"""
"""Обработчик видео"""
async with async_session_maker() as session:
can_send, reason = await ChatPermissionService.can_send_message(
session,
@@ -234,35 +270,47 @@ async def handle_video_message(message: Message):
await message.answer(f"{reason}")
return
settings = await ChatSettingsService.get_or_create_settings(session)
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("❌ Вы не зарегистрированы. Используйте /start")
return
# Рассылаем всем
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='video',
text=message.caption,
file_id=message.video.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Видео разослано!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
if settings.mode == 'broadcast':
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='video',
text=message.caption,
file_id=message.video.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(f"✅ Видео разослано: {success} получателей")
elif settings.mode == 'forward':
if settings.forward_chat_id:
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='video',
text=message.caption,
file_id=message.video.file_id,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Видео переслано в канал")
@router.message(F.document)
async def handle_document_message(message: Message):
"""Обработчик документов - глобальный чат (broadcast всем)"""
"""Обработчик документов"""
async with async_session_maker() as session:
can_send, reason = await ChatPermissionService.can_send_message(
session,
@@ -274,34 +322,47 @@ async def handle_document_message(message: Message):
await message.answer(f"{reason}")
return
settings = await ChatSettingsService.get_or_create_settings(session)
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("❌ Вы не зарегистрированы. Используйте /start")
return
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='document',
text=message.caption,
file_id=message.document.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Документ разослан!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
if settings.mode == 'broadcast':
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='document',
text=message.caption,
file_id=message.document.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(f"✅ Документ разослан: {success} получателей")
elif settings.mode == 'forward':
if settings.forward_chat_id:
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='document',
text=message.caption,
file_id=message.document.file_id,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Документ переслан в канал")
@router.message(F.animation)
async def handle_animation_message(message: Message):
"""Обработчик GIF анимаций - глобальный чат (broadcast всем)"""
"""Обработчик GIF анимаций"""
async with async_session_maker() as session:
can_send, reason = await ChatPermissionService.can_send_message(
session,
@@ -313,34 +374,47 @@ async def handle_animation_message(message: Message):
await message.answer(f"{reason}")
return
settings = await ChatSettingsService.get_or_create_settings(session)
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("❌ Вы не зарегистрированы. Используйте /start")
return
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='animation',
text=message.caption,
file_id=message.animation.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Анимация разослана!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
if settings.mode == 'broadcast':
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='animation',
text=message.caption,
file_id=message.animation.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(f"✅ Анимация разослана: {success} получателей")
elif settings.mode == 'forward':
if settings.forward_chat_id:
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='animation',
text=message.caption,
file_id=message.animation.file_id,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Анимация переслана в канал")
@router.message(F.sticker)
async def handle_sticker_message(message: Message):
"""Обработчик стикеров - глобальный чат (broadcast всем)"""
"""Обработчик стикеров"""
async with async_session_maker() as session:
can_send, reason = await ChatPermissionService.can_send_message(
session,
@@ -352,33 +426,45 @@ async def handle_sticker_message(message: Message):
await message.answer(f"{reason}")
return
settings = await ChatSettingsService.get_or_create_settings(session)
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("❌ Вы не зарегистрированы. Используйте /start")
return
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='sticker',
file_id=message.sticker.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Стикер разослан!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
if settings.mode == 'broadcast':
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='sticker',
file_id=message.sticker.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(f"✅ Стикер разослан: {success} получателей")
elif settings.mode == 'forward':
if settings.forward_chat_id:
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='sticker',
file_id=message.sticker.file_id,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Стикер переслан в канал")
@router.message(F.voice)
async def handle_voice_message(message: Message):
"""Обработчик голосовых сообщений - глобальный чат (broadcast всем)"""
"""Обработчик голосовых сообщений"""
async with async_session_maker() as session:
can_send, reason = await ChatPermissionService.can_send_message(
session,
@@ -390,25 +476,37 @@ async def handle_voice_message(message: Message):
await message.answer(f"{reason}")
return
settings = await ChatSettingsService.get_or_create_settings(session)
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
if not user:
await message.answer("❌ Вы не зарегистрированы. Используйте /start")
return
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='voice',
file_id=message.voice.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(
f"✅ Голосовое сообщение разослано!\n"
f"📤 Доставлено: {success}\n"
f"Не доставлено: {fail}"
)
if settings.mode == 'broadcast':
forwarded_ids, success, fail = await broadcast_message_with_scheduler(message, exclude_user_id=message.from_user.id)
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='voice',
file_id=message.voice.file_id,
forwarded_ids=forwarded_ids
)
await message.answer(f"✅ Голосовое сообщение разослано: {success} получателей")
elif settings.mode == 'forward':
if settings.forward_chat_id:
success, channel_msg_id = await forward_to_channel(message, settings.forward_chat_id)
if success:
await ChatMessageService.save_message(
session,
user_id=user.id,
telegram_message_id=message.message_id,
message_type='voice',
file_id=message.voice.file_id,
forwarded_ids={'channel': channel_msg_id} if channel_msg_id else None
)
await message.answer("✅ Голосовое сообщение переслано в канал")