sync: 同步 v1.0.4 并脱敏配置与镜像

This commit is contained in:
MiFaZhan
2026-10-29 14:36:49 +08:00
parent 743e8e6e6e
commit 2206a393f7
516 changed files with 18119 additions and 2253 deletions
+3 -198
View File
@@ -2,8 +2,6 @@ package agent
import (
"context"
"slices"
"strings"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
@@ -112,7 +110,7 @@ func (s *sAgentRole) RoleView(ctx context.Context, roleId int64) (res *model.Age
func (s *sAgentRole) RoleSave(ctx context.Context, in *model.AgentRoleSaveParam) (roleId int64, err error) {
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
var saveErr error
roleId, saveErr = s.saveTemplateRole(ctx, in)
roleId, saveErr = s.saveTemplateRole(rolesync.DeferRecording(ctx), in)
if saveErr != nil {
return saveErr
}
@@ -153,24 +151,17 @@ func (s *sAgentRole) saveTemplateRole(ctx context.Context, in *model.AgentRoleSa
in.DataScope = consts.SysRoleDataScopeDeptAndBelow
}
if !contexts.IsSuperAdmin(ctx) {
allowed, err := s.filterMenuIdsByAllowed(ctx, in.DeptId, in.MenuIds)
allowed, err := rolepolicy.NormalizeAssignableMenus(ctx, user.TenantId, in.DeptId, user.ID, in.MenuIds)
if err != nil {
return 0, err
}
for _, id := range in.MenuIds {
if !slices.Contains(allowed, id) {
return 0, gerror.New("角色包含超出本机构权限范围的菜单或按钮")
}
}
in.MenuIds = allowed
switch in.DataScope {
case consts.SysRoleDataScopeDept, consts.SysRoleDataScopeDeptAndBelow, consts.SysRoleDataScopePersonal, consts.SysRoleDataScopeDeptAndBelowOrPersonal, consts.SysRoleDataScopeOrgAndNextLevel, consts.SysRoleDataScopeOrgNextLevel:
default:
return 0, gerror.New("代理角色数据权限不能超出本机构及下级范围")
}
}
// 只有本次保存的目标角色是平台代理模板时才走模板语义;
// 普通角色(如「运营人员」)不能被强制改写成 is_pass=1,
// 否则任何已配置模板的机构都无法再保存第二个角色。
template, templateErr := rolepolicy.TemplateForRoles(ctx, in.RoleId)
if templateErr != nil {
return 0, templateErr
@@ -181,7 +172,6 @@ func (s *sAgentRole) saveTemplateRole(ctx context.Context, in *model.AgentRoleSa
if template != nil {
in.DataScope = consts.SysRoleDataScopeDeptAndBelow
}
// 未配置平台模板时,保留原有「本级唯一 is_pass=1 角色」下发流程。
legacyPass := in.IsPass == 1
if legacyPass {
configured, err := dao.SysConfig.Ctx(ctx).Master().Where("tenant_id", consts.DefaultSystemTenantCode).Where("config_key", rolepolicy.TemplateConfigKey).Count()
@@ -399,188 +389,3 @@ func (s *sAgentRole) inheritedRoleModel(ctx context.Context) *gdb.Model {
}
return m
}
func (s *sAgentRole) SyncInheritedRole(ctx context.Context, message *model.AgentRoleSyncMessage) error {
if message == nil || message.SourceRoleId <= 0 {
return gerror.New("invalid agent role sync message")
}
template, templateErr := rolepolicy.Template(ctx)
if templateErr != nil {
return templateErr
}
if template != nil && message.SourceDeptId == template.DeptId && (message.TenantId == template.TenantId || message.TenantId == "") {
return syncTemplateRoles(ctx, template, message.ActorId)
}
var source *entity.SysRole
sourceModel := dao.SysRole.Ctx(ctx).Where(dao.SysRole.Columns().RoleId, message.SourceRoleId)
if message.TenantId != "" {
sourceModel = sourceModel.Where(dao.SysRole.Columns().TenantId, message.TenantId)
}
if err := sourceModel.Scan(&source); err != nil {
return err
}
if source == nil || source.IsPass != 1 || source.DeletedAt != nil {
return nil
}
if message.SourceDeptId > 0 && message.SourceDeptId != source.DeptId {
return gerror.New("role sync source department changed")
}
var children []*entity.SysDept
if err := dao.SysDept.Ctx(ctx).
Where(dao.SysDept.Columns().TenantId, source.TenantId).
Where(dao.SysDept.Columns().ParentId, source.DeptId).
Where(dao.SysDept.Columns().DeptType, 1).
Scan(&children); err != nil {
return err
}
failed := 0
var firstErr error
for _, child := range children {
err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
return s.syncInheritedRoleChildrenTx(ctx, tx, message.SourceRoleId, source.TenantId, source.DeptId, message.ActorId, child.DeptId)
})
if err != nil {
failed++
if firstErr == nil {
firstErr = err
}
g.Log().Warningf(ctx, "agent role sync child failed, sourceRoleId:%d, childDeptId:%d, err:%v", source.RoleId, child.DeptId, err)
}
}
if firstErr != nil {
return gerror.Wrapf(firstErr, "agent role sync failed for %d of %d children", failed, len(children))
}
return nil
}
func (s *sAgentRole) syncInheritedRoleChildrenTx(ctx context.Context, tx gdb.TX, sourceRoleID int64, tenantId string, sourceDeptId, actorId, childDeptId int64) error {
if sourceRoleID == 0 {
return nil
}
var source *entity.SysRole
sourceModel := tx.Ctx(ctx).Model(dao.SysRole.Table()).Where(dao.SysRole.Columns().RoleId, sourceRoleID)
if tenantId != "" {
sourceModel = sourceModel.Where(dao.SysRole.Columns().TenantId, tenantId)
}
if !strings.EqualFold(g.DB().GetConfig().Type, "sqlite") {
sourceModel = sourceModel.LockUpdate()
}
if err := sourceModel.Scan(&source); err != nil {
return err
}
if source == nil || source.RoleId == 0 || source.DeletedAt != nil || source.IsPass != 1 {
return nil
}
if sourceDeptId > 0 && source.DeptId != sourceDeptId {
return gerror.New("role sync source department changed")
}
var childDepts []*entity.SysDept
childDeptModel := tx.Ctx(ctx).Model(dao.SysDept.Table()).Where(dao.SysDept.Columns().TenantId, source.TenantId).Where(dao.SysDept.Columns().ParentId, source.DeptId).Where(dao.SysDept.Columns().DeptType, 1).Where(dao.SysDept.Columns().DeptId, childDeptId)
if !strings.EqualFold(g.DB().GetConfig().Type, "sqlite") {
childDeptModel = childDeptModel.LockUpdate()
}
if err := childDeptModel.Scan(&childDepts); err != nil {
return err
}
var menus []*entity.SysRoleMenu
if err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Where(dao.SysRoleMenu.Columns().RoleId, sourceRoleID).OrderAsc(dao.SysRoleMenu.Columns().MenuId).Scan(&menus); err != nil {
return err
}
menuIDs := make([]int64, 0, len(menus))
for _, menu := range menus {
menuIDs = append(menuIDs, menu.MenuId)
}
allowed, err := rolepolicy.RestrictMenus(ctx, source.TenantId, source.DeptId, menuIDs)
if err != nil {
return err
}
template, templateErr := rolepolicy.Template(ctx)
if templateErr != nil {
return templateErr
}
filtered := make([]*entity.SysRoleMenu, 0, len(menus))
for _, menu := range menus {
if slices.Contains(allowed, menu.MenuId) {
copy := *menu
if template != nil {
copy.DataScope = consts.SysRoleMenuDataScopeRole
}
filtered = append(filtered, &copy)
}
}
menus = filtered
for _, childDept := range childDepts {
var children []*entity.SysRole
if err := tx.Ctx(ctx).Model(dao.SysRole.Table()+" r").
Fields("r.*").
Where("r.tenant_id", source.TenantId).
Where("r.dept_id", childDept.DeptId).
Where("r.created_dept", source.DeptId).
Where("r.role_id", childDept.DeptRole).
Where("r.deleted_at IS NULL").
Scan(&children); err != nil {
return err
}
if len(children) > 1 {
return gerror.Newf("multiple inherited roles in department %d for role %d", childDept.DeptId, source.RoleId)
}
if len(children) == 0 {
var legacy *entity.SysRole
if childDept.DeptRole > 0 {
if err := tx.Ctx(ctx).Model(dao.SysRole.Table()).
Where(dao.SysRole.Columns().RoleId, childDept.DeptRole).
Where(dao.SysRole.Columns().DeptId, childDept.DeptId).
Where(dao.SysRole.Columns().TenantId, source.TenantId).
Scan(&legacy); err != nil {
return err
}
}
if legacy != nil && legacy.RoleId > 0 {
if legacy.CreatedDept != source.DeptId || legacy.RoleKey != source.RoleKey {
return gerror.Newf("cannot identify inherited role for department %d", childDept.DeptId)
}
children = []*entity.SysRole{legacy}
} else {
if childDept.DeptRole > 0 {
return gerror.Newf("missing default role for department %d", childDept.DeptId)
}
roleId, err := s.createInheritedRoleTx(ctx, tx, source, childDept.DeptId, menus, actorId)
if err != nil {
return err
}
children = []*entity.SysRole{{RoleId: roleId}}
}
}
for _, child := range children {
if _, err := tx.Ctx(ctx).Model(dao.SysRole.Table()).Where(dao.SysRole.Columns().RoleId, child.RoleId).Data(do.SysRole{RoleName: strings.TrimSpace(source.RoleName), RoleKey: source.RoleKey, RoleSort: source.RoleSort, DataScope: source.DataScope, MenuCheckStrictly: source.MenuCheckStrictly, DeptCheckStrictly: source.DeptCheckStrictly, Status: source.Status, Remark: source.Remark, UpdatedBy: actorId, UpdatedAt: gtime.Now()}).OmitNil().Update(); err != nil {
return err
}
if _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Where(dao.SysRoleMenu.Columns().RoleId, child.RoleId).Delete(); err != nil {
return err
}
for _, menu := range menus {
if _, err := tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Data(do.SysRoleMenu{TenantId: source.TenantId, RoleId: child.RoleId, MenuId: menu.MenuId, DataScope: menu.DataScope}).OmitNil().Insert(); err != nil {
return err
}
}
}
}
return nil
}
func (s *sAgentRole) createInheritedRoleTx(ctx context.Context, tx gdb.TX, source *entity.SysRole, deptId int64, menus []*entity.SysRoleMenu, actorId int64) (int64, error) {
if actorId == 0 {
actorId = source.UpdatedBy
}
roleId, err := tx.Ctx(ctx).Model(dao.SysRole.Table()).Data(do.SysRole{TenantId: source.TenantId, DeptId: deptId, RoleName: strings.TrimSpace(source.RoleName), RoleKey: source.RoleKey, RoleSort: source.RoleSort, DataScope: source.DataScope, MenuCheckStrictly: source.MenuCheckStrictly, DeptCheckStrictly: source.DeptCheckStrictly, IsPass: 0, Status: source.Status, CreatedDept: source.DeptId, CreatedBy: actorId, CreatedAt: gtime.Now(), UpdatedBy: actorId, UpdatedAt: gtime.Now(), Remark: source.Remark}).OmitNil().InsertAndGetId()
if err != nil {
return 0, err
}
for _, menu := range menus {
if _, err = tx.Ctx(ctx).Model(dao.SysRoleMenu.Table()).Data(do.SysRoleMenu{TenantId: source.TenantId, RoleId: roleId, MenuId: menu.MenuId, DataScope: menu.DataScope}).OmitNil().Insert(); err != nil {
return 0, err
}
}
_, err = tx.Ctx(ctx).Model(dao.SysRoleDept.Table()).Data(do.SysRoleDept{RoleId: roleId, DeptId: deptId}).OmitNil().Insert()
return roleId, err
}