- 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
70 lines
2.3 KiB
Python
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),
|
|
)
|