Files
backend/internal/service/report_service.go
2026-01-21 21:34:11 +08:00

336 lines
9.9 KiB
Go

package service
import (
"context"
"errors"
"strconv"
"time"
apperrors "carrotskin/internal/errors"
"carrotskin/internal/model"
"carrotskin/internal/repository"
"go.uber.org/zap"
)
// reportService ReportService的实现
type reportService struct {
reportRepo repository.ReportRepository
userRepo repository.UserRepository
logger *zap.Logger
}
// NewReportService 创建ReportService实例
func NewReportService(
reportRepo repository.ReportRepository,
userRepo repository.UserRepository,
logger *zap.Logger,
) ReportService {
return &reportService{
reportRepo: reportRepo,
userRepo: userRepo,
logger: logger,
}
}
// CreateReport 创建举报
func (s *reportService) CreateReport(ctx context.Context, reporterID int64, targetType model.ReportType, targetID int64, reason string) (*model.Report, error) {
// 验证举报人存在
reporter, err := s.userRepo.FindByID(ctx, reporterID)
if err != nil {
s.logger.Error("举报人不存在", zap.Int64("reporter_id", reporterID), zap.Error(err))
return nil, apperrors.ErrUserNotFound
}
if reporter == nil {
return nil, apperrors.ErrUserNotFound
}
// 验证举报原因
if reason == "" {
return nil, errors.New("举报原因不能为空")
}
if len(reason) > 500 {
return nil, errors.New("举报原因不能超过500字符")
}
// 验证目标类型
if targetType != model.ReportTypeTexture && targetType != model.ReportTypeUser {
return nil, errors.New("无效的举报类型")
}
// 检查是否重复举报
isDuplicate, err := s.reportRepo.CheckDuplicate(ctx, reporterID, targetType, targetID)
if err != nil {
s.logger.Error("检查重复举报失败", zap.Error(err))
return nil, err
}
if isDuplicate {
return nil, errors.New("您已经举报过该对象,请勿重复举报")
}
// 创建举报记录
report := &model.Report{
ReporterID: reporterID,
TargetType: targetType,
TargetID: targetID,
Reason: reason,
Status: model.ReportStatusPending,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := s.reportRepo.Create(ctx, report); err != nil {
s.logger.Error("创建举报失败", zap.Error(err))
return nil, err
}
s.logger.Info("创建举报成功", zap.Int64("report_id", report.ID), zap.Int64("reporter_id", reporterID))
return report, nil
}
// GetByID 根据ID查询举报
func (s *reportService) GetByID(ctx context.Context, id int64) (*model.Report, error) {
report, err := s.reportRepo.FindByID(ctx, id)
if err != nil {
s.logger.Error("查询举报失败", zap.Int64("report_id", id), zap.Error(err))
return nil, err
}
return report, nil
}
// GetByReporterID 根据举报人ID查询举报记录
func (s *reportService) GetByReporterID(ctx context.Context, reporterID, userID int64, page, pageSize int) ([]*model.Report, int64, error) {
// 验证用户存在
user, err := s.userRepo.FindByID(ctx, userID)
if err != nil {
return nil, 0, err
}
if user == nil {
return nil, 0, apperrors.ErrUserNotFound
}
// 只有本人或管理员可以查看自己的举报记录
if reporterID != userID && !(user.Role == "admin") {
return nil, 0, errors.New("无权查看其他用户的举报记录")
}
reports, total, err := s.reportRepo.FindByReporterID(ctx, reporterID, page, pageSize)
if err != nil {
s.logger.Error("查询举报记录失败", zap.Error(err))
return nil, 0, err
}
return reports, total, nil
}
// GetByTarget 根据目标对象查询举报记录
func (s *reportService) GetByTarget(ctx context.Context, targetType model.ReportType, targetID, userID int64, page, pageSize int) ([]*model.Report, int64, error) {
// 验证用户存在
user, err := s.userRepo.FindByID(ctx, userID)
if err != nil {
return nil, 0, err
}
if user == nil {
return nil, 0, apperrors.ErrUserNotFound
}
// 只有管理员可以查看目标对象的举报记录
if !(user.Role == "admin") {
return nil, 0, errors.New("无权查看举报记录")
}
reports, total, err := s.reportRepo.FindByTarget(ctx, targetType, targetID, page, pageSize)
if err != nil {
s.logger.Error("查询举报记录失败", zap.Error(err))
return nil, 0, err
}
return reports, total, nil
}
// GetByStatus 根据状态查询举报记录
func (s *reportService) GetByStatus(ctx context.Context, status model.ReportStatus, page, pageSize int) ([]*model.Report, int64, error) {
reports, total, err := s.reportRepo.FindByStatus(ctx, status, page, pageSize)
if err != nil {
s.logger.Error("查询举报记录失败", zap.Error(err))
return nil, 0, err
}
return reports, total, nil
}
// Search 搜索举报记录
func (s *reportService) Search(ctx context.Context, keyword, userID int64, page, pageSize int) ([]*model.Report, int64, error) {
// 验证用户存在
user, err := s.userRepo.FindByID(ctx, userID)
if err != nil {
return nil, 0, err
}
if user == nil {
return nil, 0, apperrors.ErrUserNotFound
}
// 只有管理员可以搜索举报记录
if !(user.Role == "admin") {
return nil, 0, errors.New("无权搜索举报记录")
}
reports, total, err := s.reportRepo.Search(ctx, strconv.FormatInt(keyword, 10), page, pageSize)
if err != nil {
s.logger.Error("搜索举报记录失败", zap.Error(err))
return nil, 0, err
}
return reports, total, nil
}
// Review 处理举报记录
func (s *reportService) Review(ctx context.Context, reportID, reviewerID int64, status model.ReportStatus, reviewNote string) (*model.Report, error) {
// 验证处理人存在且是管理员
reviewer, err := s.userRepo.FindByID(ctx, reviewerID)
if err != nil {
s.logger.Error("处理人不存在", zap.Int64("reviewer_id", reviewerID), zap.Error(err))
return nil, apperrors.ErrUserNotFound
}
if reviewer == nil || !(reviewer.Role == "admin") {
return nil, errors.New("只有管理员可以处理举报")
}
// 验证状态
if status != model.ReportStatusApproved && status != model.ReportStatusRejected {
return nil, errors.New("无效的举报处理状态")
}
// 处理举报
if err := s.reportRepo.Review(ctx, reportID, status, reviewerID, reviewNote); err != nil {
s.logger.Error("处理举报失败", zap.Int64("report_id", reportID), zap.Error(err))
return nil, err
}
// 返回更新后的举报记录
report, err := s.reportRepo.FindByID(ctx, reportID)
if err != nil {
s.logger.Error("查询举报记录失败", zap.Int64("report_id", reportID), zap.Error(err))
return nil, err
}
s.logger.Info("处理举报成功", zap.Int64("report_id", reportID), zap.Int64("reviewer_id", reviewerID), zap.String("status", string(status)))
return report, nil
}
// BatchReview 批量处理举报记录
func (s *reportService) BatchReview(ctx context.Context, ids []int64, reviewerID int64, status model.ReportStatus, reviewNote string) (int64, error) {
// 验证处理人存在且是管理员
reviewer, err := s.userRepo.FindByID(ctx, reviewerID)
if err != nil {
s.logger.Error("处理人不存在", zap.Int64("reviewer_id", reviewerID), zap.Error(err))
return 0, apperrors.ErrUserNotFound
}
if reviewer == nil || !(reviewer.Role == "admin") {
return 0, errors.New("只有管理员可以处理举报")
}
// 验证状态
if status != model.ReportStatusApproved && status != model.ReportStatusRejected {
return 0, errors.New("无效的举报处理状态")
}
// 批量处理举报
affected, err := s.reportRepo.BatchReview(ctx, ids, status, reviewerID, reviewNote)
if err != nil {
s.logger.Error("批量处理举报失败", zap.Error(err))
return 0, err
}
s.logger.Info("批量处理举报成功", zap.Int("count", int(affected)), zap.Int64("reviewer_id", reviewerID), zap.String("status", string(status)))
return affected, nil
}
// Delete 删除举报记录
func (s *reportService) Delete(ctx context.Context, reportID, userID int64) error {
// 验证用户存在
user, err := s.userRepo.FindByID(ctx, userID)
if err != nil {
return err
}
if user == nil {
return apperrors.ErrUserNotFound
}
// 查询举报记录
report, err := s.reportRepo.FindByID(ctx, reportID)
if err != nil {
return err
}
if report == nil {
return errors.New("举报记录不存在")
}
// 只有举报人、管理员或处理人可以删除举报记录
if report.ReporterID != userID && !(user.Role == "admin") && (report.ReviewerID == nil || *report.ReviewerID != userID) {
return errors.New("无权删除此举报记录")
}
if err := s.reportRepo.Delete(ctx, reportID); err != nil {
s.logger.Error("删除举报记录失败", zap.Int64("report_id", reportID), zap.Error(err))
return err
}
s.logger.Info("删除举报记录成功", zap.Int64("report_id", reportID))
return nil
}
// BatchDelete 批量删除举报记录
func (s *reportService) BatchDelete(ctx context.Context, ids []int64, userID int64) (int64, error) {
// 验证用户存在
user, err := s.userRepo.FindByID(ctx, userID)
if err != nil {
return 0, err
}
if user == nil {
return 0, apperrors.ErrUserNotFound
}
// 只有管理员可以批量删除
if !(user.Role == "admin") {
return 0, errors.New("无权批量删除举报记录")
}
affected, err := s.reportRepo.BatchDelete(ctx, ids)
if err != nil {
s.logger.Error("批量删除举报记录失败", zap.Error(err))
return 0, err
}
s.logger.Info("批量删除举报记录成功", zap.Int("count", int(affected)))
return affected, nil
}
// GetStats 获取举报统计信息
func (s *reportService) GetStats(ctx context.Context) (map[string]int64, error) {
stats := make(map[string]int64)
// 统计各状态的举报数量
pendingCount, err := s.reportRepo.CountByStatus(ctx, model.ReportStatusPending)
if err != nil {
return nil, err
}
stats["pending"] = pendingCount
approvedCount, err := s.reportRepo.CountByStatus(ctx, model.ReportStatusApproved)
if err != nil {
return nil, err
}
stats["approved"] = approvedCount
rejectedCount, err := s.reportRepo.CountByStatus(ctx, model.ReportStatusRejected)
if err != nil {
return nil, err
}
stats["rejected"] = rejectedCount
stats["total"] = pendingCount + approvedCount + rejectedCount
return stats, nil
}