Files
vpn/app/routers/xui.py
T

171 lines
4.9 KiB
Python

"""Admin routes for 3x-ui API panels."""
from __future__ import annotations
import json
from fastapi import APIRouter, Depends, Form, Request, status
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.models import XuiPanel
from app.routers.admin import _is_redirect, require_admin
from app.services import xui_panels as xui_service
router = APIRouter(prefix="/admin/xui", tags=["xui"])
@router.get("", response_class=HTMLResponse)
async def xui_list(request: Request, db: AsyncSession = Depends(get_db), admin=Depends(require_admin)):
if _is_redirect(admin):
return admin
panels = await xui_service.list_panels(db)
return request.app.state.templates.TemplateResponse(
"admin/xui.html",
{
"request": request,
"admin": admin,
"panels": panels,
"app_name": request.app.state.settings.app_name,
"flash": request.query_params.get("flash"),
},
)
@router.post("")
async def xui_create(
name: str = Form(""),
base_url: str = Form(...),
username: str = Form(""),
password: str = Form(""),
api_token: str = Form(""),
verify_ssl: str = Form(""),
db: AsyncSession = Depends(get_db),
admin=Depends(require_admin),
):
if _is_redirect(admin):
return admin
try:
await xui_service.create_panel(
db,
name=name,
base_url=base_url,
username=username,
password=password,
api_token=api_token,
verify_ssl=verify_ssl == "1",
)
except Exception as exc: # noqa: BLE001
return RedirectResponse(
f"/admin/xui?flash=error:{exc}",
status_code=status.HTTP_303_SEE_OTHER,
)
return RedirectResponse("/admin/xui?flash=created", status_code=status.HTTP_303_SEE_OTHER)
@router.post("/{panel_id}/check")
async def xui_check(
panel_id: int,
db: AsyncSession = Depends(get_db),
admin=Depends(require_admin),
):
if _is_redirect(admin):
return admin
try:
await xui_service.check_panel(db, panel_id)
except Exception as exc: # noqa: BLE001
return RedirectResponse(
f"/admin/xui?flash=error:{exc}",
status_code=status.HTTP_303_SEE_OTHER,
)
return RedirectResponse("/admin/xui?flash=ok", status_code=status.HTTP_303_SEE_OTHER)
@router.post("/{panel_id}/delete")
async def xui_delete(
panel_id: int,
db: AsyncSession = Depends(get_db),
admin=Depends(require_admin),
):
if _is_redirect(admin):
return admin
await xui_service.delete_panel(db, panel_id)
return RedirectResponse("/admin/xui?flash=deleted", status_code=status.HTTP_303_SEE_OTHER)
@router.get("/{panel_id}", response_class=HTMLResponse)
async def xui_detail(
panel_id: int,
request: Request,
db: AsyncSession = Depends(get_db),
admin=Depends(require_admin),
):
if _is_redirect(admin):
return admin
panel = await db.get(XuiPanel, panel_id)
if not panel:
return RedirectResponse("/admin/xui", status_code=status.HTTP_303_SEE_OTHER)
data = None
error = None
try:
data = await xui_service.fetch_panel_data(panel)
except Exception as exc: # noqa: BLE001
error = str(exc)
info = None
if panel.panel_info:
try:
info = json.loads(panel.panel_info)
except json.JSONDecodeError:
info = None
return request.app.state.templates.TemplateResponse(
"admin/xui_detail.html",
{
"request": request,
"admin": admin,
"panel": panel,
"data": data,
"info": info,
"error": error,
"app_name": request.app.state.settings.app_name,
"flash": request.query_params.get("flash"),
},
)
@router.post("/{panel_id}/clients")
async def xui_add_client(
panel_id: int,
email: str = Form(...),
inbound_id: int = Form(...),
total_gb: int = Form(0),
limit_ip: int = Form(0),
db: AsyncSession = Depends(get_db),
admin=Depends(require_admin),
):
if _is_redirect(admin):
return admin
panel = await db.get(XuiPanel, panel_id)
if not panel:
return RedirectResponse("/admin/xui", status_code=status.HTTP_303_SEE_OTHER)
try:
await xui_service.add_xui_client(
panel,
email=email.strip(),
inbound_ids=[inbound_id],
total_gb=total_gb,
limit_ip=limit_ip,
)
except Exception as exc: # noqa: BLE001
return RedirectResponse(
f"/admin/xui/{panel_id}?flash=error:{exc}",
status_code=status.HTTP_303_SEE_OTHER,
)
return RedirectResponse(
f"/admin/xui/{panel_id}?flash=client_created",
status_code=status.HTTP_303_SEE_OTHER,
)