更新平台治理

This commit is contained in:
wangjiming
2026-08-17 09:15:36 +08:00
parent de9c8e4ffe
commit 6c1bf61ff7
13 changed files with 561 additions and 339 deletions

View File

@@ -1343,6 +1343,8 @@ class PlatformStore:
raise ValueError("protected user cannot be deleted")
# 级联删除该用户关联的数据
tables_to_clean = [
# 登录会话(避免残留 session 导致统计显示 user_id
("sessions", "user_id=?", [user_id]),
# ACL 授权
("acls", "principal_type='user' AND principal_id=?", [user_id]),
# 审批实例(申请人)
@@ -3755,12 +3757,16 @@ class PlatformStore:
sessions 表列login_at(TEXT), logout_at(TEXT), duration_seconds(INT)。
优先用 duration_seconds为空时回退计算 now-login_at未登出或 logout_at-login_at。
注意:使用 INNER JOIN 只统计仍存在于 users 表中的用户,
避免已删除用户的残留 session 记录导致显示 user_id如 u_xxxx
"""
with self.connect() as conn:
# 使用 INNER JOIN 而非 LEFT JOIN确保只统计仍然存在的用户
rows = conn.execute(
"SELECT s.user_id, s.login_at, s.logout_at, s.duration_seconds, "
"u.username, u.display_name, u.role "
"FROM sessions s LEFT JOIN users u ON s.user_id = u.id "
"FROM sessions s INNER JOIN users u ON s.user_id = u.id "
"WHERE s.login_at::timestamptz >= NOW() - make_interval(days => %s)",
(days,),
).fetchall()
@@ -3768,10 +3774,15 @@ class PlatformStore:
agg: dict[str, dict[str, Any]] = {}
for r in rows:
uid = r["user_id"] or ""
# 优先使用 display_name其次 username最后才回退到 user_id
display = r["display_name"] or r["username"] or uid
# 如果回退到了 user_id 格式(说明用户信息不完整),标记为"未知用户"
if display == uid and display.startswith("u_") and len(display) > 10:
display = "(已删除用户)"
bucket = agg.setdefault(
uid,
{
"user": r["display_name"] or r["username"] or uid,
"user": display,
"role": r["role"] or "",
"total": 0.0,
},
@@ -4182,8 +4193,8 @@ class PlatformStore:
bucket = grouped.setdefault(
key,
{
"subject_type": r.get("principal_type"),
"subject_id": r.get("principal_id"),
"principal_type": r.get("principal_type"),
"principal_id": r.get("principal_id"),
"permissions": [],
},
)
@@ -4201,8 +4212,8 @@ class PlatformStore:
for perm in e.get("permissions") or []:
flat.append(
{
"principal_type": e.get("subject_type"),
"principal_id": e.get("subject_id"),
"principal_type": e.get("principal_type") or e.get("subject_type"),
"principal_id": e.get("principal_id") or e.get("subject_id"),
"permission": perm,
}
)