Files
AnonBot/keyboards/inline.py

616 lines
19 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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()