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 }