112 lines
3 KiB
Go
112 lines
3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"go.uber.org/zap"
|
|
"gorm.io/gorm"
|
|
|
|
"veza-backend-api/internal/models"
|
|
)
|
|
|
|
// ReportService handles moderation reports (v0.803 ADM1)
|
|
type ReportService struct {
|
|
db *gorm.DB
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewReportService creates a new ReportService
|
|
func NewReportService(db *gorm.DB, logger *zap.Logger) *ReportService {
|
|
return &ReportService{db: db, logger: logger}
|
|
}
|
|
|
|
// CreateReportRequest is the request for creating a report
|
|
type CreateReportRequest struct {
|
|
ContentType string `json:"content_type" binding:"required"`
|
|
ContentID *uuid.UUID `json:"content_id"`
|
|
Reason string `json:"reason" binding:"required"`
|
|
ReportedUserID *uuid.UUID `json:"reported_user_id"`
|
|
}
|
|
|
|
// ResolveReportRequest is the request for resolving a report
|
|
type ResolveReportRequest struct {
|
|
Action string `json:"action" binding:"required"` // dismiss, warn, ban
|
|
Note string `json:"note"`
|
|
}
|
|
|
|
// ListReportsParams are the params for listing reports
|
|
type ListReportsParams struct {
|
|
Status string
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// List returns paginated reports
|
|
func (s *ReportService) List(ctx context.Context, params ListReportsParams) ([]models.Report, int64, error) {
|
|
var reports []models.Report
|
|
query := s.db.WithContext(ctx).Model(&models.Report{})
|
|
|
|
if params.Status != "" && params.Status != "all" {
|
|
query = query.Where("status = ?", params.Status)
|
|
}
|
|
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("failed to count reports: %w", err)
|
|
}
|
|
|
|
limit := params.Limit
|
|
if limit <= 0 {
|
|
limit = 20
|
|
}
|
|
if limit > 100 {
|
|
limit = 100
|
|
}
|
|
|
|
if err := query.Order("created_at DESC").Offset(params.Offset).Limit(limit).Find(&reports).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("failed to list reports: %w", err)
|
|
}
|
|
|
|
return reports, total, nil
|
|
}
|
|
|
|
// Create creates a new report
|
|
func (s *ReportService) Create(ctx context.Context, reporterID uuid.UUID, req CreateReportRequest) (*models.Report, error) {
|
|
report := &models.Report{
|
|
ReporterID: reporterID,
|
|
ReportedUserID: req.ReportedUserID,
|
|
ContentType: req.ContentType,
|
|
ContentID: req.ContentID,
|
|
Reason: req.Reason,
|
|
Status: "pending",
|
|
}
|
|
if err := s.db.WithContext(ctx).Create(report).Error; err != nil {
|
|
return nil, fmt.Errorf("failed to create report: %w", err)
|
|
}
|
|
return report, nil
|
|
}
|
|
|
|
// Resolve resolves a report (dismiss, warn, ban)
|
|
func (s *ReportService) Resolve(ctx context.Context, reportID uuid.UUID, resolvedBy uuid.UUID, action string) error {
|
|
now := time.Now()
|
|
status := "resolved"
|
|
if action == "dismiss" || action == "dismissed" {
|
|
status = "dismissed"
|
|
}
|
|
updates := map[string]interface{}{
|
|
"status": status,
|
|
"resolved_by": resolvedBy,
|
|
"resolved_at": now,
|
|
}
|
|
result := s.db.WithContext(ctx).Model(&models.Report{}).Where("id = ?", reportID).Updates(updates)
|
|
if result.Error != nil {
|
|
return fmt.Errorf("failed to resolve report: %w", result.Error)
|
|
}
|
|
if result.RowsAffected == 0 {
|
|
return fmt.Errorf("report not found")
|
|
}
|
|
return nil
|
|
}
|