Files
vpn-control-panel/app/admin/router.py

158 lines
5.1 KiB
Python

from jinja2 import Environment, FileSystemLoader
from fastapi import APIRouter, Form, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import func, select
from app.database import async_session_factory
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.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.user import UserService
router = APIRouter(prefix="/admin", tags=["admin"])
_env = Environment(loader=FileSystemLoader("app/templates"), auto_reload=False)
def _render(name: str, **context) -> str:
template = _env.get_template(name)
return template.render(**context)
@router.get("/", response_class=HTMLResponse)
async def dashboard(request: Request):
async with async_session_factory() as session:
async def _count(model, *filters):
stmt = select(func.count(model.id))
for f in filters:
stmt = stmt.where(f)
return (await session.execute(stmt)).scalar_one()
total_users = await _count(User)
active_users = await _count(User, User.is_active.is_(True))
total_tariffs = await _count(Tariff)
total_servers = await _count(Server)
active_servers = await _count(Server, Server.is_active.is_(True))
total_payments = await _count(Payment)
confirmed_payments = await _count(
Payment, Payment.status == PaymentStatus.CONFIRMED
)
rev_stmt = select(func.coalesce(func.sum(Payment.amount), 0)).where(
Payment.status == PaymentStatus.CONFIRMED
)
total_revenue = float((await session.execute(rev_stmt)).scalar_one())
return HTMLResponse(
_render(
"dashboard.html",
request=request,
total_users=total_users,
active_users=active_users,
total_tariffs=total_tariffs,
total_servers=total_servers,
active_servers=active_servers,
total_payments=total_payments,
confirmed_payments=confirmed_payments,
total_revenue=total_revenue,
)
)
@router.get("/users", response_class=HTMLResponse)
async def users_page(request: Request, error: str = ""):
async with async_session_factory() as session:
repo = UserRepository(session)
users = await repo.get_all()
return HTMLResponse(
_render("users.html", request=request, users=users, error=error)
)
@router.post("/users/create", response_class=HTMLResponse)
async def users_create(
request: Request,
telegram_id: int = Form(...),
username: str = Form(""),
full_name: str = Form(""),
language_code: str = Form("ru"),
):
async with async_session_factory() as session:
user_repo = UserRepository(session)
user_service = UserService(user_repo)
existing = await user_repo.get_by_telegram_id(telegram_id)
if existing is not None:
return HTMLResponse(
_render(
"users.html",
request=request,
users=await user_repo.get_all(),
error=f"User with telegram_id {telegram_id} already exists",
)
)
await user_service.register(
telegram_id=telegram_id,
username=username or None,
full_name=full_name or str(telegram_id),
language_code=language_code,
)
return RedirectResponse(url="/admin/users", status_code=303)
@router.get("/payments", response_class=HTMLResponse)
async def payments_page(request: Request):
async with async_session_factory() as session:
tariff_repo = TariffRepository(session)
stmt = select(Payment).order_by(Payment.created_at.desc())
result = await session.execute(stmt)
payments = list(result.scalars().all())
tariffs_map = {}
for p in payments:
if p.tariff_id not in tariffs_map:
t = await tariff_repo.get(p.tariff_id)
tariffs_map[p.tariff_id] = t.name if t else ""
return HTMLResponse(
_render(
"payments.html",
request=request,
payments=payments,
tariffs_map=tariffs_map,
)
)
@router.get("/servers", response_class=HTMLResponse)
async def servers_page(request: Request):
async with async_session_factory() as session:
repo = ServerRepository(session)
servers = await repo.get_all()
return HTMLResponse(
_render("servers.html", request=request, servers=servers)
)
@router.get("/tariffs", response_class=HTMLResponse)
async def tariffs_page(request: Request):
async with async_session_factory() as session:
repo = TariffRepository(session)
tariffs = await repo.get_all()
return HTMLResponse(
_render("tariffs.html", request=request, tariffs=tariffs)
)