Files
iotlcm/app/server/internal/logic/app/app_data_scope.go
T

398 lines
11 KiB
Go

package app
import (
"context"
"strings"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/dao"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
"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/util/gconv"
)
type appEnterpriseDataScope struct {
Configured bool
All bool
Restricted bool
DeptIds []int64
UserIds []int64
}
func appApplyEnterpriseDataScope(ctx context.Context, user *entity.SysUser, mod *gdb.Model, deptField string, userField string, legacy func(*gdb.Model) *gdb.Model) *gdb.Model {
scope, err := appResolveEnterpriseDataScope(ctx, user)
if err != nil {
g.Log().Errorf(ctx, "appApplyEnterpriseDataScope resolve error: %v", err)
return mod.Where("1 = 0")
}
if !scope.Configured {
if legacy != nil {
return legacy(mod)
}
return mod
}
if scope.All {
return mod
}
hasDeptScope := deptField != "" && len(scope.DeptIds) > 0
hasUserScope := userField != "" && len(scope.UserIds) > 0
if hasDeptScope && hasUserScope {
return mod.Where("("+deptField+" IN (?) OR "+userField+" IN (?))", scope.DeptIds, scope.UserIds)
}
if hasDeptScope {
return mod.WhereIn(deptField, scope.DeptIds)
}
if hasUserScope {
return mod.WhereIn(userField, scope.UserIds)
}
if scope.Restricted {
return mod.Where("1 = 0")
}
return mod.Where("1 = 0")
}
func appResolveEnterpriseDataScope(ctx context.Context, user *entity.SysUser) (*appEnterpriseDataScope, error) {
scope := &appEnterpriseDataScope{}
if user == nil || user.UserId <= 0 {
scope.Restricted = true
return scope, nil
}
configured, err := appAccessConfigured(ctx)
if err != nil {
return nil, err
}
scope.Configured = configured
if !configured {
return scope, nil
}
if contexts.IsSuperAdmin(ctx) {
scope.All = true
return scope, nil
}
currentRoleId, currentRoleDataScope := appCurrentRoleDataScope(ctx)
if currentRoleId > 0 && currentRoleDataScope != "" {
return appBuildEnterpriseDataScope(ctx, user, currentRoleId, currentRoleDataScope, true)
}
roles := contexts.GetRoles(ctx)
if len(roles) == 0 {
roles, err = appLoadUserRoleScopes(ctx, user)
if err != nil {
return nil, err
}
}
if len(roles) == 0 {
scope.Restricted = true
return scope, nil
}
scope.Restricted = true
for _, role := range roles {
part, err := appBuildEnterpriseDataScope(ctx, user, role.RoleId, role.DataScope, true)
if err != nil {
return nil, err
}
if part.All {
return part, nil
}
scope.DeptIds = append(scope.DeptIds, part.DeptIds...)
scope.UserIds = append(scope.UserIds, part.UserIds...)
}
scope.DeptIds = appUniqueInt64(scope.DeptIds)
scope.UserIds = appUniqueInt64(scope.UserIds)
return scope, nil
}
func appCurrentRoleDataScope(ctx context.Context) (int64, string) {
roleId := int64(0)
dataScope := ""
if value := contexts.GetDataValue(ctx, "currentRoleId"); value != nil {
roleId = gconv.Int64(value)
}
if value := contexts.GetDataValue(ctx, "currentRoleDataScope"); value != nil {
dataScope = strings.TrimSpace(gconv.String(value))
}
return roleId, dataScope
}
func appBuildEnterpriseDataScope(ctx context.Context, user *entity.SysUser, roleId int64, dataScope string, configured bool) (*appEnterpriseDataScope, error) {
scope := &appEnterpriseDataScope{
Configured: configured,
}
dataScope = strings.TrimSpace(dataScope)
if dataScope == "" {
dataScope = consts.SysRoleDataScopeAll
}
switch dataScope {
case consts.SysRoleDataScopeAll:
scope.All = true
case consts.SysRoleDataScopeCustom:
scope.Restricted = true
deptIds, err := appCustomRoleDeptIds(ctx, user.TenantId, roleId)
if err != nil {
return nil, err
}
scope.DeptIds = deptIds
case consts.SysRoleDataScopeDept:
scope.Restricted = true
if user.DeptId > 0 {
scope.DeptIds = []int64{user.DeptId}
}
case consts.SysRoleDataScopeDeptAndBelow:
scope.Restricted = true
deptIds, err := appEnterpriseDeptAndSubIds(ctx, user.TenantId, user.DeptId)
if err != nil {
return nil, err
}
scope.DeptIds = deptIds
case consts.SysRoleDataScopePersonal:
scope.Restricted = true
scope.UserIds = []int64{user.UserId}
case consts.SysRoleDataScopeDeptAndBelowOrPersonal:
scope.Restricted = true
deptIds, err := appEnterpriseDeptAndSubIds(ctx, user.TenantId, user.DeptId)
if err != nil {
return nil, err
}
scope.DeptIds = deptIds
scope.UserIds = []int64{user.UserId}
case consts.SysRoleDataScopeOrgAndNextLevel:
scope.Restricted = true
deptIds, err := appOrgAndNextLevelDeptIds(ctx, user.TenantId, user.DeptId)
if err != nil {
return nil, err
}
scope.DeptIds = deptIds
case consts.SysRoleDataScopeOrgNextLevel:
scope.Restricted = true
deptIds, err := appOrgNextLevelDeptIds(ctx, user.TenantId, user.DeptId)
if err != nil {
return nil, err
}
scope.DeptIds = deptIds
default:
scope.Restricted = true
}
scope.DeptIds = appUniqueInt64(scope.DeptIds)
scope.UserIds = appUniqueInt64(scope.UserIds)
return scope, nil
}
func appLoadUserRoleScopes(ctx context.Context, user *entity.SysUser) ([]model.Role, error) {
if user == nil || user.UserId <= 0 {
return []model.Role{}, nil
}
var userRoles []*entity.SysUserRole
if err := dao.SysUserRole.Ctx(ctx).
Where(dao.SysUserRole.Columns().UserId, user.UserId).
Scan(&userRoles); err != nil {
return nil, err
}
roleIds := make([]int64, 0, len(userRoles))
for _, userRole := range userRoles {
if userRole != nil && userRole.RoleId > 0 {
roleIds = append(roleIds, userRole.RoleId)
}
}
roleIds = appUniqueInt64(roleIds)
if len(roleIds) == 0 {
return []model.Role{}, nil
}
var rows []*entity.SysRole
err := dao.SysRole.Ctx(ctx).
Fields(dao.SysRole.Columns().RoleId, dao.SysRole.Columns().DataScope).
Where(dao.SysRole.Columns().TenantId, user.TenantId).
WhereIn(dao.SysRole.Columns().RoleId, roleIds).
Where(dao.SysRole.Columns().Status, consts.SysStatusNormal).
Scan(&rows)
if err != nil {
return nil, err
}
roles := make([]model.Role, 0, len(rows))
for _, row := range rows {
if row == nil || row.RoleId <= 0 {
continue
}
roles = append(roles, model.Role{
RoleId: row.RoleId,
DataScope: row.DataScope,
})
}
return roles, nil
}
func appCustomRoleDeptIds(ctx context.Context, tenantId string, roleId int64) ([]int64, error) {
if roleId <= 0 {
return []int64{}, nil
}
var rows []*entity.SysRoleDept
err := dao.SysRoleDept.Ctx(ctx).
Where("tenant_id", tenantId).
Where(dao.SysRoleDept.Columns().RoleId, roleId).
Scan(&rows)
if err != nil {
return nil, err
}
deptIds := make([]int64, 0, len(rows))
for _, row := range rows {
if row != nil && row.DeptId > 0 {
deptIds = append(deptIds, row.DeptId)
}
}
return appUniqueInt64(deptIds), nil
}
func appLegacyEnterpriseDeptAndSubScope(ctx context.Context, user *entity.SysUser, mod *gdb.Model, deptField string) *gdb.Model {
if user == nil || user.DeptId <= 0 || deptField == "" {
return mod.Where("1 = 0")
}
deptIds, err := appEnterpriseDeptAndSubIds(ctx, user.TenantId, user.DeptId)
if err != nil || len(deptIds) == 0 {
if err != nil {
g.Log().Errorf(ctx, "appLegacyEnterpriseDeptAndSubScope error: %v", err)
}
return mod.Where("1 = 0")
}
return mod.WhereIn(deptField, deptIds)
}
func appFilterDeptsByEnterpriseDataScope(ctx context.Context, user *entity.SysUser, depts []*entity.SysDept) ([]*entity.SysDept, error) {
scope, err := appResolveEnterpriseDataScope(ctx, user)
if err != nil {
return nil, err
}
if !scope.Configured || scope.All {
return depts, nil
}
if len(scope.DeptIds) == 0 {
return []*entity.SysDept{}, nil
}
allowed := make(map[int64]struct{}, len(scope.DeptIds))
for _, deptId := range scope.DeptIds {
allowed[deptId] = struct{}{}
}
result := make([]*entity.SysDept, 0, len(depts))
for _, dept := range depts {
if dept == nil || dept.DeptId <= 0 {
continue
}
if _, ok := allowed[dept.DeptId]; ok {
result = append(result, dept)
}
}
return result, nil
}
func appEnterpriseDeptVisibleByDataScope(ctx context.Context, user *entity.SysUser, deptId int64) (bool, error) {
if deptId <= 0 {
return false, nil
}
scope, err := appResolveEnterpriseDataScope(ctx, user)
if err != nil {
return false, err
}
if !scope.Configured || scope.All {
return true, nil
}
for _, item := range scope.DeptIds {
if item == deptId {
return true, nil
}
}
return false, nil
}
func appParentCompanyDeptId(ctx context.Context, tenantId string, deptId int64) (int64, error) {
if deptId <= 0 {
return deptId, nil
}
var dept *entity.SysDept
if err := dao.SysDept.Ctx(ctx).
Where(dao.SysDept.Columns().TenantId, tenantId).
Where(dao.SysDept.Columns().DeptId, deptId).
WhereNull(dao.SysDept.Columns().DeletedAt).
Limit(1).
Scan(&dept); err != nil {
return 0, gerror.Wrap(err, "查询上级组织失败")
}
if dept == nil || dept.DeptId == 0 {
return deptId, nil
}
if dept.ParentId == 0 || dept.DeptType == 1 {
return dept.DeptId, nil
}
return appParentCompanyDeptId(ctx, tenantId, dept.ParentId)
}
func appDeptDirectSubIds(ctx context.Context, tenantId string, deptId int64) ([]int64, error) {
if deptId <= 0 {
return []int64{}, nil
}
var rows []*entity.SysDept
err := dao.SysDept.Ctx(ctx).
Fields(dao.SysDept.Columns().DeptId).
Where(dao.SysDept.Columns().TenantId, tenantId).
Where(dao.SysDept.Columns().ParentId, deptId).
WhereNull(dao.SysDept.Columns().DeletedAt).
Scan(&rows)
if err != nil {
return nil, gerror.Wrap(err, "查询下级组织失败")
}
deptIds := make([]int64, 0, len(rows))
for _, row := range rows {
if row != nil && row.DeptId > 0 {
deptIds = append(deptIds, row.DeptId)
}
}
return appUniqueInt64(deptIds), nil
}
func appOrgAndNextLevelDeptIds(ctx context.Context, tenantId string, deptId int64) ([]int64, error) {
orgDeptId, err := appParentCompanyDeptId(ctx, tenantId, deptId)
if err != nil {
return nil, err
}
ids := []int64{}
if orgDeptId > 0 {
ids = append(ids, orgDeptId)
}
children, err := appDeptDirectSubIds(ctx, tenantId, orgDeptId)
if err != nil {
return nil, err
}
ids = append(ids, children...)
return appUniqueInt64(ids), nil
}
func appOrgNextLevelDeptIds(ctx context.Context, tenantId string, deptId int64) ([]int64, error) {
orgDeptId, err := appParentCompanyDeptId(ctx, tenantId, deptId)
if err != nil {
return nil, err
}
return appDeptDirectSubIds(ctx, tenantId, orgDeptId)
}
func appUniqueInt64(values []int64) []int64 {
result := make([]int64, 0, len(values))
seen := make(map[int64]struct{}, len(values))
for _, value := range values {
if value <= 0 {
continue
}
if _, ok := seen[value]; ok {
continue
}
seen[value] = struct{}{}
result = append(result, value)
}
return result
}