All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m18s
- 移除 IoT 卡和号卡的 card_type 字段(数据库迁移) - 优化账号列表查询,支持按店铺和企业筛选 - 账号响应增加店铺名称和企业名称字段 - 实现批量加载店铺和企业名称,避免 N+1 查询 - 更新权限检查中间件,完善权限验证逻辑 - 更新相关测试用例,确保功能正确性
114 lines
3.8 KiB
Go
114 lines
3.8 KiB
Go
package middleware
|
||
|
||
import (
|
||
"context"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// ShopStoreInterface 店铺存储接口
|
||
// 用于权限检查时查询店铺信息和下级店铺ID
|
||
type ShopStoreInterface interface {
|
||
GetByID(ctx context.Context, id uint) (*model.Shop, error)
|
||
GetByIDs(ctx context.Context, ids []uint) ([]*model.Shop, error)
|
||
GetSubordinateShopIDs(ctx context.Context, shopID uint) ([]uint, error)
|
||
}
|
||
|
||
// EnterpriseStoreInterface 企业存储接口
|
||
// 用于权限检查时查询企业信息
|
||
type EnterpriseStoreInterface interface {
|
||
GetByID(ctx context.Context, id uint) (*model.Enterprise, error)
|
||
GetByIDs(ctx context.Context, ids []uint) ([]*model.Enterprise, error)
|
||
}
|
||
|
||
// CanManageShop 检查当前用户是否有权管理目标店铺的账号
|
||
// 超级管理员和平台用户自动通过
|
||
// 代理账号只能管理自己店铺及下级店铺的账号
|
||
// 企业账号禁止管理店铺账号
|
||
func CanManageShop(ctx context.Context, targetShopID uint, shopStore ShopStoreInterface) error {
|
||
userType := GetUserTypeFromContext(ctx)
|
||
|
||
// 超级管理员和平台用户跳过权限检查
|
||
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
||
return nil
|
||
}
|
||
|
||
// 企业账号禁止管理店铺账号
|
||
if userType != constants.UserTypeAgent {
|
||
return errors.New(errors.CodeForbidden, "无权限管理店铺账号")
|
||
}
|
||
|
||
// 获取当前代理账号的店铺ID
|
||
currentShopID := GetShopIDFromContext(ctx)
|
||
if currentShopID == 0 {
|
||
return errors.New(errors.CodeForbidden, "无权限管理店铺账号")
|
||
}
|
||
|
||
// 递归查询下级店铺ID(包含自己)
|
||
subordinateIDs, err := shopStore.GetSubordinateShopIDs(ctx, currentShopID)
|
||
if err != nil {
|
||
return errors.Wrap(errors.CodeInternalError, err, "查询下级店铺失败")
|
||
}
|
||
|
||
// 检查目标店铺是否在下级列表中
|
||
for _, id := range subordinateIDs {
|
||
if id == targetShopID {
|
||
return nil
|
||
}
|
||
}
|
||
|
||
return errors.New(errors.CodeForbidden, "无权限管理该店铺的账号")
|
||
}
|
||
|
||
// CanManageEnterprise 检查当前用户是否有权管理目标企业的账号
|
||
// 超级管理员和平台用户自动通过
|
||
// 代理账号只能管理归属于自己店铺或下级店铺的企业账号
|
||
// 企业账号禁止管理其他企业账号
|
||
func CanManageEnterprise(ctx context.Context, targetEnterpriseID uint, enterpriseStore EnterpriseStoreInterface, shopStore ShopStoreInterface) error {
|
||
userType := GetUserTypeFromContext(ctx)
|
||
|
||
// 超级管理员和平台用户跳过权限检查
|
||
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
||
return nil
|
||
}
|
||
|
||
// 企业账号禁止管理其他企业账号
|
||
if userType != constants.UserTypeAgent {
|
||
return errors.New(errors.CodeForbidden, "无权限管理企业账号")
|
||
}
|
||
|
||
// 获取目标企业信息
|
||
enterprise, err := enterpriseStore.GetByID(ctx, targetEnterpriseID)
|
||
if err != nil {
|
||
return errors.Wrap(errors.CodeForbidden, err, "无权限操作该资源或资源不存在")
|
||
}
|
||
|
||
// 代理账号不能管理平台级企业(owner_shop_id为NULL)
|
||
if enterprise.OwnerShopID == nil {
|
||
return errors.New(errors.CodeForbidden, "无权限管理平台级企业账号")
|
||
}
|
||
|
||
// 获取当前代理账号的店铺ID
|
||
currentShopID := GetShopIDFromContext(ctx)
|
||
if currentShopID == 0 {
|
||
return errors.New(errors.CodeForbidden, "无权限管理企业账号")
|
||
}
|
||
|
||
// 递归查询下级店铺ID(包含自己)
|
||
subordinateIDs, err := shopStore.GetSubordinateShopIDs(ctx, currentShopID)
|
||
if err != nil {
|
||
return errors.Wrap(errors.CodeInternalError, err, "查询下级店铺失败")
|
||
}
|
||
|
||
// 检查企业归属的店铺是否在下级列表中
|
||
for _, id := range subordinateIDs {
|
||
if id == *enterprise.OwnerShopID {
|
||
return nil
|
||
}
|
||
}
|
||
|
||
return errors.New(errors.CodeForbidden, "无权限管理该企业的账号")
|
||
}
|