fix: 修复手动触发去重TTL和日限制次数,优化权限检查和错误日志

This commit is contained in:
2026-04-13 14:50:14 +08:00
parent 814a2956b3
commit 5196472d7e
2 changed files with 48 additions and 38 deletions

View File

@@ -53,9 +53,13 @@ func (s *ManualTriggerService) TriggerSingle(ctx context.Context, cardID uint, t
// 检查每日触发限制
todayCount, err := s.logStore.CountTodayTriggers(ctx, triggeredBy)
if err != nil {
s.logger.Error("查询今日触发次数失败",
zap.Uint("triggered_by", triggeredBy),
zap.String("task_type", taskType),
zap.Error(err))
return err
}
if todayCount >= 100 { // 每日最多触发100次
if todayCount >= 500 { // 每日最多触发500次
return errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
}
@@ -63,13 +67,17 @@ func (s *ManualTriggerService) TriggerSingle(ctx context.Context, cardID uint, t
dedupeKey := constants.RedisPollingManualDedupeKey(taskType)
added, err := s.redis.SAdd(ctx, dedupeKey, cardID).Result()
if err != nil {
s.logger.Error("Redis去重操作失败",
zap.Uint("card_id", cardID),
zap.String("task_type", taskType),
zap.Error(err))
return err
}
if added == 0 {
return errors.New(errors.CodeInvalidParam, "该卡已在手动触发队列中")
}
// 设置去重 key 过期时间(1小时
s.redis.Expire(ctx, dedupeKey, time.Hour)
// 设置去重 key 过期时间(24小时与日限制周期对齐
s.redis.Expire(ctx, dedupeKey, 24*time.Hour)
// 创建触发日志
cardIDsJSON, _ := json.Marshal([]uint{cardID})
@@ -83,12 +91,20 @@ func (s *ManualTriggerService) TriggerSingle(ctx context.Context, cardID uint, t
TriggeredAt: time.Now(),
}
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
}
// 加入手动触发队列(使用 List优先级高于定时轮询
queueKey := constants.RedisPollingManualQueueKey(taskType)
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
}
@@ -126,7 +142,7 @@ func (s *ManualTriggerService) TriggerBatch(ctx context.Context, cardIDs []uint,
if err != nil {
return nil, err
}
if todayCount >= 100 {
if todayCount >= 500 { // 每日最多触发500次
return nil, errors.New(errors.CodeInvalidParam, "已达到每日触发次数上限")
}
@@ -188,8 +204,8 @@ func (s *ManualTriggerService) processBatchTrigger(ctx context.Context, logID ui
}
}
// 设置去重 key 过期时间
s.redis.Expire(ctx, dedupeKey, time.Hour)
// 设置去重 key 过期时间24小时与日限制周期对齐
s.redis.Expire(ctx, dedupeKey, 24*time.Hour)
// 更新最终状态
_ = s.logStore.UpdateProgress(ctx, logID, processedCount, successCount, failedCount)
@@ -235,7 +251,7 @@ func (s *ManualTriggerService) TriggerByCondition(ctx context.Context, filter *C
if err != nil {
return nil, err
}
if todayCount >= 100 {
if todayCount >= 500 { // 每日最多触发500次
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 检查用户是否有权管理单张卡
func (s *ManualTriggerService) canManageCard(ctx context.Context, cardID uint) error {
userType := middleware.GetUserTypeFromContext(ctx)
// 超级管理员和平台用户跳过权限检查
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
return nil
}
// 企业账号禁止手动触发
if userType == constants.UserTypeEnterprise {
return errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
skip, err := s.checkUserTypePermission(ctx)
if err != nil || skip {
return err
}
// 代理账号只能管理自己店铺及下级店铺的卡
@@ -388,16 +412,9 @@ func (s *ManualTriggerService) canManageCard(ctx context.Context, cardID uint) e
// canManageCards 检查用户是否有权管理多张卡
func (s *ManualTriggerService) canManageCards(ctx context.Context, cardIDs []uint) error {
userType := middleware.GetUserTypeFromContext(ctx)
// 超级管理员和平台用户跳过权限检查
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
return nil
}
// 企业账号禁止手动触发
if userType == constants.UserTypeEnterprise {
return errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
skip, err := s.checkUserTypePermission(ctx)
if err != nil || skip {
return err
}
// 从 Context 获取预计算的下级店铺 ID 列表
@@ -434,16 +451,9 @@ func (s *ManualTriggerService) canManageCards(ctx context.Context, cardIDs []uin
// applyShopPermissionFilter 应用店铺权限过滤(代理只能筛选自己管理的卡)
func (s *ManualTriggerService) applyShopPermissionFilter(ctx context.Context, filter *ConditionFilter) error {
userType := middleware.GetUserTypeFromContext(ctx)
// 超级管理员和平台用户不需要限制
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
return nil
}
// 企业账号禁止手动触发
if userType == constants.UserTypeEnterprise {
return errors.New(errors.CodeForbidden, "企业账号无权限手动触发轮询")
skip, err := s.checkUserTypePermission(ctx)
if err != nil || skip {
return err
}
// 代理账号:限制只能查询自己店铺及下级店铺的卡

View File

@@ -270,7 +270,7 @@ func RedisPollingManualQueueKey(taskType string) string {
// RedisPollingManualDedupeKey 生成手动触发去重的 Redis 键
// 用途Set 存储已加入手动触发队列的卡 ID用于去重
// 过期时间:1小时
// 过期时间:24小时与日限制周期对齐
func RedisPollingManualDedupeKey(taskType string) string {
return fmt.Sprintf("polling:manual:dedupe:%s", taskType)
}