fix: 修复手动触发去重TTL和日限制次数,优化权限检查和错误日志
This commit is contained in:
@@ -53,9 +53,13 @@ func (s *ManualTriggerService) TriggerSingle(ctx context.Context, cardID uint, t
|
|||||||
// 检查每日触发限制
|
// 检查每日触发限制
|
||||||
todayCount, err := s.logStore.CountTodayTriggers(ctx, triggeredBy)
|
todayCount, err := s.logStore.CountTodayTriggers(ctx, triggeredBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("查询今日触发次数失败",
|
||||||
|
zap.Uint("triggered_by", triggeredBy),
|
||||||
|
zap.String("task_type", taskType),
|
||||||
|
zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if todayCount >= 100 { // 每日最多触发100次
|
if todayCount >= 500 { // 每日最多触发500次
|
||||||
return errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
|
return errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,13 +67,17 @@ func (s *ManualTriggerService) TriggerSingle(ctx context.Context, cardID uint, t
|
|||||||
dedupeKey := constants.RedisPollingManualDedupeKey(taskType)
|
dedupeKey := constants.RedisPollingManualDedupeKey(taskType)
|
||||||
added, err := s.redis.SAdd(ctx, dedupeKey, cardID).Result()
|
added, err := s.redis.SAdd(ctx, dedupeKey, cardID).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Redis去重操作失败",
|
||||||
|
zap.Uint("card_id", cardID),
|
||||||
|
zap.String("task_type", taskType),
|
||||||
|
zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if added == 0 {
|
if added == 0 {
|
||||||
return errors.New(errors.CodeInvalidParam, "该卡已在手动触发队列中")
|
return errors.New(errors.CodeInvalidParam, "该卡已在手动触发队列中")
|
||||||
}
|
}
|
||||||
// 设置去重 key 过期时间(1小时)
|
// 设置去重 key 过期时间(24小时,与日限制周期对齐)
|
||||||
s.redis.Expire(ctx, dedupeKey, time.Hour)
|
s.redis.Expire(ctx, dedupeKey, 24*time.Hour)
|
||||||
|
|
||||||
// 创建触发日志
|
// 创建触发日志
|
||||||
cardIDsJSON, _ := json.Marshal([]uint{cardID})
|
cardIDsJSON, _ := json.Marshal([]uint{cardID})
|
||||||
@@ -83,12 +91,20 @@ func (s *ManualTriggerService) TriggerSingle(ctx context.Context, cardID uint, t
|
|||||||
TriggeredAt: time.Now(),
|
TriggeredAt: time.Now(),
|
||||||
}
|
}
|
||||||
if err := s.logStore.Create(ctx, triggerLog); err != nil {
|
if err := s.logStore.Create(ctx, triggerLog); err != nil {
|
||||||
|
s.logger.Error("创建触发日志失败",
|
||||||
|
zap.Uint("card_id", cardID),
|
||||||
|
zap.Uint("triggered_by", triggeredBy),
|
||||||
|
zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加入手动触发队列(使用 List,优先级高于定时轮询)
|
// 加入手动触发队列(使用 List,优先级高于定时轮询)
|
||||||
queueKey := constants.RedisPollingManualQueueKey(taskType)
|
queueKey := constants.RedisPollingManualQueueKey(taskType)
|
||||||
if err := s.redis.LPush(ctx, queueKey, cardID).Err(); err != nil {
|
if err := s.redis.LPush(ctx, queueKey, cardID).Err(); err != nil {
|
||||||
|
s.logger.Error("写入手动触发队列失败",
|
||||||
|
zap.Uint("card_id", cardID),
|
||||||
|
zap.String("task_type", taskType),
|
||||||
|
zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +142,7 @@ func (s *ManualTriggerService) TriggerBatch(ctx context.Context, cardIDs []uint,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if todayCount >= 100 {
|
if todayCount >= 500 { // 每日最多触发500次
|
||||||
return nil, errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
|
return nil, errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,8 +204,8 @@ func (s *ManualTriggerService) processBatchTrigger(ctx context.Context, logID ui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置去重 key 过期时间
|
// 设置去重 key 过期时间(24小时,与日限制周期对齐)
|
||||||
s.redis.Expire(ctx, dedupeKey, time.Hour)
|
s.redis.Expire(ctx, dedupeKey, 24*time.Hour)
|
||||||
|
|
||||||
// 更新最终状态
|
// 更新最终状态
|
||||||
_ = s.logStore.UpdateProgress(ctx, logID, processedCount, successCount, failedCount)
|
_ = s.logStore.UpdateProgress(ctx, logID, processedCount, successCount, failedCount)
|
||||||
@@ -235,7 +251,7 @@ func (s *ManualTriggerService) TriggerByCondition(ctx context.Context, filter *C
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if todayCount >= 100 {
|
if todayCount >= 500 { // 每日最多触发500次
|
||||||
return nil, errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
|
return nil, errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,18 +373,26 @@ func isValidTaskType(taskType string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkUserTypePermission 检查用户类型是否有手动触发权限
|
||||||
|
// 返回 skip=true 表示超级管理员/平台用户直接放行
|
||||||
|
// 返回 err!=nil 表示企业账号无权限
|
||||||
|
// 返回 skip=false, err=nil 表示代理账号需继续细粒度检查
|
||||||
|
func (s *ManualTriggerService) checkUserTypePermission(ctx context.Context) (skip bool, err error) {
|
||||||
|
userType := middleware.GetUserTypeFromContext(ctx)
|
||||||
|
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if userType == constants.UserTypeEnterprise {
|
||||||
|
return false, errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// canManageCard 检查用户是否有权管理单张卡
|
// canManageCard 检查用户是否有权管理单张卡
|
||||||
func (s *ManualTriggerService) canManageCard(ctx context.Context, cardID uint) error {
|
func (s *ManualTriggerService) canManageCard(ctx context.Context, cardID uint) error {
|
||||||
userType := middleware.GetUserTypeFromContext(ctx)
|
skip, err := s.checkUserTypePermission(ctx)
|
||||||
|
if err != nil || skip {
|
||||||
// 超级管理员和平台用户跳过权限检查
|
return err
|
||||||
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 企业账号禁止手动触发
|
|
||||||
if userType == constants.UserTypeEnterprise {
|
|
||||||
return errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 代理账号只能管理自己店铺及下级店铺的卡
|
// 代理账号只能管理自己店铺及下级店铺的卡
|
||||||
@@ -388,16 +412,9 @@ func (s *ManualTriggerService) canManageCard(ctx context.Context, cardID uint) e
|
|||||||
|
|
||||||
// canManageCards 检查用户是否有权管理多张卡
|
// canManageCards 检查用户是否有权管理多张卡
|
||||||
func (s *ManualTriggerService) canManageCards(ctx context.Context, cardIDs []uint) error {
|
func (s *ManualTriggerService) canManageCards(ctx context.Context, cardIDs []uint) error {
|
||||||
userType := middleware.GetUserTypeFromContext(ctx)
|
skip, err := s.checkUserTypePermission(ctx)
|
||||||
|
if err != nil || skip {
|
||||||
// 超级管理员和平台用户跳过权限检查
|
return err
|
||||||
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 企业账号禁止手动触发
|
|
||||||
if userType == constants.UserTypeEnterprise {
|
|
||||||
return errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 Context 获取预计算的下级店铺 ID 列表
|
// 从 Context 获取预计算的下级店铺 ID 列表
|
||||||
@@ -434,16 +451,9 @@ func (s *ManualTriggerService) canManageCards(ctx context.Context, cardIDs []uin
|
|||||||
|
|
||||||
// applyShopPermissionFilter 应用店铺权限过滤(代理只能筛选自己管理的卡)
|
// applyShopPermissionFilter 应用店铺权限过滤(代理只能筛选自己管理的卡)
|
||||||
func (s *ManualTriggerService) applyShopPermissionFilter(ctx context.Context, filter *ConditionFilter) error {
|
func (s *ManualTriggerService) applyShopPermissionFilter(ctx context.Context, filter *ConditionFilter) error {
|
||||||
userType := middleware.GetUserTypeFromContext(ctx)
|
skip, err := s.checkUserTypePermission(ctx)
|
||||||
|
if err != nil || skip {
|
||||||
// 超级管理员和平台用户不需要限制
|
return err
|
||||||
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 企业账号禁止手动触发
|
|
||||||
if userType == constants.UserTypeEnterprise {
|
|
||||||
return errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 代理账号:限制只能查询自己店铺及下级店铺的卡
|
// 代理账号:限制只能查询自己店铺及下级店铺的卡
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ func RedisPollingManualQueueKey(taskType string) string {
|
|||||||
|
|
||||||
// RedisPollingManualDedupeKey 生成手动触发去重的 Redis 键
|
// RedisPollingManualDedupeKey 生成手动触发去重的 Redis 键
|
||||||
// 用途:Set 存储已加入手动触发队列的卡 ID(用于去重)
|
// 用途:Set 存储已加入手动触发队列的卡 ID(用于去重)
|
||||||
// 过期时间:1小时
|
// 过期时间:24小时(与日限制周期对齐)
|
||||||
func RedisPollingManualDedupeKey(taskType string) string {
|
func RedisPollingManualDedupeKey(taskType string) string {
|
||||||
return fmt.Sprintf("polling:manual:dedupe:%s", taskType)
|
return fmt.Sprintf("polling:manual:dedupe:%s", taskType)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user