Seed example forum threads
This commit is contained in:
parent
3a93aa93e9
commit
3c4238994a
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue