import logging from aiogram.types import Message from remnawave import RemnawaveSDK from sqlalchemy.ext.asyncio import AsyncSession from db.models.tickets import TicketStatus from db.models.users import User from misc import utils from repositories import UserRepository from repositories.tickets import TicketRepository from schemas.users import NewUserDTO, TicketCreator from services.rw import RWUserInfo, get_user_by_telegram_id from texts import ( NO_SUBSCRIPTION, NOTHING_PLACEHOLDER, SUBSCRIPTION_INFORMATION, TICKET_STATUS_EMOJIS, ) logger = logging.getLogger(__name__) class UserServiceError(Exception): ... class UserService: def __init__( self, user_repository: UserRepository, ticket_repository: TicketRepository ) -> None: self.user_repository = user_repository self.ticket_repository = ticket_repository @staticmethod def format_ticket_name( creator: TicketCreator, status: TicketStatus | None = TicketStatus.OPEN, ticket_id: int | None = None, ): return ( TICKET_STATUS_EMOJIS[status.value] + (f" T-{ticket_id:0>3}" if ticket_id else "") + " | " + (f"@{creator.username}" if creator.username else str(creator.id)) ) @staticmethod def format_subscription_message( rw_user: RWUserInfo | None, link: str | None = None, ): if rw_user is None: # Пользователь не найден в Remnawave return NO_SUBSCRIPTION status_icon, status_text = utils.format_status(rw_user.status) expire_date = rw_user.expire_at.strftime("%d.%m.%Y") days_left = utils.format_days_left(rw_user.expire_at) used_traffic = utils.format_traffic(rw_user.used_traffic_bytes, rw_user.traffic_limit_bytes) hwid_limit = utils.format_hwid_limit(rw_user.hwid_device_limit) link = link or NOTHING_PLACEHOLDER return SUBSCRIPTION_INFORMATION.format( status_icon=status_icon, status=status_text, expire_date=expire_date, days_left=days_left, used_traffic=used_traffic, hwid_limit=hwid_limit, link=link, ) async def add_user( self, session: AsyncSession, user_id: int, rw_sdk: RemnawaveSDK, referal: int | None = None, ) -> User: user = await self.user_repository.get_user_by_id(session, user_id) if user: return user rw_user = await get_user_by_telegram_id(rw_sdk, user_id) link = utils.get_subscription_link(rw_user.short_uuid) if rw_user else None referal = int(referal) if str(referal).isdigit() and user_id != int(referal) else None model = NewUserDTO(id=user_id, referal=referal, link=link) return await self.user_repository.create_user(session, model) async def update_user_link( self, session: AsyncSession, user_id: int, rw_sdk: RemnawaveSDK ) -> User: rw_user = await get_user_by_telegram_id(rw_sdk, user_id) user = await self.user_repository.get_user_by_id(session, user_id) if not rw_user: return user link = utils.get_subscription_link(rw_user.short_uuid) user = await self.user_repository.update_user_link(session, user_id, link) return user async def send_promotion_to_users(self, session: AsyncSession, msg: Message) -> list[User]: users = await self.user_repository.get_users(session) sent: list[User] = [] for user in users: try: await msg.copy_to(user.id) sent.append(user) except Exception: logger.critical("failed to send a message to user %d.", user.id, exc_info=True) return sent