188 lines
5.1 KiB
Go
188 lines
5.1 KiB
Go
package migration
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"git.handmade.network/hmn/hmn/src/auth"
|
|
"git.handmade.network/hmn/hmn/src/config"
|
|
"git.handmade.network/hmn/hmn/src/db"
|
|
"git.handmade.network/hmn/hmn/src/models"
|
|
"git.handmade.network/hmn/hmn/src/utils"
|
|
lorem "github.com/HandmadeNetwork/golorem"
|
|
"github.com/jackc/pgx/v4"
|
|
)
|
|
|
|
// Applies a cloned db to the local db.
|
|
// Applies the seed after the migration specified in `afterMigration`.
|
|
// NOTE(asaf): The db role specified in the config must have the CREATEDB attribute! `ALTER ROLE hmn WITH CREATEDB;`
|
|
func SeedFromFile(seedFile string) {
|
|
file, err := os.Open(seedFile)
|
|
if err != nil {
|
|
panic(fmt.Errorf("couldn't open seed file %s: %w", seedFile, err))
|
|
}
|
|
file.Close()
|
|
|
|
fmt.Println("Executing seed...")
|
|
cmd := exec.Command("pg_restore",
|
|
"--single-transaction",
|
|
"--dbname", config.Config.Postgres.DSN(),
|
|
seedFile,
|
|
)
|
|
fmt.Println("Running command:", cmd)
|
|
if output, err := cmd.CombinedOutput(); err != nil {
|
|
fmt.Print(string(output))
|
|
panic(fmt.Errorf("failed to execute seed: %w", err))
|
|
}
|
|
|
|
fmt.Println("Done! You may want to migrate forward from here.")
|
|
ListMigrations()
|
|
}
|
|
|
|
// Creates only what's necessary to get the site running. Not really very useful for
|
|
// local dev on its own; sample data makes things a lot better.
|
|
func BareMinimumSeed() {
|
|
Migrate(LatestVersion())
|
|
|
|
ctx := context.Background()
|
|
conn := db.NewConnWithConfig(config.PostgresConfig{
|
|
LogLevel: pgx.LogLevelWarn,
|
|
})
|
|
defer conn.Close(ctx)
|
|
|
|
tx, err := conn.Begin(ctx)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer tx.Rollback(ctx)
|
|
|
|
fmt.Println("Creating HMN project...")
|
|
_, err = tx.Exec(ctx,
|
|
`
|
|
INSERT INTO project (id, slug, name, blurb, description, personal, lifecycle, color_1, color_2, forum_enabled, blog_enabled, date_created)
|
|
VALUES (1, 'hmn', 'Handmade Network', '', '', FALSE, $1, 'ab4c47', 'a5467d', TRUE, TRUE, '2017-01-01T00:00:00Z')
|
|
`,
|
|
models.ProjectLifecycleActive,
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println("Creating main forum...")
|
|
_, err = tx.Exec(ctx, `
|
|
INSERT INTO subforum (id, slug, name, parent_id, project_id)
|
|
VALUES (2, '', 'Handmade Network', NULL, 1)
|
|
`)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
_, err = tx.Exec(ctx, `
|
|
UPDATE project SET forum_id = 2 WHERE slug = 'hmn'
|
|
`)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = tx.Commit(ctx)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// Seeds the database with sample data for local dev.
|
|
func SampleSeed() {
|
|
BareMinimumSeed()
|
|
|
|
ctx := context.Background()
|
|
conn := db.NewConnWithConfig(config.PostgresConfig{
|
|
LogLevel: pgx.LogLevelWarn,
|
|
})
|
|
defer conn.Close(ctx)
|
|
|
|
tx, err := conn.Begin(ctx)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer tx.Rollback(ctx)
|
|
|
|
fmt.Println("Creating admin user (\"admin\"/\"password\")...")
|
|
seedUser(ctx, conn, models.User{Username: "admin", Email: "admin@handmade.network", IsStaff: true})
|
|
|
|
fmt.Println("Creating normal users (all with password \"password\")...")
|
|
alice := seedUser(ctx, conn, models.User{Username: "alice", Name: "Alice"})
|
|
bob := seedUser(ctx, conn, models.User{Username: "bob", Name: "Bob"})
|
|
charlie := seedUser(ctx, conn, models.User{Username: "charlie", Name: "Charlie"})
|
|
|
|
fmt.Println("Creating a spammer...")
|
|
seedUser(ctx, conn, models.User{Username: "spam", Name: "Hot singletons in your local area", Status: models.UserStatusConfirmed})
|
|
|
|
_ = []*models.User{alice, bob, charlie}
|
|
|
|
// admin := CreateAdminUser("admin", "12345678")
|
|
// user := CreateUser("regular_user", "12345678")
|
|
// hmnProject := CreateProject("hmn", "Handmade Network")
|
|
// Create category
|
|
// Create thread
|
|
// Create accepted user project
|
|
// Create pending user project
|
|
// Create showcase items
|
|
// Create codelanguages
|
|
// Create library and library resources
|
|
|
|
err = tx.Commit(ctx)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func seedUser(ctx context.Context, conn db.ConnOrTx, input models.User) *models.User {
|
|
user, err := db.QueryOne[models.User](ctx, conn,
|
|
`
|
|
INSERT INTO hmn_user (
|
|
username, password, email,
|
|
is_staff,
|
|
status,
|
|
name, bio, blurb, signature,
|
|
darktheme,
|
|
showemail, edit_library,
|
|
date_joined, registration_ip, avatar_asset_id
|
|
)
|
|
VALUES (
|
|
$1, $2, $3,
|
|
$4,
|
|
$5,
|
|
$6, $7, $8, $9,
|
|
TRUE,
|
|
$10, FALSE,
|
|
'2017-01-01T00:00:00Z', '192.168.2.1', null
|
|
)
|
|
RETURNING $columns
|
|
`,
|
|
input.Username, "", utils.OrDefault(input.Email, fmt.Sprintf("%s@example.com", input.Username)),
|
|
input.IsStaff,
|
|
utils.OrDefault(input.Status, models.UserStatusApproved),
|
|
utils.OrDefault(input.Name, randomName()), utils.OrDefault(input.Bio, lorem.Paragraph(0, 2)), utils.OrDefault(input.Blurb, lorem.Sentence(0, 14)), utils.OrDefault(input.Signature, lorem.Sentence(0, 16)),
|
|
input.ShowEmail,
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
err = auth.SetPassword(ctx, conn, input.Username, "password")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return user
|
|
}
|
|
|
|
func randomName() string {
|
|
return "John Doe" // chosen by fair dice roll. guaranteed to be random.
|
|
}
|
|
|
|
func randomBool() bool {
|
|
return rand.Intn(2) == 1
|
|
}
|