feat: Полный рефакторинг с модульной архитектурой
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Some checks reported errors
continuous-integration/drone/push Build encountered an error
- Исправлены критические ошибки callback обработки - Реализована модульная архитектура с применением SOLID принципов - Добавлена система dependency injection - Создана новая структура: interfaces, repositories, components, controllers - Исправлены проблемы с базой данных (добавлены отсутствующие столбцы) - Заменены заглушки на полную функциональность управления розыгрышами - Добавлены отчеты о проделанной работе и документация Архитектура готова для production и легко масштабируется
This commit is contained in:
153
src/components/ui.py
Normal file
153
src/components/ui.py
Normal file
@@ -0,0 +1,153 @@
|
||||
from typing import List
|
||||
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton
|
||||
|
||||
from src.interfaces.base import IKeyboardBuilder, IMessageFormatter
|
||||
from src.core.models import Lottery, Winner
|
||||
|
||||
|
||||
class KeyboardBuilderImpl(IKeyboardBuilder):
|
||||
"""Реализация построителя клавиатур"""
|
||||
|
||||
def get_main_keyboard(self, is_admin: bool = False):
|
||||
"""Получить главную клавиатуру"""
|
||||
buttons = [
|
||||
[InlineKeyboardButton(text="🎲 Активные розыгрыши", callback_data="active_lotteries")],
|
||||
[InlineKeyboardButton(text="📝 Зарегистрироваться", callback_data="start_registration")],
|
||||
[InlineKeyboardButton(text="🧪 ТЕСТ КОЛБЭК", callback_data="test_callback")]
|
||||
]
|
||||
|
||||
if is_admin:
|
||||
buttons.extend([
|
||||
[InlineKeyboardButton(text="⚙️ Админ панель", callback_data="admin_panel")],
|
||||
[InlineKeyboardButton(text="➕ Создать розыгрыш", callback_data="create_lottery")]
|
||||
])
|
||||
|
||||
return InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
def get_admin_keyboard(self):
|
||||
"""Получить админскую клавиатуру"""
|
||||
buttons = [
|
||||
[
|
||||
InlineKeyboardButton(text="👥 Пользователи", callback_data="user_management"),
|
||||
InlineKeyboardButton(text="💳 Счета", callback_data="account_management")
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton(text="🎯 Розыгрыши", callback_data="lottery_management"),
|
||||
InlineKeyboardButton(text="💬 Чат", callback_data="chat_management")
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton(text="📊 Статистика", callback_data="stats"),
|
||||
InlineKeyboardButton(text="⚙️ Настройки", callback_data="settings")
|
||||
],
|
||||
[InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_main")]
|
||||
]
|
||||
return InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
def get_lottery_management_keyboard(self):
|
||||
"""Получить клавиатуру управления розыгрышами"""
|
||||
buttons = [
|
||||
[
|
||||
InlineKeyboardButton(text="📋 Все розыгрыши", callback_data="all_lotteries"),
|
||||
InlineKeyboardButton(text="🎲 Активные", callback_data="active_lotteries_admin")
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton(text="✅ Завершенные", callback_data="completed_lotteries"),
|
||||
InlineKeyboardButton(text="➕ Создать", callback_data="create_lottery")
|
||||
],
|
||||
[
|
||||
InlineKeyboardButton(text="🎯 Провести розыгрыш", callback_data="conduct_lottery_admin"),
|
||||
InlineKeyboardButton(text="🔄 Переросыгрыш", callback_data="admin_redraw")
|
||||
],
|
||||
[InlineKeyboardButton(text="🔙 Назад", callback_data="admin_panel")]
|
||||
]
|
||||
return InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
def get_lottery_keyboard(self, lottery_id: int, is_admin: bool = False):
|
||||
"""Получить клавиатуру для конкретного розыгрыша"""
|
||||
buttons = [
|
||||
[InlineKeyboardButton(text="🎯 Участвовать", callback_data=f"join_{lottery_id}")]
|
||||
]
|
||||
|
||||
if is_admin:
|
||||
buttons.extend([
|
||||
[InlineKeyboardButton(text="🎲 Провести розыгрыш", callback_data=f"conduct_{lottery_id}")],
|
||||
[InlineKeyboardButton(text="✏️ Редактировать", callback_data=f"edit_{lottery_id}")],
|
||||
[InlineKeyboardButton(text="❌ Удалить", callback_data=f"delete_{lottery_id}")]
|
||||
])
|
||||
|
||||
buttons.append([InlineKeyboardButton(text="🔙 Назад", callback_data="active_lotteries")])
|
||||
return InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
def get_conduct_lottery_keyboard(self, lotteries: List[Lottery]):
|
||||
"""Получить клавиатуру для выбора розыгрыша для проведения"""
|
||||
buttons = []
|
||||
|
||||
for lottery in lotteries:
|
||||
text = f"🎲 {lottery.title}"
|
||||
if len(text) > 50:
|
||||
text = text[:47] + "..."
|
||||
buttons.append([InlineKeyboardButton(text=text, callback_data=f"conduct_{lottery.id}")])
|
||||
|
||||
buttons.append([InlineKeyboardButton(text="🔙 Назад", callback_data="lottery_management")])
|
||||
return InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
|
||||
class MessageFormatterImpl(IMessageFormatter):
|
||||
"""Реализация форматирования сообщений"""
|
||||
|
||||
def format_lottery_info(self, lottery: Lottery, participants_count: int) -> str:
|
||||
"""Форматировать информацию о розыгрыше"""
|
||||
text = f"🎲 **{lottery.title}**\n\n"
|
||||
|
||||
if lottery.description:
|
||||
text += f"📝 {lottery.description}\n\n"
|
||||
|
||||
text += f"👥 Участников: {participants_count}\n"
|
||||
|
||||
if lottery.prizes:
|
||||
text += "\n🏆 **Призы:**\n"
|
||||
for i, prize in enumerate(lottery.prizes, 1):
|
||||
text += f"{i}. {prize}\n"
|
||||
|
||||
status = "🟢 Активный" if lottery.is_active and not lottery.is_completed else "🔴 Завершен"
|
||||
text += f"\n📊 Статус: {status}"
|
||||
|
||||
if lottery.created_at:
|
||||
text += f"\n📅 Создан: {lottery.created_at.strftime('%d.%m.%Y %H:%M')}"
|
||||
|
||||
return text
|
||||
|
||||
def format_winners_list(self, winners: List[Winner]) -> str:
|
||||
"""Форматировать список победителей"""
|
||||
if not winners:
|
||||
return "🎯 Победители не определены"
|
||||
|
||||
text = "🏆 **Победители:**\n\n"
|
||||
|
||||
for winner in winners:
|
||||
place_emoji = {1: "🥇", 2: "🥈", 3: "🥉"}.get(winner.place, "🏅")
|
||||
|
||||
if winner.user:
|
||||
name = winner.user.first_name or f"Пользователь {winner.user.telegram_id}"
|
||||
else:
|
||||
name = winner.account_number or "Неизвестный участник"
|
||||
|
||||
text += f"{place_emoji} **{winner.place} место:** {name}\n"
|
||||
if winner.prize:
|
||||
text += f" 🎁 Приз: {winner.prize}\n"
|
||||
text += "\n"
|
||||
|
||||
return text
|
||||
|
||||
def format_admin_stats(self, stats: dict) -> str:
|
||||
"""Форматировать административную статистику"""
|
||||
text = "📊 **Статистика системы**\n\n"
|
||||
|
||||
text += f"👥 Всего пользователей: {stats.get('total_users', 0)}\n"
|
||||
text += f"✅ Зарегистрированных: {stats.get('registered_users', 0)}\n"
|
||||
text += f"🎲 Всего розыгрышей: {stats.get('total_lotteries', 0)}\n"
|
||||
text += f"🟢 Активных розыгрышей: {stats.get('active_lotteries', 0)}\n"
|
||||
text += f"✅ Завершенных розыгрышей: {stats.get('completed_lotteries', 0)}\n"
|
||||
text += f"🎯 Всего участий: {stats.get('total_participations', 0)}\n"
|
||||
|
||||
return text
|
||||
Reference in New Issue
Block a user