package service import ( "context" "errors" "fmt" "with_you/internal/config" "with_you/internal/model" "with_you/internal/repository" "go.uber.org/zap" ) // ReportService 举报服务接口(用户端) type ReportService interface { // CreateReport 创建举报 CreateReport(ctx context.Context, reporterID, targetType, targetID, reason, description string) (*model.Report, error) // HasUserReported 检查用户是否已举报 HasUserReported(ctx context.Context, reporterID, targetType, targetID string) (bool, error) } // reportServiceImpl 举报服务实现 type reportServiceImpl struct { reportRepo repository.ReportRepository postRepo repository.PostRepository commentRepo repository.CommentRepository messageRepo repository.MessageRepository userRepo repository.UserRepository notifyRepo repository.SystemNotificationRepository pushService PushService txManager repository.TransactionManager logService OperationLogService config *config.ReportConfig } // NewReportService 创建举报服务 func NewReportService( reportRepo repository.ReportRepository, postRepo repository.PostRepository, commentRepo repository.CommentRepository, messageRepo repository.MessageRepository, userRepo repository.UserRepository, notifyRepo repository.SystemNotificationRepository, pushService PushService, txManager repository.TransactionManager, logService OperationLogService, cfg *config.Config, ) ReportService { reportConfig := &cfg.Report if reportConfig.AutoHideThreshold == 0 { reportConfig.AutoHideThreshold = 3 } return &reportServiceImpl{ reportRepo: reportRepo, postRepo: postRepo, commentRepo: commentRepo, messageRepo: messageRepo, userRepo: userRepo, notifyRepo: notifyRepo, pushService: pushService, txManager: txManager, logService: logService, config: reportConfig, } } // CreateReport 创建举报 func (s *reportServiceImpl) CreateReport(ctx context.Context, reporterID, targetType, targetID, reason, description string) (*model.Report, error) { // 验证举报类型 reportTargetType := model.ReportTargetType(targetType) if reportTargetType != model.ReportTargetTypePost && reportTargetType != model.ReportTargetTypeComment && reportTargetType != model.ReportTargetTypeMessage { return nil, errors.New("invalid target type") } // 验证举报原因 reportReason := model.ReportReason(reason) if reportReason != model.ReportReasonSpam && reportReason != model.ReportReasonInappropriate && reportReason != model.ReportReasonHarassment && reportReason != model.ReportReasonMisinformation && reportReason != model.ReportReasonOther { return nil, errors.New("invalid reason") } // 检查目标内容是否存在 if err := s.validateTargetExists(ctx, reportTargetType, targetID); err != nil { return nil, err } // 检查用户是否已举报过 hasReported, err := s.reportRepo.HasUserReported(reporterID, reportTargetType, targetID) if err != nil { zap.L().Error("failed to check if user has reported", zap.Error(err)) return nil, errors.New("failed to check report status") } if hasReported { return nil, errors.New("you have already reported this content") } // 创建举报 report := &model.Report{ ReporterID: reporterID, TargetType: reportTargetType, TargetID: targetID, Reason: reportReason, Description: description, Status: model.ReportStatusPending, } // 使用事务处理 var createdReport *model.Report err = s.txManager.RunInTransaction(ctx, func(ctx context.Context) error { // 创建举报记录 if err := s.reportRepo.CreateWithContext(ctx, report); err != nil { return fmt.Errorf("failed to create report: %w", err) } createdReport = report // 检查举报次数是否达到阈值 count, err := s.reportRepo.GetReportCount(reportTargetType, targetID) if err != nil { zap.L().Error("failed to get report count", zap.Error(err)) return nil // 不阻止举报创建 } // 达到阈值,自动隐藏内容 if int(count) >= s.config.AutoHideThreshold { if err := s.hideTargetContent(ctx, reportTargetType, targetID); err != nil { zap.L().Error("failed to hide target content", zap.Error(err)) return nil // 不阻止举报创建 } zap.L().Info("content auto-hidden due to report threshold", zap.String("target_type", targetType), zap.String("target_id", targetID), zap.Int64("report_count", count), ) } return nil }) if err != nil { return nil, err } // 记录操作日志 if s.logService != nil { s.logService.RecordOperation(&model.OperationLog{ UserID: reporterID, Operation: "create_report", TargetType: "report", TargetID: report.ID, Module: "report", }) } return createdReport, nil } // HasUserReported 检查用户是否已举报 func (s *reportServiceImpl) HasUserReported(ctx context.Context, reporterID, targetType, targetID string) (bool, error) { return s.reportRepo.HasUserReported(reporterID, model.ReportTargetType(targetType), targetID) } // validateTargetExists 验证目标内容是否存在 func (s *reportServiceImpl) validateTargetExists(ctx context.Context, targetType model.ReportTargetType, targetID string) error { switch targetType { case model.ReportTargetTypePost: post, err := s.postRepo.GetByID(targetID) if err != nil || post == nil { return errors.New("post not found") } case model.ReportTargetTypeComment: comment, err := s.commentRepo.GetByID(targetID) if err != nil || comment == nil { return errors.New("comment not found") } case model.ReportTargetTypeMessage: _, err := s.messageRepo.GetMessageByID(targetID) if err != nil { return errors.New("message not found") } } return nil } // hideTargetContent 隐藏目标内容 func (s *reportServiceImpl) hideTargetContent(ctx context.Context, targetType model.ReportTargetType, targetID string) error { switch targetType { case model.ReportTargetTypePost: post, err := s.postRepo.GetByID(targetID) if err != nil { return err } if post != nil && post.Status != model.PostStatusDeleted { post.Status = model.PostStatusDeleted return s.postRepo.Update(post) } case model.ReportTargetTypeComment: comment, err := s.commentRepo.GetByID(targetID) if err != nil { return err } if comment != nil && comment.Status != model.CommentStatusDeleted { comment.Status = model.CommentStatusDeleted return s.commentRepo.Update(comment) } case model.ReportTargetTypeMessage: // 消息隐藏通过更新状态实现 return s.messageRepo.UpdateMessageStatus(targetID, model.MessageStatusDeleted) } return nil }