backend-ci.yml's `test -z "$(gofmt -l .)"` strict gate (added in
13c21ac11) failed on a backlog of unformatted files. None of the
85 files in this commit had been edited since the gate was added
because no push touched veza-backend-api/** in between, so the
gate never fired until today's CI fixes triggered it.
The diff is exclusively whitespace alignment in struct literals
and trailing-space comments. `go build ./...` and the full test
suite (with VEZA_SKIP_INTEGRATION=1 -short) pass identically.
288 lines
10 KiB
Go
288 lines
10 KiB
Go
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
|
|
}
|