139 lines
4.6 KiB
Go
139 lines
4.6 KiB
Go
package controllers
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"server/models"
|
||
"server/pkg/jwtutil"
|
||
|
||
"github.com/beego/beego/v2/client/orm"
|
||
)
|
||
|
||
// CRM 客户 / 供应商的删除权限规则:
|
||
// 1. 平台管理员(UserType=platform)可删除;
|
||
// 2. 租户管理员(绑定「租户管理员」角色,或未分配角色/角色未配置权限等既有"全权限"情形)可删除;
|
||
// 3. 记录的创建人可删除自己创建的记录。
|
||
// 其余用户一律禁止删除。删除本身为软删除(置 delete_time)。
|
||
|
||
// canDeleteCrmRecord 判断当前用户是否有权删除指定记录。
|
||
// createUserID 为记录的创建人用户ID(历史数据可能为空)。
|
||
func canDeleteCrmRecord(claims *jwtutil.Claims, createUserID string) bool {
|
||
if claims == nil {
|
||
return false
|
||
}
|
||
// 平台管理员
|
||
if claims.UserType == "platform" {
|
||
return true
|
||
}
|
||
// 创建人本人
|
||
uid := fmt.Sprintf("%d", claims.UserID)
|
||
if createUserID != "" && createUserID == uid {
|
||
return true
|
||
}
|
||
// 租户管理员 / 具备全权限的租户用户
|
||
return isTenantAdmin(claims.UserID, claims.TenantId)
|
||
}
|
||
|
||
// isTenantAdmin 判断用户在指定租户内是否具备管理员(全权限)身份。
|
||
// 判定与既有权限约定保持一致:
|
||
// - 未分配角色(group_id=0)视为全权限;
|
||
// - 角色名为「租户管理员」视为管理员;
|
||
// - 角色未配置 rights(空/空数组/null)视为全权限。
|
||
func isTenantAdmin(userID int, tenantID int) bool {
|
||
if tenantID <= 0 || models.Orm == nil {
|
||
return false
|
||
}
|
||
var tu models.SystemTenantUser
|
||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||
Filter("uid", userID).
|
||
Filter("tid", tenantID).
|
||
Filter("delete_time__isnull", true).
|
||
One(&tu); err != nil {
|
||
return false
|
||
}
|
||
if tu.GroupID == 0 {
|
||
return true
|
||
}
|
||
var role models.AdminRole
|
||
if err := models.Orm.QueryTable(new(models.AdminRole)).
|
||
Filter("id", tu.GroupID).
|
||
Filter("cid", 2).
|
||
Filter("tenant_id", tenantID).
|
||
One(&role); err != nil {
|
||
return false
|
||
}
|
||
if role.Name == "租户管理员" {
|
||
return true
|
||
}
|
||
rights := ""
|
||
if role.Rights != nil {
|
||
rights = strings.TrimSpace(*role.Rights)
|
||
}
|
||
return rights == "" || rights == "[]" || rights == "null"
|
||
}
|
||
|
||
// ========================== CRM 数据范围(用户级隔离) ==========================
|
||
//
|
||
// 数据可见范围约定(仅作用于用户级业务数据):
|
||
// - 平台管理员 / 租户管理员(含未分配角色、角色未配置权限等全权限情形)→ 可见租户内全部数据;
|
||
// - 其他用户 → 仅可见「负责人是自己」或「由自己创建」的数据。
|
||
//
|
||
// 租户共享数据不在此列,始终对全租户可见:供应商、客户公海、产品列表、产品分类。
|
||
// 后续如需按角色配置数据范围,只需扩展 crmScopeSelfOnly 的判定。
|
||
|
||
// crmScopeSelfOnly 判断当前用户是否只能看「本人」数据(true=仅本人)。
|
||
func crmScopeSelfOnly(claims *jwtutil.Claims) bool {
|
||
if claims == nil {
|
||
return true
|
||
}
|
||
if claims.UserType == "platform" {
|
||
return false
|
||
}
|
||
return !isTenantAdmin(claims.UserID, claims.TenantId)
|
||
}
|
||
|
||
// crmApplyOwnerScope 为列表查询条件追加数据范围限制(需要「仅本人」时)。
|
||
// 需要用户级隔离的模块请在构造完 tenant 条件后调用。
|
||
func crmApplyOwnerScope(cond *orm.Condition, claims *jwtutil.Claims) *orm.Condition {
|
||
if !crmScopeSelfOnly(claims) {
|
||
return cond
|
||
}
|
||
uid := pipelineUID(claims)
|
||
return cond.AndCond(orm.NewCondition().
|
||
Or("owner_user_id", uid).
|
||
Or("create_user_id", uid))
|
||
}
|
||
|
||
// canAccessCrmRecord 判断当前用户是否有权访问(查看 / 编辑 / 删除)指定记录。
|
||
// ownerUserID / createUserID 为记录的负责人与创建人(历史数据可能为空)。
|
||
func canAccessCrmRecord(claims *jwtutil.Claims, ownerUserID, createUserID string) bool {
|
||
if claims == nil {
|
||
return false
|
||
}
|
||
// 平台 / 租户管理员可访问全部
|
||
if !crmScopeSelfOnly(claims) {
|
||
return true
|
||
}
|
||
uid := pipelineUID(claims)
|
||
if ownerUserID != "" && ownerUserID == uid {
|
||
return true
|
||
}
|
||
return createUserID != "" && createUserID == uid
|
||
}
|
||
|
||
// crmNameDuplicated 判断同租户内是否已存在同名记录(不含软删除),用于创建时的唯一性校验。
|
||
// model 传 new(models.XXX);nameField 为数据库列名(如 clue_name)。
|
||
func crmNameDuplicated(model interface{}, tenantID, nameField, name string) bool {
|
||
name = strings.TrimSpace(name)
|
||
if name == "" || strings.TrimSpace(tenantID) == "" || models.Orm == nil {
|
||
return false
|
||
}
|
||
cnt, err := models.Orm.QueryTable(model).
|
||
Filter("tenant_id", tenantID).
|
||
Filter("delete_time__isnull", true).
|
||
Filter(nameField, name).
|
||
Count()
|
||
return err == nil && cnt > 0
|
||
}
|