veza/veza-backend-api/cmd/tools/seed/seed_content.go

289 lines
10 KiB
Go
Raw Normal View History

package main
import (
"database/sql"
"fmt"
"time"
)
// SeedContent creates files, user_storage_quotas, courses, lessons, gear_items, groups.
func SeedContent(db *sql.DB, cfg Config, users []SeededUser, tracks []SeededTrack) error {
fmt.Println("\n═══ CONTENT ═══")
artists := GetArtists(users)
// ── 1. Files (simulated entries for tracks and avatars) ──────────────────
p := NewProgress("files", cfg.FileEntries)
fileRows := make([][]interface{}, 0, cfg.FileEntries)
// Audio files for tracks
for i, t := range tracks {
if i >= cfg.FileEntries*2/3 {
break
}
fileSize := int64(t.Duration) * int64(randInt(16000, 32000))
storagePath := fmt.Sprintf("audio/%s.mp3", t.ID)
url := fmt.Sprintf("https://cdn.veza.music/%s", storagePath)
fileRows = append(fileRows, []interface{}{
newUUID(), t.CreatorID,
fmt.Sprintf("%s.mp3", t.ID), fmt.Sprintf("%s.mp3", t.Title),
"audio/mpeg", fileSize, storagePath, "s3",
"veza-audio", url, nil, // thumbnail_url
fmt.Sprintf("%x", rng.Int63()), nil, // file_hash, metadata
true, time.Now(), nil, // is_processed, processed_at, processing_error
true, "clean", time.Now(), // virus_scanned, virus_scan_result, virus_scanned_at
false, // is_public
time.Now(), time.Now(), nil,
})
}
// Avatar files for users
avatarCount := cfg.FileEntries / 3
for i := 0; i < avatarCount && i < len(users); i++ {
u := users[i]
fileSize := int64(randInt(50000, 500000)) // 50KB - 500KB
storagePath := fmt.Sprintf("avatars/%s.jpg", u.ID)
url := fmt.Sprintf("https://cdn.veza.music/%s", storagePath)
fileRows = append(fileRows, []interface{}{
newUUID(), u.ID,
fmt.Sprintf("%s.jpg", u.ID), "avatar.jpg",
"image/jpeg", fileSize, storagePath, "s3",
"veza-avatars", url, nil,
fmt.Sprintf("%x", rng.Int63()), nil,
true, time.Now(), nil,
true, "clean", time.Now(),
true,
u.CreatedAt, u.CreatedAt, nil,
})
}
_, err := BulkInsert(db, "files",
"id, user_id, filename, original_filename, mime_type, file_size, storage_path, storage_provider, bucket_name, url, thumbnail_url, file_hash, metadata, is_processed, processed_at, processing_error, virus_scanned, virus_scan_result, virus_scanned_at, is_public, created_at, updated_at, deleted_at",
fileRows)
if err != nil {
return fmt.Errorf("insert files: %w", err)
}
p.Update(len(fileRows))
p.Done()
// ── 2. User storage quotas ───────────────────────────────────────────────
p = NewProgress("user_storage_quotas", len(artists))
quotaRows := make([][]interface{}, 0, len(artists))
for _, a := range artists {
usedBytes := int64(randInt(100, 5000)) * 1024 * 1024 // 100MB - 5GB
maxBytes := int64(10) * 1024 * 1024 * 1024 // 10GB
quotaRows = append(quotaRows, []interface{}{
newUUID(), a.ID, usedBytes, maxBytes, time.Now(), time.Now(),
})
}
_, _ = BulkInsert(db, "user_storage_quotas",
"id, user_id, used_bytes, max_bytes, created_at, updated_at",
quotaRows)
p.Update(len(quotaRows))
p.Done()
// ── 3. Courses & Lessons ─────────────────────────────────────────────────
p = NewProgress("courses", cfg.Courses)
courseRows := make([][]interface{}, 0, cfg.Courses)
type courseInfo struct {
id string
lessonCount int
}
courses := make([]courseInfo, 0, cfg.Courses)
courseCategories := []string{"production", "mixing", "sound-design", "songwriting", "djing", "mastering"}
levels := []string{"beginner", "intermediate", "advanced"}
lessonTitles := []string{
"Getting Started", "Setting Up Your DAW", "Understanding Audio Basics",
"Your First Beat", "Melody and Harmony", "Sound Design Fundamentals",
"Arrangement Techniques", "Mixing Basics", "EQ and Compression",
"Effects and Processing", "Mastering Your Track", "Final Project",
"Advanced Techniques", "Creative Workflows", "Industry Standards",
}
for i := 0; i < cfg.Courses && i < len(artists); i++ {
id := newUUID()
artist := artists[i%len(artists)]
title := fmt.Sprintf("%s Masterclass — %s", GenreForArtist(i)[0].Name, pick([]string{"From Zero to Pro", "Complete Guide", "Deep Dive", "Essentials", "Workshop"}))
slug := fmt.Sprintf("course-%d", i)
category := pick(courseCategories)
level := pick(levels)
price := randInt(0, 9999) // 0 = free
lessonCount := randInt(5, 15)
createdAt := RandomTimeAfter(artist.CreatedAt)
var publishedAt interface{} = createdAt
status := "published"
if randChance(10) {
status = "draft"
publishedAt = nil
}
c := courseInfo{id: id, lessonCount: lessonCount}
courses = append(courses, c)
courseRows = append(courseRows, []interface{}{
id, artist.ID, title, slug,
fmt.Sprintf("Learn %s with %s. Comprehensive course covering everything from basics to advanced techniques.", category, artist.DisplayName),
category, fmt.Sprintf("{music,production,%s}", category),
price, "EUR", "fixed", status, level, "fr",
lessonCount, publishedAt, createdAt, createdAt,
})
}
_, err = BulkInsert(db, "courses",
"id, creator_id, title, slug, description, category, tags, price_cents, currency, pricing_model, status, level, language, lesson_count, published_at, created_at, updated_at",
courseRows)
if err != nil {
return fmt.Errorf("insert courses: %w", err)
}
p.Update(len(courseRows))
p.Done()
// Lessons
totalLessons := 0
for _, c := range courses {
totalLessons += c.lessonCount
}
p = NewProgress("lessons", totalLessons)
lessonRows := make([][]interface{}, 0, totalLessons)
for _, c := range courses {
for li := 0; li < c.lessonCount; li++ {
title := lessonTitles[li%len(lessonTitles)]
lessonRows = append(lessonRows, []interface{}{
newUUID(), c.id, li, title,
fmt.Sprintf("Lesson %d: %s", li+1, title),
randInt(300, 1800), // duration 5-30min
li < 2, // first 2 lessons free preview
"completed",
})
}
}
_, _ = BulkInsert(db, "lessons",
"id, course_id, order_index, title, description, duration_seconds, is_preview_free, transcoding_status",
lessonRows)
p.Update(totalLessons)
p.Done()
// Course enrollments
enrollCount := cfg.Courses * 5
p = NewProgress("course_enrollments", enrollCount)
enrollRows := make([][]interface{}, 0, enrollCount)
enrollSeen := make(map[string]bool)
for i := 0; i < enrollCount*2 && len(enrollRows) < enrollCount; i++ {
c := courses[rng.Intn(len(courses))]
u := users[rng.Intn(len(users))]
key := c.id + ":" + u.ID
if enrollSeen[key] {
continue
}
enrollSeen[key] = true
enrollRows = append(enrollRows, []interface{}{
newUUID(), u.ID, c.id, "active", time.Now(),
})
}
_, _ = BulkInsert(db, "course_enrollments",
"id, user_id, course_id, status, purchased_at",
enrollRows)
p.Update(len(enrollRows))
p.Done()
// ── 4. Gear items ────────────────────────────────────────────────────────
p = NewProgress("gear_items", cfg.GearItems)
gearRows := make([][]interface{}, 0, cfg.GearItems)
conditions := []string{"Excellent", "Good", "Fair"}
for i := 0; i < cfg.GearItems; i++ {
artist := artists[rng.Intn(len(artists))]
gear := pick(gearTemplates)
purchaseDate := RandomTimeAfter(artist.CreatedAt).Format("2006-01-02")
gearRows = append(gearRows, []interface{}{
newUUID(), artist.ID, gear.Name, gear.Category, gear.Brand, gear.Model,
"Active", pick(conditions), gear.Price, "EUR", purchaseDate,
true, time.Now(), time.Now(),
})
}
_, _ = BulkInsert(db, "gear_items",
"id, user_id, name, category, brand, model, status, condition, purchase_price, currency, purchase_date, is_public, created_at, updated_at",
gearRows)
p.Update(cfg.GearItems)
p.Done()
// ── 5. Groups ────────────────────────────────────────────────────────────
p = NewProgress("groups", cfg.Groups)
groupRows := make([][]interface{}, 0, cfg.Groups)
type groupInfo struct {
id string
creatorID string
}
groups := make([]groupInfo, 0, cfg.Groups)
groupNames := []string{
"Electronic Producers", "Hip-Hop Collective", "Ambient Sound Lab",
"Jazz Fusion Circle", "Indie Artists Network", "Vinyl Enthusiasts",
"Sound Design Guild", "Remix Community", "Songwriters Hub",
"Studio Gear Talk", "Music Theory Nerds", "Live Performance Group",
"Lo-Fi Producers", "Techno Underground", "Acoustic Sessions",
}
for i := 0; i < cfg.Groups; i++ {
id := newUUID()
creator := users[rng.Intn(len(users))]
name := groupNames[i%len(groupNames)]
if i >= len(groupNames) {
name = fmt.Sprintf("%s #%d", pick(groupNames), i)
}
createdAt := RandomTimeAfter(creator.CreatedAt)
g := groupInfo{id: id, creatorID: creator.ID}
groups = append(groups, g)
groupRows = append(groupRows, []interface{}{
id, name, fmt.Sprintf("A community for %s enthusiasts", name),
creator.ID, nil, true, 1, createdAt, createdAt, nil,
})
}
_, _ = BulkInsert(db, "groups",
"id, name, description, creator_id, avatar_url, is_public, member_count, created_at, updated_at, deleted_at",
groupRows)
p.Update(cfg.Groups)
p.Done()
// Group members
memberCount := cfg.Groups * 15
p = NewProgress("group_members", memberCount)
gmRows := make([][]interface{}, 0, memberCount)
gmSeen := make(map[string]bool)
for _, g := range groups {
// Add creator
key := g.id + ":" + g.creatorID
gmSeen[key] = true
gmRows = append(gmRows, []interface{}{
newUUID(), g.id, g.creatorID, "admin", time.Now(), time.Now(),
})
// Add random members
count := randInt(5, 30)
for j := 0; j < count; j++ {
u := users[rng.Intn(len(users))]
key = g.id + ":" + u.ID
if gmSeen[key] {
continue
}
gmSeen[key] = true
gmRows = append(gmRows, []interface{}{
newUUID(), g.id, u.ID, "member", time.Now(), time.Now(),
})
}
}
_, _ = BulkInsert(db, "group_members",
"id, group_id, user_id, role, joined_at, created_at",
gmRows)
// Update member counts
_, _ = db.Exec("UPDATE groups SET member_count = (SELECT COUNT(*) FROM group_members WHERE group_members.group_id = groups.id)")
p.Update(len(gmRows))
p.Done()
return nil
}