fix templates v3

This commit is contained in:
tamakyi
2026-10-22 18:26:30 +08:00
parent b939d26ff0
commit 0181fc5c66
4 changed files with 93 additions and 3 deletions
+2 -2
View File
@@ -276,7 +276,7 @@
<div class="uk-card-body uk-padding-remove-top">
<hr>
<h5 class="uk-text-center">{{t .LangCode "qitem.answerTitle"}}</h5>
<form id="tb-answer-form" method="post" action="/_/{{ .PageUser.Domain }}/{{ .Question.ID }}/answer{{ if .NextQuery }}?{{ .NextQuery }}{{ end }}" enctype="multipart/form-data">
<form id="tb-answer-form" method="post" action="{{ if .AnswerAction }}{{ .AnswerAction }}{{ else }}/_/{{ .PageUser.Domain }}/{{ .Question.ID }}/answer{{ end }}" enctype="multipart/form-data">
{{ .CSRFTokenHTML }}
<div class="uk-margin uk-text-center">
<textarea name="answer" class="uk-textarea" rows="5" maxlength="{{ .Limits.AnswerContentLen }}"
@@ -436,7 +436,7 @@
{{ if and .CanDelete .NextUnreadID }}
<!-- 下一条未读:标记本条已读并跳转,会改状态,故用 POST 表单而非链接 -->
<span class="tb-foot-sep" aria-hidden="true">·</span>
<form class="uk-display-inline" method="post" action="/_/{{ .PageUser.Domain }}/{{ .Question.ID }}/next-unread{{ if .NextQuery }}?{{ .NextQuery }}{{ end }}">
<form class="uk-display-inline" method="post" action="{{ if .NextUnreadAction }}{{ .NextUnreadAction }}{{ else }}/_/{{ .PageUser.Domain }}/{{ .Question.ID }}/next-unread{{ end }}">
{{ .CSRFTokenHTML }}
<button type="submit" class="uk-button uk-button-link" title="{{t .LangCode "qitem.nextUnreadTitle"}}">{{t .LangCode "qitem.nextUnread"}} ›</button>
</form>
+51
View File
@@ -0,0 +1,51 @@
package templates
import (
"strings"
"testing"
"time"
)
// 从后台进入单题页时,表单 action 必须原样带上筛选参数。
// 回归点:曾经写成 action="...?{{ .NextQuery }}",html/template 会把查询片段整体编码,
// = 和 & 变成 %3d / %26,服务端解析不出 from,跳转后「返回」掉回箱主页(线上实测过)。
func TestOwnerFormsKeepAdminQuery(t *testing.T) {
data := publicBaseData()
data["CanDelete"] = true
data["IsOwnPage"] = true
data["NextUnreadID"] = uint(2)
data["BackFrom"] = "admin"
data["BackTo"] = "/user/questions?from=admin&sort=new"
data["AnswerAction"] = "/_/tester/1/answer?from=admin&sort=new"
data["NextUnreadAction"] = "/_/tester/1/next-unread?from=admin&sort=new"
data["Question"] = map[string]interface{}{
"ID": 1, "Content": "测试提问", "Answer": "",
"CreatedAt": time.Now(), "UpdatedAt": time.Now(),
"IsPrivate": false, "IsPinned": false, "IsRead": false,
"Token": "abc123", "ReceiveReplyEmail": "",
}
data["QuestionToken"] = "abc123"
data["AskUploadImages"] = []interface{}{}
data["AnswerUploadImages"] = []interface{}{}
data["FollowUps"] = []interface{}{}
data["CanFollowUp"] = false
data["IsQuestioner"] = false
out, err := renderToString(t, "question/item", data)
if err != nil {
t.Fatalf("render question/item: %v", err)
}
for _, want := range []string{
`action="/_/tester/1/answer?from=admin&amp;sort=new"`,
`action="/_/tester/1/next-unread?from=admin&amp;sort=new"`,
`href="/user/questions?from=admin&amp;sort=new"`,
} {
if !strings.Contains(out, want) {
t.Fatalf("渲染结果缺少 %s", want)
}
}
if strings.Contains(strings.ToLower(out), "%3d") || strings.Contains(out, "%26") {
t.Fatal("action 里的 = / & 被 percent-encode 了,服务端会解析不出 from=admin")
}
}