- FastAPI REST API with JWT auth - aiogram 3 Telegram bot with admin middleware - APScheduler daily tasks (expiry, reminders, revoke, sync) - SQLAlchemy 2 async ORM with Alembic migrations - Jinja2 admin panel (Dashboard, Users, Payments, Servers, Tariffs) - VPN provider abstraction with MockProvider - Stats service with revenue/subscription analytics - Docker Compose (PostgreSQL + Redis + app) - Healthcheck endpoint
62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
from loguru import logger
|
|
|
|
from app.database import async_session_factory
|
|
from app.models.payment import PaymentStatus
|
|
from app.repositories.notification import NotificationRepository
|
|
from app.repositories.payment import PaymentRepository
|
|
from app.repositories.tariff import TariffRepository
|
|
from app.repositories.user import UserRepository
|
|
from app.services.billing import BillingService
|
|
from app.services.notification import NotificationService
|
|
from app.services.user import UserService
|
|
|
|
|
|
async def expire_subscriptions() -> None:
|
|
logger.info("[Scheduler] Starting subscription expiry check")
|
|
|
|
async with async_session_factory() as session:
|
|
payment_repo = PaymentRepository(session)
|
|
tariff_repo = TariffRepository(session)
|
|
user_repo = UserRepository(session)
|
|
|
|
billing = BillingService(payment_repo, tariff_repo, user_repo)
|
|
user_service = UserService(user_repo)
|
|
notification_service = NotificationService(
|
|
NotificationRepository(session), user_repo
|
|
)
|
|
|
|
expired_ids = await billing.expire_subscriptions()
|
|
|
|
if not expired_ids:
|
|
logger.info("[Scheduler] No expired subscriptions found")
|
|
return
|
|
|
|
for user_id in set(expired_ids):
|
|
user = await user_service.get_by_id(user_id)
|
|
if user is None:
|
|
continue
|
|
|
|
tariff = None
|
|
expired_payments = await payment_repo.get_by_user_and_status(
|
|
user_id=user_id, status=PaymentStatus.CONFIRMED
|
|
)
|
|
if expired_payments:
|
|
tariff = await tariff_repo.get(expired_payments[0].tariff_id)
|
|
|
|
await user_service.deactivate(user_id)
|
|
await notification_service.send_subscription_expired(
|
|
user_id=user_id,
|
|
tariff_name=tariff.name if tariff else None,
|
|
)
|
|
|
|
logger.info(
|
|
"[Scheduler] User {} deactivated, expired notification sent",
|
|
user_id,
|
|
)
|
|
|
|
logger.info(
|
|
"[Scheduler] Expired {} subscriptions, deactivated {} users",
|
|
len(expired_ids),
|
|
len(set(expired_ids)),
|
|
)
|