398 lines
11 KiB
Go
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
|
|
}
|