feat: Полный рефакторинг с модульной архитектурой
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:
2025-11-17 05:34:08 +09:00
parent 4e06e6296c
commit 4a741715f5
24 changed files with 3427 additions and 1050 deletions

179
src/interfaces/base.py Normal file
View File

@@ -0,0 +1,179 @@
from abc import ABC, abstractmethod
from typing import Optional, List, Dict, Any
from src.core.models import User, Lottery, Participation, Winner
class IUserRepository(ABC):
"""Интерфейс репозитория пользователей"""
@abstractmethod
async def get_by_telegram_id(self, telegram_id: int) -> Optional[User]:
"""Получить пользователя по Telegram ID"""
pass
@abstractmethod
async def create(self, **kwargs) -> User:
"""Создать нового пользователя"""
pass
@abstractmethod
async def update(self, user: User) -> User:
"""Обновить пользователя"""
pass
@abstractmethod
async def get_all(self) -> List[User]:
"""Получить всех пользователей"""
pass
class ILotteryRepository(ABC):
"""Интерфейс репозитория розыгрышей"""
@abstractmethod
async def get_by_id(self, lottery_id: int) -> Optional[Lottery]:
"""Получить розыгрыш по ID"""
pass
@abstractmethod
async def create(self, **kwargs) -> Lottery:
"""Создать новый розыгрыш"""
pass
@abstractmethod
async def get_active(self) -> List[Lottery]:
"""Получить активные розыгрыши"""
pass
@abstractmethod
async def get_all(self) -> List[Lottery]:
"""Получить все розыгрыши"""
pass
@abstractmethod
async def update(self, lottery: Lottery) -> Lottery:
"""Обновить розыгрыш"""
pass
class IParticipationRepository(ABC):
"""Интерфейс репозитория участий"""
@abstractmethod
async def create(self, **kwargs) -> Participation:
"""Создать новое участие"""
pass
@abstractmethod
async def get_by_lottery(self, lottery_id: int) -> List[Participation]:
"""Получить участия по розыгрышу"""
pass
@abstractmethod
async def get_count_by_lottery(self, lottery_id: int) -> int:
"""Получить количество участников в розыгрыше"""
pass
class IWinnerRepository(ABC):
"""Интерфейс репозитория победителей"""
@abstractmethod
async def create(self, **kwargs) -> Winner:
"""Создать запись о победителе"""
pass
@abstractmethod
async def get_by_lottery(self, lottery_id: int) -> List[Winner]:
"""Получить победителей розыгрыша"""
pass
class ILotteryService(ABC):
"""Интерфейс сервиса розыгрышей"""
@abstractmethod
async def create_lottery(self, title: str, description: str, prizes: List[str], creator_id: int) -> Lottery:
"""Создать новый розыгрыш"""
pass
@abstractmethod
async def conduct_draw(self, lottery_id: int) -> Dict[str, Any]:
"""Провести розыгрыш"""
pass
@abstractmethod
async def get_active_lotteries(self) -> List[Lottery]:
"""Получить активные розыгрыши"""
pass
class IUserService(ABC):
"""Интерфейс сервиса пользователей"""
@abstractmethod
async def get_or_create_user(self, telegram_id: int, **kwargs) -> User:
"""Получить или создать пользователя"""
pass
@abstractmethod
async def register_user(self, telegram_id: int, phone: str, club_card_number: str) -> bool:
"""Зарегистрировать пользователя"""
pass
class IBotController(ABC):
"""Интерфейс контроллера бота"""
@abstractmethod
async def handle_start(self, message_or_callback):
"""Обработать команду /start"""
pass
@abstractmethod
async def handle_admin_panel(self, callback):
"""Обработать admin panel"""
pass
class IMessageFormatter(ABC):
"""Интерфейс форматирования сообщений"""
@abstractmethod
def format_lottery_info(self, lottery: Lottery, participants_count: int) -> str:
"""Форматировать информацию о розыгрыше"""
pass
@abstractmethod
def format_winners_list(self, winners: List[Winner]) -> str:
"""Форматировать список победителей"""
pass
class IKeyboardBuilder(ABC):
"""Интерфейс создания клавиатур"""
@abstractmethod
def get_main_keyboard(self, is_admin: bool):
"""Получить главную клавиатуру"""
pass
@abstractmethod
def get_admin_keyboard(self):
"""Получить админскую клавиатуру"""
pass
@abstractmethod
def get_lottery_keyboard(self, lottery_id: int, is_admin: bool):
"""Получить клавиатуру для розыгрыша"""
pass
@abstractmethod
def get_lottery_management_keyboard(self):
"""Получить клавиатуру управления розыгрышами"""
pass
@abstractmethod
def get_conduct_lottery_keyboard(self, lotteries: List[Lottery]):
"""Получить клавиатуру для выбора розыгрыша для проведения"""
pass