Files
backend/internal/service/report_service.go
lafay 67a5660952
All checks were successful
Build Backend / build (push) Successful in 3m54s
Build Backend / build-docker (push) Successful in 1m9s
refactor: unify code formatting and improve push/search implementations
- Remove BOM from all Go source files
- Standardize import ordering and whitespace across handlers and services
- Replace PostgreSQL full-text search with ILIKE pattern matching in post and user repositories
- Enhance JPush client with TLS transport, rate limit monitoring, and simplified API
- Refactor PushService to include userID in device management methods
- Add MaxDevicesPerUser limit and extract helper functions for push payload construction
2026-04-28 14:53:04 +08:00

218 lines
6.5 KiB
Go

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
}