Extract monolithic seed main.go into separate files per domain: users, tracks, playlists, chat, analytics, marketplace, social, content, live, moderation, notifications, and misc. Add config, fake data helpers, and utility modules. Update Makefile targets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
195 lines
8 KiB
Go
195 lines
8 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// SeedMisc creates support_tickets, api_keys, announcements, data_exports,
|
|
// login_history, audit_logs, and user_preferences.
|
|
func SeedMisc(db *sql.DB, cfg Config, users []SeededUser) error {
|
|
fmt.Println("\n═══ MISC ═══")
|
|
|
|
artists := GetArtists(users)
|
|
admins := GetAdmins(users)
|
|
|
|
// ── 1. Support tickets ───────────────────────────────────────────────────
|
|
p := NewProgress("support_tickets", cfg.SupportTickets)
|
|
ticketRows := make([][]interface{}, 0, cfg.SupportTickets)
|
|
ticketCategories := []string{"technical", "billing", "general", "feature", "account"}
|
|
ticketStatuses := []string{"open", "open", "in_progress", "resolved", "closed"}
|
|
ticketSubjects := []string{
|
|
"Cannot upload audio file", "Payment not received", "Account access issue",
|
|
"Feature request: dark mode", "Playlist sync problem", "Mobile app crash",
|
|
"Stream quality issues", "Profile picture upload failed", "How to sell beats?",
|
|
"Collaboration feature not working", "Missing analytics data", "Copyright claim dispute",
|
|
"Email notifications not arriving", "Two-factor auth setup", "Delete my account",
|
|
}
|
|
|
|
for i := 0; i < cfg.SupportTickets; i++ {
|
|
user := users[rng.Intn(len(users))]
|
|
subject := pick(ticketSubjects)
|
|
ticketRows = append(ticketRows, []interface{}{
|
|
newUUID(), user.ID, user.Email,
|
|
subject, fmt.Sprintf("Details about: %s. Please help!", subject),
|
|
pick(ticketCategories), pick(ticketStatuses),
|
|
RandomTimeAfter(user.CreatedAt),
|
|
})
|
|
}
|
|
_, _ = BulkInsert(db, "support_tickets",
|
|
"id, user_id, email, subject, message, category, status, created_at",
|
|
ticketRows)
|
|
p.Update(cfg.SupportTickets)
|
|
p.Done()
|
|
|
|
// ── 2. API keys ──────────────────────────────────────────────────────────
|
|
p = NewProgress("api_keys", cfg.APIKeys)
|
|
apiRows := make([][]interface{}, 0, cfg.APIKeys)
|
|
apiNames := []string{
|
|
"Production Bot", "Beat Distributor", "Analytics Dashboard",
|
|
"Auto-Upload Script", "Playlist Sync", "Stream Monitor",
|
|
}
|
|
|
|
for i := 0; i < cfg.APIKeys && i < len(artists); i++ {
|
|
artist := artists[i%len(artists)]
|
|
prefix := fmt.Sprintf("veza_%s", newUUID()[:8])
|
|
hashedKey := fmt.Sprintf("$2a$10$%s", newUUID()) // Placeholder hash
|
|
name := apiNames[i%len(apiNames)]
|
|
scopes := pick([]string{"{read,write,tracks}", "{read,tracks,marketplace}", "{read}", "{read,write}"})
|
|
|
|
apiRows = append(apiRows, []interface{}{
|
|
newUUID(), artist.ID, name, prefix, hashedKey, scopes, time.Now(),
|
|
})
|
|
}
|
|
_, _ = BulkInsert(db, "api_keys",
|
|
"id, user_id, name, prefix, hashed_key, scopes, created_at",
|
|
apiRows)
|
|
p.Update(len(apiRows))
|
|
p.Done()
|
|
|
|
// ── 3. Announcements ─────────────────────────────────────────────────────
|
|
p = NewProgress("announcements", cfg.Announcements)
|
|
annRows := make([][]interface{}, 0, cfg.Announcements)
|
|
annData := []struct{ title, content, atype string }{
|
|
{"Welcome to Veza!", "We're thrilled to launch Veza — an ethical music platform built for artists and listeners.", "info"},
|
|
{"Marketplace Now Open", "Buy and sell beats, samples, and presets directly on the platform.", "feature"},
|
|
{"New: Live Streaming", "Stream your sessions live to your followers. Available now for all creators.", "feature"},
|
|
{"Scheduled Maintenance", "Brief maintenance window planned for this weekend. Streams may be briefly interrupted.", "warning"},
|
|
{"Community Guidelines Updated", "We've updated our community guidelines. Please review them.", "info"},
|
|
{"Mobile App Beta", "The mobile app is now in beta. Sign up to be a tester!", "feature"},
|
|
{"Holiday Sale", "Special discounts on marketplace products this week.", "info"},
|
|
{"New Audio Quality Options", "Hi-Res audio streaming is now available for premium users.", "feature"},
|
|
{"Creator Fund Launched", "Earn more from your music with our new creator support fund.", "info"},
|
|
{"Platform Update v2.0", "Major platform update with improved UI, faster streaming, and new features.", "feature"},
|
|
}
|
|
|
|
adminID := ""
|
|
if len(admins) > 0 {
|
|
adminID = admins[0].ID
|
|
} else {
|
|
adminID = users[0].ID
|
|
}
|
|
|
|
for i := 0; i < cfg.Announcements && i < len(annData); i++ {
|
|
a := annData[i]
|
|
annRows = append(annRows, []interface{}{
|
|
newUUID(), a.title, a.content, a.atype,
|
|
true, time.Now(), adminID, DaysAgo(cfg.Announcements - i),
|
|
})
|
|
}
|
|
_, _ = BulkInsert(db, "announcements",
|
|
"id, title, content, type, is_active, starts_at, created_by, created_at",
|
|
annRows)
|
|
p.Update(len(annRows))
|
|
p.Done()
|
|
|
|
// ── 4. Data exports (RGPD) ───────────────────────────────────────────────
|
|
p = NewProgress("data_exports", cfg.DataExports)
|
|
exportRows := make([][]interface{}, 0, cfg.DataExports)
|
|
exportStatuses := []string{"completed", "completed", "pending", "processing"}
|
|
|
|
for i := 0; i < cfg.DataExports; i++ {
|
|
user := users[rng.Intn(len(users))]
|
|
status := pick(exportStatuses)
|
|
createdAt := RandomTimeAfter(user.CreatedAt)
|
|
expiresAt := createdAt.Add(7 * 24 * time.Hour) // 7 day expiry
|
|
|
|
var completedAt interface{}
|
|
var s3Key interface{}
|
|
var fileSize interface{}
|
|
if status == "completed" {
|
|
completedAt = RandomTimeAfter(createdAt)
|
|
s3Key = fmt.Sprintf("exports/%s/%s.zip", user.ID, newUUID()[:8])
|
|
fs := int64(randInt(1000000, 50000000)) // 1MB - 50MB
|
|
fileSize = fs
|
|
}
|
|
|
|
exportRows = append(exportRows, []interface{}{
|
|
newUUID(), user.ID, status, s3Key, fileSize,
|
|
expiresAt, createdAt, completedAt, nil,
|
|
})
|
|
}
|
|
_, _ = BulkInsert(db, "data_exports",
|
|
"id, user_id, status, s3_key, file_size_bytes, expires_at, created_at, completed_at, error_message",
|
|
exportRows)
|
|
p.Update(cfg.DataExports)
|
|
p.Done()
|
|
|
|
// ── 5. Login history ─────────────────────────────────────────────────────
|
|
loginCount := len(users) * 3 // ~3 login entries per user on average
|
|
p = NewProgress("login_history", loginCount)
|
|
loginRows := make([][]interface{}, 0, loginCount)
|
|
for i := 0; i < loginCount; i++ {
|
|
user := users[rng.Intn(len(users))]
|
|
loginAt := RandomTimeAfter(user.CreatedAt)
|
|
loginAt = RealisticHour(loginAt)
|
|
success := randChance(95) // 95% success rate
|
|
reason := ""
|
|
if !success {
|
|
reason = pick([]string{"invalid_password", "account_locked", "expired_session"})
|
|
}
|
|
|
|
loginRows = append(loginRows, []interface{}{
|
|
newUUID(), user.ID, GenIP(), GenUserAgent(),
|
|
success, reason, loginAt,
|
|
})
|
|
}
|
|
_, _ = BulkInsert(db, "login_history",
|
|
"id, user_id, ip_address, user_agent, success, reason, created_at",
|
|
loginRows)
|
|
p.Update(loginCount)
|
|
p.Done()
|
|
|
|
// ── 6. User preferences ──────────────────────────────────────────────────
|
|
prefCount := len(users) / 3 // ~33% have explicit preferences
|
|
p = NewProgress("user_preferences", prefCount)
|
|
prefRows := make([][]interface{}, 0, prefCount)
|
|
themes := []string{"light", "dark", "auto"}
|
|
langs := []string{"fr", "en", "de", "es"}
|
|
contrasts := []string{"normal", "high"}
|
|
densities := []string{"comfortable", "compact", "spacious"}
|
|
|
|
prefSeen := make(map[string]bool)
|
|
for i := 0; i < prefCount; i++ {
|
|
user := users[rng.Intn(len(users))]
|
|
if prefSeen[user.ID] {
|
|
continue
|
|
}
|
|
prefSeen[user.ID] = true
|
|
prefRows = append(prefRows, []interface{}{
|
|
user.ID, pick(themes), pick(langs), "UTC",
|
|
"{}", "{}", `{"quality":"high","autoplay":true}`,
|
|
pick(contrasts), pick(densities),
|
|
randInt(180, 280), randInt(14, 20),
|
|
time.Now(),
|
|
})
|
|
}
|
|
_, _ = BulkInsert(db, "user_preferences",
|
|
"user_id, theme, language, timezone, notifications, privacy, audio, contrast, density, accent_hue, font_size, updated_at",
|
|
prefRows)
|
|
p.Update(len(prefRows))
|
|
p.Done()
|
|
|
|
return nil
|
|
}
|