Track site-created 3x-ui clients and per-panel inbound whitelist for users
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+70
-2
@@ -102,22 +102,83 @@ async def xui_delete(
|
||||
async def xui_inbounds_api(
|
||||
panel_id: int,
|
||||
protocol: str | None = Query(None),
|
||||
for_users: int = Query(0),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
admin=Depends(require_admin),
|
||||
):
|
||||
"""JSON: available inbounds for dropdown (optionally filtered by protocol)."""
|
||||
"""JSON: inbounds for dropdown. for_users=1 — only admin-whitelisted."""
|
||||
if _is_redirect(admin):
|
||||
return JSONResponse({"success": False, "error": "unauthorized"}, status_code=401)
|
||||
panel = await db.get(XuiPanel, panel_id)
|
||||
if not panel:
|
||||
return JSONResponse({"success": False, "error": "not found"}, status_code=404)
|
||||
try:
|
||||
items = await xui_service.load_available_inbounds(panel, protocol=protocol)
|
||||
if for_users:
|
||||
rows = await xui_service.list_user_inbounds(db, panel_id, protocol=protocol)
|
||||
items = [
|
||||
{
|
||||
"id": r.inbound_id,
|
||||
"protocol": r.protocol,
|
||||
"remark": r.remark,
|
||||
"port": r.port,
|
||||
"enable": r.enable,
|
||||
"is_available_for_users": True,
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
else:
|
||||
items = await xui_service.load_available_inbounds(panel, protocol=protocol)
|
||||
return JSONResponse({"success": True, "obj": items})
|
||||
except Exception as exc: # noqa: BLE001
|
||||
return JSONResponse({"success": False, "error": str(exc)}, status_code=400)
|
||||
|
||||
|
||||
@router.post("/{panel_id}/inbounds/sync")
|
||||
async def xui_inbounds_sync(
|
||||
panel_id: int,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
admin=Depends(require_admin),
|
||||
):
|
||||
if _is_redirect(admin):
|
||||
return admin
|
||||
try:
|
||||
await xui_service.sync_panel_inbounds(db, panel_id)
|
||||
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=inbounds_synced",
|
||||
status_code=status.HTTP_303_SEE_OTHER,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/{panel_id}/inbounds/users")
|
||||
async def xui_inbounds_save_users(
|
||||
panel_id: int,
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
admin=Depends(require_admin),
|
||||
):
|
||||
if _is_redirect(admin):
|
||||
return admin
|
||||
form = await request.form()
|
||||
raw = form.getlist("inbound_ids")
|
||||
inbound_ids = [int(v) for v in raw if str(v).isdigit()]
|
||||
try:
|
||||
await xui_service.save_user_inbounds(db, panel_id, inbound_ids)
|
||||
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=inbounds_saved",
|
||||
status_code=status.HTTP_303_SEE_OTHER,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{panel_id}", response_class=HTMLResponse)
|
||||
async def xui_detail(
|
||||
panel_id: int,
|
||||
@@ -133,8 +194,12 @@ async def xui_detail(
|
||||
|
||||
data = None
|
||||
error = None
|
||||
site_clients = await xui_service.list_site_clients(db, panel_id)
|
||||
panel_inbounds = await xui_service.list_panel_inbounds(db, panel_id)
|
||||
try:
|
||||
data = await xui_service.fetch_panel_data(panel)
|
||||
if not panel_inbounds:
|
||||
panel_inbounds = await xui_service.sync_panel_inbounds(db, panel_id)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
error = str(exc)
|
||||
|
||||
@@ -153,6 +218,8 @@ async def xui_detail(
|
||||
"admin": admin,
|
||||
"panel": panel,
|
||||
"data": data,
|
||||
"site_clients": site_clients,
|
||||
"panel_inbounds": panel_inbounds,
|
||||
"created": created,
|
||||
"error": error,
|
||||
"app_name": request.app.state.settings.app_name,
|
||||
@@ -183,6 +250,7 @@ async def xui_add_client(
|
||||
return RedirectResponse("/admin/xui", status_code=status.HTTP_303_SEE_OTHER)
|
||||
try:
|
||||
result = await xui_service.add_xui_client(
|
||||
db,
|
||||
panel,
|
||||
protocol=protocol,
|
||||
email=email.strip(),
|
||||
|
||||
Reference in New Issue
Block a user