Seed example forum threads

This commit is contained in:
Ben Visness 2022-05-07 14:31:37 -05:00
parent 3a93aa93e9
commit 3c4238994a
3 changed files with 89 additions and 16 deletions

View File

@ -33,6 +33,7 @@ type ConnOrTx interface {
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error) Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error)
// Both raw database connections and transactions in pgx can begin/commit // Both raw database connections and transactions in pgx can begin/commit
// transactions. For database connections it does the obvious thing; for // transactions. For database connections it does the obvious thing; for

View File

@ -628,7 +628,7 @@ func UserCanEditPost(ctx context.Context, connOrTx db.ConnOrTx, user models.User
func CreateNewPost( func CreateNewPost(
ctx context.Context, ctx context.Context,
tx pgx.Tx, conn db.ConnOrTx,
projectId int, projectId int,
threadId int, threadType models.ThreadType, threadId int, threadType models.ThreadType,
userId int, userId int,
@ -637,7 +637,7 @@ func CreateNewPost(
ipString string, ipString string,
) (postId, versionId int) { ) (postId, versionId int) {
// Create post // Create post
err := tx.QueryRow(ctx, err := conn.QueryRow(ctx,
` `
INSERT INTO post (postdate, thread_id, thread_type, current_id, author_id, project_id, reply_id, preview) INSERT INTO post (postdate, thread_id, thread_type, current_id, author_id, project_id, reply_id, preview)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
@ -657,10 +657,10 @@ func CreateNewPost(
} }
// Create and associate version // Create and associate version
versionId = CreatePostVersion(ctx, tx, postId, unparsedContent, ipString, "", nil) versionId = CreatePostVersion(ctx, conn, postId, unparsedContent, ipString, "", nil)
// Fix up thread // Fix up thread
err = FixThreadPostIds(ctx, tx, threadId) err = FixThreadPostIds(ctx, conn, threadId)
if err != nil { if err != nil {
panic(oops.New(err, "failed to fix up thread post IDs")) panic(oops.New(err, "failed to fix up thread post IDs"))
} }
@ -678,7 +678,7 @@ func CreateNewPost(
} }
updates := strings.Join(updateEntries, ", ") updates := strings.Join(updateEntries, ", ")
_, err = tx.Exec(ctx, _, err = conn.Exec(ctx,
` `
UPDATE project UPDATE project
SET `+updates+` SET `+updates+`
@ -768,7 +768,7 @@ func DeletePost(
const maxPostContentLength = 200000 const maxPostContentLength = 200000
func CreatePostVersion(ctx context.Context, tx pgx.Tx, postId int, unparsedContent string, ipString string, editReason string, editorId *int) (versionId int) { func CreatePostVersion(ctx context.Context, conn db.ConnOrTx, postId int, unparsedContent string, ipString string, editReason string, editorId *int) (versionId int) {
if len(unparsedContent) > maxPostContentLength { if len(unparsedContent) > maxPostContentLength {
logging.ExtractLogger(ctx).Warn(). logging.ExtractLogger(ctx).Warn().
Str("preview", unparsedContent[:400]). Str("preview", unparsedContent[:400]).
@ -787,7 +787,7 @@ func CreatePostVersion(ctx context.Context, tx pgx.Tx, postId int, unparsedConte
} }
// Create post version // Create post version
err := tx.QueryRow(ctx, err := conn.QueryRow(ctx,
` `
INSERT INTO post_version (post_id, text_raw, text_parsed, ip, date, edit_reason, editor_id) INSERT INTO post_version (post_id, text_raw, text_parsed, ip, date, edit_reason, editor_id)
VALUES ($1, $2, $3, $4, $5, $6, $7) VALUES ($1, $2, $3, $4, $5, $6, $7)
@ -806,7 +806,7 @@ func CreatePostVersion(ctx context.Context, tx pgx.Tx, postId int, unparsedConte
} }
// Update post with version id and preview // Update post with version id and preview
_, err = tx.Exec(ctx, _, err = conn.Exec(ctx,
` `
UPDATE post UPDATE post
SET current_id = $1, preview = $2 SET current_id = $1, preview = $2
@ -822,7 +822,7 @@ func CreatePostVersion(ctx context.Context, tx pgx.Tx, postId int, unparsedConte
// Update asset usage // Update asset usage
_, err = tx.Exec(ctx, _, err = conn.Exec(ctx,
` `
DELETE FROM post_asset_usage DELETE FROM post_asset_usage
WHERE post_id = $1 WHERE post_id = $1
@ -839,7 +839,7 @@ func CreatePostVersion(ctx context.Context, tx pgx.Tx, postId int, unparsedConte
keys = append(keys, key) keys = append(keys, key)
} }
assetIDs, err := db.QueryScalar[uuid.UUID](ctx, tx, assetIDs, err := db.QueryScalar[uuid.UUID](ctx, conn,
` `
SELECT id SELECT id
FROM asset FROM asset
@ -857,7 +857,7 @@ func CreatePostVersion(ctx context.Context, tx pgx.Tx, postId int, unparsedConte
values = append(values, []interface{}{postId, assetID}) values = append(values, []interface{}{postId, assetID})
} }
_, err = tx.CopyFrom(ctx, pgx.Identifier{"post_asset_usage"}, []string{"post_id", "asset_id"}, pgx.CopyFromRows(values)) _, err = conn.CopyFrom(ctx, pgx.Identifier{"post_asset_usage"}, []string{"post_id", "asset_id"}, pgx.CopyFromRows(values))
if err != nil { if err != nil {
panic(oops.New(err, "failed to insert post asset usage")) panic(oops.New(err, "failed to insert post asset usage"))
} }
@ -873,8 +873,8 @@ Ensures that the first_id and last_id on the thread are still good.
Returns errThreadEmpty if the thread contains no visible posts any more. Returns errThreadEmpty if the thread contains no visible posts any more.
You should probably mark the thread as deleted in this case. You should probably mark the thread as deleted in this case.
*/ */
func FixThreadPostIds(ctx context.Context, tx pgx.Tx, threadId int) error { func FixThreadPostIds(ctx context.Context, conn db.ConnOrTx, threadId int) error {
posts, err := db.Query[models.Post](ctx, tx, posts, err := db.Query[models.Post](ctx, conn,
` `
SELECT $columns SELECT $columns
FROM post FROM post
@ -902,7 +902,7 @@ func FixThreadPostIds(ctx context.Context, tx pgx.Tx, threadId int) error {
return errThreadEmpty return errThreadEmpty
} }
_, err = tx.Exec(ctx, _, err = conn.Exec(ctx,
` `
UPDATE thread UPDATE thread
SET first_id = $1, last_id = $2 SET first_id = $1, last_id = $2

View File

@ -10,7 +10,9 @@ import (
"git.handmade.network/hmn/hmn/src/auth" "git.handmade.network/hmn/hmn/src/auth"
"git.handmade.network/hmn/hmn/src/config" "git.handmade.network/hmn/hmn/src/config"
"git.handmade.network/hmn/hmn/src/db" "git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/hmndata"
"git.handmade.network/hmn/hmn/src/models" "git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
"git.handmade.network/hmn/hmn/src/utils" "git.handmade.network/hmn/hmn/src/utils"
lorem "github.com/HandmadeNetwork/golorem" lorem "github.com/HandmadeNetwork/golorem"
"github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4"
@ -117,9 +119,26 @@ func SampleSeed() {
charlie := seedUser(ctx, conn, models.User{Username: "charlie", Name: "Charlie"}) charlie := seedUser(ctx, conn, models.User{Username: "charlie", Name: "Charlie"})
fmt.Println("Creating a spammer...") fmt.Println("Creating a spammer...")
seedUser(ctx, conn, models.User{Username: "spam", Name: "Hot singletons in your local area", Status: models.UserStatusConfirmed}) spammer := seedUser(ctx, conn, models.User{
Username: "spam",
Status: models.UserStatusConfirmed,
Name: "Hot singletons in your local area",
Bio: "Howdy, everybody I go by Jarva seesharpe from Bangalore. In this way, assuming you need to partake in a shared global instance with me then, at that poi",
})
_ = []*models.User{alice, bob, charlie} users := []*models.User{alice, bob, charlie, spammer}
fmt.Println("Creating some threads...")
for i := 0; i < 5; i++ {
thread := seedThread(ctx, conn, models.Thread{})
populateThread(ctx, conn, thread, users, rand.Intn(5)+1)
}
// spam-only thread
{
thread := seedThread(ctx, conn, models.Thread{})
populateThread(ctx, conn, thread, []*models.User{spammer}, 1)
}
// admin := CreateAdminUser("admin", "12345678") // admin := CreateAdminUser("admin", "12345678")
// user := CreateUser("regular_user", "12345678") // user := CreateUser("regular_user", "12345678")
@ -178,6 +197,59 @@ func seedUser(ctx context.Context, conn db.ConnOrTx, input models.User) *models.
return user return user
} }
func seedThread(ctx context.Context, conn db.ConnOrTx, input models.Thread) *models.Thread {
input.Type = utils.OrDefault(input.Type, models.ThreadTypeForumPost)
var defaultSubforum *int
if input.Type == models.ThreadTypeForumPost {
id := 2
defaultSubforum = &id
}
thread, err := db.QueryOne[models.Thread](ctx, conn,
`
INSERT INTO thread (
title,
type, sticky,
project_id, subforum_id,
first_id, last_id
)
VALUES (
$1,
$2, $3,
$4, $5,
$6, $7
)
RETURNING $columns
`,
utils.OrDefault(input.Title, lorem.Sentence(3, 8)),
utils.OrDefault(input.Type, models.ThreadTypeForumPost), false,
utils.OrDefault(input.ProjectID, models.HMNProjectID), utils.OrDefault(input.SubforumID, defaultSubforum),
-1, -1,
)
if err != nil {
panic(oops.New(err, "failed to create thread"))
}
return thread
}
func populateThread(ctx context.Context, conn db.ConnOrTx, thread *models.Thread, users []*models.User, numPosts int) {
var lastPostId int
for i := 0; i < numPosts; i++ {
user := users[i%len(users)]
var replyId *int
if lastPostId != 0 {
if rand.Intn(10) < 3 {
replyId = &lastPostId
}
}
hmndata.CreateNewPost(ctx, conn, thread.ProjectID, thread.ID, thread.Type, user.ID, replyId, lorem.Paragraph(1, 10), "192.168.2.1")
}
}
func randomName() string { func randomName() string {
return "John Doe" // chosen by fair dice roll. guaranteed to be random. return "John Doe" // chosen by fair dice roll. guaranteed to be random.
} }