""" Inline клавиатуры для бота """ from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton from aiogram.utils.keyboard import InlineKeyboardBuilder from models.question import Question from typing import List from services.utils import escape_html def get_answer_keyboard(question_id: int, from_user_id: int = None) -> InlineKeyboardMarkup: """ Клавиатура для ответа на вопрос Args: question_id: ID вопроса from_user_id: ID отправителя вопроса (для блокировки) Returns: Inline клавиатура """ builder = InlineKeyboardBuilder() builder.add( InlineKeyboardButton( text="💬 Ответить", callback_data=f"answer_{question_id}" ) ) builder.add( InlineKeyboardButton( text="❌ Отклонить", callback_data=f"reject_{question_id}" ) ) # Добавляем кнопку блокировки, если есть ID отправителя if from_user_id: builder.add( InlineKeyboardButton( text="🚫 Заблокировать", callback_data=f"block_{from_user_id}_{question_id}" ) ) builder.add( InlineKeyboardButton( text="🗑️ Удалить", callback_data=f"delete_{question_id}" ) ) builder.adjust(1) # По одной кнопке в ряд return builder.as_markup() def get_admin_keyboard() -> InlineKeyboardMarkup: """ Клавиатура для администраторов Returns: Inline клавиатура """ builder = InlineKeyboardBuilder() builder.add( InlineKeyboardButton( text="📊 Статистика", callback_data="admin_stats" ) ) builder.add( InlineKeyboardButton( text="📢 Рассылка", callback_data="admin_broadcast" ) ) builder.add( InlineKeyboardButton( text="🔍 Назначить суперпользователя", callback_data="admin_assign_superuser" ) ) builder.add( InlineKeyboardButton( text="🚫 Забанить пользователя", callback_data="admin_ban_user" ) ) builder.add( InlineKeyboardButton( text="🚦 Rate Limiting", callback_data="admin_rate_limit" ) ) builder.adjust(2) # По две кнопки в ряд return builder.as_markup() def get_superuser_assignment_keyboard(users: List, page: int = 0, per_page: int = 10) -> InlineKeyboardMarkup: """ Клавиатура для назначения суперпользователей Args: users: Список пользователей page: Номер страницы per_page: Количество пользователей на странице Returns: Inline клавиатура с пользователями для назначения """ builder = InlineKeyboardBuilder() # Вычисляем диапазон пользователей для текущей страницы start_idx = page * per_page end_idx = min(start_idx + per_page, len(users)) page_users = users[start_idx:end_idx] # Добавляем кнопки для пользователей for user in page_users: # Определяем статус пользователя status_emoji = "🔍" if user.is_superuser else "👤" button_text = f"{status_emoji} {user.display_name}" # Обрезаем текст если слишком длинный if len(button_text) > 30: button_text = button_text[:27] + "..." builder.add( InlineKeyboardButton( text=button_text, callback_data=f"assign_superuser_{user.telegram_id}" ) ) # Настраиваем расположение кнопок: 1 кнопка в ряд для лучшей читаемости builder.adjust(1) # Добавляем управляющие кнопки control_buttons = [] # Кнопка "Предыдущая" (если есть предыдущие страницы) if page > 0: control_buttons.append( InlineKeyboardButton( text="⬅️ Предыдущая", callback_data=f"superuser_page_{page - 1}" ) ) # Кнопка "Следующая" (если есть следующие страницы) total_pages = (len(users) + per_page - 1) // per_page if page < total_pages - 1: control_buttons.append( InlineKeyboardButton( text="Следующая ➡️", callback_data=f"superuser_page_{page + 1}" ) ) # Добавляем управляющие кнопки if control_buttons: builder.row(*control_buttons) # Кнопка "Назад" builder.add( InlineKeyboardButton( text="🔙 Назад к админ панели", callback_data="back_to_admin" ) ) return builder.as_markup() def get_superuser_confirm_keyboard(user_id: int, is_superuser: bool) -> InlineKeyboardMarkup: """ Клавиатура для подтверждения назначения/снятия суперпользователя Args: user_id: ID пользователя is_superuser: Текущий статус суперпользователя Returns: Inline клавиатура с кнопками подтверждения """ builder = InlineKeyboardBuilder() if is_superuser: # Если уже суперпользователь, предлагаем снять права builder.add( InlineKeyboardButton( text="❌ Снять права суперпользователя", callback_data=f"remove_superuser_{user_id}" ) ) else: # Если не суперпользователь, предлагаем назначить builder.add( InlineKeyboardButton( text="✅ Назначить суперпользователем", callback_data=f"confirm_superuser_{user_id}" ) ) builder.add( InlineKeyboardButton( text="🔙 Назад к списку", callback_data="admin_assign_superuser" ) ) return builder.as_markup() def get_ban_user_keyboard(users: List, page: int = 0, per_page: int = 10) -> InlineKeyboardMarkup: """ Клавиатура для выбора пользователя для бана Args: users: Список пользователей page: Номер страницы per_page: Количество пользователей на странице Returns: Inline клавиатура с пользователями для бана """ builder = InlineKeyboardBuilder() # Вычисляем диапазон пользователей для текущей страницы start_idx = page * per_page end_idx = min(start_idx + per_page, len(users)) page_users = users[start_idx:end_idx] # Добавляем кнопки для пользователей for user in page_users: # Определяем статус пользователя status_emoji = "🚫" if user.is_banned else "👤" button_text = f"{status_emoji} {user.display_name}" # Обрезаем текст если слишком длинный if len(button_text) > 30: button_text = button_text[:27] + "..." builder.add( InlineKeyboardButton( text=button_text, callback_data=f"ban_user_select_{user.telegram_id}" ) ) # Настраиваем расположение кнопок: 1 кнопка в ряд для лучшей читаемости builder.adjust(1) # Добавляем управляющие кнопки control_buttons = [] # Кнопка "Предыдущая" (если есть предыдущие страницы) if page > 0: control_buttons.append( InlineKeyboardButton( text="⬅️ Предыдущая", callback_data=f"ban_user_page_{page - 1}" ) ) # Кнопка "Следующая" (если есть следующие страницы) total_pages = (len(users) + per_page - 1) // per_page if page < total_pages - 1: control_buttons.append( InlineKeyboardButton( text="Следующая ➡️", callback_data=f"ban_user_page_{page + 1}" ) ) # Добавляем управляющие кнопки if control_buttons: builder.row(*control_buttons) # Кнопка "Назад" builder.add( InlineKeyboardButton( text="🔙 Назад к админ панели", callback_data="back_to_admin" ) ) return builder.as_markup() def get_ban_duration_keyboard(user_id: int) -> InlineKeyboardMarkup: """ Клавиатура для выбора срока бана Args: user_id: ID пользователя для бана Returns: Inline клавиатура с вариантами срока бана """ builder = InlineKeyboardBuilder() # Варианты срока бана ban_options = [ ("1 час", "ban_1h"), ("1 день", "ban_1d"), ("3 дня", "ban_3d"), ("1 неделя", "ban_1w"), ("1 месяц", "ban_1m"), ("Навсегда", "ban_forever") ] for text, callback_data in ban_options: builder.add( InlineKeyboardButton( text=text, callback_data=f"{callback_data}_{user_id}" ) ) builder.adjust(2) # По две кнопки в ряд # Кнопка "Назад" builder.add( InlineKeyboardButton( text="🔙 Назад к списку", callback_data="admin_ban_user" ) ) return builder.as_markup() def get_ban_confirm_keyboard(user_id: int, duration: str, reason: str = None) -> InlineKeyboardMarkup: """ Клавиатура для подтверждения бана пользователя Args: user_id: ID пользователя duration: Срок бана reason: Причина бана Returns: Inline клавиатура с кнопками подтверждения """ builder = InlineKeyboardBuilder() builder.add( InlineKeyboardButton( text="✅ Подтвердить бан", callback_data=f"confirm_ban_{user_id}_{duration}" ) ) builder.add( InlineKeyboardButton( text="❌ Отменить", callback_data=f"ban_user_select_{user_id}" ) ) builder.adjust(1) return builder.as_markup() def get_unban_keyboard(user_id: int) -> InlineKeyboardMarkup: """ Клавиатура для разбана пользователя Args: user_id: ID пользователя Returns: Inline клавиатура с кнопкой разбана """ builder = InlineKeyboardBuilder() builder.add( InlineKeyboardButton( text="✅ Разбанить пользователя", callback_data=f"unban_user_{user_id}" ) ) builder.add( InlineKeyboardButton( text="🔙 Назад к списку", callback_data="admin_ban_user" ) ) builder.adjust(1) return builder.as_markup() def get_stats_keyboard() -> InlineKeyboardMarkup: """ Клавиатура для статистики Returns: Inline клавиатура """ builder = InlineKeyboardBuilder() builder.add( InlineKeyboardButton( text="📈 Общая статистика", callback_data="stats_general" ) ) builder.add( InlineKeyboardButton( text="⬅️ Назад", callback_data="back_to_admin" ) ) builder.adjust(2) return builder.as_markup() def get_user_questions_keyboard(questions: list, page: int = 0, per_page: int = 9, total_questions: int = None) -> InlineKeyboardMarkup: """ Клавиатура со списком вопросов пользователя Args: questions: Список вопросов для текущей страницы page: Номер страницы per_page: Количество вопросов на странице total_questions: Общее количество вопросов (для расчета пагинации) Returns: Inline клавиатура """ builder = InlineKeyboardBuilder() # Если не передано общее количество вопросов, используем длину списка if total_questions is None: total_questions = len(questions) # Вычисляем общее количество страниц total_pages = (total_questions + per_page - 1) // per_page if total_questions > 0 else 1 # Добавляем кнопки для вопросов for i, question_data in enumerate(questions): # Проверяем, является ли элемент кортежем (question, author_user) или просто question if isinstance(question_data, tuple): question, author_user = question_data else: question = question_data status_emoji = { 'pending': '⏳', 'answered': '✅', 'rejected': '❌', 'deleted': '🗑️' } emoji = status_emoji.get(question.status.value, '❓') # Используем user_question_number для отображения display_number = question.user_question_number if question.user_question_number is not None else (page * per_page + i + 1) text = f"{emoji} Вопрос #{display_number}" # Обрезаем текст если слишком длинный if len(text) > 30: text = text[:27] + "..." builder.add( InlineKeyboardButton( text=text, callback_data=f"view_question_{question.id}" ) ) # Настраиваем расположение кнопок: 3 кнопки в ряд для вопросов builder.adjust(3) # Добавляем управляющие кнопки только если есть больше одной страницы if total_pages > 1: control_buttons = [] # Кнопка "Предыдущая" (только если не первая страница) if page > 0: control_buttons.append( InlineKeyboardButton( text="⬅️ Предыдущая", callback_data=f"questions_page_{page - 1}" ) ) # Кнопка "В меню" control_buttons.append( InlineKeyboardButton( text="🏠 В меню", callback_data="back_to_main" ) ) # Кнопка "Следующая" (только если не последняя страница) if page < total_pages - 1: control_buttons.append( InlineKeyboardButton( text="Следующая ➡️", callback_data=f"questions_page_{page + 1}" ) ) # Добавляем управляющие кнопки в отдельный ряд builder.row(*control_buttons) else: # Если только одна страница, добавляем только кнопку "В меню" builder.row( InlineKeyboardButton( text="🏠 В меню", callback_data="back_to_main" ) ) return builder.as_markup() def get_question_view_keyboard(question: Question) -> InlineKeyboardMarkup: """ Клавиатура для просмотра конкретного вопроса Args: question: Объект вопроса Returns: Inline клавиатура """ builder = InlineKeyboardBuilder() if question.status.value == 'pending': # Если вопрос ожидает ответа builder.add( InlineKeyboardButton( text="💬 Ответить", callback_data=f"answer_{question.id}" ) ) builder.add( InlineKeyboardButton( text="❌ Отклонить", callback_data=f"reject_{question.id}" ) ) elif question.status.value == 'answered': # Если вопрос уже отвечен builder.add( InlineKeyboardButton( text="✏️ Редактировать ответ", callback_data=f"edit_answer_{question.id}" ) ) # Общие действия builder.add( InlineKeyboardButton( text="🗑️ Удалить", callback_data=f"delete_{question.id}" ) ) builder.add( InlineKeyboardButton( text="⬅️ К списку вопросов", callback_data="back_to_questions" ) ) builder.adjust(1) return builder.as_markup() def get_rate_limit_keyboard() -> InlineKeyboardMarkup: """ Клавиатура для управления rate limiting Returns: Inline клавиатура с кнопками rate limiting """ builder = InlineKeyboardBuilder() builder.add( InlineKeyboardButton( text="📊 Статистика Rate Limiting", callback_data="rate_limit_stats" ) ) builder.add( InlineKeyboardButton( text="🔄 Сбросить статистику", callback_data="rate_limit_reset_stats" ) ) builder.add( InlineKeyboardButton( text="⚙️ Адаптировать конфигурацию", callback_data="rate_limit_adapt" ) ) builder.add( InlineKeyboardButton( text="⬅️ Назад к админке", callback_data="back_to_admin" ) ) builder.adjust(1) return builder.as_markup()