Files
vpn-control-panel/app/api/v1/stats.py
smolkik-code 7c7c88621d Initial commit: VPN Control Panel
- 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
2026-07-05 17:50:11 +07:00

70 lines
2.3 KiB
Python

from fastapi import APIRouter, Depends
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_db
from app.models.payment import Payment, PaymentStatus
from app.models.server import Server
from app.models.tariff import Tariff
from app.models.user import User
from app.schemas.stats import StatsResponse
router = APIRouter(prefix="/stats", tags=["Stats"])
@router.get("", response_model=StatsResponse)
async def get_stats(
db: AsyncSession = Depends(get_db),
):
stmt = select(func.count(User.id))
total_users = (await db.execute(stmt)).scalar_one()
stmt = select(func.count(User.id)).where(User.is_active.is_(True))
active_users = (await db.execute(stmt)).scalar_one()
stmt = select(func.count(Tariff.id))
total_tariffs = (await db.execute(stmt)).scalar_one()
stmt = select(func.count(Tariff.id)).where(Tariff.is_active.is_(True))
active_tariffs = (await db.execute(stmt)).scalar_one()
stmt = select(func.count(Server.id))
total_servers = (await db.execute(stmt)).scalar_one()
stmt = select(func.count(Server.id)).where(Server.is_active.is_(True))
active_servers = (await db.execute(stmt)).scalar_one()
stmt = select(func.count(Payment.id))
total_payments = (await db.execute(stmt)).scalar_one()
stmt = (
select(func.count(Payment.id))
.where(Payment.status == PaymentStatus.CONFIRMED)
)
confirmed_payments = (await db.execute(stmt)).scalar_one()
stmt = (
select(func.count(Payment.id))
.where(Payment.status == PaymentStatus.PENDING)
)
pending_payments = (await db.execute(stmt)).scalar_one()
stmt = (
select(func.coalesce(func.sum(Payment.amount), 0))
.where(Payment.status == PaymentStatus.CONFIRMED)
)
total_revenue = float((await db.execute(stmt)).scalar_one())
return StatsResponse(
total_users=total_users,
active_users=active_users,
total_tariffs=total_tariffs,
active_tariffs=active_tariffs,
total_servers=total_servers,
active_servers=active_servers,
total_payments=total_payments,
confirmed_payments=confirmed_payments,
pending_payments=pending_payments,
total_revenue=round(total_revenue, 2),
)