From c1785d79a474853e98b9f921b264e0475efa1981 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Sun, 4 Jul 2021 17:48:08 -0500 Subject: [PATCH] Get forum post creation working --- .../2021-07-04T213658Z_DropThreadFields.go | 45 +++++++ .../2021-07-04T220228Z_FixPostConstraints.go | 69 +++++++++++ src/models/thread.go | 10 +- src/templates/src/editor.html | 16 +-- src/website/forums.go | 112 +++++++++++++----- 5 files changed, 206 insertions(+), 46 deletions(-) create mode 100644 src/migration/migrations/2021-07-04T213658Z_DropThreadFields.go create mode 100644 src/migration/migrations/2021-07-04T220228Z_FixPostConstraints.go diff --git a/src/migration/migrations/2021-07-04T213658Z_DropThreadFields.go b/src/migration/migrations/2021-07-04T213658Z_DropThreadFields.go new file mode 100644 index 0000000..37f202c --- /dev/null +++ b/src/migration/migrations/2021-07-04T213658Z_DropThreadFields.go @@ -0,0 +1,45 @@ +package migrations + +import ( + "context" + "time" + + "git.handmade.network/hmn/hmn/src/migration/types" + "git.handmade.network/hmn/hmn/src/oops" + "github.com/jackc/pgx/v4" +) + +func init() { + registerMigration(DropThreadFields{}) +} + +type DropThreadFields struct{} + +func (m DropThreadFields) Version() types.MigrationVersion { + return types.MigrationVersion(time.Date(2021, 7, 4, 21, 36, 58, 0, time.UTC)) +} + +func (m DropThreadFields) Name() string { + return "DropThreadFields" +} + +func (m DropThreadFields) Description() string { + return "Drop unnecessary thread fields" +} + +func (m DropThreadFields) Up(ctx context.Context, tx pgx.Tx) error { + _, err := tx.Exec(ctx, ` + ALTER TABLE handmade_thread + DROP hits, + DROP reply_count; + `) + if err != nil { + return oops.New(err, "failed to drop thread fields") + } + + return nil +} + +func (m DropThreadFields) Down(ctx context.Context, tx pgx.Tx) error { + panic("Implement me") +} diff --git a/src/migration/migrations/2021-07-04T220228Z_FixPostConstraints.go b/src/migration/migrations/2021-07-04T220228Z_FixPostConstraints.go new file mode 100644 index 0000000..a3684cb --- /dev/null +++ b/src/migration/migrations/2021-07-04T220228Z_FixPostConstraints.go @@ -0,0 +1,69 @@ +package migrations + +import ( + "context" + "time" + + "git.handmade.network/hmn/hmn/src/migration/types" + "git.handmade.network/hmn/hmn/src/oops" + "github.com/jackc/pgx/v4" +) + +func init() { + registerMigration(FixPostConstraints{}) +} + +type FixPostConstraints struct{} + +func (m FixPostConstraints) Version() types.MigrationVersion { + return types.MigrationVersion(time.Date(2021, 7, 4, 22, 2, 28, 0, time.UTC)) +} + +func (m FixPostConstraints) Name() string { + return "FixPostConstraints" +} + +func (m FixPostConstraints) Description() string { + return "Update post-related constraints to make insertion sane" +} + +func (m FixPostConstraints) Up(ctx context.Context, tx pgx.Tx) error { + _, err := tx.Exec(ctx, ` + ALTER TABLE handmade_thread + ALTER locked SET DEFAULT FALSE, + ALTER first_id SET NOT NULL, + ALTER last_id SET NOT NULL; + `) + if err != nil { + return oops.New(err, "failed to update thread constraints") + } + + _, err = tx.Exec(ctx, ` + ALTER TABLE handmade_post + ALTER deleted SET DEFAULT FALSE, + ALTER readonly SET DEFAULT FALSE, + ALTER CONSTRAINT handmade_post_current_id_fkey DEFERRABLE INITIALLY DEFERRED; + `) + if err != nil { + return oops.New(err, "failed to update project constraints") + } + + _, err = tx.Exec(ctx, ` + CREATE SEQUENCE handmade_postversion_id_seq + START WITH 40000 -- this is well out of the way of existing IDs + OWNED BY handmade_postversion.id; + + ALTER TABLE handmade_postversion + ALTER id SET DEFAULT nextval('handmade_postversion_id_seq'), + ALTER CONSTRAINT handmade_postversion_post_id_fkey DEFERRABLE INITIALLY DEFERRED; + `) + if err != nil { + return oops.New(err, "failed to update postversion constraints") + } + + return nil +} + +func (m FixPostConstraints) Down(ctx context.Context, tx pgx.Tx) error { + panic("Implement me") +} diff --git a/src/models/thread.go b/src/models/thread.go index 525fb47..1d47246 100644 --- a/src/models/thread.go +++ b/src/models/thread.go @@ -5,12 +5,10 @@ type Thread struct { CategoryID int `db:"category_id"` - Title string `db:"title"` - Hits int `db:"hits"` - ReplyCount int `db:"reply_count"` - Sticky bool `db:"sticky"` - Locked bool `db:"locked"` - Deleted bool `db:"deleted"` + Title string `db:"title"` + Sticky bool `db:"sticky"` + Locked bool `db:"locked"` + Deleted bool `db:"deleted"` FirstID *int `db:"first_id"` LastID *int `db:"last_id"` diff --git a/src/templates/src/editor.html b/src/templates/src/editor.html index dd3a444..5fe8c8e 100644 --- a/src/templates/src/editor.html +++ b/src/templates/src/editor.html @@ -46,33 +46,29 @@
-
- {{/* - {% if are_editing %} + {{ if .IsEditing }} - + - {% endif %} + {{ end }} + {{/* TODO: Sticky threads {% if user.is_staff and post and post.depth == 0 %}
{% endif %} + */}} - - - {% if are_previewing %} - {% include "edit_preview.html" %} - {% endif %} + {{/* {% if context_reply_to %}

The post you're replying to:

diff --git a/src/website/forums.go b/src/website/forums.go index 496a35a..2ab5ff1 100644 --- a/src/website/forums.go +++ b/src/website/forums.go @@ -3,6 +3,7 @@ package website import ( "errors" "math" + "net" "net/http" "strconv" "strings" @@ -518,18 +519,14 @@ func ForumPostRedirect(c *RequestContext) ResponseData { type editorData struct { templates.BaseData - SubmitUrl string - PostTitle string - PostBody string - SubmitLabel string - PreviewLabel string + SubmitUrl string + PostTitle string + PostBody string + SubmitLabel string + IsEditing bool // false if new post, true if updating existing one } func ForumNewThread(c *RequestContext) ResponseData { - if c.Req.Method == http.MethodPost { - // TODO: Get preview data - } - baseData := getBaseData(c) baseData.Title = "Create New Thread" baseData.MathjaxEnabled = true @@ -547,19 +544,10 @@ func ForumNewThread(c *RequestContext) ResponseData { var res ResponseData err := res.WriteTemplate("editor.html", editorData{ - BaseData: baseData, - SubmitUrl: hmnurl.BuildForumNewThread(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(currentCatId), true), - SubmitLabel: "Post New Thread", - PreviewLabel: "Preview", + BaseData: baseData, + SubmitUrl: hmnurl.BuildForumNewThread(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(currentCatId), true), + SubmitLabel: "Post New Thread", }, c.Perf) - // err := res.WriteTemplate("forum_thread.html", forumThreadData{ - // BaseData: baseData, - // Thread: templates.ThreadToTemplate(&thread), - // Posts: posts, - // CategoryUrl: hmnurl.BuildForumCategory(c.CurrentProject.Slug, currentSubforumSlugs, 1), - // ReplyUrl: hmnurl.BuildForumPostReply(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, *thread.FirstID), - // Pagination: pagination, - // }, c.Perf) if err != nil { panic(err) } @@ -572,6 +560,7 @@ func ForumNewThreadSubmit(c *RequestContext) ResponseData { if err != nil { panic(err) } + defer tx.Rollback(c.Context()) c.Perf.StartBlock("SQL", "Fetch category tree") categoryTree := models.GetFullCategoryTree(c.Context(), c.Conn) @@ -593,41 +582,104 @@ func ForumNewThreadSubmit(c *RequestContext) ResponseData { } parsed := parsing.ParsePostInput(unparsed, false) + now := time.Now() + + ip := net.ParseIP(c.Req.RemoteAddr) // Create thread var threadId int err = tx.QueryRow(c.Context(), ` - INSERT INTO handmade_thread (title, sticky, locked, category_id) + INSERT INTO handmade_thread (title, sticky, category_id, first_id, last_id) + VALUES ($1, $2, $3, $4, $5) RETURNING id `, title, sticky, - false, currentCatId, + -1, + -1, ).Scan(&threadId) if err != nil { panic(oops.New(err, "failed to create thread")) } - // Create post version - _, err = tx.Exec(c.Context(), + // Create post + var postId int + err = tx.QueryRow(c.Context(), ` - INSERT INTO handmade_postversion (post_id, text_raw, text_parsed) - VALUES ($1, $2, $3) + INSERT INTO handmade_post (postdate, category_id, thread_id, preview, current_id, author_id, category_kind, project_id) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + RETURNING id `, - // TODO: post id + now, + currentCatId, + threadId, + "lol", // TODO: Actual previews + -1, + c.CurrentUser.ID, + models.CatKindForum, + c.CurrentProject.ID, + ).Scan(&postId) + if err != nil { + panic(oops.New(err, "failed to create post")) + } + + // Create post version + var versionId int + err = tx.QueryRow(c.Context(), + ` + INSERT INTO handmade_postversion (post_id, text_raw, text_parsed, ip, date) + VALUES ($1, $2, $3, $4, $5) + RETURNING id + `, + postId, unparsed, parsed, + ip, + now, + ).Scan(&versionId) + if err != nil { + panic(oops.New(err, "failed to create post version")) + } + + // Update post with version id + _, err = tx.Exec(c.Context(), + ` + UPDATE handmade_post + SET current_id = $1 + WHERE id = $2 + `, + versionId, + postId, ) + if err != nil { + panic(oops.New(err, "failed to set current post version")) + } + + // Update thread with post id + _, err = tx.Exec(c.Context(), + ` + UPDATE handmade_thread + SET + first_id = $1, + last_id = $1 + WHERE id = $2 + `, + postId, + threadId, + ) + if err != nil { + panic(oops.New(err, "failed to set thread post ids")) + } err = tx.Commit(c.Context()) if err != nil { return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new forum thread")) } - // TODO: Redirect to newly created thread - return c.Redirect(hmnurl.BuildForumNewThread(models.HMNProjectSlug, nil, false), http.StatusSeeOther) + newThreadUrl := hmnurl.BuildForumThread(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(currentCatId), threadId, title, 1) + return c.Redirect(newThreadUrl, http.StatusSeeOther) } func validateSubforums(lineageBuilder *models.CategoryLineageBuilder, project *models.Project, catPath string) (int, bool) {