Вывод всех запрещенных слов
This commit is contained in:
243
bot/handlers/commands/users/listwords.py
Normal file
243
bot/handlers/commands/users/listwords.py
Normal file
@@ -0,0 +1,243 @@
|
||||
"""
|
||||
Обработчик команды /listwords - отображение всех правил модерации
|
||||
"""
|
||||
from aiogram import Router, F
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import Message, CallbackQuery
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
|
||||
from bot.filters.admin import IsAdmin
|
||||
from configs import settings, COMMANDS
|
||||
from database import get_manager
|
||||
from middleware.loggers import logger
|
||||
from bot.utils.decorators import log_action
|
||||
|
||||
__all__ = ("router",)
|
||||
CMD: str = "list"
|
||||
router: Router = Router(name="listwords_cmd_router")
|
||||
|
||||
|
||||
def get_refresh_kb(page: int = 0):
|
||||
"""Клавиатура с кнопкой обновления"""
|
||||
ikb = InlineKeyboardBuilder()
|
||||
ikb.button(text="🔄 Обновить", callback_data=f"listwords:refresh:{page}")
|
||||
ikb.button(text="📊 Статистика", callback_data="stats")
|
||||
ikb.adjust(2)
|
||||
return ikb.as_markup()
|
||||
|
||||
|
||||
async def format_banwords_list(page: int = 0) -> str:
|
||||
"""
|
||||
Форматирует список всех банвордов с разбивкой по типам.
|
||||
|
||||
Args:
|
||||
page: Номер страницы (для будущей пагинации)
|
||||
|
||||
Returns:
|
||||
Отформатированная строка со всеми правилами
|
||||
"""
|
||||
manager = get_manager()
|
||||
|
||||
# Получаем все данные из БД
|
||||
try:
|
||||
# Используем существующий метод get_all_words_list()
|
||||
data = await manager.get_all_words_list()
|
||||
stats = await manager.get_stats()
|
||||
|
||||
# Извлекаем данные из словаря
|
||||
permanent_words = list(data.get('substring', set()))
|
||||
permanent_lemmas = list(data.get('lemma', set()))
|
||||
permanent_parts = list(data.get('part', set()))
|
||||
temp_words = list(data.get('temp_substring', set()))
|
||||
temp_lemmas = list(data.get('temp_lemma', set()))
|
||||
conflict_words = list(data.get('conflict_substring', set()))
|
||||
conflict_lemmas = list(data.get('conflict_lemma', set()))
|
||||
exceptions = list(data.get('whitelist', set()))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка получения данных из БД: {e}", log_type="LISTWORDS")
|
||||
return "❌ <b>Ошибка загрузки данных из базы</b>"
|
||||
|
||||
# === ФОРМИРУЕМ ВЫВОД ===
|
||||
|
||||
output = "📋 <b>СПИСОК ПРАВИЛ МОДЕРАЦИИ</b>\n\n"
|
||||
|
||||
# Статистика
|
||||
total_count = (
|
||||
len(permanent_words) + len(permanent_lemmas) + len(permanent_parts) +
|
||||
len(temp_words) + len(temp_lemmas) +
|
||||
len(conflict_words) + len(conflict_lemmas)
|
||||
)
|
||||
|
||||
output += f"📊 <b>Общая статистика:</b>\n"
|
||||
output += f"├─ Всего правил: <code>{total_count}</code>\n"
|
||||
output += f"├─ Исключений: <code>{len(exceptions)}</code>\n"
|
||||
output += f"├─ Удалений за всё время: <code>{stats.get('total_deletions', 0)}</code>\n"
|
||||
output += f"└─ Администраторов: <code>{stats.get('admins', 0)}</code>\n\n"
|
||||
|
||||
# === ПОСТОЯННЫЕ ПРАВИЛА ===
|
||||
if permanent_words or permanent_lemmas or permanent_parts:
|
||||
output += "🔴 <b>ПОСТОЯННЫЕ ПРАВИЛА:</b>\n\n"
|
||||
|
||||
if permanent_words:
|
||||
output += f"📝 <b>Подстроки</b> ({len(permanent_words)}):\n"
|
||||
words_str = ', '.join([f"<code>{w}</code>" for w in sorted(permanent_words)[:20]])
|
||||
if len(permanent_words) > 20:
|
||||
words_str += f" ... <i>(+{len(permanent_words) - 20} ещё)</i>"
|
||||
output += f"{words_str}\n\n"
|
||||
|
||||
if permanent_lemmas:
|
||||
output += f"🔤 <b>Леммы</b> ({len(permanent_lemmas)}):\n"
|
||||
lemmas_str = ', '.join([f"<code>{w}</code>" for w in sorted(permanent_lemmas)[:20]])
|
||||
if len(permanent_lemmas) > 20:
|
||||
lemmas_str += f" ... <i>(+{len(permanent_lemmas) - 20} ещё)</i>"
|
||||
output += f"{lemmas_str}\n\n"
|
||||
|
||||
if permanent_parts:
|
||||
output += f"🧩 <b>Части</b> ({len(permanent_parts)}):\n"
|
||||
parts_str = ', '.join([f"<code>{w}</code>" for w in sorted(permanent_parts)[:20]])
|
||||
if len(permanent_parts) > 20:
|
||||
parts_str += f" ... <i>(+{len(permanent_parts) - 20} ещё)</i>"
|
||||
output += f"{parts_str}\n\n"
|
||||
|
||||
# === ВРЕМЕННЫЕ ПРАВИЛА ===
|
||||
if temp_words or temp_lemmas:
|
||||
output += "⏱ <b>ВРЕМЕННЫЕ ПРАВИЛА:</b>\n\n"
|
||||
|
||||
if temp_words:
|
||||
output += f"📝 <b>Временные подстроки</b> ({len(temp_words)}):\n"
|
||||
# Для временных слов нужна дополнительная информация о времени истечения
|
||||
# Пока просто выводим список
|
||||
words_str = ', '.join([f"<code>{w}</code>" for w in sorted(temp_words)[:15]])
|
||||
if len(temp_words) > 15:
|
||||
words_str += f" ... <i>(+{len(temp_words) - 15} ещё)</i>"
|
||||
output += f"{words_str}\n\n"
|
||||
|
||||
if temp_lemmas:
|
||||
output += f"🔤 <b>Временные леммы</b> ({len(temp_lemmas)}):\n"
|
||||
lemmas_str = ', '.join([f"<code>{w}</code>" for w in sorted(temp_lemmas)[:15]])
|
||||
if len(temp_lemmas) > 15:
|
||||
lemmas_str += f" ... <i>(+{len(temp_lemmas) - 15} ещё)</i>"
|
||||
output += f"{lemmas_str}\n\n"
|
||||
|
||||
# === КОНФЛИКТНЫЕ ПРАВИЛА ===
|
||||
if conflict_words or conflict_lemmas:
|
||||
output += "⚔️ <b>КОНФЛИКТНЫЕ ПРАВИЛА:</b>\n"
|
||||
output += "<i>(работают только в режиме <code>/stopconflict</code> <code>время</code>)</i>\n\n"
|
||||
|
||||
if conflict_words:
|
||||
output += f"📝 <b>Конфликтные слова</b> ({len(conflict_words)}):\n"
|
||||
words_str = ', '.join([f"<code>{w}</code>" for w in sorted(conflict_words)[:15]])
|
||||
if len(conflict_words) > 15:
|
||||
words_str += f" ... <i>(+{len(conflict_words) - 15} ещё)</i>"
|
||||
output += f"{words_str}\n\n"
|
||||
|
||||
if conflict_lemmas:
|
||||
output += f"🔤 <b>Конфликтные леммы</b> ({len(conflict_lemmas)}):\n"
|
||||
lemmas_str = ', '.join([f"<code>{w}</code>" for w in sorted(conflict_lemmas)[:15]])
|
||||
if len(conflict_lemmas) > 15:
|
||||
lemmas_str += f" ... <i>(+{len(conflict_lemmas) - 15} ещё)</i>"
|
||||
output += f"{lemmas_str}\n\n"
|
||||
|
||||
# === ИСКЛЮЧЕНИЯ (WHITELIST) ===
|
||||
if exceptions:
|
||||
output += f"✅ <b>ИСКЛЮЧЕНИЯ</b> ({len(exceptions)}):\n"
|
||||
exc_str = ', '.join([f"<code>{exceptions}</code>" for w in sorted(exceptions)[:15]])
|
||||
if len(exceptions) > 15:
|
||||
exc_str += f" ... <i>(+{len(exceptions) - 15} ещё)</i>"
|
||||
output += f"{exc_str}\n\n"
|
||||
|
||||
# === АКТИВНЫЕ РЕЖИМЫ ===
|
||||
active_modes = []
|
||||
|
||||
if await manager.is_silence_active():
|
||||
active_modes.append("🔇 Режим тишины")
|
||||
|
||||
if await manager.is_conflict_active():
|
||||
active_modes.append("⚔️ Режим антиконфликта")
|
||||
|
||||
if active_modes:
|
||||
output += "🔴 <b>АКТИВНЫЕ РЕЖИМЫ:</b>\n"
|
||||
for mode in active_modes:
|
||||
output += f"{mode}\n"
|
||||
output += "\n"
|
||||
|
||||
# === ПУСТОЙ СПИСОК ===
|
||||
if total_count == 0:
|
||||
output = (
|
||||
"📋 <b>СПИСОК ПРАВИЛ МОДЕРАЦИИ</b>\n\n"
|
||||
"⚠️ <i>Правила модерации не настроены</i>\n\n"
|
||||
"Используйте команды добавления:\n"
|
||||
"• /addword — добавить подстроку\n"
|
||||
"• /addlemma — добавить лемму\n"
|
||||
"• /addpart — добавить часть\n\n"
|
||||
"📖 Подробнее: /start"
|
||||
)
|
||||
|
||||
# Ограничение длины (Telegram limit 4096)
|
||||
if len(output) > 4000:
|
||||
output = output[:3950] + "\n\n<i>... список обрезан, слишком много правил</i>"
|
||||
|
||||
return output
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("listwords:refresh"))
|
||||
@router.message(Command(*COMMANDS[CMD], prefix=settings.PREFIX, ignore_case=True), IsAdmin())
|
||||
@log_action(action_name="LISTWORDS_COMMAND")
|
||||
async def listwords_cmd(update: Message | CallbackQuery) -> None:
|
||||
"""
|
||||
Обработчик команды /listwords.
|
||||
Отображает список всех правил модерации с разбивкой по категориям.
|
||||
Доступно только администраторам.
|
||||
Args:
|
||||
update: Message или CallbackQuery
|
||||
"""
|
||||
# Определяем тип update
|
||||
if isinstance(update, CallbackQuery):
|
||||
message = update.message
|
||||
is_callback = True
|
||||
# Извлекаем номер страницы из callback_data
|
||||
try:
|
||||
page = int(update.data.split(":")[-1])
|
||||
except:
|
||||
page = 0
|
||||
else:
|
||||
message = update
|
||||
is_callback = False
|
||||
page = 0
|
||||
|
||||
# Формируем список
|
||||
try:
|
||||
text = await format_banwords_list(page)
|
||||
keyboard = get_refresh_kb(page)
|
||||
|
||||
if is_callback:
|
||||
try:
|
||||
await message.edit_text(
|
||||
text=text,
|
||||
parse_mode="HTML",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
await update.answer("✅ Список обновлён")
|
||||
except TelegramBadRequest as e:
|
||||
if 'message is not modified' in str(e).lower():
|
||||
await update.answer('✅ Список уже актуален')
|
||||
return
|
||||
raise # Другие ошибки пробрасываем
|
||||
else:
|
||||
await message.answer(
|
||||
text=text,
|
||||
parse_mode="HTML",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка отправки списка банвордов: {e}", log_type="LISTWORDS")
|
||||
|
||||
error_text = "❌ <b>Ошибка загрузки списка</b>\n\nПопробуйте позже"
|
||||
|
||||
if is_callback:
|
||||
await update.answer(f"❌ Ошибка загрузки: {e}", show_alert=True)
|
||||
else:
|
||||
await message.answer(error_text, parse_mode="HTML")
|
||||
Reference in New Issue
Block a user