1
This commit is contained in:
parent
ca0bbeddbf
commit
e816524972
|
|
@ -208,7 +208,7 @@ async def start_service(
|
|||
account_id: int,
|
||||
user: Dict[str, Any] = Depends(get_current_user)
|
||||
):
|
||||
"""启动交易服务"""
|
||||
"""启动交易服务(需该账号 owner 或管理员)"""
|
||||
require_account_owner(account_id, user)
|
||||
try:
|
||||
program = program_name_for_account(account_id)
|
||||
|
|
@ -235,7 +235,7 @@ async def stop_service(
|
|||
account_id: int,
|
||||
user: Dict[str, Any] = Depends(get_current_user)
|
||||
):
|
||||
"""停止交易服务"""
|
||||
"""停止交易服务(需该账号 owner 或管理员)"""
|
||||
require_account_owner(account_id, user)
|
||||
try:
|
||||
program = program_name_for_account(account_id)
|
||||
|
|
@ -262,7 +262,7 @@ async def restart_service(
|
|||
account_id: int,
|
||||
user: Dict[str, Any] = Depends(get_current_user)
|
||||
):
|
||||
"""重启交易服务"""
|
||||
"""重启交易服务(需该账号 owner 或管理员)"""
|
||||
require_account_owner(account_id, user)
|
||||
try:
|
||||
program = program_name_for_account(account_id)
|
||||
|
|
@ -287,9 +287,7 @@ async def restart_service(
|
|||
async def ensure_trading_program(account_id: int, user: Dict[str, Any] = Depends(get_current_user)):
|
||||
if int(account_id) <= 0:
|
||||
raise HTTPException(status_code=400, detail="account_id 必须 >= 1")
|
||||
# 允许管理员或该账号 owner 执行(owner 用于“我重建配置再启动”)
|
||||
if (user.get("role") or "user") != "admin":
|
||||
require_account_owner(int(account_id), user)
|
||||
require_account_owner(int(account_id), user)
|
||||
sup = ensure_account_program(int(account_id))
|
||||
if not sup.ok:
|
||||
raise HTTPException(status_code=500, detail=sup.error or "生成 supervisor 配置失败")
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ async def grant_user_account(user_id: int, account_id: int, payload: GrantReq, _
|
|||
if not a:
|
||||
raise HTTPException(status_code=404, detail="账号不存在")
|
||||
try:
|
||||
if payload.role == "owner":
|
||||
UserAccountMembership.clear_other_owners_for_account(int(account_id), int(user_id))
|
||||
UserAccountMembership.add(int(user_id), int(account_id), role=payload.role)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
|
|
|
|||
|
|
@ -217,6 +217,14 @@ class UserAccountMembership:
|
|||
(int(user_id), int(account_id)),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def clear_other_owners_for_account(account_id: int, keep_user_id: int):
|
||||
"""每个账号仅允许一名 owner:将本账号下其他用户的 owner 降为 viewer。"""
|
||||
db.execute_update(
|
||||
"UPDATE user_account_memberships SET role = 'viewer' WHERE account_id = %s AND user_id != %s AND role = 'owner'",
|
||||
(int(account_id), int(keep_user_id)),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def list_for_user(user_id: int):
|
||||
return db.execute_query(
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ const UserAccountGroup = ({ user, allAccounts, onServiceAction }) => {
|
|||
disabled={associating}
|
||||
>
|
||||
<option value="viewer">观察者 (Viewer)</option>
|
||||
<option value="trader">交易员 (Trader)</option>
|
||||
<option value="owner">拥有者 (Owner,每账号仅一个)</option>
|
||||
</select>
|
||||
<button
|
||||
onClick={handleGrant}
|
||||
|
|
|
|||
|
|
@ -310,10 +310,10 @@ const ConfigPanel = () => {
|
|||
setMessage('')
|
||||
try {
|
||||
const res = await api.ensureAccountTradingProgram(accountId)
|
||||
setMessage(`已生成/刷新 supervisor 配置:${res.program || ''}`)
|
||||
setMessage(`已成功生成进程配置文件:${res.program || ''}`)
|
||||
await loadAccountTradingStatus()
|
||||
} catch (error) {
|
||||
setMessage('生成 supervisor 配置失败: ' + (error.message || '未知错误'))
|
||||
setMessage('生成进程配置失败:' + (error.message || '未知错误'))
|
||||
} finally {
|
||||
setSystemBusy(false)
|
||||
}
|
||||
|
|
@ -906,7 +906,7 @@ const ConfigPanel = () => {
|
|||
<p>修改配置后,交易系统将在下次扫描时自动使用新配置</p>
|
||||
</div>
|
||||
|
||||
{/* 我的交易进程(按账号;owner/admin 可启停) */}
|
||||
{/* 我的交易进程(按账号;该账号 owner 或 admin 可启停) */}
|
||||
{currentAccountMeta && currentAccountMeta.status === 'active' ? (
|
||||
<div className="system-section">
|
||||
<div className="system-header">
|
||||
|
|
@ -924,21 +924,21 @@ const ConfigPanel = () => {
|
|||
<button type="button" className="system-btn primary" onClick={handleTriggerScan} disabled={systemBusy || !accountTradingStatus?.running} title="通知该账号交易进程立即执行一次市场扫描(无需重启)">
|
||||
立即扫描
|
||||
</button>
|
||||
<button type="button" className="system-btn" onClick={handleAccountTradingEnsure} disabled={systemBusy} title="为该账号生成/刷新 supervisor program 配置(需要 owner/admin)">
|
||||
<button type="button" className="system-btn" onClick={handleAccountTradingEnsure} disabled={systemBusy} title="为该账号生成/刷新 supervisor 进程配置文件(需该账号 owner 或管理员)">
|
||||
生成配置
|
||||
</button>
|
||||
<button type="button" className="system-btn" onClick={handleAccountTradingStop} disabled={systemBusy || !accountTradingStatus?.running} title="停止该账号交易进程(需要 owner/admin)">
|
||||
<button type="button" className="system-btn" onClick={handleAccountTradingStop} disabled={systemBusy || !accountTradingStatus?.running} title="停止该账号交易进程(需该账号 owner 或管理员)">
|
||||
停止
|
||||
</button>
|
||||
<button type="button" className="system-btn" onClick={handleAccountTradingStart} disabled={systemBusy || accountTradingStatus?.running} title="启动该账号交易进程(需要 owner/admin)">
|
||||
<button type="button" className="system-btn" onClick={handleAccountTradingStart} disabled={systemBusy || accountTradingStatus?.running} title="启动该账号交易进程(需该账号 owner 或管理员)">
|
||||
启动
|
||||
</button>
|
||||
<button type="button" className="system-btn primary" onClick={handleAccountTradingRestart} disabled={systemBusy} title="重启该账号交易进程(需要 owner/admin)">
|
||||
<button type="button" className="system-btn primary" onClick={handleAccountTradingRestart} disabled={systemBusy} title="重启该账号交易进程(需该账号 owner 或管理员)">
|
||||
重启
|
||||
</button>
|
||||
</div>
|
||||
<div className="system-hint">
|
||||
提示:若按钮报“无权限”,请让管理员在用户授权里把该账号分配为 owner;若报 supervisor 相关错误,请检查后端对 `/www/server/panel/plugin/supervisor` 的写权限与 supervisorctl 可执行权限。
|
||||
提示:生成配置、启停/重启进程、修改 API 密钥均需该账号的 owner(每账号仅一个)。若报“无权限”请让管理员将该账号分配为 owner;若报 supervisor 相关错误,请检查后端写权限与 supervisorctl。
|
||||
</div>
|
||||
{accountTradingErr ? (
|
||||
<div className="system-hint" style={{ color: '#b00020' }}>
|
||||
|
|
|
|||
|
|
@ -816,10 +816,11 @@ export const api = {
|
|||
grantUserAccount: async (userId, accountId, role = 'viewer') => {
|
||||
const uid = Number(userId);
|
||||
const aid = Number(accountId);
|
||||
const roleVal = role === 'owner' ? 'owner' : 'viewer';
|
||||
const response = await fetch(buildUrl(`/api/admin/users/${uid}/accounts/${aid}`), {
|
||||
method: 'PUT',
|
||||
headers: withAuthHeaders({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify({ role: role === 'owner' ? 'owner' : 'viewer' }),
|
||||
body: JSON.stringify({ role: roleVal }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ detail: '授权失败' }));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user