import datetime import logging from aiogram.types import Message, User as TelegramUser from remnawave import RemnawaveSDK from sqlalchemy.ext.asyncio import AsyncSession from bot.texts import ( NO_SUBSCRIPTION, NOTHING_PLACEHOLDER, SUBSCRIPTION_INFORMATION, ) from db.models.users import User from misc import utils from repositories import UserRepository from repositories.subscriptions import SubscriptionRepository from schemas.subscriptions import InternalSquads, SubscriptionPlan, SubscriptionStatus from schemas.users import NewUserDTO from services import rw logger = logging.getLogger(__name__) class UserServiceError(Exception): ... class UserService: def __init__( self, user_repository: UserRepository, subscription_repository: SubscriptionRepository ) -> None: self.user_repository = user_repository self.subscription_repository = subscription_repository @staticmethod def format_subscription_message( rw_user: rw.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 rw.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 | None: rw_user = await rw.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 async def buy_subscription( self, session: AsyncSession, subscription: SubscriptionPlan, rw_sdk: RemnawaveSDK, user: TelegramUser, ): duration = utils.convert_duration_to_timedelta(subscription.duration) squads = [InternalSquads.DEFAULT] if subscription.whitelists: squads.append(InternalSquads.WHITELISTS) ## If subscription exists, add. rw_user = await rw.get_user_by_telegram_id(rw_sdk, user.id) if rw_user: db_subscription = await self.subscription_repository.get_subscription_by_user_id( session, user.id ) if db_subscription: db_subscription = await self.subscription_repository.update_sub( session, user.id, end_date=rw_user.expire_at + duration, autorenew=False, status=SubscriptionStatus.ACTIVE, devices=int(subscription.devices), whitelists=subscription.whitelists, plan_price_paid=utils.calculate_price(subscription), duration_days=duration.days, ) else: db_subscription = await self.subscription_repository.create_subscription( session, user_id=user.id, end_date=rw_user.expire_at + duration, autorenew=False, status=SubscriptionStatus.ACTIVE, devices=int(subscription.devices), whitelists=subscription.whitelists, plan_price_paid=utils.calculate_price(subscription), duration_days=duration.days, ) await rw.add_days(rw_sdk, rw_user.uuid, duration.days) await rw.update_squads(rw_sdk, rw_user.uuid, squads) await rw.set_hwid_limit(rw_sdk, rw_user.uuid, subscription.devices) await self.update_user_link(session, user.id, rw_sdk) return db_subscription # Create expire = datetime.datetime.now(datetime.UTC) + duration username = "tg_" + str(user.username or user.id) rw_user = await rw.create_user( rw_sdk, username=username, telegram_id=user.id, expire_at=expire, hwid_device_limit=subscription.devices, squad_uuids=squads, ) db_subscription = await self.subscription_repository.get_subscription_by_user_id( session, user.id ) if db_subscription: db_subscription = await self.subscription_repository.update_sub( session, user.id, end_date=expire, autorenew=False, status=SubscriptionStatus.ACTIVE, devices=int(subscription.devices), whitelists=subscription.whitelists, plan_price_paid=utils.calculate_price(subscription), duration_days=duration.days, ) else: db_subscription = await self.subscription_repository.create_subscription( session, user_id=user.id, end_date=expire, autorenew=False, status=SubscriptionStatus.ACTIVE, devices=int(subscription.devices), whitelists=subscription.whitelists, plan_price_paid=utils.calculate_price(subscription), duration_days=duration.days, ) await self.update_user_link(session, user.id, rw_sdk) return db_subscription