Files
new_lottery_bot/src/handlers/message_management.py
Andrew K. Choi 84adcce57b feat: массовое удаление broadcast сообщений у всех получателей
- Quick delete теперь удаляет сообщения у всех получателей broadcast
- Добавлен метод get_message_by_telegram_id в ChatMessageService
- При удалении проходит по всем forwarded_message_ids и удаляет у каждого
- Показывает статистику удаления админу (автоматически исчезает через 3 сек)
- Помечает сообщение как удалённое в БД
2025-11-17 11:54:15 +09:00

163 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Хэндлеры для управления сообщениями администратором
"""
import logging
from aiogram import Router, F, Bot
from aiogram.types import Message, CallbackQuery
from aiogram.filters import Command
from ..core.config import ADMIN_IDS
from ..core.database import async_session_maker
from ..core.chat_services import ChatMessageService
logger = logging.getLogger(__name__)
message_admin_router = Router(name="message_admin")
def is_admin(user_id: int) -> bool:
"""Проверка, является ли пользователь администратором"""
return user_id in ADMIN_IDS
@message_admin_router.message(Command("delete"))
async def delete_replied_message(message: Message):
"""
Удаление сообщения по команде /delete
Работает только если команда является ответом на сообщение бота
"""
if not is_admin(message.from_user.id):
await message.answer("❌ Недостаточно прав")
return
if not message.reply_to_message:
await message.answer("⚠️ Ответьте на сообщение бота командой /delete чтобы удалить его")
return
if message.reply_to_message.from_user.id != message.bot.id:
await message.answer("⚠️ Можно удалять только сообщения бота")
return
try:
# Удаляем сообщение бота
await message.reply_to_message.delete()
# Удаляем команду
await message.delete()
logger.info(f"Администратор {message.from_user.id} удалил сообщение {message.reply_to_message.message_id}")
except Exception as e:
logger.error(f"Ошибка при удалении сообщения: {e}")
await message.answer(f"Не удалось удалить сообщение: {str(e)}")
@message_admin_router.callback_query(F.data == "delete_message")
async def delete_message_callback(callback: CallbackQuery):
"""
Удаление сообщения по нажатию кнопки
"""
if not is_admin(callback.from_user.id):
await callback.answer("❌ Недостаточно прав", show_alert=True)
return
try:
await callback.message.delete()
await callback.answer("✅ Сообщение удалено")
logger.info(f"Администратор {callback.from_user.id} удалил сообщение через кнопку")
except Exception as e:
logger.error(f"Ошибка при удалении сообщения через кнопку: {e}")
await callback.answer(f"❌ Ошибка: {str(e)}", show_alert=True)
# Функция-фильтр для проверки триггерных слов
def is_delete_trigger(message: Message) -> bool:
"""Проверяет, является ли сообщение триггером для удаления"""
if not message.text:
return False
text_lower = message.text.lower().strip()
triggers = ["удалить", "delete", "del", "🗑️", "🗑", ""]
return any(trigger in text_lower for trigger in triggers)
@message_admin_router.message(F.reply_to_message, is_delete_trigger)
async def quick_delete_replied_message(message: Message):
"""
Быстрое удаление сообщения по reply с триггерными словами или emoji
Работает для админов при ответе на любое сообщение
Триггеры:
- "удалить", "delete", "del"
- 🗑️ (мусорная корзина)
- ❌ (крестик)
Удаляет сообщение у всех получателей broadcast рассылки
"""
if not is_admin(message.from_user.id):
return # Не админ - пропускаем
try:
replied_msg = message.reply_to_message
deleted_count = 0
# Пытаемся найти сообщение в БД по telegram_message_id
async with async_session_maker() as session:
chat_message = await ChatMessageService.get_message_by_telegram_id(
session,
telegram_message_id=replied_msg.message_id
)
# Если нашли broadcast сообщение - удаляем у всех получателей
if chat_message and chat_message.forwarded_message_ids:
bot = message.bot
for user_telegram_id, forwarded_msg_id in chat_message.forwarded_message_ids.items():
try:
await bot.delete_message(
chat_id=int(user_telegram_id),
message_id=forwarded_msg_id
)
deleted_count += 1
except Exception as e:
logger.warning(f"Не удалось удалить сообщение у {user_telegram_id}: {e}")
# Помечаем как удалённое в БД
await ChatMessageService.delete_message(
session,
message_id=chat_message.id,
deleted_by=message.from_user.id
)
logger.info(
f"Администратор {message.from_user.id} удалил broadcast сообщение "
f"{replied_msg.message_id} у {deleted_count} получателей"
)
# Удаляем исходное сообщение (на которое ответили)
await replied_msg.delete()
# Удаляем команду админа
await message.delete()
# Если было broadcast удаление - показываем статистику
if deleted_count > 0:
status_msg = await message.answer(
f"✅ Сообщение удалено у {deleted_count} получателей",
reply_to_message_id=None
)
# Удаляем статус через 3 секунды
import asyncio
await asyncio.sleep(3)
try:
await status_msg.delete()
except:
pass
except Exception as e:
logger.error(f"Ошибка при быстром удалении сообщения: {e}")
try:
await message.answer(
f"Не удалось удалить: {str(e)}",
reply_to_message_id=message.message_id
)
except:
pass