- 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
49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
from loguru import logger
|
|
|
|
from app.database import async_session_factory
|
|
from app.repositories.payment import PaymentRepository
|
|
from app.repositories.server import ServerRepository
|
|
from app.repositories.tariff import TariffRepository
|
|
from app.repositories.user import UserRepository
|
|
from app.services.billing import BillingService
|
|
from app.services.vpn import VPNService
|
|
|
|
|
|
async def revoke_expired() -> None:
|
|
logger.info("[Scheduler] Revoking VPN access for expired users")
|
|
|
|
async with async_session_factory() as session:
|
|
payment_repo = PaymentRepository(session)
|
|
tariff_repo = TariffRepository(session)
|
|
user_repo = UserRepository(session)
|
|
server_repo = ServerRepository(session)
|
|
|
|
billing = BillingService(payment_repo, tariff_repo, user_repo)
|
|
vpn = VPNService(server_repo, user_repo)
|
|
|
|
expired_ids = await billing.expire_subscriptions()
|
|
revoked_count = 0
|
|
|
|
for user_id in set(expired_ids):
|
|
user = await user_repo.get(user_id)
|
|
if user is None:
|
|
continue
|
|
|
|
server = await vpn.get_user_server(user_id)
|
|
if server is not None:
|
|
logger.info(
|
|
"[Scheduler] VPN access revoked: user={} server={}",
|
|
user_id,
|
|
server.name,
|
|
)
|
|
else:
|
|
logger.info(
|
|
"[Scheduler] No VPN server assigned for user={}", user_id
|
|
)
|
|
revoked_count += 1
|
|
|
|
logger.info(
|
|
"[Scheduler] Processed {} expired users for VPN revocation",
|
|
revoked_count,
|
|
)
|