233 lines
7.7 KiB
Python
233 lines
7.7 KiB
Python
"""
|
||
Admin handlers for QR code management
|
||
"""
|
||
|
||
import logging
|
||
from typing import Optional
|
||
|
||
from aiogram import F, types
|
||
from aiogram.filters import Command
|
||
from aiogram.types import (
|
||
InlineKeyboardButton,
|
||
InlineKeyboardMarkup,
|
||
Message,
|
||
CallbackQuery,
|
||
)
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
|
||
from config import config
|
||
from qr_service import QRService
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def create_admin_keyboard() -> InlineKeyboardMarkup:
|
||
"""Create admin keyboard"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="🎫 Генерировать QR-коды", callback_data="admin_generate_qr")
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="📊 Статистика", callback_data="admin_stats")
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="🔧 Настройки", callback_data="admin_settings")
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def create_qr_type_keyboard() -> InlineKeyboardMarkup:
|
||
"""Create QR type selection keyboard"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="💰 Награда", callback_data="qr_type_reward")
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="🧠 Викторина", callback_data="qr_type_quiz")
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="🛒 Магазин", callback_data="qr_type_shop")
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(text="❌ Отмена", callback_data="admin_cancel")
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def create_main_keyboard() -> InlineKeyboardMarkup:
|
||
"""Create main keyboard with mini app button"""
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="🎯 Открыть Викторины",
|
||
web_app=types.WebAppInfo(url=config.frontend_url)
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
async def handle_admin_command(message: Message) -> None:
|
||
"""Handle /admin command"""
|
||
if not config.has_admin_privileges(message.from_user.id):
|
||
await message.answer(
|
||
"❌ У вас нет прав для доступа к панели администратора."
|
||
)
|
||
return
|
||
|
||
user_role = "Администратор" if config.is_admin(message.from_user.id) else "Оператор"
|
||
|
||
await message.answer(
|
||
f"🛡️ Панель администратора\n\n"
|
||
f"👤 Ваша роль: {user_role}\n"
|
||
f"🆔 ID: {message.from_user.id}\n\n"
|
||
f"Выберите действие:",
|
||
reply_markup=create_admin_keyboard()
|
||
)
|
||
|
||
|
||
async def handle_generate_qr_callback(callback: CallbackQuery) -> None:
|
||
"""Handle generate QR callback"""
|
||
if not config.has_admin_privileges(callback.from_user.id):
|
||
await callback.answer("❌ Доступ запрещен", show_alert=True)
|
||
return
|
||
|
||
await callback.message.edit_text(
|
||
"🎫 Выберите тип QR-кода для генерации:",
|
||
reply_markup=create_qr_type_keyboard()
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
async def handle_qr_type_callback(callback: CallbackQuery) -> None:
|
||
"""Handle QR type selection callback"""
|
||
if not config.has_admin_privileges(callback.from_user.id):
|
||
await callback.answer("❌ Доступ запрещен", show_alert=True)
|
||
return
|
||
|
||
qr_type = callback.data.split("_")[-1]
|
||
type_descriptions = {
|
||
"reward": "💰 Награда (звёзды)",
|
||
"quiz": "🧠 Викторина",
|
||
"shop": "🛒 Магазин"
|
||
}
|
||
|
||
# Store the selected type in user state
|
||
# For simplicity, we'll use a simple approach. In production, use a proper state machine
|
||
|
||
instructions = {
|
||
"reward": "Введите сумму награды в звёздах (1-1000):",
|
||
"quiz": "Введите ID викторины:",
|
||
"shop": "Введите действие для магазина (например: discount_10):"
|
||
}
|
||
|
||
await callback.message.edit_text(
|
||
f"🎫 {type_descriptions.get(qr_type, qr_type)}\n\n"
|
||
f"{instructions.get(qr_type)}",
|
||
reply_markup=types.InlineKeyboardMarkup(
|
||
inline_keyboard=[
|
||
[types.InlineKeyboardButton(text="❌ Отмена", callback_data="admin_cancel")]
|
||
]
|
||
)
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
async def handle_qr_generation_text(message: Message) -> None:
|
||
"""Handle QR generation text input"""
|
||
if not config.has_admin_privileges(message.from_user.id):
|
||
await message.answer("❌ Доступ запрещен")
|
||
return
|
||
|
||
# This is a simplified approach. In production, use proper state management
|
||
text = message.text.strip()
|
||
|
||
# Try to determine the type based on context
|
||
# For now, we'll assume it's a reward if it's a number
|
||
try:
|
||
amount = int(text)
|
||
if 1 <= amount <= 1000:
|
||
# Generate reward QR codes
|
||
await generate_reward_qr_codes(message, amount)
|
||
return
|
||
except ValueError:
|
||
pass
|
||
|
||
# If not a number, ask for clarification
|
||
await message.answer(
|
||
"🎫 Пожалуйста, уточните тип QR-кода:\n\n"
|
||
"1. Для награды: введите число (1-1000)\n"
|
||
"2. Для викторины: введите 'quiz ID' (например: quiz 123)\n"
|
||
"3. Для магазина: введите 'shop действие' (например: shop discount_10)\n\n"
|
||
"Или используйте /admin для выбора типа",
|
||
reply_markup=create_admin_keyboard()
|
||
)
|
||
|
||
|
||
async def generate_reward_qr_codes(message: Message, amount: int, count: int = 5) -> None:
|
||
"""Generate reward QR codes"""
|
||
async with QRService() as qr_service:
|
||
try:
|
||
is_valid, error_msg = qr_service.validate_qr_request("reward", str(amount), count)
|
||
if not is_valid:
|
||
await message.answer(f"❌ {error_msg}")
|
||
return
|
||
|
||
tokens = await qr_service.generate_qr_codes("reward", str(amount), count)
|
||
|
||
response_text = qr_service.format_qr_examples(
|
||
tokens,
|
||
"reward",
|
||
f"QR-коды для награды {amount} ⭐"
|
||
)
|
||
|
||
await message.answer(
|
||
response_text,
|
||
reply_markup=create_admin_keyboard()
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"Error generating QR codes: {e}")
|
||
await message.answer(
|
||
f"❌ Ошибка при генерации QR-кодов: {e}",
|
||
reply_markup=create_admin_keyboard()
|
||
)
|
||
|
||
|
||
async def handle_admin_cancel_callback(callback: CallbackQuery) -> None:
|
||
"""Handle admin cancel callback"""
|
||
await callback.message.edit_text(
|
||
"❌ Операция отменена",
|
||
reply_markup=create_admin_keyboard()
|
||
)
|
||
await callback.answer()
|
||
|
||
|
||
async def handle_admin_stats_callback(callback: CallbackQuery) -> None:
|
||
"""Handle admin stats callback"""
|
||
if not config.has_admin_privileges(callback.from_user.id):
|
||
await callback.answer("❌ Доступ запрещен", show_alert=True)
|
||
return
|
||
|
||
# Placeholder for stats
|
||
await callback.answer("📊 Статистика в разработке", show_alert=True)
|
||
|
||
|
||
async def handle_admin_settings_callback(callback: CallbackQuery) -> None:
|
||
"""Handle admin settings callback"""
|
||
if not config.is_admin(callback.from_user.id):
|
||
await callback.answer("❌ Только администраторы могут менять настройки", show_alert=True)
|
||
return
|
||
|
||
# Placeholder for settings
|
||
await callback.answer("🔧 Настройки в разработке", show_alert=True) |