- Added notifications for successful payments in `api/core/notifications.py`. - Created main API entry point in `api/main.py` with FastAPI integration. - Established routing structure in `api/routes/__init__.py` and `api/routes/pally.py` for handling payment callbacks. - Developed billing handlers in `bot/handlers/billing.py` and `bot/handlers/buy.py` for subscription management. - Introduced state management for user interactions in `bot/states/`. - Created user interface elements in `bot/keyboards/` for navigation and payment processing. - Set up middleware for dependency injection in `bot/middlewares/di.py`. - Added support for user commands and interactions in `bot/handlers/common.py` and `bot/handlers/support.py`. - Implemented logging and error handling throughout the bot's functionality. - Created entry point script for API server in `entrypoints/api.sh`.
100 lines
3.2 KiB
Python
100 lines
3.2 KiB
Python
import logging
|
|
|
|
from aiogram.types import Message
|
|
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 schemas.users import NewUserDTO
|
|
from services.rw import RWUserInfo, get_user_by_telegram_id
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class UserServiceError(Exception): ...
|
|
|
|
|
|
class UserService:
|
|
def __init__(self, user_repository: UserRepository) -> None:
|
|
self.user_repository = user_repository
|
|
|
|
@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 | None:
|
|
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
|