"""
Обработчики команд управления администраторами
"""
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")