Files
tg_bot_language/services/user_service.py
mamonov.ep 3e5c1be464 feat: add translation language setting & onboarding flow
- Add separate translation_language setting (independent from interface language)
- Implement 3-step onboarding for new users:
  1. Choose interface language
  2. Choose learning language
  3. Choose translation language
- Fix localization issues when using callback.message (user_id from state)
- Add UserService.get_user_by_id() method
- Add get_user_translation_lang() helper in i18n
- Update all handlers to use correct translation language
- Add localization keys for onboarding (ru/en/ja)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 16:35:08 +03:00

159 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()