From d78ed8e2fe8764d98cb20327188dcde3ce33ccdc Mon Sep 17 00:00:00 2001 From: dsh Date: Fri, 28 Aug 2026 19:59:32 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=96=87=E7=AB=A0=E6=96=B0?= =?UTF-8?q?=E5=BB=BA/=E7=BC=96=E8=BE=91=E8=A1=A8=E5=8D=95=E6=94=B6?= =?UTF-8?q?=E6=95=9B=E4=B8=BA=E5=8D=95=E4=B8=80=E6=A8=A1=E6=9D=BF=20articl?= =?UTF-8?q?e=5Fform=EF=BC=8C=E5=88=A0=E9=99=A4=E4=B8=A4=E5=A5=97=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 templates/partials/article_form.html(define article_form): 按 .FormIsMy 分支渲染——管理员变体(标签/置顶勾选/草稿发布双按钮/ /api/admin/articles)与作者变体(状态下拉/保存取消//api/my/articles) - renderArticleForm / renderMyArticleForm 均渲染 article_form,各自 设置 FormIsMy=false/true;JS 统一(API_BASE/redirectBase/editor/ 错误提示均单份) - 删除 templates/admin/article_create.html 与 templates/user/my_article_form.html(约 360 行 → 一份 ~230 行) - 新增 TestArticleFormTemplateVariants 断言两个变体渲染差异; 测试环境注册两个工作区的新建页路由 --- handlers/article.go | 6 +- handlers/article_form_template_test.go | 49 +++++ handlers/my_articles.go | 6 +- handlers/security_test.go | 2 + .../article_form.html} | 59 ++++-- templates/user/my_article_form.html | 170 ------------------ 6 files changed, 104 insertions(+), 188 deletions(-) create mode 100644 handlers/article_form_template_test.go rename templates/{admin/article_create.html => partials/article_form.html} (76%) delete mode 100644 templates/user/my_article_form.html diff --git a/handlers/article.go b/handlers/article.go index a607ad3..4bb36b7 100644 --- a/handlers/article.go +++ b/handlers/article.go @@ -119,15 +119,17 @@ func applyFormToData(data gin.H, f articleForm) { data["SessionToken"] = f.SessionToken } -// renderArticleForm 使用给定的表单值和可选的错误消息渲染共享的文章表单模板。 +// renderArticleForm 使用给定的表单值和可选的错误消息渲染管理员工作区的 +// 文章表单(与作者工作区共用一份模板,FormIsMy=false 表示管理员变体)。 func renderArticleForm(c *gin.Context, db *gorm.DB, f articleForm, errMsg string) { data := DefaultData(c) data["Title"] = f.TitleText + data["FormIsMy"] = false if errMsg != "" { data["Error"] = errMsg } applyFormToData(data, f) - c.HTML(http.StatusOK, "article_create", data) + c.HTML(http.StatusOK, "article_form", data) } // sessionAuthorID 从会话中提取已登录用户的 ID,兼容 int/uint/int64/float64 diff --git a/handlers/article_form_template_test.go b/handlers/article_form_template_test.go new file mode 100644 index 0000000..58127be --- /dev/null +++ b/handlers/article_form_template_test.go @@ -0,0 +1,49 @@ +package handlers + +import ( + "net/http" + "strings" + "testing" +) + +// TestArticleFormTemplateVariants 验证管理员与作者工作区共用同一份 +// article_form 模板(templates/partials/article_form.html)时的两个变体: +// - 管理员:含置顶勾选(is_top)/ /api/admin/articles 前缀,作者 API 不出现 +// - 作者:含状态下拉 / /api/my/articles 前缀,置顶与管理员 API 不出现 +func TestArticleFormTemplateVariants(t *testing.T) { + e := newSecurityTestEnv(t) + + // 管理员新建页(FormIsMy=false 变体)。 + admin := e.login(t, "admin") + w := e.do(http.MethodGet, "/admin/articles/new", admin, nil, "") + if w.Code != http.StatusOK { + t.Fatalf("admin GET /admin/articles/new: status = %d", w.Code) + } + body := w.Body.String() + for _, want := range []string{`id="articleForm"`, `id="articleSessionToken"`, "isTopCheckbox", `"/api/admin/articles"`} { + if !strings.Contains(body, want) { + t.Fatalf("admin variant missing %q", want) + } + } + if strings.Contains(body, "/api/my/articles") { + t.Fatal("admin variant must not reference the author API") + } + + // 作者新建页(FormIsMy=true 变体)。 + alice := e.login(t, "alice") + w = e.do(http.MethodGet, "/my/articles/new", alice, nil, "") + if w.Code != http.StatusOK { + t.Fatalf("author GET /my/articles/new: status = %d", w.Code) + } + body = w.Body.String() + for _, want := range []string{`id="articleForm"`, `id="articleSessionToken"`, `"/api/my/articles"`, `name="status"`} { + if !strings.Contains(body, want) { + t.Fatalf("author variant missing %q", want) + } + } + for _, forbid := range []string{"isTopCheckbox", "/api/admin/articles"} { + if strings.Contains(body, forbid) { + t.Fatalf("author variant must not contain %q", forbid) + } + } +} diff --git a/handlers/my_articles.go b/handlers/my_articles.go index 178c9f8..cbe1c93 100644 --- a/handlers/my_articles.go +++ b/handlers/my_articles.go @@ -177,13 +177,15 @@ func MyArticleDelete(db *gorm.DB) gin.HandlerFunc { } } -// renderMyArticleForm 为普通用户渲染文章表单。 +// renderMyArticleForm 为普通用户渲染文章表单 +// (与管理员工作区共用一份模板,FormIsMy=true 表示作者变体)。 func renderMyArticleForm(c *gin.Context, db *gorm.DB, f articleForm, errMsg string) { data := DefaultData(c) data["Title"] = f.TitleText + data["FormIsMy"] = true if errMsg != "" { data["Error"] = errMsg } applyFormToData(data, f) - c.HTML(http.StatusOK, "my_article_form", data) + c.HTML(http.StatusOK, "article_form", data) } diff --git a/handlers/security_test.go b/handlers/security_test.go index 449ec29..271d176 100644 --- a/handlers/security_test.go +++ b/handlers/security_test.go @@ -106,6 +106,7 @@ func newSecurityTestEnv(t *testing.T) *securityTestEnv { uid, _ := sessionAuthorID(c) c.String(http.StatusOK, "uid=%d", uid) }) + protected.GET("/articles/new", MyArticleCreatePage(db)) } myAPI := r.Group("/api/my/articles", middleware.AuthRequired(db)) @@ -139,6 +140,7 @@ func newSecurityTestEnv(t *testing.T) *securityTestEnv { { admin.GET("/users/:id/edit", UserEditPage(db)) admin.GET("/comments", CommentListPage(db)) + admin.GET("/articles/new", ArticleCreatePage(db)) } usersAPI := r.Group("/api/admin/users", middleware.AuthRequired(db), middleware.AdminRequired(db)) diff --git a/templates/admin/article_create.html b/templates/partials/article_form.html similarity index 76% rename from templates/admin/article_create.html rename to templates/partials/article_form.html index 76e7880..4143491 100644 --- a/templates/admin/article_create.html +++ b/templates/partials/article_form.html @@ -1,4 +1,4 @@ -{{define "article_create"}} +{{define "article_form"}} {{template "header" .}} {{template "markdown_assets" .}} @@ -12,12 +12,12 @@
- +
-
@@ -53,7 +53,8 @@ placeholder="https://..."> - + + {{if not .FormIsMy}}

{{index .Tr "article_tags_hint"}}

+ {{end}} {{template "article_attachments" .}} @@ -73,14 +75,37 @@

{{index .Tr "article_published_at_hint"}}

- + + {{if not .FormIsMy}}
+ {{end}} - + {{if .FormIsMy}} + +
+ + +
+
+ + + {{index .Tr "article_cancel"}} + +
+ {{else}} +
+ {{end}}
@@ -99,15 +125,19 @@ - - - -{{template "footer" .}} -{{end}}