""" Обработчики команд управления администраторами """ from aiogram import Router, F from aiogram.filters import Command from aiogram.types import Message, CallbackQuery from aiogram.utils.keyboard import InlineKeyboardBuilder from bot.filters.admin import IsSuperAdmin from configs import settings, COMMANDS from database import get_manager from middleware.loggers import logger from bot.utils.decorators import log_action __all__ = ("router",) router: Router = Router(name="admin_management_router") # ================= ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ================= def parse_user_id(text: str, command: str) -> tuple[bool, str | int]: """ Парсит ID пользователя из команды. Args: text: Полный текст сообщения command: Название команды Returns: (success, result): result это либо user_id (int), либо текст ошибки (str) """ parts = text.split(maxsplit=1) if len(parts) < 2: return False, f"❌ Использование: /{command} " user_id_str = parts[1].strip() # Валидация ID try: user_id = int(user_id_str) if user_id <= 0: return False, "❌ ID должен быть положительным числом" if user_id > 9999999999: # Максимальный Telegram ID return False, "❌ Некорректный ID пользователя" return True, user_id except ValueError: return False, "❌ ID должен быть числом" def format_admin_info(user_id: int, username: str | None = None) -> str: """Форматирует информацию об админе""" if username: return f"{user_id} (@{username})" return f"{user_id}" def get_refresh_admins_kb(): """Клавиатура для обновления списка админов""" ikb = InlineKeyboardBuilder() ikb.button(text="🔄 Обновить", callback_data="listadmins:refresh") ikb.button(text="➕ Добавить", callback_data="admin:help_add") ikb.adjust(2) return ikb.as_markup() # ================= ДОБАВЛЕНИЕ АДМИНИСТРАТОРА ================= @router.message(Command(*COMMANDS.get("addadmin", ["addadmin"]), prefix=settings.PREFIX, ignore_case=True), IsSuperAdmin()) @log_action(action_name="ADD_ADMIN", log_args=True) async def add_admin_cmd(message: Message) -> None: """ Добавляет нового администратора бота. Доступно только владельцам бота (OWNER_ID). Использование: /addadmin Пример: /addadmin 123456789 """ success, result = parse_user_id(message.text, "addadmin") if not success: await message.answer(result, parse_mode="HTML") return user_id = result # Проверка: нельзя добавить самого себя if user_id == message.from_user.id: await message.answer( "⚠️ Вы уже владелец бота\n\n" "Вам не нужно добавлять себя в администраторы", parse_mode="HTML" ) return # Проверка: нельзя добавить другого владельца if user_id in settings.OWNER_ID: await message.answer( "⚠️ Этот пользователь уже владелец бота\n\n" "Владельцы имеют полные права автоматически", parse_mode="HTML" ) return manager = get_manager() try: # Проверяем, уже админ ли is_already_admin = await manager.is_admin(user_id) if is_already_admin: await message.answer( f"⚠️ Пользователь {format_admin_info(user_id)} уже является администратором", parse_mode="HTML" ) return # Добавляем администратора added = await manager.add_admin( user_id=user_id, added_by=message.from_user.id ) if added: text = ( f"✅ Администратор добавлен\n\n" f"👤 ID: {format_admin_info(user_id)}\n" f"👑 Добавил: {format_admin_info(message.from_user.id, message.from_user.username)}\n\n" f"📋 Права администратора:\n" f"├─ Управление банвордами\n" f"├─ Просмотр статистики\n" f"├─ Активация режимов модерации\n" f"└─ Все команды бота\n\n" f"⚠️ Не может управлять другими админами\n" f"Список админов: /listadmins" ) logger.info( f"Администратор добавлен: {user_id} (добавил: {message.from_user.id})", log_type="ADMIN_MGMT" ) else: text = "❌ Ошибка добавления администратора\n\nПопробуйте позже" await message.answer(text, parse_mode="HTML") except Exception as e: logger.error(f"Ошибка добавления администратора: {e}", log_type="ADMIN_MGMT") await message.answer("❌ Ошибка добавления\n\nПопробуйте позже", parse_mode="HTML") # ================= УДАЛЕНИЕ АДМИНИСТРАТОРА ================= @router.message(Command(*COMMANDS.get("remadmin", ["remadmin"]), prefix=settings.PREFIX, ignore_case=True), IsSuperAdmin()) @log_action(action_name="REMOVE_ADMIN", log_args=True) async def remove_admin_cmd(message: Message) -> None: """ Удаляет администратора бота. Доступно только владельцам бота (OWNER_ID). Использование: /remadmin Пример: /remadmin 123456789 """ success, result = parse_user_id(message.text, "remadmin") if not success: await message.answer(result, parse_mode="HTML") return user_id = result # Проверка: нельзя удалить владельца if user_id in settings.OWNER_ID: await message.answer( "⚠️ Нельзя удалить владельца\n\n" "Владельцы имеют права постоянно", parse_mode="HTML" ) return # Проверка: нельзя удалить самого себя (если вы владелец) if user_id == message.from_user.id: await message.answer( "⚠️ Нельзя удалить самого себя", parse_mode="HTML" ) return manager = get_manager() try: # Проверяем, является ли администратором is_admin = await manager.is_admin(user_id) if not is_admin: await message.answer( f"⚠️ Пользователь {format_admin_info(user_id)} не является администратором", parse_mode="HTML" ) return # Удаляем администратора removed = await manager.remove_admin(user_id=user_id) if removed: text = ( f"🗑 Администратор удалён\n\n" f"👤 ID: {format_admin_info(user_id)}\n" f"👑 Удалил: {format_admin_info(message.from_user.id, message.from_user.username)}\n\n" f"⚠️ Пользователь больше не имеет доступа к командам бота" ) logger.info( f"Администратор удалён: {user_id} (удалил: {message.from_user.id})", log_type="ADMIN_MGMT" ) else: text = "❌ Ошибка удаления администратора\n\nПопробуйте позже" await message.answer(text, parse_mode="HTML") except Exception as e: logger.error(f"Ошибка удаления администратора: {e}", log_type="ADMIN_MGMT") await message.answer("❌ Ошибка удаления\n\nПопробуйте позже", parse_mode="HTML") # ================= СПИСОК АДМИНИСТРАТОРОВ ================= @router.callback_query(F.data == "listadmins:refresh") @router.message(Command(*COMMANDS.get("listadmins", ["listadmins"]), prefix=settings.PREFIX, ignore_case=True), IsSuperAdmin()) @log_action(action_name="LIST_ADMINS") async def list_admins_cmd(update: Message | CallbackQuery) -> None: """ Показывает список всех администраторов бота. Доступно только владельцам бота (OWNER_ID). Использование: /listadmins """ # Определяем тип update if isinstance(update, CallbackQuery): message = update.message is_callback = True else: message = update is_callback = False manager = get_manager() try: # Получаем всех админов из БД db_admins = await manager.repo.get_admins() # Получаем статистику stats = await manager.get_stats() # === ФОРМИРУЕМ ВЫВОД === output = "👥 СПИСОК АДМИНИСТРАТОРОВ\n\n" # Владельцы (OWNER_ID) output += "👑 Владельцы бота (полные права):\n" for owner_id in settings.OWNER_ID: output += f'├─ {owner_id}\n' output += "\n" # Администраторы из БД if db_admins: output += f"⚙️ Администраторы ({len(db_admins)}):\n" for admin_id in sorted(db_admins): output += f'├─ {admin_id}\n' output += "\n" output += "📋 Права администраторов:\n" output += "├─ Управление банвордами\n" output += "├─ Просмотр статистики\n" output += "├─ Активация режимов модерации\n" output += "└─ Все команды бота (кроме управления админами)\n\n" else: output += "⚙️ Администраторы:\n" output += "└─ Нет дополнительных администраторов\n\n" # Общая статистика total_admins = len(settings.OWNER_ID) + len(db_admins) output += f"📊 Итого: {total_admins} администратор(ов)\n\n" # Команды управления output += "🔧 Управление:\n" output += "• /addadmin ID — добавить админа\n" output += "• /remadmin ID — удалить админа\n\n" output += "💡 Только владельцы могут управлять администраторами" # Клавиатура keyboard = get_refresh_admins_kb() # Отправка if is_callback: await message.edit_text( text=output, parse_mode="HTML", reply_markup=keyboard ) await update.answer("✅ Список обновлён") else: await message.answer( text=output, parse_mode="HTML", reply_markup=keyboard ) except Exception as e: logger.error(f"Ошибка получения списка администраторов: {e}", log_type="ADMIN_MGMT") error_text = "❌ Ошибка загрузки списка\n\nПопробуйте позже" if is_callback: await update.answer("❌ Ошибка загрузки", show_alert=True) else: await message.answer(error_text, parse_mode="HTML") # ================= ВСПОМОГАТЕЛЬНЫЕ CALLBACK ================= @router.callback_query(F.data == "admin:help_add") async def admin_help_add_callback(callback: CallbackQuery) -> None: """Показывает помощь по добавлению админа""" text = ( "➕ Как добавить администратора?\n\n" "1️⃣ Узнайте Telegram ID пользователя\n" " • Используйте бота @userinfobot\n" " • Или попросите пользователя написать /start\n\n" "2️⃣ Выполните команду:\n" " /addadmin ID\n\n" "Пример:\n" "/addadmin 123456789" ) await callback.answer() await callback.message.answer(text, parse_mode="HTML") @router.message(Command(*COMMANDS.get("adminhelp", ["adminhelp"]), prefix=settings.PREFIX, ignore_case=True), IsSuperAdmin()) async def admin_help_cmd(message: Message) -> None: """ Показывает подробную справку по управлению администраторами. Использование: /adminhelp """ text = ( "👥 УПРАВЛЕНИЕ АДМИНИСТРАТОРАМИ\n\n" "🔐 Уровни доступа:\n\n" "👑 Владельцы (OWNER_ID):\n" "├─ Все права администратора\n" "├─ Управление другими админами\n" "└─ Указываются в конфигурации\n\n" "⚙️ Администраторы:\n" "├─ Управление банвордами\n" "├─ Просмотр статистики\n" "├─ Активация режимов модерации\n" "└─ НЕ могут управлять админами\n\n" "📝 Команды:\n" "• /listadmins — список всех админов\n" "• /addadmin ID — добавить админа\n" "• /remadmin ID — удалить админа\n\n" "💡 Как узнать ID пользователя?\n" "• Используйте бота @userinfobot\n" "• Попросите пользователя написать боту\n" "• ID отображается в логах бота\n\n" "⚠️ Важно:\n" "├─ Нельзя удалить владельца\n" "├─ Нельзя удалить самого себя\n" "└─ Все действия логируются" ) await message.answer(text, parse_mode="HTML") @router.message(Command(*COMMANDS.get("checkadmin", ["checkadmin"]), prefix=settings.PREFIX, ignore_case=True), IsSuperAdmin()) @log_action(action_name="CHECK_ADMIN") async def check_admin_cmd(message: Message) -> None: """ Проверяет, является ли пользователь администратором. Использование: /checkadmin """ success, result = parse_user_id(message.text, "checkadmin") if not success: await message.answer(result, parse_mode="HTML") return user_id = result manager = get_manager() try: # Проверяем статус is_owner = user_id in settings.OWNER_ID is_db_admin = await manager.is_admin(user_id) text = f"🔍 Проверка пользователя\n\n" text += f"👤 ID: {user_id}\n\n" if is_owner: text += "👑 Статус: Владелец бота\n" text += "✅ Полные права администратора\n" text += "✅ Может управлять админами" elif is_db_admin: text += "⚙️ Статус: Администратор\n" text += "✅ Доступ к командам бота\n" text += "❌ Не может управлять админами" else: text += "👤 Статус: Обычный пользователь\n" text += "❌ Нет прав администратора\n\n" text += f"Добавить в админы: /addadmin {user_id}" await message.answer(text, parse_mode="HTML") except Exception as e: logger.error(f"Ошибка проверки администратора: {e}", log_type="ADMIN_MGMT") await message.answer("❌ Ошибка проверки", parse_mode="HTML")