chore: 初始开源发布
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
This commit is contained in:
@@ -0,0 +1,586 @@
|
||||
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"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rolepolicy"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rolesync"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type sAgentRole struct {
|
||||
*sAgentMenu
|
||||
}
|
||||
|
||||
// NewAgentRole 创建代理商角色管理服务实例。
|
||||
func NewAgentRole() *sAgentRole {
|
||||
return &sAgentRole{
|
||||
sAgentMenu: &sAgentMenu{
|
||||
agentBase: newAgentBase(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterAgentRole(NewAgentRole())
|
||||
}
|
||||
|
||||
// RoleList 查询当前登录组织本级角色列表。
|
||||
func (s *sAgentRole) RoleList(ctx context.Context, in *model.AgentRoleListParam) (list []*model.AgentRoleListModel, total int, err error) {
|
||||
currentDeptId := contexts.GetDeptId(ctx)
|
||||
if currentDeptId == 0 {
|
||||
return nil, 0, gerror.New("当前用户未绑定组织")
|
||||
}
|
||||
if err = service.AgentDept().EnsureCurrentDeptDefaultRole(ctx); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
m := s.roleModel(ctx).Where(dao.SysRole.Columns().DeptId, currentDeptId)
|
||||
if in.RoleName != "" {
|
||||
m = m.WhereLike(dao.SysRole.Columns().RoleName, "%"+in.RoleName+"%")
|
||||
}
|
||||
if in.RoleKey != "" {
|
||||
m = m.WhereLike(dao.SysRole.Columns().RoleKey, "%"+in.RoleKey+"%")
|
||||
}
|
||||
if in.Status != "" {
|
||||
m = m.Where(dao.SysRole.Columns().Status, in.Status)
|
||||
}
|
||||
if len(in.CreatedAt) == 2 {
|
||||
begin, end := gtime.NewFromStr(in.CreatedAt[0]), gtime.NewFromStr(in.CreatedAt[1])
|
||||
m = m.WhereBetween(dao.SysRole.Columns().CreatedAt, begin, end.EndOfDay())
|
||||
}
|
||||
total, err = m.Count()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
err = m.Order(dao.SysRole.Columns().RoleId, "ASC").
|
||||
Scan(&list)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defaultRoleId, err := s.currentDeptDefaultRoleId(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
for _, role := range list {
|
||||
role.IsDefaultRole = defaultRoleId != 0 && role.RoleId == defaultRoleId
|
||||
}
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
// RoleView 查询角色详情,并返回当前登录组织可分配的菜单树。
|
||||
func (s *sAgentRole) RoleView(ctx context.Context, roleId int64) (res *model.AgentRoleViewModel, err error) {
|
||||
role, err := service.SysRole().View(ctx, &model.SysRoleViewParam{RoleId: roleId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if role == nil || role.RoleId == 0 {
|
||||
return nil, gerror.New("角色不存在")
|
||||
}
|
||||
if role.DeptId != contexts.GetDeptId(ctx) {
|
||||
return nil, gerror.New("只能操作本级角色")
|
||||
}
|
||||
tree, allowed, err := s.AllowedMenuTree(ctx, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isDefaultRole, err := s.isCurrentDeptDefaultRole(ctx, role.RoleId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.AgentRoleViewModel{
|
||||
SysRoleViewModel: *role,
|
||||
AllowedMenuIds: allowed,
|
||||
MenuTree: tree,
|
||||
IsDefaultRole: isDefaultRole,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RoleSave 保存代理商角色,按角色ID区分新增和修改流程。
|
||||
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)
|
||||
if saveErr != nil {
|
||||
return saveErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := rolesync.EnqueueRole(ctx, roleId, contexts.GetUserId(ctx)); err != nil {
|
||||
return roleId, err
|
||||
}
|
||||
return roleId, nil
|
||||
}
|
||||
|
||||
func (s *sAgentRole) saveTemplateRole(ctx context.Context, in *model.AgentRoleSaveParam) (roleId int64, err error) {
|
||||
user := contexts.GetUser(ctx)
|
||||
if user == nil {
|
||||
return 0, gerror.New("登录已过期")
|
||||
}
|
||||
if in.DeptId == 0 {
|
||||
in.DeptId = user.DeptId
|
||||
}
|
||||
if in.DeptId != user.DeptId {
|
||||
return 0, gerror.New("只能维护本级角色")
|
||||
}
|
||||
if err = s.ensureRoleNotCurrentDeptDefault(ctx, in.RoleId); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if in.RoleId > 0 {
|
||||
if err = s.ensureRoleNotInherited(ctx, in.RoleId); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if in.Status == "" {
|
||||
in.Status = "0"
|
||||
}
|
||||
if in.DataScope == "" {
|
||||
in.DataScope = consts.SysRoleDataScopeDeptAndBelow
|
||||
}
|
||||
if !contexts.IsSuperAdmin(ctx) {
|
||||
allowed, err := s.filterMenuIdsByAllowed(ctx, in.DeptId, in.MenuIds)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, id := range in.MenuIds {
|
||||
if !slices.Contains(allowed, id) {
|
||||
return 0, gerror.New("角色包含超出本机构权限范围的菜单或按钮")
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
if in.IsPass != 0 && in.IsPass != 1 {
|
||||
return 0, gerror.New("传递标记无效")
|
||||
}
|
||||
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()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
legacyPass = configured == 0
|
||||
}
|
||||
if legacyPass {
|
||||
in.DataScope = consts.SysRoleDataScopeDeptAndBelow
|
||||
var dept *entity.SysDept
|
||||
deptModel := s.deptModel(ctx).Where(dao.SysDept.Columns().DeptId, in.DeptId)
|
||||
if dao.SysDept.DB().GetConfig().Type != "sqlite" {
|
||||
deptModel = deptModel.LockUpdate()
|
||||
}
|
||||
if err := deptModel.Scan(&dept); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if dept == nil {
|
||||
return 0, gerror.New("当前机构不存在")
|
||||
}
|
||||
count, err := s.roleModel(ctx).
|
||||
Where(dao.SysRole.Columns().DeptId, in.DeptId).
|
||||
Where("is_pass", 1).
|
||||
WhereNot(dao.SysRole.Columns().RoleId, in.RoleId).
|
||||
Count()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if count > 0 {
|
||||
return 0, gerror.New("每个机构只能配置一个下级管理员角色")
|
||||
}
|
||||
}
|
||||
|
||||
if in.RoleId == 0 {
|
||||
return s.addRole(ctx, in)
|
||||
}
|
||||
return s.editRole(ctx, in)
|
||||
}
|
||||
|
||||
// addRole 新增代理商角色,并同步角色的数据权限配置。
|
||||
func (s *sAgentRole) addRole(ctx context.Context, in *model.AgentRoleSaveParam) (int64, error) {
|
||||
deptId := in.DeptId
|
||||
role, err := service.SysRole().Add(ctx, &model.SysRoleAddParam{
|
||||
RoleName: in.RoleName,
|
||||
RoleKey: in.RoleKey,
|
||||
RoleSort: in.RoleSort,
|
||||
DataScope: in.DataScope,
|
||||
MenuCheckStrictly: in.MenuCheckStrictly,
|
||||
Status: in.Status,
|
||||
Remark: in.Remark,
|
||||
MenuIds: in.MenuIds,
|
||||
DeptId: &deptId,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if role == nil {
|
||||
return 0, nil
|
||||
}
|
||||
if _, err = dao.SysRole.Ctx(ctx).
|
||||
Where(dao.SysRole.Columns().RoleId, role.RoleId).
|
||||
Data(do.SysRole{IsPass: in.IsPass}).Update(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err = s.updateRoleDataScope(ctx, role.RoleId, in); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return role.RoleId, nil
|
||||
}
|
||||
|
||||
// editRole 修改代理商角色,并禁止在代理商页面移动角色所属组织。
|
||||
func (s *sAgentRole) editRole(ctx context.Context, in *model.AgentRoleSaveParam) (int64, error) {
|
||||
current, err := s.RoleView(ctx, in.RoleId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if current.DeptId != in.DeptId {
|
||||
return 0, gerror.New("不能在代理商页面移动角色所属组织")
|
||||
}
|
||||
deptId := in.DeptId
|
||||
roleName := in.RoleName
|
||||
roleKey := in.RoleKey
|
||||
roleSort := in.RoleSort
|
||||
menuCheckStrictly := in.MenuCheckStrictly
|
||||
status := in.Status
|
||||
remark := in.Remark
|
||||
role, err := service.SysRole().Edit(ctx, &model.SysRoleEditParam{
|
||||
RoleId: in.RoleId,
|
||||
RoleName: &roleName,
|
||||
RoleKey: &roleKey,
|
||||
RoleSort: &roleSort,
|
||||
MenuCheckStrictly: &menuCheckStrictly,
|
||||
Status: &status,
|
||||
Remark: &remark,
|
||||
MenuIds: in.MenuIds,
|
||||
DeptId: &deptId,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err = s.updateRoleDataScope(ctx, in.RoleId, in); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err = dao.SysRole.Ctx(ctx).
|
||||
Where(dao.SysRole.Columns().RoleId, in.RoleId).
|
||||
Data(do.SysRole{IsPass: in.IsPass}).Update(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if role == nil {
|
||||
return in.RoleId, nil
|
||||
}
|
||||
return role.RoleId, nil
|
||||
}
|
||||
|
||||
// updateRoleDataScope 更新角色数据权限和组织树勾选配置。
|
||||
func (s *sAgentRole) updateRoleDataScope(ctx context.Context, roleId int64, in *model.AgentRoleSaveParam) error {
|
||||
deptCheckStrictly := in.DeptCheckStrictly
|
||||
return service.SysRole().EditRoleDataScope(ctx, &model.SysRoleDataScopeEditParam{
|
||||
RoleId: roleId,
|
||||
DataScope: in.DataScope,
|
||||
DeptCheckStrictly: &deptCheckStrictly,
|
||||
DeptIds: []int64{in.DeptId},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *sAgentRole) isCurrentDeptDefaultRole(ctx context.Context, roleId int64) (bool, error) {
|
||||
defaultRoleId, err := s.currentDeptDefaultRoleId(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return defaultRoleId != 0 && roleId == defaultRoleId, nil
|
||||
}
|
||||
|
||||
func (s *sAgentRole) ensureRoleInCurrentDept(ctx context.Context, roleId int64) error {
|
||||
currentDeptId := contexts.GetDeptId(ctx)
|
||||
if currentDeptId == 0 {
|
||||
return gerror.New("当前用户未绑定组织")
|
||||
}
|
||||
count, err := s.roleModel(ctx).
|
||||
Where(dao.SysRole.Columns().RoleId, roleId).
|
||||
Where(dao.SysRole.Columns().DeptId, currentDeptId).
|
||||
Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return gerror.New("只能操作本级角色")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sAgentRole) ensureRoleNotInherited(ctx context.Context, roleId int64) error {
|
||||
if roleId <= 0 {
|
||||
return nil
|
||||
}
|
||||
if contexts.IsSuperAdmin(ctx) {
|
||||
return nil
|
||||
}
|
||||
count, err := s.inheritedRoleModel(ctx).
|
||||
Where("r.role_id", roleId).
|
||||
Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return gerror.New("上级下发角色由上级角色统一维护,当前组织只能查看")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sAgentRole) ensureRoleNoUsers(ctx context.Context, roleId int64) error {
|
||||
count, err := dao.SysUserRole.Ctx(ctx).
|
||||
Where(dao.SysUserRole.Columns().RoleId, roleId).
|
||||
Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return gerror.New("该角色已绑定用户,不能删除")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RoleDelete 删除代理商角色,删除前校验本级机构默认角色不可被删除。
|
||||
func (s *sAgentRole) RoleDelete(ctx context.Context, roleIds []int64) (err error) {
|
||||
for _, roleId := range roleIds {
|
||||
if err = s.ensureRoleInCurrentDept(ctx, roleId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = s.ensureRoleNotCurrentDeptDefault(ctx, roleId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = s.ensureRoleNotInherited(ctx, roleId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = s.ensureRoleNoUsers(ctx, roleId); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = service.SysRole().Delete(ctx, &model.SysRoleDeleteParam{RoleIds: roleIds})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sAgentRole) inheritedRoleModel(ctx context.Context) *gdb.Model {
|
||||
m := g.Model(dao.SysRole.Table()+" r").
|
||||
LeftJoin(dao.SysDept.Table()+" d", "d.dept_id = r.dept_id AND d.tenant_id = r.tenant_id").
|
||||
Where("r.deleted_at IS NULL").
|
||||
Where("d.deleted_at IS NULL").
|
||||
Where("r.created_dept > 0").
|
||||
Where("r.dept_id <> r.created_dept").
|
||||
Where("d.parent_id = r.created_dept")
|
||||
if tenantId := contexts.GetTenantId(ctx); tenantId != "" {
|
||||
m = m.Where("r.tenant_id", tenantId)
|
||||
}
|
||||
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, ©)
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user