Merge remote-tracking branch 'origin/main' (仓库 .git 修复)
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
target/*
|
||||||
|
!target/userbase.jar
|
||||||
|
src
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
*.log
|
||||||
|
.workbuddy
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- 清理孤儿业务角色(指向不存在的应用)
|
||||||
|
-- 场景:角色授权页 RoleModuleTree?roleId=2 报 "角色所属应用不存在: 3"
|
||||||
|
-- 根因:sys_app_role 中存在 all_app_flag=0 的普通角色,其 app_id 指向
|
||||||
|
-- application_info 中已不存在的应用(应用被删,当时无级联清理)。
|
||||||
|
-- 说明:本脚本只读诊断 + 备份 + 清理,请先执行第 1 步确认,再执行第 2/3 步。
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- 1) 诊断:列出全部"指向不存在应用"的普通角色(孤儿角色)
|
||||||
|
SELECT r.id AS role_id,
|
||||||
|
r.name AS role_name,
|
||||||
|
r.app_id AS missing_app_id
|
||||||
|
FROM sys_app_role r
|
||||||
|
WHERE r.all_app_flag = 0
|
||||||
|
AND r.app_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM application_info a WHERE a.id = r.app_id
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 2) 备份(执行清理前先保留,便于回滚)
|
||||||
|
CREATE TABLE IF NOT EXISTS _bak_orphan_role LIKE sys_app_role;
|
||||||
|
INSERT INTO _bak_orphan_role
|
||||||
|
SELECT * FROM sys_app_role r
|
||||||
|
WHERE r.all_app_flag = 0
|
||||||
|
AND r.app_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM application_info a WHERE a.id = r.app_id
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS _bak_orphan_role_rel LIKE sys_app_role_module_rel;
|
||||||
|
INSERT INTO _bak_orphan_role_rel
|
||||||
|
SELECT * FROM sys_app_role_module_rel
|
||||||
|
WHERE role_id IN (SELECT id FROM _bak_orphan_role);
|
||||||
|
|
||||||
|
-- 3) 清理:先删模块授权关系,再删孤儿角色本身
|
||||||
|
DELETE FROM sys_app_role_module_rel
|
||||||
|
WHERE role_id IN (SELECT id FROM _bak_orphan_role);
|
||||||
|
|
||||||
|
DELETE FROM sys_app_role
|
||||||
|
WHERE id IN (SELECT id FROM _bak_orphan_role);
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import ctypes
|
||||||
|
from ctypes import wintypes
|
||||||
|
|
||||||
|
rstrtmgr = ctypes.windll.rstrtmgr
|
||||||
|
|
||||||
|
class RM_UNIQUE_PROCESS(ctypes.Structure):
|
||||||
|
_fields_ = [("dwProcessId", wintypes.DWORD),
|
||||||
|
("ProcessStartTime", wintypes.FILETIME)]
|
||||||
|
|
||||||
|
class RM_PROCESS_INFO(ctypes.Structure):
|
||||||
|
_fields_ = [("Process", RM_UNIQUE_PROCESS),
|
||||||
|
("strAppName", ctypes.c_wchar * 255),
|
||||||
|
("strServiceShortName", ctypes.c_wchar * 63),
|
||||||
|
("ApplicationType", ctypes.c_int),
|
||||||
|
("AppStatus", ctypes.c_uint),
|
||||||
|
("TSSessionId", wintypes.DWORD),
|
||||||
|
("bRestartable", wintypes.BOOL)]
|
||||||
|
|
||||||
|
RmStartSession = rstrtmgr.RmStartSession
|
||||||
|
RmStartSession.argtypes = [ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint32, ctypes.c_wchar_p]
|
||||||
|
RmStartSession.restype = ctypes.c_uint32
|
||||||
|
|
||||||
|
RmRegisterResources = rstrtmgr.RmRegisterResources
|
||||||
|
RmRegisterResources.argtypes = [ctypes.c_uint32, ctypes.c_uint32, ctypes.c_wchar_p,
|
||||||
|
ctypes.c_uint32, ctypes.POINTER(ctypes.c_void_p),
|
||||||
|
ctypes.c_uint32, ctypes.c_wchar_p]
|
||||||
|
RmRegisterResources.restype = ctypes.c_uint32
|
||||||
|
|
||||||
|
RmGetList = rstrtmgr.RmGetList
|
||||||
|
RmGetList.argtypes = [ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32),
|
||||||
|
ctypes.POINTER(RM_PROCESS_INFO), ctypes.POINTER(ctypes.c_uint32)]
|
||||||
|
RmGetList.restype = ctypes.c_uint32
|
||||||
|
|
||||||
|
RmEndSession = rstrtmgr.RmEndSession
|
||||||
|
RmEndSession.argtypes = [ctypes.c_uint32]
|
||||||
|
RmEndSession.restype = ctypes.c_uint32
|
||||||
|
|
||||||
|
session = ctypes.c_uint32(0)
|
||||||
|
desc = ctypes.create_unicode_buffer("diag")
|
||||||
|
rc = RmStartSession(ctypes.byref(session), 0, desc)
|
||||||
|
if rc != 0:
|
||||||
|
print("RmStartSession failed", rc)
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
path = ctypes.create_unicode_buffer(r"C:\ub-build\userbase\classes\application.yml")
|
||||||
|
rc = RmRegisterResources(session, 1, path, 0, None, 0, None)
|
||||||
|
print("RmRegisterResources rc=", rc)
|
||||||
|
|
||||||
|
nNeeded = ctypes.c_uint32(0)
|
||||||
|
nActual = ctypes.c_uint32(0)
|
||||||
|
reason = ctypes.c_uint32(0)
|
||||||
|
rc = RmGetList(session, ctypes.byref(nNeeded), ctypes.byref(nActual), None, ctypes.byref(reason))
|
||||||
|
print("first RmGetList rc=", rc, "needed=", nNeeded.value)
|
||||||
|
if nNeeded.value > 0:
|
||||||
|
arr = (RM_PROCESS_INFO * nNeeded.value)()
|
||||||
|
nActual = ctypes.c_uint32(nNeeded.value)
|
||||||
|
rc = RmGetList(session, ctypes.byref(nNeeded), ctypes.byref(nActual), arr, ctypes.byref(reason))
|
||||||
|
print("second RmGetList rc=", rc, "actual=", nActual.value)
|
||||||
|
for i in range(nActual.value):
|
||||||
|
p = arr[i]
|
||||||
|
print("HOLDER PID=", p.Process.dwProcessId, "app=", p.strAppName)
|
||||||
|
else:
|
||||||
|
print("NO PROCESS HOLDER (likely ACL/permission, not a lock)")
|
||||||
|
RmEndSession(session)
|
||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user