Files
iotlcm/admin-svr/server/internal/logic/agent/agent_role.go
T

392 lines
12 KiB
Go

package agent
import (
"context"
"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(rolesync.DeferRecording(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 := rolepolicy.NormalizeAssignableMenus(ctx, user.TenantId, in.DeptId, user.ID, in.MenuIds)
if err != nil {
return 0, err
}
in.MenuIds = allowed
switch in.DataScope {
case consts.SysRoleDataScopeDept, consts.SysRoleDataScopeDeptAndBelow, consts.SysRoleDataScopePersonal, consts.SysRoleDataScopeDeptAndBelowOrPersonal, consts.SysRoleDataScopeOrgAndNextLevel, consts.SysRoleDataScopeOrgNextLevel:
default:
return 0, gerror.New("代理角色数据权限不能超出本机构及下级范围")
}
}
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
}
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
}