Files
game-marathon/bot/handlers/marathons.py
2026-01-04 02:47:38 +07:00

263 lines
9.5 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.
from aiogram import Router, F
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery
from keyboards.main_menu import get_main_menu
from keyboards.inline import get_marathons_keyboard, get_marathon_details_keyboard, get_settings_keyboard
from services.api_client import api_client
router = Router()
@router.message(Command("marathons"))
@router.message(F.text == "📊 Мои марафоны")
async def cmd_marathons(message: Message):
"""Show user's marathons."""
user = await api_client.get_user_by_telegram_id(message.from_user.id)
if not user:
await message.answer(
"Сначала привяжи аккаунт через настройки профиля на сайте.",
reply_markup=get_main_menu()
)
return
marathons = await api_client.get_user_marathons(message.from_user.id)
if not marathons:
await message.answer(
"<b>Мои марафоны</b>\n\n"
"У тебя пока нет активных марафонов.\n"
"Присоединись к марафону на сайте!",
reply_markup=get_main_menu()
)
return
text = "<b>📊 Мои марафоны</b>\n\n"
for m in marathons:
status_emoji = {
"preparing": "",
"active": "🎮",
"finished": "🏁"
}.get(m.get("status"), "")
text += f"{status_emoji} <b>{m.get('title')}</b>\n"
text += f" Очки: {m.get('total_points', 0)} | "
text += f"Место: #{m.get('position', '?')}\n\n"
await message.answer(
text,
reply_markup=get_marathons_keyboard(marathons)
)
@router.callback_query(F.data.startswith("marathon:"))
async def marathon_details(callback: CallbackQuery):
"""Show marathon details."""
marathon_id = int(callback.data.split(":")[1])
details = await api_client.get_marathon_details(
marathon_id=marathon_id,
telegram_id=callback.from_user.id
)
if not details:
await callback.answer("Не удалось загрузить данные марафона", show_alert=True)
return
marathon = details.get("marathon", {})
participant = details.get("participant", {})
active_events = details.get("active_events", [])
current_assignment = details.get("current_assignment")
status_text = {
"preparing": "⏳ Подготовка",
"active": "🎮 Активен",
"finished": "🏁 Завершён"
}.get(marathon.get("status"), "")
text = f"<b>{marathon.get('title')}</b>\n"
text += f"Статус: {status_text}\n\n"
text += f"<b>📈 Твоя статистика:</b>\n"
text += f"• Очки: <b>{participant.get('total_points', 0)}</b>\n"
text += f"• Место: <b>#{details.get('position', '?')}</b>\n"
text += f"• Стрик: <b>{participant.get('current_streak', 0)}</b> 🔥\n"
text += f"• Дропов: <b>{participant.get('drop_count', 0)}</b>\n\n"
if active_events:
text += "<b>⚡ Активные события:</b>\n"
for event in active_events:
event_emoji = {
"golden_hour": "🌟",
"jackpot": "🎰",
"double_risk": "",
"common_enemy": "👥",
"swap": "🔄",
"game_choice": "🎲"
}.get(event.get("type"), "📌")
text += f"{event_emoji} {event.get('type', '').replace('_', ' ').title()}\n"
text += "\n"
if current_assignment:
challenge = current_assignment.get("challenge", {})
game = challenge.get("game", {})
text += f"<b>🎯 Текущее задание:</b>\n"
text += f"Игра: {game.get('title', 'N/A')}\n"
text += f"Задание: {challenge.get('title', 'N/A')}\n"
text += f"Сложность: {challenge.get('difficulty', 'N/A')}\n"
text += f"Очки: {challenge.get('points', 0)}\n"
await callback.message.edit_text(
text,
reply_markup=get_marathon_details_keyboard(marathon_id)
)
await callback.answer()
@router.callback_query(F.data == "back_to_marathons")
async def back_to_marathons(callback: CallbackQuery):
"""Go back to marathons list."""
marathons = await api_client.get_user_marathons(callback.from_user.id)
if not marathons:
await callback.message.edit_text(
"<b>Мои марафоны</b>\n\n"
"У тебя пока нет активных марафонов."
)
await callback.answer()
return
text = "<b>📊 Мои марафоны</b>\n\n"
for m in marathons:
status_emoji = {
"preparing": "",
"active": "🎮",
"finished": "🏁"
}.get(m.get("status"), "")
text += f"{status_emoji} <b>{m.get('title')}</b>\n"
text += f" Очки: {m.get('total_points', 0)} | "
text += f"Место: #{m.get('position', '?')}\n\n"
await callback.message.edit_text(
text,
reply_markup=get_marathons_keyboard(marathons)
)
await callback.answer()
@router.message(Command("stats"))
@router.message(F.text == "📈 Статистика")
async def cmd_stats(message: Message):
"""Show user's overall statistics."""
user = await api_client.get_user_by_telegram_id(message.from_user.id)
if not user:
await message.answer(
"Сначала привяжи аккаунт через настройки профиля на сайте.",
reply_markup=get_main_menu()
)
return
stats = await api_client.get_user_stats(message.from_user.id)
if not stats:
await message.answer(
"<b>📈 Статистика</b>\n\n"
"Пока нет данных для отображения.\n"
"Начни участвовать в марафонах!",
reply_markup=get_main_menu()
)
return
text = f"<b>📈 Общая статистика</b>\n\n"
text += f"👤 <b>{user.get('nickname', 'Игрок')}</b>\n\n"
text += f"🏆 Марафонов завершено: <b>{stats.get('marathons_completed', 0)}</b>\n"
text += f"🎮 Марафонов активно: <b>{stats.get('marathons_active', 0)}</b>\n"
text += f"✅ Заданий выполнено: <b>{stats.get('challenges_completed', 0)}</b>\n"
text += f"💰 Всего очков: <b>{stats.get('total_points', 0)}</b>\n"
text += f"🔥 Лучший стрик: <b>{stats.get('best_streak', 0)}</b>\n"
await message.answer(text, reply_markup=get_main_menu())
@router.message(Command("settings"))
@router.message(F.text == "⚙️ Настройки")
async def cmd_settings(message: Message):
"""Show notification settings."""
user = await api_client.get_user_by_telegram_id(message.from_user.id)
if not user:
await message.answer(
"Сначала привяжи аккаунт через настройки профиля на сайте.",
reply_markup=get_main_menu()
)
return
# Get current notification settings
settings = await api_client.get_notification_settings(message.from_user.id)
if not settings:
settings = {"notify_events": True, "notify_disputes": True, "notify_moderation": True}
await message.answer(
"<b>⚙️ Настройки уведомлений</b>\n\n"
"Нажми на категорию, чтобы включить/выключить:\n\n"
"✅ — уведомления включены\n"
"❌ — уведомления выключены\n\n"
"<i>Уведомления о старте/финише марафонов и коды безопасности нельзя отключить.</i>",
reply_markup=get_settings_keyboard(settings)
)
@router.callback_query(F.data.startswith("toggle:"))
async def toggle_notification(callback: CallbackQuery):
"""Toggle notification setting."""
setting_name = callback.data.split(":")[1]
# Get current settings
current_settings = await api_client.get_notification_settings(callback.from_user.id)
if not current_settings:
await callback.answer("Не удалось загрузить настройки", show_alert=True)
return
# Toggle the setting
current_value = current_settings.get(setting_name, True)
new_value = not current_value
# Update on backend
result = await api_client.update_notification_settings(
callback.from_user.id,
{setting_name: new_value}
)
if not result or result.get("error"):
await callback.answer("Не удалось сохранить настройки", show_alert=True)
return
# Update keyboard with new values
await callback.message.edit_reply_markup(
reply_markup=get_settings_keyboard(result)
)
status = "включены" if new_value else "выключены"
setting_names = {
"notify_events": "События",
"notify_disputes": "Споры",
"notify_moderation": "Модерация"
}
await callback.answer(f"{setting_names.get(setting_name, setting_name)}: {status}")
@router.callback_query(F.data == "back_to_menu")
async def back_to_menu(callback: CallbackQuery):
"""Go back to main menu from settings."""
await callback.message.delete()
await callback.message.answer(
"Главное меню",
reply_markup=get_main_menu()
)
await callback.answer()