Implement user-specific question numbering and update database schema. Added triggers for automatic question numbering and adjustments upon deletion. Enhanced CRUD operations to manage user_question_number effectively.
This commit is contained in:
660
handlers/admin.py
Normal file
660
handlers/admin.py
Normal file
@@ -0,0 +1,660 @@
|
||||
"""
|
||||
Обработчики для администраторов
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
from aiogram import F, Router
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import CallbackQuery, Message
|
||||
|
||||
from config import config
|
||||
from config.constants import DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE, MIN_PAGE_NUMBER, PERCENTAGE_DECIMAL_PLACES, TIME_DECIMAL_PLACES
|
||||
from keyboards.inline import (
|
||||
get_admin_keyboard, get_ban_confirm_keyboard, get_ban_duration_keyboard,
|
||||
get_ban_user_keyboard, get_rate_limit_keyboard, get_stats_keyboard,
|
||||
get_superuser_assignment_keyboard, get_superuser_confirm_keyboard, get_unban_keyboard
|
||||
)
|
||||
from services.auth.auth_new import AuthService
|
||||
from services.infrastructure.database import DatabaseService
|
||||
from services.infrastructure.logger import get_logger
|
||||
from services.business.message_service import MessageService
|
||||
from services.business.pagination_service import PaginationService
|
||||
from services.permissions.decorators import require_admin_or_superuser, require_permission
|
||||
from services.rate_limiting.rate_limit_service import RateLimitService
|
||||
from services.business.user_service import UserService
|
||||
from services.utils import format_stats
|
||||
from dependencies import inject_admin_services
|
||||
|
||||
logger = get_logger(__name__)
|
||||
router = Router()
|
||||
|
||||
|
||||
async def _format_users_list(
|
||||
users: list,
|
||||
page: int,
|
||||
per_page: int,
|
||||
pagination_service: PaginationService
|
||||
) -> str:
|
||||
"""Форматирование списка пользователей для отображения"""
|
||||
try:
|
||||
# Рассчитываем пагинацию
|
||||
page_users, total_users, current_page, total_pages = pagination_service.calculate_pagination(
|
||||
users, page, per_page
|
||||
)
|
||||
|
||||
# Формируем информацию о пагинации
|
||||
start_idx = current_page * per_page
|
||||
end_idx = min(start_idx + per_page, total_users)
|
||||
pagination_info = pagination_service.format_pagination_info(
|
||||
current_page, total_pages, start_idx, end_idx, total_users
|
||||
)
|
||||
|
||||
# Формируем текст сообщения
|
||||
users_text = f"🔍 <b>Управление суперпользователями</b>\n\n"
|
||||
users_text += pagination_info
|
||||
|
||||
# Добавляем информацию о пользователях
|
||||
for i, user in enumerate(page_users, start_idx + 1):
|
||||
status_emoji = "🔍" if user.is_superuser else "👤"
|
||||
users_text += f"{i}. {status_emoji} {user.display_name}\n"
|
||||
if user.username:
|
||||
users_text += f" @{user.username}\n"
|
||||
created_at_str = user.created_at.strftime('%d.%m.%Y') if user.created_at else 'Неизвестно'
|
||||
users_text += f" 📅 {created_at_str}\n\n"
|
||||
|
||||
users_text += "💡 Нажмите на пользователя для изменения его статуса."
|
||||
|
||||
return users_text
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при форматировании списка пользователей: {e}")
|
||||
return "❌ Ошибка при форматировании списка пользователей."
|
||||
|
||||
|
||||
# Функция is_admin теперь импортируется из services.auth
|
||||
|
||||
|
||||
@router.message(Command("stats"))
|
||||
@require_permission("view_stats", "❌ У вас нет прав для выполнения этой команды.")
|
||||
async def cmd_stats(message: Message, database: DatabaseService = None):
|
||||
"""Обработчик команды /stats"""
|
||||
await show_stats(message, database)
|
||||
|
||||
|
||||
@router.message(F.text == "👑 Админ панель")
|
||||
@require_permission("admin_panel", "❌ У вас нет прав для доступа к админ панели.")
|
||||
async def admin_panel_button(message: Message):
|
||||
"""Обработчик кнопки 'Админ панель'"""
|
||||
admin_text = "👑 <b>Админ панель</b>\n\n"
|
||||
admin_text += "Выберите действие:"
|
||||
|
||||
await message.answer(
|
||||
admin_text,
|
||||
reply_markup=get_admin_keyboard(),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
|
||||
@router.message(F.text == "📊 Статистика")
|
||||
@require_permission("view_stats", "❌ У вас нет прав для просмотра статистики.")
|
||||
async def stats_button(message: Message, database: DatabaseService = None):
|
||||
"""Обработчик кнопки 'Статистика'"""
|
||||
await show_stats(message, database)
|
||||
|
||||
|
||||
async def show_stats(message: Message, database: DatabaseService = None):
|
||||
"""Показать статистику"""
|
||||
try:
|
||||
if not database:
|
||||
from dependencies import get_database
|
||||
database = get_database()
|
||||
|
||||
# Получаем статистику
|
||||
users_stats = await database.get_users_stats()
|
||||
questions_stats = await database.get_questions_stats()
|
||||
|
||||
# Объединяем статистику
|
||||
all_stats = {**users_stats, **questions_stats}
|
||||
|
||||
# Форматируем и отправляем
|
||||
stats_text = format_stats(all_stats)
|
||||
|
||||
await message.answer(
|
||||
stats_text,
|
||||
reply_markup=get_stats_keyboard(),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при получении статистики: {e}")
|
||||
await message.answer(
|
||||
"❌ Произошла ошибка при получении статистики. Попробуйте позже."
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@router.message(F.text == "📢 Рассылка")
|
||||
@require_permission("broadcast", "❌ У вас нет прав для рассылки.")
|
||||
async def broadcast_button(message: Message):
|
||||
"""Обработчик кнопки 'Рассылка'"""
|
||||
await message.answer(
|
||||
"📢 <b>Рассылка</b>\n\n"
|
||||
"Функция рассылки будет добавлена в следующих версиях.\n\n"
|
||||
"💡 Планируемые возможности:\n"
|
||||
"• Рассылка сообщений всем пользователям\n"
|
||||
"• Рассылка по группам пользователей\n"
|
||||
"• Планирование рассылок\n"
|
||||
"• Статистика доставки",
|
||||
reply_markup=get_admin_keyboard(),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
|
||||
@router.message(F.text == "⚙️ Настройки")
|
||||
@require_permission("admin_panel", "❌ У вас нет прав для изменения настроек.")
|
||||
async def settings_button(message: Message):
|
||||
"""Обработчик кнопки 'Настройки'"""
|
||||
settings_text = "⚙️ <b>Настройки бота</b>\n\n"
|
||||
settings_text += f"🔧 <b>Текущие настройки:</b>\n"
|
||||
settings_text += f"• Режим отладки: {'Включен' if config.DEBUG else 'Выключен'}\n"
|
||||
settings_text += f"• Макс. длина вопроса: {config.MAX_QUESTION_LENGTH} символов\n"
|
||||
settings_text += f"• Макс. длина ответа: {config.MAX_ANSWER_LENGTH} символов\n"
|
||||
settings_text += f"• Путь к БД: {config.DATABASE_PATH}\n\n"
|
||||
settings_text += f"👑 <b>Администраторы:</b>\n"
|
||||
for admin_id in config.ADMINS:
|
||||
settings_text += f"• {admin_id}\n"
|
||||
|
||||
settings_text += "\n💡 Настройки изменяются в файле .env"
|
||||
|
||||
await message.answer(
|
||||
settings_text,
|
||||
reply_markup=get_admin_keyboard(),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "admin_stats")
|
||||
@require_permission("view_stats", "❌ У вас нет прав")
|
||||
async def admin_stats_callback(callback: CallbackQuery, database: DatabaseService = None):
|
||||
"""Обработчик кнопки 'Статистика' в админ панели"""
|
||||
await show_stats(callback.message, database)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
|
||||
|
||||
@router.callback_query(F.data == "admin_broadcast")
|
||||
@require_permission("broadcast", "❌ У вас нет прав")
|
||||
async def admin_broadcast_callback(callback: CallbackQuery):
|
||||
"""Обработчик кнопки 'Рассылка' в админ панели"""
|
||||
await callback.message.edit_text(
|
||||
"📢 <b>Рассылка</b>\n\n"
|
||||
"Функция рассылки будет добавлена в следующих версиях.\n\n"
|
||||
"💡 Планируемые возможности:\n"
|
||||
"• Рассылка сообщений всем пользователям\n"
|
||||
"• Рассылка по группам пользователей\n"
|
||||
"• Планирование рассылок\n"
|
||||
"• Статистика доставки",
|
||||
reply_markup=get_admin_keyboard(),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "stats_general")
|
||||
@require_permission("view_stats", "❌ У вас нет прав")
|
||||
async def stats_general_callback(callback: CallbackQuery, database: DatabaseService = None):
|
||||
"""Обработчик кнопки 'Общая статистика'"""
|
||||
await show_stats(callback.message, database)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
|
||||
|
||||
@router.callback_query(F.data == "back_to_admin")
|
||||
@require_permission("admin_panel", "❌ У вас нет прав")
|
||||
async def back_to_admin_callback(callback: CallbackQuery):
|
||||
"""Обработчик кнопки 'Назад' в админ панель"""
|
||||
admin_text = "👑 <b>Админ панель</b>\n\n"
|
||||
admin_text += "Выберите действие:"
|
||||
|
||||
await callback.message.edit_text(
|
||||
admin_text,
|
||||
reply_markup=get_admin_keyboard(),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "admin_assign_superuser")
|
||||
@require_permission("manage_users", "❌ У вас нет прав для управления пользователями.")
|
||||
async def admin_assign_superuser_callback(
|
||||
callback: CallbackQuery,
|
||||
user_service: UserService,
|
||||
message_service: MessageService
|
||||
):
|
||||
"""Обработчик кнопки 'Назначить суперпользователя'"""
|
||||
|
||||
try:
|
||||
# Получаем пользователей с пагинацией (оптимизированный запрос)
|
||||
users = await user_service.database.get_all_users(limit=MAX_PAGE_SIZE, offset=MIN_PAGE_NUMBER)
|
||||
|
||||
if not users:
|
||||
await message_service.edit_message(
|
||||
callback,
|
||||
"👥 <b>Управление суперпользователями</b>\n\n"
|
||||
"❌ Пользователи не найдены.",
|
||||
get_admin_keyboard()
|
||||
)
|
||||
await message_service.send_callback_answer(callback)
|
||||
return
|
||||
|
||||
# Показываем первую страницу
|
||||
await show_superuser_assignment_page(
|
||||
callback,
|
||||
users,
|
||||
page=MIN_PAGE_NUMBER,
|
||||
message_service=message_service
|
||||
)
|
||||
await message_service.send_callback_answer(callback)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при получении списка пользователей: {e}")
|
||||
await message_service.edit_message(
|
||||
callback,
|
||||
"❌ Произошла ошибка при загрузке списка пользователей.",
|
||||
get_admin_keyboard()
|
||||
)
|
||||
await message_service.send_callback_answer(callback)
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("superuser_page_"))
|
||||
@require_permission("manage_users", "❌ У вас нет прав для управления пользователями.")
|
||||
async def superuser_page_callback(callback: CallbackQuery, database: DatabaseService = None):
|
||||
"""Обработчик пагинации списка пользователей для назначения суперпользователей"""
|
||||
|
||||
try:
|
||||
# Извлекаем номер страницы
|
||||
page = int(callback.data.split("_")[-1])
|
||||
|
||||
if not database:
|
||||
from dependencies import get_database
|
||||
database = get_database()
|
||||
|
||||
# Получаем всех пользователей
|
||||
users = await database.get_all_users(limit=MAX_PAGE_SIZE, offset=MIN_PAGE_NUMBER)
|
||||
|
||||
if not users:
|
||||
await callback.answer("❌ Пользователи не найдены", show_alert=True)
|
||||
return
|
||||
|
||||
# Показываем нужную страницу
|
||||
await show_superuser_assignment_page(callback, users, page)
|
||||
await callback.answer()
|
||||
|
||||
except ValueError:
|
||||
await callback.answer("❌ Неверный номер страницы", show_alert=True)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при пагинации пользователей: {e}")
|
||||
await callback.answer("❌ Ошибка при загрузке страницы", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("assign_superuser_"))
|
||||
@require_permission("manage_users", "❌ У вас нет прав для управления пользователями.")
|
||||
async def assign_superuser_callback(callback: CallbackQuery, database: DatabaseService = None, validator = None):
|
||||
"""Обработчик выбора пользователя для назначения суперпользователем"""
|
||||
|
||||
try:
|
||||
# Извлекаем ID пользователя
|
||||
user_id_str = callback.data.split("_")[-1]
|
||||
|
||||
# Валидируем callback data
|
||||
if validator:
|
||||
validation_result = validator.validate_callback_data(callback.data)
|
||||
if not validation_result:
|
||||
logger.warning(f"⚠️ Невалидный callback data от пользователя {callback.from_user.id}: {callback.data}")
|
||||
await callback.answer("❌ Неверные данные", show_alert=True)
|
||||
return
|
||||
|
||||
# Валидируем user_id
|
||||
try:
|
||||
user_id = int(user_id_str)
|
||||
if validator:
|
||||
user_id_validation = validator.validate_telegram_id(user_id)
|
||||
if not user_id_validation:
|
||||
logger.warning(f"⚠️ Невалидный user_id в callback: {user_id}")
|
||||
await callback.answer("❌ Неверный ID пользователя", show_alert=True)
|
||||
return
|
||||
except ValueError:
|
||||
logger.warning(f"⚠️ Неверный формат user_id в callback: {user_id_str}")
|
||||
await callback.answer("❌ Неверный формат ID", show_alert=True)
|
||||
return
|
||||
|
||||
if not database:
|
||||
from dependencies import get_database
|
||||
database = get_database()
|
||||
|
||||
# Получаем информацию о пользователе
|
||||
user = await database.get_user(user_id)
|
||||
if not user:
|
||||
await callback.answer("❌ Пользователь не найден", show_alert=True)
|
||||
return
|
||||
|
||||
# Формируем текст с информацией о пользователе
|
||||
user_text = f"👤 <b>Информация о пользователе</b>\n\n"
|
||||
user_text += f"🆔 ID: {user.telegram_id}\n"
|
||||
user_text += f"👤 Имя: {user.display_name}\n"
|
||||
user_text += f"📝 Полное имя: {user.full_name}\n"
|
||||
user_text += f"🔗 Ссылка: {user.profile_link}\n"
|
||||
created_at_str = user.created_at.strftime('%d.%m.%Y %H:%M') if user.created_at else 'Неизвестно'
|
||||
user_text += f"📅 Регистрация: {created_at_str}\n"
|
||||
user_text += f"✅ Активен: {'Да' if user.is_active else 'Нет'}\n"
|
||||
user_text += f"🔍 Суперпользователь: {'Да' if user.is_superuser else 'Нет'}\n\n"
|
||||
|
||||
if user.is_superuser:
|
||||
user_text += "❓ <b>Хотите снять права суперпользователя?</b>"
|
||||
else:
|
||||
user_text += "❓ <b>Хотите назначить суперпользователем?</b>"
|
||||
|
||||
# Показываем информацию и кнопки подтверждения
|
||||
await callback.message.edit_text(
|
||||
user_text,
|
||||
reply_markup=get_superuser_confirm_keyboard(user_id, user.is_superuser),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
except ValueError:
|
||||
await callback.answer("❌ Неверный ID пользователя", show_alert=True)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при получении информации о пользователе: {e}")
|
||||
await callback.answer("❌ Ошибка при загрузке информации", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("confirm_superuser_"))
|
||||
@require_permission("manage_users", "❌ У вас нет прав для управления пользователями.")
|
||||
async def confirm_superuser_callback(callback: CallbackQuery, database: DatabaseService = None, validator = None):
|
||||
"""Обработчик подтверждения назначения суперпользователем"""
|
||||
|
||||
try:
|
||||
# Извлекаем ID пользователя
|
||||
user_id_str = callback.data.split("_")[-1]
|
||||
|
||||
# Валидируем callback data
|
||||
if validator:
|
||||
validation_result = validator.validate_callback_data(callback.data)
|
||||
if not validation_result:
|
||||
logger.warning(f"⚠️ Невалидный callback data от пользователя {callback.from_user.id}: {callback.data}")
|
||||
await callback.answer("❌ Неверные данные", show_alert=True)
|
||||
return
|
||||
|
||||
# Валидируем user_id
|
||||
try:
|
||||
user_id = int(user_id_str)
|
||||
if validator:
|
||||
user_id_validation = validator.validate_telegram_id(user_id)
|
||||
if not user_id_validation:
|
||||
logger.warning(f"⚠️ Невалидный user_id в callback: {user_id}")
|
||||
await callback.answer("❌ Неверный ID пользователя", show_alert=True)
|
||||
return
|
||||
except ValueError:
|
||||
logger.warning(f"⚠️ Неверный формат user_id в callback: {user_id_str}")
|
||||
await callback.answer("❌ Неверный формат ID", show_alert=True)
|
||||
return
|
||||
|
||||
if not database:
|
||||
from dependencies import get_database
|
||||
database = get_database()
|
||||
|
||||
# Получаем пользователя
|
||||
user = await database.get_user(user_id)
|
||||
if not user:
|
||||
await callback.answer("❌ Пользователь не найден", show_alert=True)
|
||||
return
|
||||
|
||||
# Назначаем суперпользователем
|
||||
user.is_superuser = True
|
||||
await database.update_user(user)
|
||||
|
||||
await callback.message.edit_text(
|
||||
f"✅ <b>Права назначены!</b>\n\n"
|
||||
f"👤 Пользователь {user.display_name} теперь является суперпользователем.\n\n"
|
||||
f"🔍 Суперпользователи могут видеть информацию об авторах вопросов.",
|
||||
reply_markup=get_superuser_confirm_keyboard(user_id, True),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await callback.answer("✅ Права суперпользователя назначены!")
|
||||
|
||||
except ValueError:
|
||||
await callback.answer("❌ Неверный ID пользователя", show_alert=True)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при назначении суперпользователя: {e}")
|
||||
await callback.answer("❌ Ошибка при назначении прав", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("remove_superuser_"))
|
||||
@require_permission("manage_users", "❌ У вас нет прав для управления пользователями.")
|
||||
async def remove_superuser_callback(callback: CallbackQuery, database: DatabaseService = None, validator = None):
|
||||
"""Обработчик снятия прав суперпользователя"""
|
||||
|
||||
try:
|
||||
# Извлекаем ID пользователя
|
||||
user_id_str = callback.data.split("_")[-1]
|
||||
|
||||
# Валидируем callback data
|
||||
if validator:
|
||||
validation_result = validator.validate_callback_data(callback.data)
|
||||
if not validation_result:
|
||||
logger.warning(f"⚠️ Невалидный callback data от пользователя {callback.from_user.id}: {callback.data}")
|
||||
await callback.answer("❌ Неверные данные", show_alert=True)
|
||||
return
|
||||
|
||||
# Валидируем user_id
|
||||
try:
|
||||
user_id = int(user_id_str)
|
||||
if validator:
|
||||
user_id_validation = validator.validate_telegram_id(user_id)
|
||||
if not user_id_validation:
|
||||
logger.warning(f"⚠️ Невалидный user_id в callback: {user_id}")
|
||||
await callback.answer("❌ Неверный ID пользователя", show_alert=True)
|
||||
return
|
||||
except ValueError:
|
||||
logger.warning(f"⚠️ Неверный формат user_id в callback: {user_id_str}")
|
||||
await callback.answer("❌ Неверный формат ID", show_alert=True)
|
||||
return
|
||||
|
||||
if not database:
|
||||
from dependencies import get_database
|
||||
database = get_database()
|
||||
|
||||
# Получаем пользователя
|
||||
user = await database.get_user(user_id)
|
||||
if not user:
|
||||
await callback.answer("❌ Пользователь не найден", show_alert=True)
|
||||
return
|
||||
|
||||
# Снимаем права суперпользователя
|
||||
user.is_superuser = False
|
||||
await database.update_user(user)
|
||||
|
||||
await callback.message.edit_text(
|
||||
f"❌ <b>Права сняты!</b>\n\n"
|
||||
f"👤 Пользователь {user.display_name} больше не является суперпользователем.\n\n"
|
||||
f"👤 Теперь он видит анонимные вопросы без информации об авторах.",
|
||||
reply_markup=get_superuser_confirm_keyboard(user_id, False),
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await callback.answer("❌ Права суперпользователя сняты!")
|
||||
|
||||
except ValueError:
|
||||
await callback.answer("❌ Неверный ID пользователя", show_alert=True)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при снятии прав суперпользователя: {e}")
|
||||
await callback.answer("❌ Ошибка при снятии прав", show_alert=True)
|
||||
|
||||
|
||||
async def show_superuser_assignment_page(
|
||||
callback: CallbackQuery,
|
||||
users: list,
|
||||
page: int = MIN_PAGE_NUMBER,
|
||||
per_page: int = DEFAULT_PAGE_SIZE,
|
||||
pagination_service: PaginationService = None,
|
||||
message_service: MessageService = None
|
||||
):
|
||||
"""Показать страницу с пользователями для назначения суперпользователей"""
|
||||
try:
|
||||
# Используем сервисы если они переданы, иначе создаем временные
|
||||
if not pagination_service:
|
||||
from dependencies import get_pagination_service
|
||||
pagination_service = get_pagination_service()
|
||||
|
||||
if not message_service:
|
||||
from dependencies import get_message_service
|
||||
message_service = get_message_service()
|
||||
|
||||
# Формируем текст сообщения
|
||||
users_text = await _format_users_list(users, page, per_page, pagination_service)
|
||||
|
||||
# Создаем клавиатуру
|
||||
keyboard = get_superuser_assignment_keyboard(users, page, per_page)
|
||||
|
||||
# Отправляем или редактируем сообщение
|
||||
await message_service.edit_message(callback, users_text, keyboard)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при отображении страницы пользователей: {e}")
|
||||
await message_service.edit_message(
|
||||
callback,
|
||||
"❌ Произошла ошибка при отображении списка пользователей.",
|
||||
get_admin_keyboard()
|
||||
)
|
||||
|
||||
|
||||
# ===========================================
|
||||
# Rate Limiting callback обработчики
|
||||
# ===========================================
|
||||
|
||||
@router.callback_query(F.data == "admin_rate_limit")
|
||||
async def admin_rate_limit_menu(
|
||||
callback: CallbackQuery,
|
||||
message_service: MessageService,
|
||||
auth: AuthService
|
||||
):
|
||||
"""Показать меню rate limiting"""
|
||||
try:
|
||||
if not auth.is_admin(callback.from_user.id):
|
||||
await callback.answer("❌ Доступ запрещен. Только для администраторов.", show_alert=True)
|
||||
return
|
||||
|
||||
text = "🚦 <b>Управление Rate Limiting</b>\n\n"
|
||||
text += "Выберите действие для управления системой ограничения скорости отправки сообщений:"
|
||||
|
||||
await message_service.edit_message(callback, text, get_rate_limit_keyboard())
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при отображении меню rate limiting: {e}")
|
||||
await callback.answer("❌ Произошла ошибка при отображении меню.", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "rate_limit_stats")
|
||||
@inject_admin_services
|
||||
async def rate_limit_stats_callback(
|
||||
callback: CallbackQuery,
|
||||
rate_limit_service: RateLimitService,
|
||||
message_service: MessageService,
|
||||
auth: AuthService,
|
||||
**kwargs
|
||||
):
|
||||
"""Показать статистику rate limiting"""
|
||||
try:
|
||||
if not auth.is_admin(callback.from_user.id):
|
||||
await callback.answer("❌ Доступ запрещен. Только для администраторов.", show_alert=True)
|
||||
return
|
||||
|
||||
stats = rate_limit_service.get_stats()
|
||||
|
||||
stats_text = "📊 <b>Статистика Rate Limiting</b>\n\n"
|
||||
stats_text += "🔢 <b>Общая статистика:</b>\n"
|
||||
stats_text += f"• Всего запросов: {stats.get('total_requests', 0)}\n"
|
||||
stats_text += f"• Успешных запросов: {stats.get('successful_requests', 0)}\n"
|
||||
stats_text += f"• Неудачных запросов: {stats.get('failed_requests', 0)}\n"
|
||||
stats_text += f"• Процент успеха: {stats.get('success_rate', 0.0):.{PERCENTAGE_DECIMAL_PLACES}%}\n"
|
||||
stats_text += f"• Процент ошибок: {stats.get('error_rate', 0.0):.{PERCENTAGE_DECIMAL_PLACES}%}\n"
|
||||
stats_text += f"• Среднее время ожидания: {stats.get('average_wait_time', 0.0):.{TIME_DECIMAL_PLACES}f}с\n\n"
|
||||
|
||||
stats_text += "🔍 <b>Детальная статистика:</b>\n"
|
||||
stats_text += f"• RetryAfter ошибок: {stats.get('retry_after_errors', 0)}\n"
|
||||
stats_text += f"• Других ошибок: {stats.get('other_errors', 0)}\n"
|
||||
stats_text += f"• Процент RetryAfter: {stats.get('retry_after_rate', 0.0):.{PERCENTAGE_DECIMAL_PLACES}%}\n"
|
||||
stats_text += f"• Процент других ошибок: {stats.get('other_error_rate', 0.0):.{PERCENTAGE_DECIMAL_PLACES}%}\n"
|
||||
|
||||
await message_service.edit_message(callback, stats_text, get_rate_limit_keyboard())
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при получении статистики rate limiting: {e}")
|
||||
await callback.answer("❌ Произошла ошибка при получении статистики.", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "rate_limit_reset_stats")
|
||||
@inject_admin_services
|
||||
async def reset_rate_limit_stats_callback(
|
||||
callback: CallbackQuery,
|
||||
rate_limit_service: RateLimitService,
|
||||
message_service: MessageService,
|
||||
auth: AuthService,
|
||||
**kwargs
|
||||
):
|
||||
"""Сбросить статистику rate limiting"""
|
||||
try:
|
||||
if not auth.is_admin(callback.from_user.id):
|
||||
await callback.answer("❌ Доступ запрещен. Только для администраторов.", show_alert=True)
|
||||
return
|
||||
|
||||
rate_limit_service.reset_stats()
|
||||
await callback.answer("✅ Статистика rate limiting сброшена.", show_alert=True)
|
||||
|
||||
# Обновляем сообщение
|
||||
text = "🚦 <b>Управление Rate Limiting</b>\n\n"
|
||||
text += "Выберите действие для управления системой ограничения скорости отправки сообщений:"
|
||||
await message_service.edit_message(callback, text, get_rate_limit_keyboard())
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при сбросе статистики rate limiting: {e}")
|
||||
await callback.answer("❌ Произошла ошибка при сбросе статистики.", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "rate_limit_adapt")
|
||||
@inject_admin_services
|
||||
async def adapt_rate_limit_config_callback(
|
||||
callback: CallbackQuery,
|
||||
rate_limit_service: RateLimitService,
|
||||
message_service: MessageService,
|
||||
auth: AuthService,
|
||||
**kwargs
|
||||
):
|
||||
"""Адаптировать конфигурацию rate limiting"""
|
||||
try:
|
||||
if not auth.is_admin(callback.from_user.id):
|
||||
await callback.answer("❌ Доступ запрещен. Только для администраторов.", show_alert=True)
|
||||
return
|
||||
|
||||
if rate_limit_service.should_adapt_config():
|
||||
await rate_limit_service.adapt_config_if_needed()
|
||||
await callback.answer("✅ Конфигурация rate limiting адаптирована на основе текущей производительности.", show_alert=True)
|
||||
else:
|
||||
await callback.answer("ℹ️ Адаптация конфигурации не требуется. Недостаточно данных или производительность в норме.", show_alert=True)
|
||||
|
||||
# Обновляем сообщение
|
||||
text = "🚦 <b>Управление Rate Limiting</b>\n\n"
|
||||
text += "Выберите действие для управления системой ограничения скорости отправки сообщений:"
|
||||
await message_service.edit_message(callback, text, get_rate_limit_keyboard())
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при адаптации конфигурации rate limiting: {e}")
|
||||
await callback.answer("❌ Произошла ошибка при адаптации конфигурации.", show_alert=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user