- Quick delete теперь удаляет сообщения у всех получателей broadcast - Добавлен метод get_message_by_telegram_id в ChatMessageService - При удалении проходит по всем forwarded_message_ids и удаляет у каждого - Показывает статистику удаления админу (автоматически исчезает через 3 сек) - Помечает сообщение как удалённое в БД
163 lines
6.8 KiB
Python
163 lines
6.8 KiB
Python
"""
|
||
Хэндлеры для управления сообщениями администратором
|
||
"""
|
||
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
|