This commit is contained in:
2026-09-15 16:02:45 +08:00
parent 112c5f8e46
commit ade2453083
70 changed files with 1441 additions and 707 deletions
+24 -10
View File
@@ -2,6 +2,7 @@ package service
import (
"context"
"log/slog"
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/global"
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto"
@@ -100,6 +101,11 @@ func (s *CollectService) List(ctx context.Context, userID int64, request *dto.Co
// 穿搭可能已删除,跳过。
continue
}
// 越权防护(纵深防御):DAO 已按可见性联表过滤,此处再挡一次查询与读取之间
// 发生的「转私密 / 被封禁 / 审核驳回」变更,避免下发他人非公开穿搭内容。
if outfit.UserID != userID && !isOutfitPublicVisible(outfit) {
continue
}
outfitItems, uerr := s.itemResponses(ctx, outfit.ID)
if uerr != nil {
continue
@@ -133,19 +139,27 @@ func (s *CollectService) GetByTarget(ctx context.Context, userID int64, request
}
targetID := outfit.ID
// 是否已收藏:Redis 优先,回落 MySQL。
isCollected, err := redisdao.CollectIsMember(ctx, CollectTypeOutfit, targetID, userID)
if err != nil {
if rec, derr := s.collectDao.CollectGetByTargetAndUser(ctx, CollectTypeOutfit, targetID, userID); derr == nil {
isCollected = rec.Status == InteractStatusOn
// 是否已收藏:以 MySQL 为权威。
// Redis 集合带 TTL,过期后会被后续写入重建为「仅含新成员」,导致 SIsMember/SCard 长期低估,
// 因此只在 DB 异常时用 Redis 兜底(降级可用性优先于精确性)。
isCollected := false
if rec, derr := s.collectDao.CollectGetByTargetAndUser(ctx, CollectTypeOutfit, targetID, userID); derr == nil {
isCollected = rec.Status == InteractStatusOn
} else if !isNotFound(derr) {
slog.WarnContext(ctx, "query collect record failed, fallback to redis",
"target_id", targetID, "user_id", userID, "error", derr)
if v, rerr := redisdao.CollectIsMember(ctx, CollectTypeOutfit, targetID, userID); rerr == nil {
isCollected = v
}
}
// 收藏总数:Redis 优先,回落 MySQL。
count, err := redisdao.CollectCount(ctx, CollectTypeOutfit, targetID)
if err != nil || count == 0 {
if dbCnt, derr := s.collectDao.CollectCountByTarget(ctx, CollectTypeOutfit, targetID); derr == nil {
count = dbCnt
// 收藏总数:以 MySQL 为权威(同上,Redis 仅在 DB 异常时兜底)。
count, derr := s.collectDao.CollectCountByTarget(ctx, CollectTypeOutfit, targetID)
if derr != nil {
slog.WarnContext(ctx, "count collect failed, fallback to redis",
"target_id", targetID, "error", derr)
if rcnt, rerr := redisdao.CollectCount(ctx, CollectTypeOutfit, targetID); rerr == nil {
count = rcnt
}
}