From ede4617b007fa1a10c80de98599c948145377f42 Mon Sep 17 00:00:00 2001 From: "Andrew K. Choi" Date: Sat, 7 Mar 2026 08:53:48 +0900 Subject: [PATCH 1/2] Enhance login display with raffle participation history MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Show active vs closed raffles for each login - Display win/loss status (🏆 for winners, ✗ for non-winners) - Limit display to 5 active + 3 closed raffles - Update help documentation with detailed status explanation - Add status icons (✅/⏸️) for active/inactive logins --- src/handlers/help_handlers.py | 36 +++++++++----- src/handlers/registration_handlers.py | 71 ++++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 19 deletions(-) diff --git a/src/handlers/help_handlers.py b/src/handlers/help_handlers.py index 23eb0bd..15cdc23 100644 --- a/src/handlers/help_handlers.py +++ b/src/handlers/help_handlers.py @@ -150,24 +150,36 @@ async def help_logins(callback: CallbackQuery): "В этом разделе вы всегда сможете найти свои добавленные логины в розыгрыши, " "которые администратор указал для вас в системе.\n\n" - "⚠️ Важное уточнение:\n\n" - "Имейте в виду, что логины, которые не отыграны по условиям розыгрыша, " - "не добавляются в список. В списке отображаются только активные логины, " - "которые соответствуют условиям текущих и будущих розыгрышей.\n\n" + "Какая информация показывается?\n\n" + "Для каждого логина вы сможете увидеть:\n" + "🎲 Активные розыгрыши - розыгрыши в которых сейчас участвует логин\n" + "🏁 Завершенные розыгрыши - прошедшие розыгрыши:\n" + " 🏆 ВЫИГРАЛ - если логин победил (указано место)\n" + " ✗ Не выиграл - если логин не получил приз\n\n" + + "⚠️ Важное уточнение о статусе логинов:\n\n" + "✅ Зеленый (активный) - логин участвует в новых розыгрышах\n" + "⏸️ Серый (неактивный) - логин не участвует в новых розыгрышах\n\n" + + "Имейте в виду, что логины, которые участвовали в закрытых розыгрышах, " + "не добавляются в новые розыгрыши. В списке отображаются только те логины, " + "которые активны и соответствуют условиям текущих розыгрышей.\n\n" + + "Как это работает:\n\n" + "1️⃣ Если у вас есть 100 логинов\n" + "2️⃣ 60 из них участвовали в прошедших/закрытых розыгрышах\n" + "3️⃣ Статус этих 60 логинов будет ⏸️ (неактивны)\n" + "4️⃣ Они не добавляются в новые розыгрыши\n" + "5️⃣ В новых розыгрышах участвуют только оставшиеся активные логины\n\n" "Как использовать:\n\n" "1️⃣ Откройте главное меню\n" "2️⃣ Нажмите кнопку \"Мои логины\"\n" - "3️⃣ Вы увидите список всех ваших активных логинов\n\n" - - "📋 Что показывается:\n\n" - " ✅ Активные логины, добавленные администратором\n" - " ✅ Логины, соответствующие условиям розыгрышей\n" - " ❌ Неотыгранные логины (в них не проводятся розыгрыши)\n\n" + "3️⃣ Вы увидите полный список всех ваших логинов с информацией\n\n" "💡 Совет:\n" - "Если вы не видите ожидаемый логин в списке, это значит, что он не соответствует " - "условиям текущих розыгрышей или администратор еще не добавил его в систему. " + "Если вы не видите ожидаемый логин в списке активных розыгрышей, " + "это может означать, что он уже участвовал в закрытых розыгрышах и помечен как неактивный. " "Свяжитесь с администратором для уточнения.\n\n" "🔄 Обновление информации:\n" diff --git a/src/handlers/registration_handlers.py b/src/handlers/registration_handlers.py index 6899448..9c03af1 100644 --- a/src/handlers/registration_handlers.py +++ b/src/handlers/registration_handlers.py @@ -2,6 +2,8 @@ from aiogram import Router, F from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from aiogram.filters import Command, StateFilter +from sqlalchemy import select +from sqlalchemy.orm import selectinload from src.filters.case_insensitive import CaseInsensitiveCommand from aiogram.fsm.context import FSMContext @@ -11,6 +13,7 @@ import logging from src.core.database import async_session_maker from src.core.registration_services import RegistrationService, AccountService from src.core.services import UserService +from src.core.models import Participation, Winner, Lottery logger = logging.getLogger(__name__) router = Router() @@ -222,7 +225,7 @@ async def show_verification_code(message: Message): @router.message(Command("my_accounts")) async def show_user_accounts(message: Message): - """Показать счета пользователя""" + """Показать логины пользователя с информацией о розыгрышах""" async with async_session_maker() as session: user = await UserService.get_user_by_telegram_id(session, message.from_user.id) @@ -234,15 +237,69 @@ async def show_user_accounts(message: Message): if not accounts: await message.answer( - "У вас пока нет привязанных счетов.\n\n" - "Счета добавляются администратором." + "У вас пока нет привязанных логинов.\n\n" + "Логины добавляются администратором." ) return - text = f"💳 Ваши счета (Клубная карта: {user.club_card_number}):\n\n" + text = f"📱 Ваши логины (Клубная карта: {user.club_card_number})\n\n" for i, account in enumerate(accounts, 1): - status = "✅" if account.is_active else "❌" - text += f"{i}. {status} {account.account_number}\n" + # Получаем participations для этого account с загруженными данными о lottery + participations = await session.execute( + select(Participation) + .where(Participation.account_id == account.id) + .options(selectinload(Participation.lottery)) + ) + participations = participations.scalars().all() + + # Определяем статус логина + active_participations = [p for p in participations if not p.lottery.is_completed] + closed_participations = [p for p in participations if p.lottery.is_completed] + + # Основная информация о логине + status_icon = "✅" if account.is_active and active_participations else "⏸️" + text += f"{i}. {status_icon} {account.account_number}\n" + + if active_participations: + text += " 🎲 Активные розыгрыши:\n" + for p in active_participations[:5]: # Показываем не более 5 + status = "🟢" + text += f" {status} {p.lottery.title}\n" + if len(active_participations) > 5: + text += f" ... и еще {len(active_participations) - 5}\n" + + if closed_participations: + text += " 🏁 Завершенные розыгрыши:\n" + for p in closed_participations[:3]: # Показываем не более 3 + # Проверяем, выиграл ли в этом розыгрыше + winner_result = await session.execute( + select(Winner) + .where( + (Winner.lottery_id == p.lottery_id) & + (Winner.account_number == account.account_number) + ) + ) + winner = winner_result.scalar_one_or_none() + + if winner: + text += f" 🏆 {p.lottery.title} - ВЫИГРАЛ! ({winner.place} место)\n" + else: + text += f" ✗ {p.lottery.title}\n" + + if len(closed_participations) > 3: + text += f" ... и еще {len(closed_participations) - 3} закрытых\n" + + if not participations: + text += " ℹ️ В розыгрышах не участвовал\n" + + text += "\n" - await message.answer(text) + # Добавляем примечание о неактивных логинах + if any(not acc.is_active for acc in accounts): + text += "⏸️ - Логин не участвует в новых розыгрышах\n" + text += "✅ - Логин активен и может участвовать\n\n" + + text += "💡 Заметка: Логины, участвовавшие в закрытых розыгрышах, не добавляются в новые розыгрыши." + + await message.answer(text, parse_mode="HTML") -- 2.49.1 From 782f70232703adce3aa0515df21b7fde08c15154 Mon Sep 17 00:00:00 2001 From: "Andrew K. Choi" Date: Sat, 7 Mar 2026 08:55:35 +0900 Subject: [PATCH 2/2] Fix registration button handling and add debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Improve btn_registration handler to directly set state instead of creating fake callback - Add /register command handler for registration - Add text-based registration triggers ('регистрация', 'регистр', 'register') - Add debug logging to handle_start to track registration status - Ensure registration button is shown correctly for unregistered users --- main.py | 41 ++++++++++++++++++++++++------- src/controllers/bot_controller.py | 6 +++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/main.py b/main.py index d174198..f1b2715 100644 --- a/main.py +++ b/main.py @@ -134,18 +134,41 @@ async def btn_chat(message: Message, state: FSMContext): @router.message(F.text == "📝 Регистрация") async def btn_registration(message: Message, state: FSMContext): """Обработчик кнопки 'Регистрация'""" - from aiogram.types import CallbackQuery + from src.handlers.registration_handlers import RegistrationStates + from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton - fake_callback = CallbackQuery( - id="fake", - from_user=message.from_user, - chat_instance="0", - data="start_registration", - message=message + logger.info(f"User {message.from_user.id} pressed Registration button") + + text = ( + "📝 Регистрация в системе\n\n" + "Для участия в розыгрышах необходимо зарегистрироваться.\n\n" + "Шаг 1 из 3: Придумайте никнейм\n\n" + "🎭 Введите ваш никнейм для чата:\n" + "• От 2 до 20 символов\n" + "• Может содержать буквы, цифры, пробелы\n" + "• Это имя будут видеть другие участники" ) - from src.handlers.registration_handlers import start_registration - await start_registration(fake_callback, state) + await message.answer( + text, + reply_markup=InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="❌ Отмена", callback_data="back_to_main")] + ]) + ) + + await state.set_state(RegistrationStates.waiting_for_nickname) + + +@router.message(CaseInsensitiveCommand("register")) +async def cmd_register(message: Message, state: FSMContext): + """Обработчик команды /register (регистронезависимо)""" + await btn_registration(message, state) + + +@router.message(F.text.lower().in_(["регистрация", "регистр", "register"])) +async def text_registration(message: Message, state: FSMContext): + """Обработчик текста для регистрации""" + await btn_registration(message, state) @router.message(F.text == "🔑 Мой код") diff --git a/src/controllers/bot_controller.py b/src/controllers/bot_controller.py index 30b7682..53506f3 100644 --- a/src/controllers/bot_controller.py +++ b/src/controllers/bot_controller.py @@ -35,6 +35,9 @@ class BotController(IBotController): async def handle_start(self, message: Message): """Обработать команду /start""" from src.utils.keyboards import get_main_reply_keyboard + import logging + + logger = logging.getLogger(__name__) user = await self.user_service.get_or_create_user( telegram_id=message.from_user.id, @@ -43,6 +46,9 @@ class BotController(IBotController): last_name=message.from_user.last_name ) + # Логирование статуса регистрации + logger.info(f"User {message.from_user.id}: is_registered={user.is_registered}, is_admin={self.is_admin(message.from_user.id)}") + welcome_text = f"👋 Добро пожаловать, {user.first_name or 'дорогой пользователь'}!\n\n" welcome_text += "🎲 Это бот для участия в розыгрышах.\n\n" -- 2.49.1