Let 3x-ui assign inbound and share link on create.

Stop requiring inbound selection in the site UI; send the create request to the chosen panel and use the link it returns.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-26 03:40:24 +03:00
co-authored by Cursor
parent c28235b09a
commit 8dc090bd67
7 changed files with 169 additions and 174 deletions
+14 -8
View File
@@ -3909,6 +3909,7 @@ async def api_add_user_connection(request: Request, user_id: str, req: AddUserCo
created = await xui_create_vless_config(
data.get('settings', {}),
name=req.name or user.get('username') or 'user',
# Optional hint only — panel assigns inbound + share link
inbound_id=req.xui_inbound_id or panel.get('default_inbound_id') or None,
panel_id=panel_id,
)
@@ -4490,8 +4491,6 @@ async def _create_config_for_protocol(
"""Create VPN client; returns {client_id, config, subscription_url, protocol, server_id}."""
protocol = protocol or 'xui'
if protocol_base(protocol) == 'xui':
if not xui_inbound_id:
raise RuntimeError('Select a VLESS inbound for this invite link')
from managers.xui_api import xui_create_vless_config
from managers.xui_servers import get_xui_server, ensure_xui_servers
ensure_xui_servers(data.get('settings') or {})
@@ -4499,11 +4498,13 @@ async def _create_config_for_protocol(
if not panel:
raise RuntimeError('Add a 3x-ui server in Settings first')
panel_id = panel.get('id') or ''
# Prefer invite/default inbound; otherwise 3x-ui picks first VLESS on that panel
inbound = xui_inbound_id or panel.get('default_inbound_id') or None
expiry_ms = _expiry_ms_from_duration_days(duration_days)
created = await xui_create_vless_config(
data.get('settings', {}),
name=name,
inbound_id=xui_inbound_id,
inbound_id=inbound,
expiry_time=expiry_ms,
panel_id=panel_id,
)
@@ -4515,6 +4516,7 @@ async def _create_config_for_protocol(
'protocol': 'xui',
'server_id': 0,
'xui_panel_id': panel_id,
'xui_inbound_id': int(created.get('inbound_id') or 0),
'expires_at': (
datetime.fromtimestamp(expiry_ms / 1000).isoformat()
if expiry_ms > 0 else None
@@ -4609,10 +4611,9 @@ async def api_create_invite(request: Request, req: InviteCreateRequest):
if not panel:
return JSONResponse({'error': 'Add a 3x-ui server in Settings first'}, status_code=400)
panel_id = panel.get('id') or ''
# Inbound is optional — 3x-ui panel assigns it (or uses server default) on redeem
if not inbound_id:
inbound_id = int(panel.get('default_inbound_id') or 0)
if not inbound_id:
return JSONResponse({'error': 'Select a VLESS inbound'}, status_code=400)
link = {
'id': str(uuid.uuid4()),
'name': (req.name or 'Invite').strip() or 'Invite',
@@ -4677,9 +4678,14 @@ async def api_update_invite(request: Request, invite_id: str, req: InviteUpdateR
link['enabled'] = bool(req.enabled)
if req.reset_used:
link['used_count'] = 0
# Validate inbound for xui
if protocol_base(link.get('protocol') or 'xui') == 'xui' and not int(link.get('xui_inbound_id') or 0):
return JSONResponse({'error': 'Select a VLESS inbound'}, status_code=400)
if protocol_base(link.get('protocol') or 'xui') == 'xui':
from managers.xui_servers import get_xui_server, ensure_xui_servers
ensure_xui_servers(data.setdefault('settings', {}))
panel = get_xui_server(data.get('settings') or {}, link.get('xui_panel_id') or None)
if not panel:
return JSONResponse({'error': 'Add a 3x-ui server in Settings first'}, status_code=400)
if not link.get('xui_panel_id'):
link['xui_panel_id'] = panel.get('id') or ''
save_data(data)
return {'status': 'success', 'invite': _invite_public_view(link)}