159 lines
5.7 KiB
Go
159 lines
5.7 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"database/sql"
|
||
|
|
"fmt"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// SeedModeration creates reports, moderation_actions, user_strikes, user_suspensions.
|
||
|
|
func SeedModeration(db *sql.DB, cfg Config, users []SeededUser, tracks []SeededTrack) error {
|
||
|
|
fmt.Println("\n═══ MODERATION ═══")
|
||
|
|
|
||
|
|
mods := GetModerators(users)
|
||
|
|
admins := GetAdmins(users)
|
||
|
|
moderators := append(mods, admins...)
|
||
|
|
if len(moderators) == 0 {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── 1. Reports ───────────────────────────────────────────────────────────
|
||
|
|
p := NewProgress("reports", cfg.Reports)
|
||
|
|
reportRows := make([][]interface{}, 0, cfg.Reports)
|
||
|
|
|
||
|
|
reportReasons := []string{
|
||
|
|
"spam", "harassment", "copyright", "inappropriate_content",
|
||
|
|
"misleading", "hate_speech", "violence", "impersonation",
|
||
|
|
}
|
||
|
|
reportStatuses := []string{"pending", "pending", "reviewed", "resolved", "dismissed"}
|
||
|
|
|
||
|
|
type reportInfo struct {
|
||
|
|
id string
|
||
|
|
}
|
||
|
|
reports := make([]reportInfo, 0, cfg.Reports)
|
||
|
|
|
||
|
|
for i := 0; i < cfg.Reports; i++ {
|
||
|
|
id := newUUID()
|
||
|
|
reporter := users[rng.Intn(len(users))]
|
||
|
|
reason := pick(reportReasons)
|
||
|
|
status := pick(reportStatuses)
|
||
|
|
createdAt := RandomTimeAfter(reporter.CreatedAt)
|
||
|
|
|
||
|
|
// Report target: user or track
|
||
|
|
var reportedUserID interface{}
|
||
|
|
var contentType string
|
||
|
|
var contentID interface{}
|
||
|
|
if randChance(60) && len(tracks) > 0 {
|
||
|
|
t := tracks[rng.Intn(len(tracks))]
|
||
|
|
contentType = "track"
|
||
|
|
contentID = t.ID
|
||
|
|
} else {
|
||
|
|
u := users[rng.Intn(len(users))]
|
||
|
|
reportedUserID = u.ID
|
||
|
|
contentType = "user"
|
||
|
|
}
|
||
|
|
|
||
|
|
reports = append(reports, reportInfo{id: id})
|
||
|
|
reportRows = append(reportRows, []interface{}{
|
||
|
|
id, reporter.ID, reportedUserID, contentType, contentID,
|
||
|
|
fmt.Sprintf("Reported for %s", reason),
|
||
|
|
status, nil, nil, // resolved_by, resolved_at
|
||
|
|
createdAt,
|
||
|
|
pick(reportReasons), "normal", "", "", nil, // category, priority, resolution_note, resolution_action, assigned_to
|
||
|
|
createdAt,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := BulkInsert(db, "reports",
|
||
|
|
"id, reporter_id, reported_user_id, content_type, content_id, reason, status, resolved_by, resolved_at, created_at, category, priority, resolution_note, resolution_action, assigned_to, updated_at",
|
||
|
|
reportRows)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("insert reports: %w", err)
|
||
|
|
}
|
||
|
|
p.Update(cfg.Reports)
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
// ── 2. Moderation actions ────────────────────────────────────────────────
|
||
|
|
actionCount := cfg.Reports / 2 // ~50% of reports get an action
|
||
|
|
p = NewProgress("moderation_actions", actionCount)
|
||
|
|
actionRows := make([][]interface{}, 0, actionCount)
|
||
|
|
actionTypes := []string{"warn", "mute", "suspend", "ban", "content_removal", "dismiss"}
|
||
|
|
|
||
|
|
for i := 0; i < actionCount && i < len(reports); i++ {
|
||
|
|
mod := moderators[rng.Intn(len(moderators))]
|
||
|
|
action := pick(actionTypes)
|
||
|
|
targetUser := users[rng.Intn(len(users))]
|
||
|
|
|
||
|
|
actionRows = append(actionRows, []interface{}{
|
||
|
|
newUUID(), mod.ID, targetUser.ID,
|
||
|
|
nil, nil, // target_content_type, target_content_id
|
||
|
|
action, fmt.Sprintf("Action: %s — reviewed by moderator", action),
|
||
|
|
"{}", time.Now(),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
_, _ = BulkInsert(db, "moderation_actions",
|
||
|
|
"id, moderator_id, target_user_id, target_content_type, target_content_id, action, reason, metadata, created_at",
|
||
|
|
actionRows)
|
||
|
|
p.Update(len(actionRows))
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
// ── 3. User strikes ──────────────────────────────────────────────────────
|
||
|
|
strikeCount := cfg.Reports / 5
|
||
|
|
p = NewProgress("user_strikes", strikeCount)
|
||
|
|
strikeRows := make([][]interface{}, 0, strikeCount)
|
||
|
|
strikeReasons := []string{"spam", "harassment", "copyright_violation", "inappropriate_content"}
|
||
|
|
|
||
|
|
for i := 0; i < strikeCount; i++ {
|
||
|
|
targetUser := users[rng.Intn(len(users))]
|
||
|
|
mod := moderators[rng.Intn(len(moderators))]
|
||
|
|
reason := pick(strikeReasons)
|
||
|
|
severity := pick([]string{"warning", "minor", "major", "critical"})
|
||
|
|
expiresAt := time.Now().AddDate(0, 3, 0) // 3 months
|
||
|
|
|
||
|
|
strikeRows = append(strikeRows, []interface{}{
|
||
|
|
newUUID(), targetUser.ID, nil, // report_id
|
||
|
|
reason, severity, mod.ID,
|
||
|
|
true, false, nil, false, nil, nil, nil, // is_active, appealed, appeal_text, appeal_resolved, appeal_result, appeal_resolved_by, appeal_resolved_at
|
||
|
|
expiresAt, time.Now(), time.Now(),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
_, _ = BulkInsert(db, "user_strikes",
|
||
|
|
"id, user_id, report_id, reason, severity, issued_by, is_active, appealed, appeal_text, appeal_resolved, appeal_result, appeal_resolved_by, appeal_resolved_at, expires_at, created_at, updated_at",
|
||
|
|
strikeRows)
|
||
|
|
p.Update(len(strikeRows))
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
// ── 4. User suspensions (very few) ───────────────────────────────────────
|
||
|
|
suspCount := strikeCount / 3
|
||
|
|
if suspCount < 2 {
|
||
|
|
suspCount = 2
|
||
|
|
}
|
||
|
|
p = NewProgress("user_suspensions", suspCount)
|
||
|
|
suspRows := make([][]interface{}, 0, suspCount)
|
||
|
|
|
||
|
|
for i := 0; i < suspCount; i++ {
|
||
|
|
targetUser := users[randInt(len(users)/2, len(users)-1)] // Pick from second half (less important)
|
||
|
|
mod := moderators[rng.Intn(len(moderators))]
|
||
|
|
reason := pick(strikeReasons)
|
||
|
|
suspendedUntil := time.Now().Add(time.Duration(randInt(1, 30)) * 24 * time.Hour)
|
||
|
|
|
||
|
|
suspRows = append(suspRows, []interface{}{
|
||
|
|
newUUID(), targetUser.ID,
|
||
|
|
fmt.Sprintf("Suspended for %s", reason),
|
||
|
|
mod.ID, suspendedUntil,
|
||
|
|
true, nil, nil, // is_active, lifted_by, lifted_at
|
||
|
|
time.Now(),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
_, _ = BulkInsert(db, "user_suspensions",
|
||
|
|
"id, user_id, reason, suspended_by, suspended_until, is_active, lifted_by, lifted_at, created_at",
|
||
|
|
suspRows)
|
||
|
|
p.Update(len(suspRows))
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|