pipeline-sdlc/wwwroot/api/work_env.dspy
ymq af178f98ad fix: 机构远程空间配置表单取值/赋值 bug + get 支持 owner_type
根因:bricks.Form.getValue() 返回 FormData 对象(非普通对象),v.remote_host=undefined 传空值报格式非法;setValue 是 InlineForm 方法,Form 无此方法导致加载失败
- 取值 getValue→_getValue(返回 {name:value} 普通对象)
- 加载遍历 name_inputs 逐个 setValue
- work_env.dspy get 加 owner_type 参数,org 页面加载 org 级(原 user 级优先导致看不到 org 配置)
2026-08-14 15:15:24 +08:00

131 lines
6.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# work_env.dspy - 工作环境管理 API沙箱本地/远程切换 + 目录迁移)
# action: get / set / ensure_remote_bwrap
user_id = await get_user()
if not user_id:
return json.dumps({'ok': False, 'error': '未登录'}, ensure_ascii=False)
action = (params_kw or {}).get('action', 'get')
from pipeline_service.work_env import (
get_work_env, set_work_env, ensure_remote_bwrap, get_org_pubkey,
)
from pipeline_service.deploy_account import account_name_for, sanitize_username
from app_audit.audit_service import audit_log
client_ip = ''
try:
client_ip = request.get('client_ip', '') or ''
except Exception:
pass
# 查用户 username账号名 ag_<username>)和 org_id
username = user_id
org_id = ''
try:
async with get_sor_context(request._run_ns, 'pipeline') as _sor:
_u = await _sor.sqlExe("SELECT username, orgid FROM users WHERE id=${u}$", {'u': user_id})
if _u:
username = getattr(_u[0], 'username', user_id) or user_id
org_id = getattr(_u[0], 'orgid', '') or ''
except Exception:
pass
if action == 'get':
_ot = (params_kw or {}).get('owner_type', '')
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
if _ot == 'org':
env = await get_work_env(sor, '', org_id)
elif _ot == 'user':
env = await get_work_env(sor, user_id, '')
else:
env = await get_work_env(sor, user_id, org_id)
return json.dumps({'ok': True, 'env': env, 'account_name': account_name_for(username)}, ensure_ascii=False)
except Exception as e:
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
elif action == 'set':
owner_type = (params_kw or {}).get('owner_type', 'user')
mode = (params_kw or {}).get('mode', 'local')
account_name = (params_kw or {}).get('account_name', '') or account_name_for(username)
# owner_id 与权限校验
owner_id = (params_kw or {}).get('owner_id', '')
if owner_type == 'user':
# 用户级:强制只能设自己,不允许设别人
owner_id = user_id
elif owner_type == 'org':
# 机构级仅平台超管owner.superuser可设置且只能设自己所在机构
owner_id = org_id
if not owner_id:
return json.dumps({'ok': False, 'error': '当前用户无机构'}, ensure_ascii=False)
async with get_sor_context(request._run_ns, 'pipeline') as _sor:
_adm = await _sor.sqlExe(
"SELECT 1 FROM userrole WHERE userid=${u}$ AND roleid='owner.superuser' LIMIT 1",
{'u': user_id})
if not _adm:
return json.dumps({'ok': False, 'error': '只有平台管理员能设置机构级工作环境'}, ensure_ascii=False)
else:
return json.dumps({'ok': False, 'error': 'owner_type 必须是 user 或 org'}, ensure_ascii=False)
remote_config = {
'remote_host': (params_kw or {}).get('remote_host', ''),
'remote_port': (params_kw or {}).get('remote_port', 22),
'remote_user': (params_kw or {}).get('remote_user', ''),
'remote_key_path': (params_kw or {}).get('remote_key_path', ''),
'remote_dir': (params_kw or {}).get('remote_dir', ''),
}
try:
async with get_sor_context(request._run_ns, 'pipeline') as sor:
r = await set_work_env(sor, owner_type, owner_id, mode, remote_config, account_name)
# 审计:工作环境变更(尤其远程主机变更,高风险)
await audit_log(sor, user_id, username, 'work_env_set',
target=owner_type + ':' + str(owner_id),
detail='mode=' + mode + ' host=' + str(remote_config.get('remote_host', '')),
result='ok' if r.get('ok') else 'fail', client_ip=client_ip)
return json.dumps(r, ensure_ascii=False)
except Exception as e:
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
elif action == 'ensure_remote_bwrap':
remote_config = {
'remote_host': (params_kw or {}).get('remote_host', ''),
'remote_port': (params_kw or {}).get('remote_port', 22),
'remote_user': (params_kw or {}).get('remote_user', ''),
'remote_key_path': (params_kw or {}).get('remote_key_path', ''),
}
try:
r = await ensure_remote_bwrap(remote_config)
async with get_sor_context(request._run_ns, 'pipeline') as sor:
await audit_log(sor, user_id, username, 'remote_bwrap',
target=str(remote_config.get('remote_host', '')),
detail='部署/校验远程沙箱',
result='ok' if r.get('ok') else 'fail', client_ip=client_ip)
return json.dumps(r, ensure_ascii=False)
except Exception as e:
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
elif action == 'get_org_pubkey':
# 获取机构 public key供 admin 复制到远程主机 authorized_keys。仅超管。
try:
async with get_sor_context(request._run_ns, 'pipeline') as _sor:
_adm = await _sor.sqlExe(
"SELECT 1 FROM userrole WHERE userid=${u}$ AND roleid='owner.superuser' LIMIT 1",
{'u': user_id})
if not _adm:
return json.dumps({'ok': False, 'error': '只有平台管理员能获取机构公钥'}, ensure_ascii=False)
_oid = (params_kw or {}).get('org_id', '') or org_id
r = get_org_pubkey(_oid)
async with get_sor_context(request._run_ns, 'pipeline') as sor:
await audit_log(sor, user_id, username, 'org_key_gen',
target='org:' + str(_oid), detail='获取/生成机构公钥',
result='ok' if r.get('ok') else 'fail', client_ip=client_ip)
return json.dumps(r, ensure_ascii=False)
except Exception as e:
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
else:
return json.dumps({'ok': False, 'error': '未知 action: ' + str(action)}, ensure_ascii=False)