Вывод всех запрещенных слов
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