209 lines
9.0 KiB
Python
209 lines
9.0 KiB
Python
"""
|
|
Сервис для управления пользователями
|
|
"""
|
|
from datetime import datetime
|
|
from typing import Optional, Tuple
|
|
from aiogram.types import User as TelegramUser
|
|
|
|
from models.user import User
|
|
from services.infrastructure.database import DatabaseService
|
|
from services.utils import UtilsService
|
|
from services.infrastructure.logger import get_logger
|
|
from services.infrastructure.metrics import get_metrics_service
|
|
from services.infrastructure.logging_decorators import log_function_call, log_business_event
|
|
from services.infrastructure.logging_utils import log_user_created, log_user_blocked
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
class UserService:
|
|
"""Сервис для управления пользователями"""
|
|
|
|
def __init__(self, database: DatabaseService, utils: UtilsService):
|
|
self.database = database
|
|
self.utils = utils
|
|
self.metrics = get_metrics_service()
|
|
|
|
@log_business_event("create_or_update_user", log_params=True, log_result=True)
|
|
async def create_or_update_user(self, telegram_user: TelegramUser, chat_id: int) -> User:
|
|
"""
|
|
Создание или обновление пользователя
|
|
|
|
Args:
|
|
telegram_user: Объект пользователя из Telegram
|
|
chat_id: ID чата
|
|
|
|
Returns:
|
|
Объект пользователя
|
|
"""
|
|
try:
|
|
# Проверяем, существует ли пользователь
|
|
existing_user = await self.database.get_user(telegram_user.id)
|
|
|
|
if existing_user:
|
|
# Обновляем существующего пользователя
|
|
logger.info(f"👤 Обновление существующего пользователя {telegram_user.id}")
|
|
self.metrics.increment_users("updated")
|
|
return await self._update_existing_user(existing_user, telegram_user, chat_id)
|
|
else:
|
|
# Создаем нового пользователя
|
|
logger.info(f"👤 Создание нового пользователя {telegram_user.id}")
|
|
self.metrics.increment_users("created")
|
|
return await self._create_new_user(telegram_user, chat_id)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при создании/обновлении пользователя {telegram_user.id}: {e}")
|
|
raise
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
async def _update_existing_user(self, existing_user: User, telegram_user: TelegramUser, chat_id: int) -> User:
|
|
"""Обновление существующего пользователя"""
|
|
existing_user.username = telegram_user.username
|
|
existing_user.first_name = telegram_user.first_name or "Пользователь"
|
|
existing_user.last_name = telegram_user.last_name
|
|
existing_user.chat_id = chat_id
|
|
existing_user.update_timestamp()
|
|
|
|
return await self.database.update_user(existing_user)
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
async def _create_new_user(self, telegram_user: TelegramUser, chat_id: int) -> User:
|
|
"""Создание нового пользователя"""
|
|
user = User(
|
|
telegram_id=telegram_user.id,
|
|
username=telegram_user.username,
|
|
first_name=telegram_user.first_name or "Пользователь",
|
|
last_name=telegram_user.last_name,
|
|
chat_id=chat_id,
|
|
profile_link=self.utils.generate_anonymous_id(),
|
|
is_active=True,
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now()
|
|
)
|
|
|
|
return await self.database.create_user(user)
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
async def get_user_by_profile_link(self, profile_link: str) -> Optional[User]:
|
|
"""
|
|
Получение пользователя по ссылке профиля
|
|
|
|
Args:
|
|
profile_link: Ссылка профиля
|
|
|
|
Returns:
|
|
Объект пользователя или None
|
|
"""
|
|
try:
|
|
return await self.database.get_user_by_profile_link(profile_link)
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при получении пользователя по ссылке {profile_link}: {e}")
|
|
return None
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
async def get_user_by_telegram_id(self, telegram_id: int) -> Optional[User]:
|
|
"""
|
|
Получение пользователя по Telegram ID
|
|
|
|
Args:
|
|
telegram_id: ID пользователя в Telegram
|
|
|
|
Returns:
|
|
Объект пользователя или None
|
|
"""
|
|
try:
|
|
return await self.database.get_user(telegram_id)
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при получении пользователя {telegram_id}: {e}")
|
|
return None
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
def generate_referral_link(self, bot_username: str, user: User) -> str:
|
|
"""
|
|
Генерация реферальной ссылки для пользователя
|
|
|
|
Args:
|
|
bot_username: Имя бота
|
|
user: Объект пользователя
|
|
|
|
Returns:
|
|
Реферальная ссылка
|
|
"""
|
|
return self.utils.generate_referral_link(bot_username, user.profile_link)
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
async def is_user_blocked(self, blocker_id: int, blocked_id: int) -> bool:
|
|
"""
|
|
Проверка, заблокирован ли пользователь
|
|
|
|
Args:
|
|
blocker_id: ID пользователя, который блокирует
|
|
blocked_id: ID пользователя, которого блокируют
|
|
|
|
Returns:
|
|
True если заблокирован, False иначе
|
|
"""
|
|
try:
|
|
return await self.database.is_user_blocked(blocker_id, blocked_id)
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при проверке блокировки {blocker_id} -> {blocked_id}: {e}")
|
|
return False
|
|
|
|
@log_business_event("block_user", log_params=True, log_result=True)
|
|
async def block_user(self, blocker_id: int, blocked_id: int) -> bool:
|
|
"""
|
|
Блокировка пользователя
|
|
|
|
Args:
|
|
blocker_id: ID пользователя, который блокирует
|
|
blocked_id: ID пользователя, которого блокируют
|
|
|
|
Returns:
|
|
True если успешно заблокирован
|
|
"""
|
|
try:
|
|
await self.database.block_user(blocker_id, blocked_id)
|
|
logger.info(f"Пользователь {blocked_id} заблокирован пользователем {blocker_id}")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при блокировке пользователя {blocked_id}: {e}")
|
|
return False
|
|
|
|
@log_business_event("unblock_user", log_params=True, log_result=True)
|
|
async def unblock_user(self, blocker_id: int, blocked_id: int) -> bool:
|
|
"""
|
|
Разблокировка пользователя
|
|
|
|
Args:
|
|
blocker_id: ID пользователя, который разблокирует
|
|
blocked_id: ID пользователя, которого разблокируют
|
|
|
|
Returns:
|
|
True если успешно разблокирован
|
|
"""
|
|
try:
|
|
result = await self.database.unblock_user(blocker_id, blocked_id)
|
|
if result:
|
|
logger.info(f"Пользователь {blocked_id} разблокирован пользователем {blocker_id}")
|
|
return result
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при разблокировке пользователя {blocked_id}: {e}")
|
|
return False
|
|
|
|
@log_function_call(log_params=True, log_result=True)
|
|
async def get_blocked_users(self, user_id: int) -> list:
|
|
"""
|
|
Получение списка заблокированных пользователей
|
|
|
|
Args:
|
|
user_id: ID пользователя
|
|
|
|
Returns:
|
|
Список ID заблокированных пользователей
|
|
"""
|
|
try:
|
|
return await self.database.user_blocks.get_blocked_users(user_id)
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при получении заблокированных пользователей для {user_id}: {e}")
|
|
return []
|