sno-quiz/bot/handlers.py
2025-09-17 22:22:14 +03:00

194 lines
6.9 KiB
Python
Raw 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.

"""
Bot handlers
"""
import logging
from typing import Optional
from aiogram import F, types
from aiogram.filters import CommandStart, Command
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, Message, WebAppInfo
from aiogram.utils.keyboard import InlineKeyboardBuilder
from config import config
from utils import (
parse_startapp_parameter,
get_welcome_message,
validate_reward_amount,
validate_quiz_id,
)
logger = logging.getLogger(__name__)
def create_main_keyboard(startapp_param: Optional[str] = None) -> InlineKeyboardMarkup:
"""Create main keyboard with mini app button"""
builder = InlineKeyboardBuilder()
# Mini app URL with startapp parameter
mini_app_url = config.frontend_url
if startapp_param:
mini_app_url = f"{config.frontend_url}?startapp={startapp_param}"
builder.row(
InlineKeyboardButton(
text="🎯 Открыть Викторины",
web_app=WebAppInfo(url=mini_app_url)
)
)
builder.row(
InlineKeyboardButton(
text="📊 Статистика",
callback_data="stats"
)
)
return builder.as_markup()
async def handle_start_command(message: Message) -> None:
"""Handle /start command"""
startapp_param = None
# Extract startapp parameter from command arguments
if message.text and len(message.text.split()) > 1:
startapp_param = message.text.split(maxsplit=1)[1]
# Parse the startapp parameter
try:
parsed_param = parse_startapp_parameter(startapp_param)
# Validate parameters
if parsed_param["type"] == "reward":
amount = parsed_param.get("amount", 0)
if not validate_reward_amount(amount):
logger.warning(f"Invalid reward amount: {amount}")
parsed_param = {"type": "main"}
elif parsed_param["type"] == "quiz":
quiz_id = parsed_param.get("quiz_id", "")
if not validate_quiz_id(quiz_id):
logger.warning(f"Invalid quiz ID: {quiz_id}")
parsed_param = {"type": "main"}
# Get welcome message
welcome_text = get_welcome_message(parsed_param)
# Log the start event
logger.info(
f"User {message.from_user.id} started bot with param: {startapp_param}, "
f"parsed as: {parsed_param}"
)
# Send welcome message with keyboard
keyboard = create_main_keyboard(startapp_param)
await message.answer(welcome_text, reply_markup=keyboard)
except Exception as e:
logger.error(f"Error handling start command: {e}")
# Fallback to main message
fallback_text = get_welcome_message({"type": "main"})
keyboard = create_main_keyboard()
await message.answer(fallback_text, reply_markup=keyboard)
async def handle_text_message(message: Message) -> None:
"""Handle text messages"""
text = message.text.lower()
if any(word in text for word in ["викторина", "опрос", "тест"]):
await message.answer(
"🎯 Хотите пройти викторину? Нажмите на кнопку ниже!",
reply_markup=create_main_keyboard()
)
elif any(word in text for word in ["звезд", "балл", "монет"]):
await message.answer(
"⭐ Узнайте свой баланс и потратьте звёзды в мини-приложении!",
reply_markup=create_main_keyboard()
)
elif any(word in text for word in ["магазин", "приз", "подарок"]):
await message.answer(
"🛒 Загляните в наш магазин призов!",
reply_markup=create_main_keyboard()
)
else:
await message.answer(
"🌟 Я бот для управления викторинами! Используйте кнопки ниже для доступа к мини-приложению.",
reply_markup=create_main_keyboard()
)
async def handle_stats_callback(callback: types.CallbackQuery) -> None:
"""Handle stats button click"""
await callback.answer("Статистика доступна в мини-приложении!", show_alert=True)
async def handle_help_command(message: Message) -> None:
"""Handle /help command"""
help_text = """
🌟 <b>Звёздные Викторины - Помощь</b>
🎯 <b>Как начать:</b>
Нажмите на кнопку "Открыть Викторины" и начните проходить викторины!
🎁 <b>Как получить звёзды:</b>
• Проходите викторины
• Сканируйте QR-коды
• Участвуйте в акциях
🛒 <b>Как потратить звёзды:</b>
• Обменивайте на призы в магазине
• Получайте скидки и бонусы
📱 <b>QR-коды:</b>
• Сканируйте QR-коды через камеру телефона
• Или используйте встроенный сканер в приложении
🔗 <b>Deep Links:</b>
• `reward_X` - получить X звёзд
• `quiz_X` - открыть викторину X
• `shop` - перейти в магазин
❓ <b>Вопросы?</b>
Используйте кнопки ниже для доступа к мини-приложению!
"""
await message.answer(help_text, reply_markup=create_main_keyboard())
async def handle_unknown_command(message: Message) -> None:
"""Handle unknown commands"""
await message.answer(
"❌ Неизвестная команда. Используйте /help для получения помощи.",
reply_markup=create_main_keyboard()
)
async def handle_qr_info_command(message: Message) -> None:
"""Handle /qr command for QR information"""
info_text = """
🎫 <b>Информация о QR-кодах</b>
🔒 <b>Система безопасности:</b>
• QR-коды содержат уникальные токены
• Каждый токен одноразовый
• Срок действия - 30 дней
• Проверка на стороне сервера
🎯 <b>Типы QR-кодов:</b>
• 💰 <b>reward</b> - начисление звёзд
• 🧠 <b>quiz</b> - открытие викторины
• 🛒 <b>shop</b> - действия в магазине
📱 <b>Как использовать:</b>
1. Администратор генерирует QR-коды
2. QR-коды размещаются в нужных местах
3. Пользователи сканируют их через приложение
4. Приложение отправляет токен на валидацию
⚡ <b>Для администраторов:</b>
Используйте /admin для генерации QR-кодов
"""
await message.answer(info_text, reply_markup=create_main_keyboard())