from aiogram import F, Router from aiogram.filters import Command, CommandObject, CommandStart from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery, Message from sqlalchemy.ext.asyncio import AsyncSession from bot.keyboards.client import ( close_kb, construct_devices_list, main_menu, prompt_hwid_deletion_kb, subscription_controls, ) from bot.keyboards.common import return_to_menu from bot.texts import ( CALLBACK_FALLBACK, FAQ_TEXT, GENERAL_PROCESSING, HWID_LIST, NO_CONNECTIONS, NO_SUBSCRIPTION, PROMPT_HWID_DELETION, STANDARD_FALLBACK, SUCCESSFUL_HWID_DELETION, ) from db.models.users import User from misc import utils from misc.utils import ( build_main_menu_text, convert_duration_to_int, format_subscription_link, ) from schemas.di import DependenciesDTO from schemas.subscriptions import ( InternalSquads, SubscriptionDuration, SubscriptionPlan, SubscriptionStatus, ) from services.rw import delete_hwid, get_hwid_list, get_user_by_telegram_id router = Router() @router.message(CommandStart(deep_link=True, deep_link_encoded=True)) async def fetch_referal( msg: Message, command: CommandObject, state: FSMContext, session: AsyncSession, deps: DependenciesDTO, ): await state.clear() data = command.args.split("_") if not data: await standard_start(msg, state, session, deps) return referal = int(data[1]) user = await deps.user_service.add_user( session, user_id=msg.from_user.id, referal=referal, rw_sdk=deps.rw_sdk ) await msg.answer( build_main_menu_text( format_subscription_link(user.subscription_link), balance=user.balance ), reply_markup=main_menu, ) @router.message(Command(commands=["start", "cancel"])) async def standard_start( msg: Message, state: FSMContext, session: AsyncSession, deps: DependenciesDTO, ): await state.clear() user = await deps.user_service.add_user(session, user_id=msg.from_user.id, rw_sdk=deps.rw_sdk) await msg.answer( build_main_menu_text( format_subscription_link(user.subscription_link), balance=user.balance ), reply_markup=main_menu, ) @router.callback_query(F.data == "menu:main") async def main_menu_cb( cb: CallbackQuery, state: FSMContext, session: AsyncSession, deps: DependenciesDTO ): await state.clear() user = await deps.user_repository.get_user_by_id(session, cb.from_user.id) await cb.message.edit_text( build_main_menu_text( format_subscription_link(user.subscription_link), balance=user.balance ), reply_markup=main_menu, ) @router.callback_query(F.data == "update_link") async def update_link( cb: CallbackQuery, state: FSMContext, session: AsyncSession, deps: DependenciesDTO ): await state.clear() await cb.message.edit_text(GENERAL_PROCESSING) user = await deps.user_service.update_user_link(session, cb.from_user.id, deps.rw_sdk) await cb.answer("✅") await cb.message.edit_text( build_main_menu_text( format_subscription_link(user.subscription_link), balance=user.balance ), reply_markup=main_menu, ) @router.callback_query(F.data == "faq") async def faq(cb: CallbackQuery, state: FSMContext): await state.clear() await cb.message.edit_text(FAQ_TEXT, reply_markup=return_to_menu) @router.callback_query(F.data == "sub_info") async def sub_info( cb: CallbackQuery, state: FSMContext, deps: DependenciesDTO, session: AsyncSession ): await state.clear() await cb.message.edit_text(GENERAL_PROCESSING, reply_markup=close_kb) rw_user = await get_user_by_telegram_id(deps.rw_sdk, cb.from_user.id) user: User | None = await deps.user_service.update_user_link( session, cb.from_user.id, deps.rw_sdk ) sub = await deps.subscriptions_repository.get_subscription_by_user_id(session, cb.from_user.id) if not rw_user: await cb.message.edit_text(NO_SUBSCRIPTION, reply_markup=return_to_menu) return if not user: await cb.answer(CALLBACK_FALLBACK) return dto = SubscriptionPlan( devices=max(rw_user.hwid_device_limit, 3), whitelists=bool(rw_user.active_squads.count(InternalSquads.WHITELISTS)), ) if rw_user and not sub: try: sub = await deps.subscriptions_repository.create_subscription( session, user_id=user.id, end_date=rw_user.expire_at, devices=dto.devices, duration_days=convert_duration_to_int(SubscriptionDuration.MONTH) * 30, whitelists=dto.whitelists, plan_price_paid=utils.calculate_price(dto), ) except Exception: await cb.answer(CALLBACK_FALLBACK) return else: await deps.subscriptions_repository.update_sub( session, cb.from_user.id, status=( SubscriptionStatus.ACTIVE if rw_user.status == "ACTIVE" else SubscriptionStatus.EXPIRED ), end_date=rw_user.expire_at, devices=dto.devices, whitelists=dto.whitelists, duration_days=convert_duration_to_int(SubscriptionDuration.MONTH) * 30, plan_price_paid=utils.calculate_price(dto), autorenew=sub.autorenew ) await cb.message.edit_text( deps.user_service.format_subscription_message( rw_user, link=user.subscription_link, autorenew=sub.autorenew ), reply_markup=subscription_controls( show_autorenew=bool(rw_user), current_autorenewal_status=sub.autorenew ), ) @router.callback_query(F.data == "hwid_control") async def hwid_control(cb: CallbackQuery, state: FSMContext, deps: DependenciesDTO): await state.clear() await cb.message.edit_text(GENERAL_PROCESSING, reply_markup=close_kb) rw_user = await get_user_by_telegram_id(deps.rw_sdk, cb.from_user.id) if not rw_user: await cb.message.edit_text(NO_SUBSCRIPTION, reply_markup=return_to_menu) return devices = await get_hwid_list(deps.rw_sdk, rw_user.uuid) if not devices: await cb.message.edit_text(NO_CONNECTIONS, reply_markup=return_to_menu) return hwid_limit = max(rw_user.hwid_device_limit, 3) await cb.message.edit_text( text=HWID_LIST.format(count=len(devices), limit=hwid_limit), reply_markup=construct_devices_list(devices), ) @router.callback_query(F.data.startswith("hwid:")) async def prompt_delete_hwid(cb: CallbackQuery, state: FSMContext): await state.clear() hwid = cb.data.split(":")[1] await cb.message.edit_text(PROMPT_HWID_DELETION, reply_markup=prompt_hwid_deletion_kb(hwid)) @router.callback_query(F.data.startswith("delete_hwid:")) async def delete_hwid_bot(cb: CallbackQuery, state: FSMContext, deps: DependenciesDTO): await state.clear() hwid = cb.data.split(":")[1] await cb.message.edit_text(GENERAL_PROCESSING, reply_markup=close_kb) rw_user = await get_user_by_telegram_id(deps.rw_sdk, cb.from_user.id) if not rw_user: await cb.message.edit_text(STANDARD_FALLBACK, reply_markup=return_to_menu) return status = await delete_hwid(deps.rw_sdk, rw_user.uuid, hwid) if status: await cb.message.edit_text(SUCCESSFUL_HWID_DELETION, reply_markup=return_to_menu) else: await cb.message.edit_text(STANDARD_FALLBACK, reply_markup=return_to_menu) @router.callback_query(F.data == "toggle:autorenewal") async def toggle_autorenewal( cb: CallbackQuery, state: FSMContext, session: AsyncSession, deps: DependenciesDTO ): await state.clear() await cb.message.edit_text(GENERAL_PROCESSING) sub = await deps.subscriptions_repository.get_subscription_by_user_id(session, cb.from_user.id) if not sub: await cb.answer(CALLBACK_FALLBACK) return new_autorenew = not sub.autorenew sub = await deps.subscriptions_repository.update_subscription_autorenew( session, sub.user_id, new_autorenew ) rw_user = await get_user_by_telegram_id(deps.rw_sdk, cb.from_user.id) user: User | None = await deps.user_service.update_user_link( session, cb.from_user.id, deps.rw_sdk ) status_text = "включено" if new_autorenew else "отключено" await cb.answer(f"Автопродление {status_text}") await cb.message.edit_text( deps.user_service.format_subscription_message( rw_user, link=user.subscription_link, autorenew=sub.autorenew ), reply_markup=subscription_controls( show_autorenew=bool(rw_user), current_autorenewal_status=sub.autorenew ), )