from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from database.models import User, LanguageLevel from typing import Optional from utils.levels import set_user_level_for_language, get_default_level class UserService: """Сервис для работы с пользователями""" @staticmethod async def get_or_create_user(session: AsyncSession, telegram_id: int, username: Optional[str] = None) -> User: """ Получить пользователя или создать нового Args: session: Сессия базы данных telegram_id: Telegram ID пользователя username: Username пользователя Returns: Объект пользователя """ # Попытка найти существующего пользователя result = await session.execute( select(User).where(User.telegram_id == telegram_id) ) user = result.scalar_one_or_none() if user: return user # Создание нового пользователя new_user = User( telegram_id=telegram_id, username=username, level=LanguageLevel.A1 ) session.add(new_user) await session.commit() await session.refresh(new_user) return new_user @staticmethod async def get_user_by_telegram_id(session: AsyncSession, telegram_id: int) -> Optional[User]: """ Получить пользователя по Telegram ID Args: session: Сессия базы данных telegram_id: Telegram ID пользователя Returns: Объект пользователя или None """ result = await session.execute( select(User).where(User.telegram_id == telegram_id) ) return result.scalar_one_or_none() @staticmethod async def get_user_by_id(session: AsyncSession, user_id: int) -> Optional[User]: """ Получить пользователя по внутреннему ID Args: session: Сессия базы данных user_id: ID пользователя в БД Returns: Объект пользователя или None """ result = await session.execute( select(User).where(User.id == user_id) ) return result.scalar_one_or_none() @staticmethod async def update_user_level(session: AsyncSession, user_id: int, level: str, language: str = None): """ Обновить уровень пользователя для языка изучения. Args: session: Сессия базы данных user_id: ID пользователя level: Новый уровень (строка, например "B1" или "N4") language: Язык (если None, берётся learning_language пользователя) """ result = await session.execute( select(User).where(User.id == user_id) ) user = result.scalar_one_or_none() if user: # Сохраняем в JSON для всех языков set_user_level_for_language(user, level, language) # Для обратной совместимости обновляем старое поле level (только для CEFR) if level in ["A1", "A2", "B1", "B2", "C1", "C2"]: user.level = LanguageLevel[level] await session.commit() @staticmethod async def update_user_language(session: AsyncSession, user_id: int, language: str): """ Обновить язык интерфейса пользователя Args: session: Сессия базы данных user_id: ID пользователя language: Новый язык (ru/en) """ result = await session.execute( select(User).where(User.id == user_id) ) user = result.scalar_one_or_none() if user: user.language_interface = language await session.commit() @staticmethod async def update_user_learning_language(session: AsyncSession, user_id: int, language: str): """ Обновить язык изучения пользователя Args: session: Сессия базы данных user_id: ID пользователя language: Новый язык изучения (ISO2) """ result = await session.execute( select(User).where(User.id == user_id) ) user = result.scalar_one_or_none() if user: user.learning_language = language await session.commit() @staticmethod async def update_user_translation_language(session: AsyncSession, user_id: int, language: str): """ Обновить язык перевода пользователя Args: session: Сессия базы данных user_id: ID пользователя language: Новый язык перевода (ru/en/ja) """ result = await session.execute( select(User).where(User.id == user_id) ) user = result.scalar_one_or_none() if user: user.translation_language = language await session.commit() @staticmethod async def update_user_tasks_count(session: AsyncSession, user_id: int, count: int): """ Обновить количество заданий пользователя Args: session: Сессия базы данных user_id: ID пользователя count: Количество заданий (5-15) """ # Валидация диапазона count = max(5, min(15, count)) result = await session.execute( select(User).where(User.id == user_id) ) user = result.scalar_one_or_none() if user: user.tasks_count = count await session.commit() @staticmethod async def update_user_ai_model(session: AsyncSession, user_id: int, model_id: Optional[int]): """ Обновить AI модель пользователя Args: session: Сессия базы данных user_id: ID пользователя model_id: ID модели или None для глобальной """ result = await session.execute( select(User).where(User.id == user_id) ) user = result.scalar_one_or_none() if user: user.ai_model_id = model_id await session.commit()