Compare commits

..

3 Commits

Author SHA1 Message Date
5c01486bd8 Merge pull request 'v2_functions' (#9) from v2_functions into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #9
2026-03-06 23:57:00 +00:00
782f702327 Fix registration button handling and add debug logging
Some checks failed
continuous-integration/drone/pr Build is failing
- 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
2026-03-07 08:55:35 +09:00
ede4617b00 Enhance login display with raffle participation history
- 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
2026-03-07 08:53:48 +09:00
4 changed files with 126 additions and 28 deletions

41
main.py
View File

@@ -134,18 +134,41 @@ async def btn_chat(message: Message, state: FSMContext):
@router.message(F.text == "📝 Регистрация") @router.message(F.text == "📝 Регистрация")
async def btn_registration(message: Message, state: FSMContext): 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( logger.info(f"User {message.from_user.id} pressed Registration button")
id="fake",
from_user=message.from_user, text = (
chat_instance="0", "📝 Регистрация в системе\n\n"
data="start_registration", "Для участия в розыгрышах необходимо зарегистрироваться.\n\n"
message=message "Шаг 1 из 3: Придумайте никнейм\n\n"
"🎭 Введите ваш никнейм для чата:\n"
"• От 2 до 20 символов\n"
"• Может содержать буквы, цифры, пробелы\n"
"• Это имя будут видеть другие участники"
) )
from src.handlers.registration_handlers import start_registration await message.answer(
await start_registration(fake_callback, state) 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 == "🔑 Мой код") @router.message(F.text == "🔑 Мой код")

View File

@@ -35,6 +35,9 @@ class BotController(IBotController):
async def handle_start(self, message: Message): async def handle_start(self, message: Message):
"""Обработать команду /start""" """Обработать команду /start"""
from src.utils.keyboards import get_main_reply_keyboard from src.utils.keyboards import get_main_reply_keyboard
import logging
logger = logging.getLogger(__name__)
user = await self.user_service.get_or_create_user( user = await self.user_service.get_or_create_user(
telegram_id=message.from_user.id, telegram_id=message.from_user.id,
@@ -43,6 +46,9 @@ class BotController(IBotController):
last_name=message.from_user.last_name 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 = f"👋 Добро пожаловать, {user.first_name or 'дорогой пользователь'}!\n\n"
welcome_text += "🎲 Это бот для участия в розыгрышах.\n\n" welcome_text += "🎲 Это бот для участия в розыгрышах.\n\n"

View File

@@ -150,24 +150,36 @@ async def help_logins(callback: CallbackQuery):
"В этом разделе вы всегда сможете найти свои добавленные логины в розыгрыши, " "В этом разделе вы всегда сможете найти свои добавленные логины в розыгрыши, "
"которые администратор указал для вас в системе.\n\n" "которые администратор указал для вас в системе.\n\n"
"⚠️ <b>Важное уточнение:</b>\n\n" "<b>Какая информация показывается?</b>\n\n"
"Имейте в виду, что логины, которые не отыграны по условиям розыгрыша, " "Для каждого логина вы сможете увидеть:\n"
"<b>не добавляются в список</b>. В списке отображаются только активные логины, " "🎲 <b>Активные розыгрыши</b> - розыгрыши в которых сейчас участвует логин\n"
"которые соответствуют условиям текущих и будущих розыгрышей.\n\n" "🏁 <b>Завершенные розыгрыши</b> - прошедшие розыгрыши:\n"
" 🏆 ВЫИГРАЛ - если логин победил (указано место)\n"
"Не выиграл - если логин не получил приз\n\n"
"⚠️ <b>Важное уточнение о статусе логинов:</b>\n\n"
"✅ <b>Зеленый (активный)</b> - логин участвует в новых розыгрышах\n"
"⏸️ <b>Серый (неактивный)</b> - логин не участвует в новых розыгрышах\n\n"
"Имейте в виду, что логины, которые участвовали в закрытых розыгрышах, "
"<b>не добавляются в новые розыгрыши</b>. В списке отображаются только те логины, "
"которые активны и соответствуют условиям текущих розыгрышей.\n\n"
"<b>Как это работает:</b>\n\n"
"1⃣ Если у вас есть 100 логинов\n"
"2⃣ 60 из них участвовали в прошедших/закрытых розыгрышах\n"
"3⃣ Статус этих 60 логинов будет ⏸️ (неактивны)\n"
"4⃣ Они не добавляются в новые розыгрыши\n"
"5В новых розыгрышах участвуют только оставшиеся активные логины\n\n"
"<b>Как использовать:</b>\n\n" "<b>Как использовать:</b>\n\n"
"1⃣ Откройте главное меню\n" "1⃣ Откройте главное меню\n"
"2⃣ Нажмите кнопку <i>\"Мои логины\"</i>\n" "2⃣ Нажмите кнопку <i>\"Мои логины\"</i>\n"
"3⃣ Вы увидите список всех ваших активных логинов\n\n" "3⃣ Вы увидите полный список всех ваших логинов с информацией\n\n"
"📋 <b>Что показывается:</b>\n\n"
" ✅ Активные логины, добавленные администратором\n"
" ✅ Логины, соответствующие условиям розыгрышей\n"
" ❌ Неотыгранные логины (в них не проводятся розыгрыши)\n\n"
"💡 <b>Совет:</b>\n" "💡 <b>Совет:</b>\n"
"Если вы не видите ожидаемый логин в списке, это значит, что он не соответствует " "Если вы не видите ожидаемый логин в списке активных розыгрышей, "
"условиям текущих розыгрышей или администратор еще не добавил его в систему. " "это может означать, что он уже участвовал в закрытых розыгрышах и помечен как неактивный. "
"Свяжитесь с администратором для уточнения.\n\n" "Свяжитесь с администратором для уточнения.\n\n"
"🔄 <b>Обновление информации:</b>\n" "🔄 <b>Обновление информации:</b>\n"

View File

@@ -2,6 +2,8 @@
from aiogram import Router, F from aiogram import Router, F
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.filters import Command, StateFilter from aiogram.filters import Command, StateFilter
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from src.filters.case_insensitive import CaseInsensitiveCommand from src.filters.case_insensitive import CaseInsensitiveCommand
from aiogram.fsm.context import FSMContext from aiogram.fsm.context import FSMContext
@@ -11,6 +13,7 @@ import logging
from src.core.database import async_session_maker from src.core.database import async_session_maker
from src.core.registration_services import RegistrationService, AccountService from src.core.registration_services import RegistrationService, AccountService
from src.core.services import UserService from src.core.services import UserService
from src.core.models import Participation, Winner, Lottery
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
router = Router() router = Router()
@@ -222,7 +225,7 @@ async def show_verification_code(message: Message):
@router.message(Command("my_accounts")) @router.message(Command("my_accounts"))
async def show_user_accounts(message: Message): async def show_user_accounts(message: Message):
"""Показать счета пользователя""" """Показать логины пользователя с информацией о розыгрышах"""
async with async_session_maker() as session: async with async_session_maker() as session:
user = await UserService.get_user_by_telegram_id(session, message.from_user.id) 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: if not accounts:
await message.answer( await message.answer(
"У вас пока нет привязанных счетов.\n\n" "У вас пока нет привязанных логинов.\n\n"
"Счета добавляются администратором." "Логины добавляются администратором."
) )
return return
text = f"💳 Ваши счета (Клубная карта: {user.club_card_number}):\n\n" text = f"📱 <b>Ваши логины</b> (Клубная карта: {user.club_card_number})\n\n"
for i, account in enumerate(accounts, 1): for i, account in enumerate(accounts, 1):
status = "" if account.is_active else "" # Получаем participations для этого account с загруженными данными о lottery
text += f"{i}. {status} {account.account_number}\n" participations = await session.execute(
select(Participation)
.where(Participation.account_id == account.id)
.options(selectinload(Participation.lottery))
)
participations = participations.scalars().all()
await message.answer(text) # Определяем статус логина
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} <b>{account.account_number}</b>\n"
if active_participations:
text += " 🎲 <b>Активные розыгрыши:</b>\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 += " 🏁 <b>Завершенные розыгрыши:</b>\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} - <b>ВЫИГРАЛ!</b> ({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"
# Добавляем примечание о неактивных логинах
if any(not acc.is_active for acc in accounts):
text += "⏸️ - Логин не участвует в новых розыгрышах\n"
text += "✅ - Логин активен и может участвовать\n\n"
text += "💡 <b>Заметка:</b> Логины, участвовавшие в закрытых розыгрышах, не добавляются в новые розыгрыши."
await message.answer(text, parse_mode="HTML")