diff --git a/bot/handlers/client/menus.py b/bot/handlers/client/menus.py index 0b1f6ed..2a70cd0 100644 --- a/bot/handlers/client/menus.py +++ b/bot/handlers/client/menus.py @@ -10,9 +10,7 @@ from bot.texts import ( CALLBACK_FALLBACK, FAQ_TEXT, GENERAL_PROCESSING, - GENERAL_SUCCESS, NO_SUBSCRIPTION, - NOTHING_PLACEHOLDER, ) from db.models.users import User from misc import utils diff --git a/bot/main.py b/bot/main.py index 3451ec4..ca194be 100644 --- a/bot/main.py +++ b/bot/main.py @@ -1,4 +1,5 @@ import asyncio +import contextlib import logging from aiogram import Bot, Dispatcher @@ -21,6 +22,7 @@ from services.renewal_service import RenewalService from services.user_service import UserService logging.basicConfig(level=logging.DEBUG) +contextlib.suppress(asyncio.CancelledError) async def main(): @@ -78,10 +80,7 @@ async def main(): await dp.start_polling(bot) finally: scheduler_task.cancel() - try: - await scheduler_task - except asyncio.CancelledError: - pass + await scheduler_task if __name__ == "__main__": diff --git a/bot/scheduler.py b/bot/scheduler.py index 93d9d36..1fb7431 100644 --- a/bot/scheduler.py +++ b/bot/scheduler.py @@ -1,7 +1,7 @@ import asyncio import logging -from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker +from sqlalchemy.ext.asyncio import async_sessionmaker from services.renewal_service import RenewalService diff --git a/bot/texts.py b/bot/texts.py index c46bb31..eeb49e6 100644 --- a/bot/texts.py +++ b/bot/texts.py @@ -227,4 +227,4 @@ AUTORENEWAL_INSUFFICIENT_FUNDS = ( AUTORENEWAL_SUCCESS = ( "✅ Подписка продлена автоматически. Списано {price}₽." "Новая дата окончания: {end_date}." -) \ No newline at end of file +) diff --git a/config.py b/config.py index 2e73f46..695a8ee 100644 --- a/config.py +++ b/config.py @@ -1,5 +1,5 @@ from dotenv import load_dotenv -from pydantic import Field, SecretStr +from pydantic import Field from pydantic_settings import BaseSettings load_dotenv(override=True) @@ -10,11 +10,11 @@ class Settings(BaseSettings): "postgresql+asyncpg://malenia:skibidi@localhost:5432/malenia_db", alias="POSTGRES_URL" ) - bot_token: SecretStr = Field(alias="BOT_TOKEN") + bot_token: str = Field(alias="BOT_TOKEN") admins: list[int] = Field(alias="ADMINS") - pally_shop_id: SecretStr = Field(alias="PALLY_SHOP_ID") - pally_token: SecretStr = Field(alias="PALLY_TOKEN") + pally_shop_id: str = Field(alias="PALLY_SHOP_ID") + pally_token: str = Field(alias="PALLY_TOKEN") referal_bonus: int = Field(10, alias="REFERAL_BONUS") deposit_threshold: int = Field(50) @@ -23,7 +23,7 @@ class Settings(BaseSettings): remnawave_url: str = Field(alias="REMNAWAVE_URL") subscription_url: str = Field(alias="SUBSCRIPTION_URL") - remnawave_token: SecretStr = Field(alias="REMNAWAVE_TOKEN") + remnawave_token: str = Field(alias="REMNAWAVE_TOKEN") min_devices: int = Field(3, alias="MIN_DEVICES") max_devices: int = Field(12, alias="MAX_DEVICES") diff --git a/repositories/subscriptions.py b/repositories/subscriptions.py index 1e53b2e..ad43b14 100644 --- a/repositories/subscriptions.py +++ b/repositories/subscriptions.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime, timedelta from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncSession @@ -10,13 +10,12 @@ class SubscriptionRepository: async def get_subscriptions_for_autorenewal( self, session: AsyncSession, *, days_before_expiry: int = 1 ) -> list[Subscription]: - from datetime import timedelta - threshold = datetime.now(timezone.utc) + timedelta(days=days_before_expiry) + threshold = datetime.now(UTC) + timedelta(days=days_before_expiry) stmt = ( select(Subscription) .where( - Subscription.autorenew == True, + Subscription.autorenew == True, # noqa: E712 Subscription.status == SubscriptionStatus.ACTIVE, Subscription.end_date <= threshold, ) diff --git a/schemas/di.py b/schemas/di.py index 9c269f0..7e6ab25 100644 --- a/schemas/di.py +++ b/schemas/di.py @@ -1,6 +1,5 @@ from dataclasses import dataclass -from aiogram import Bot from remnawave import RemnawaveSDK from misc.pally import PallyClient diff --git a/schemas/users.py b/schemas/users.py index 461b990..f148f70 100644 --- a/schemas/users.py +++ b/schemas/users.py @@ -1,6 +1,8 @@ from dataclasses import dataclass + from pydantic import BaseModel + class NewUserDTO(BaseModel): id: int referal: int | None = None diff --git a/services/renewal_service.py b/services/renewal_service.py index 68eda61..4be75e9 100644 --- a/services/renewal_service.py +++ b/services/renewal_service.py @@ -13,6 +13,7 @@ from misc import utils from repositories.subscriptions import SubscriptionRepository from repositories.users import UserRepository from schemas.subscriptions import InternalSquads, SubscriptionPlan, SubscriptionStatus +from services import rw as rw_service logger = logging.getLogger(__name__) @@ -48,22 +49,14 @@ class RenewalService: return utils.calculate_price(plan) async def _renew_subscription_in_rw(self, subscription: Subscription) -> None: - from services import rw as rw_service - rw_user = await rw_service.get_user_by_telegram_id(self.rw_sdk, subscription.user_id) if not rw_user: raise RenewalServiceError(f"RW user not found for user_id={subscription.user_id}") - duration = datetime.timedelta(days=subscription.duration_days) squads = [InternalSquads.DEFAULT] if subscription.whitelists: squads.append(InternalSquads.WHITELISTS) - if rw_user.expire_at > datetime.datetime.now(datetime.UTC): - new_expire = rw_user.expire_at + duration - else: - new_expire = datetime.datetime.now(datetime.UTC) + duration - await rw_service.add_days(self.rw_sdk, rw_user.uuid, subscription.duration_days) await rw_service.update_squads(self.rw_sdk, rw_user.uuid, squads) await rw_service.set_hwid_limit(self.rw_sdk, rw_user.uuid, subscription.devices) @@ -95,10 +88,7 @@ class RenewalService: await self.subscription_repository.update_subscription_autorenew( session, user_id, False ) - await self._notify_user( - user_id, - AUTORENEWAL_INSUFFICIENT_FUNDS - ) + await self._notify_user(user_id, AUTORENEWAL_INSUFFICIENT_FUNDS) return False result = await self.user_repository.decrease_user_balance( @@ -143,7 +133,7 @@ class RenewalService: user_id, AUTORENEWAL_SUCCESS.format( price=price, - end_date=new_end_date.strftime('%d.%m.%Y'), + end_date=new_end_date.strftime("%d.%m.%Y"), ), ) @@ -171,9 +161,7 @@ class RenewalService: else: results["failed"] += 1 except Exception: - logger.exception( - "Error processing autorenewal for user %d", subscription.user_id - ) + logger.exception("Error processing autorenewal for user %d", subscription.user_id) results["failed"] += 1 logger.info(