chore: 初始开源发布
iotlcm-app:小程序端 + 用户端服务。 - app/:uni-app 小程序前端(基于 unibest,MIT) - 微信 AppID → YOUR_WX_APPID,uni-app AppID → __UNI__YOURAPPID - 内网后端地址 → admin.iotlcm.example.com - 应用标题与 unibest 模板 README 重写(保留上游致谢与 MIT 声明) - server/:GoFrame 用户端服务(基于 XiuAdmin,Apache-2.0) - module xiuadmin → git.5iot.com/iotlcm-public/iotlcm-app(360 文件) - 支付回调地址 → app.iotlcm.example.com,商户名与应用名泛化 - 真实手机号 → 合法 11 位编造号(保留号段前 3 位 + 后 4 位) - 依赖号码尾部的断言同步更新 - 补 server/LICENSE(Apache-2.0) - 移除内部资产:CI 触发器 - 补根 README,LF 行尾 + .gitattributes 已知:TestSysDept_RefreshDeptAncestors 在源仓同一提交上同样失败,属既有缺陷。
This commit is contained in:
@@ -0,0 +1,397 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user