diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2024-11-05 14:04:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-05 14:04:26 +0800 |
commit | 4a469c8e1b3c1d153316aec9fd8cbdd3e1dd54e8 (patch) | |
tree | 3fc7eae5668299c7dbd5933cd14839bbccacefdd /modules | |
parent | b068dbd40ee3b4dc7d18cdcf168f0c24cea234c0 (diff) | |
download | gitea-4a469c8e1b3c1d153316aec9fd8cbdd3e1dd54e8.tar.gz gitea-4a469c8e1b3c1d153316aec9fd8cbdd3e1dd54e8.zip |
Refactor template ctx and render utils (#32422)
Clean up the templates
Diffstat (limited to 'modules')
-rw-r--r-- | modules/templates/helper.go | 41 | ||||
-rw-r--r-- | modules/templates/util_date.go | 18 | ||||
-rw-r--r-- | modules/templates/util_date_legacy.go | 23 | ||||
-rw-r--r-- | modules/templates/util_render.go | 61 | ||||
-rw-r--r-- | modules/templates/util_render_legacy.go | 52 | ||||
-rw-r--r-- | modules/templates/util_render_test.go | 33 |
6 files changed, 150 insertions, 78 deletions
diff --git a/modules/templates/helper.go b/modules/templates/helper.go index a01aad06a1..efaa10624b 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -73,11 +73,6 @@ func NewFuncMap() template.FuncMap { return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" }, - // for backward compatibility only, do not use them anymore - "TimeSince": timeSinceLegacy, - "TimeSinceUnix": timeSinceLegacy, - "DateTime": dateTimeLegacy, - // ----------------------------------------------------------------- // setting "AppName": func() string { @@ -156,18 +151,8 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // render - "RenderCommitMessage": RenderCommitMessage, - "RenderCommitMessageLinkSubject": renderCommitMessageLinkSubject, - - "RenderCommitBody": renderCommitBody, - "RenderCodeBlock": renderCodeBlock, - "RenderIssueTitle": renderIssueTitle, - "RenderEmoji": renderEmoji, - "ReactionToEmoji": reactionToEmoji, - - "RenderMarkdownToHtml": RenderMarkdownToHtml, - "RenderLabel": renderLabel, - "RenderLabels": RenderLabels, + "RenderCodeBlock": renderCodeBlock, + "ReactionToEmoji": reactionToEmoji, // ----------------------------------------------------------------- // misc @@ -179,6 +164,22 @@ func NewFuncMap() template.FuncMap { "FilenameIsImage": filenameIsImage, "TabSizeClass": tabSizeClass, + + // for backward compatibility only, do not use them anymore + "TimeSince": timeSinceLegacy, + "TimeSinceUnix": timeSinceLegacy, + "DateTime": dateTimeLegacy, + + "RenderEmoji": renderEmojiLegacy, + "RenderLabel": renderLabelLegacy, + "RenderLabels": renderLabelsLegacy, + "RenderIssueTitle": renderIssueTitleLegacy, + + "RenderMarkdownToHtml": renderMarkdownToHtmlLegacy, + + "RenderCommitMessage": renderCommitMessageLegacy, + "RenderCommitMessageLinkSubject": renderCommitMessageLinkSubjectLegacy, + "RenderCommitBody": renderCommitBodyLegacy, } } @@ -296,3 +297,9 @@ func userThemeName(user *user_model.User) string { } return setting.UI.DefaultTheme } + +func panicIfDevOrTesting() { + if !setting.IsProd || setting.IsInTesting { + panic("legacy template functions are for backward compatibility only, do not use them in new code") + } +} diff --git a/modules/templates/util_date.go b/modules/templates/util_date.go index b9e04401f1..4a794e6f30 100644 --- a/modules/templates/util_date.go +++ b/modules/templates/util_date.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/translation" ) type DateUtils struct{} @@ -54,23 +53,6 @@ func parseLegacy(datetime string) time.Time { return t } -func dateTimeLegacy(format string, datetime any, _ ...string) template.HTML { - if !setting.IsProd || setting.IsInTesting { - panic("dateTimeLegacy is for backward compatibility only, do not use it in new code") - } - if s, ok := datetime.(string); ok { - datetime = parseLegacy(s) - } - return dateTimeFormat(format, datetime) -} - -func timeSinceLegacy(time any, _ translation.Locale) template.HTML { - if !setting.IsProd || setting.IsInTesting { - panic("timeSinceLegacy is for backward compatibility only, do not use it in new code") - } - return TimeSince(time) -} - func anyToTime(any any) (t time.Time, isZero bool) { switch v := any.(type) { case nil: diff --git a/modules/templates/util_date_legacy.go b/modules/templates/util_date_legacy.go new file mode 100644 index 0000000000..ceefb00447 --- /dev/null +++ b/modules/templates/util_date_legacy.go @@ -0,0 +1,23 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package templates + +import ( + "html/template" + + "code.gitea.io/gitea/modules/translation" +) + +func dateTimeLegacy(format string, datetime any, _ ...string) template.HTML { + panicIfDevOrTesting() + if s, ok := datetime.(string); ok { + datetime = parseLegacy(s) + } + return dateTimeFormat(format, datetime) +} + +func timeSinceLegacy(time any, _ translation.Locale) template.HTML { + panicIfDevOrTesting() + return TimeSince(time) +} diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index 6eee007f34..1201828345 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -24,13 +24,21 @@ import ( "code.gitea.io/gitea/modules/util" ) +type RenderUtils struct { + ctx context.Context +} + +func NewRenderUtils(ctx context.Context) *RenderUtils { + return &RenderUtils{ctx: ctx} +} + // RenderCommitMessage renders commit message with XSS-safe and special links. -func RenderCommitMessage(ctx context.Context, msg string, metas map[string]string) template.HTML { +func (ut *RenderUtils) RenderCommitMessage(msg string, metas map[string]string) template.HTML { cleanMsg := template.HTMLEscapeString(msg) // we can safely assume that it will not return any error, since there // shouldn't be any special HTML. fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ - Ctx: ctx, + Ctx: ut.ctx, Metas: metas, }, cleanMsg) if err != nil { @@ -44,9 +52,9 @@ func RenderCommitMessage(ctx context.Context, msg string, metas map[string]strin return renderCodeBlock(template.HTML(msgLines[0])) } -// renderCommitMessageLinkSubject renders commit message as a XSS-safe link to +// RenderCommitMessageLinkSubject renders commit message as a XSS-safe link to // the provided default url, handling for special links without email to links. -func renderCommitMessageLinkSubject(ctx context.Context, msg, urlDefault string, metas map[string]string) template.HTML { +func (ut *RenderUtils) RenderCommitMessageLinkSubject(msg, urlDefault string, metas map[string]string) template.HTML { msgLine := strings.TrimLeftFunc(msg, unicode.IsSpace) lineEnd := strings.IndexByte(msgLine, '\n') if lineEnd > 0 { @@ -60,7 +68,7 @@ func renderCommitMessageLinkSubject(ctx context.Context, msg, urlDefault string, // we can safely assume that it will not return any error, since there // shouldn't be any special HTML. renderedMessage, err := markup.RenderCommitMessageSubject(&markup.RenderContext{ - Ctx: ctx, + Ctx: ut.ctx, DefaultLink: urlDefault, Metas: metas, }, template.HTMLEscapeString(msgLine)) @@ -71,8 +79,8 @@ func renderCommitMessageLinkSubject(ctx context.Context, msg, urlDefault string, return renderCodeBlock(template.HTML(renderedMessage)) } -// renderCommitBody extracts the body of a commit message without its title. -func renderCommitBody(ctx context.Context, msg string, metas map[string]string) template.HTML { +// RenderCommitBody extracts the body of a commit message without its title. +func (ut *RenderUtils) RenderCommitBody(msg string, metas map[string]string) template.HTML { msgLine := strings.TrimSpace(msg) lineEnd := strings.IndexByte(msgLine, '\n') if lineEnd > 0 { @@ -86,7 +94,7 @@ func renderCommitBody(ctx context.Context, msg string, metas map[string]string) } renderedMessage, err := markup.RenderCommitMessage(&markup.RenderContext{ - Ctx: ctx, + Ctx: ut.ctx, Metas: metas, }, template.HTMLEscapeString(msgLine)) if err != nil { @@ -105,22 +113,22 @@ func renderCodeBlock(htmlEscapedTextToRender template.HTML) template.HTML { return template.HTML(htmlWithCodeTags) } -// renderIssueTitle renders issue/pull title with defined post processors -func renderIssueTitle(ctx context.Context, text string, metas map[string]string) template.HTML { +// RenderIssueTitle renders issue/pull title with defined post processors +func (ut *RenderUtils) RenderIssueTitle(text string, metas map[string]string) template.HTML { renderedText, err := markup.RenderIssueTitle(&markup.RenderContext{ - Ctx: ctx, + Ctx: ut.ctx, Metas: metas, }, template.HTMLEscapeString(text)) if err != nil { log.Error("RenderIssueTitle: %v", err) - return template.HTML("") + return "" } return template.HTML(renderedText) } -// renderLabel renders a label -// locale is needed due to an import cycle with our context providing the `Tr` function -func renderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { +// RenderLabel renders a label +func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML { + locale := ut.ctx.Value(translation.ContextKey).(translation.Locale) var extraCSSClasses string textColor := util.ContrastColor(label.Color) labelScope := label.ExclusiveScope() @@ -134,12 +142,12 @@ func renderLabel(ctx context.Context, locale translation.Locale, label *issues_m if labelScope == "" { // Regular label return HTMLFormat(`<div class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s">%s</div>`, - extraCSSClasses, textColor, label.Color, descriptionText, renderEmoji(ctx, label.Name)) + extraCSSClasses, textColor, label.Color, descriptionText, ut.RenderEmoji(label.Name)) } // Scoped label - scopeHTML := renderEmoji(ctx, labelScope) - itemHTML := renderEmoji(ctx, label.Name[len(labelScope)+1:]) + scopeHTML := ut.RenderEmoji(labelScope) + itemHTML := ut.RenderEmoji(label.Name[len(labelScope)+1:]) // Make scope and item background colors slightly darker and lighter respectively. // More contrast needed with higher luminance, empirically tweaked. @@ -176,13 +184,12 @@ func renderLabel(ctx context.Context, locale translation.Locale, label *issues_m textColor, itemColor, itemHTML) } -// renderEmoji renders html text with emoji post processors -func renderEmoji(ctx context.Context, text string) template.HTML { - renderedText, err := markup.RenderEmoji(&markup.RenderContext{Ctx: ctx}, - template.HTMLEscapeString(text)) +// RenderEmoji renders html text with emoji post processors +func (ut *RenderUtils) RenderEmoji(text string) template.HTML { + renderedText, err := markup.RenderEmoji(&markup.RenderContext{Ctx: ut.ctx}, template.HTMLEscapeString(text)) if err != nil { log.Error("RenderEmoji: %v", err) - return template.HTML("") + return "" } return template.HTML(renderedText) } @@ -200,9 +207,9 @@ func reactionToEmoji(reaction string) template.HTML { return template.HTML(fmt.Sprintf(`<img alt=":%s:" src="%s/assets/img/emoji/%s.png"></img>`, reaction, setting.StaticURLPrefix, url.PathEscape(reaction))) } -func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //nolint:revive +func (ut *RenderUtils) MarkdownToHtml(input string) template.HTML { //nolint:revive output, err := markdown.RenderString(&markup.RenderContext{ - Ctx: ctx, + Ctx: ut.ctx, Metas: map[string]string{"mode": "document"}, }, input) if err != nil { @@ -211,7 +218,7 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n return output } -func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML { +func (ut *RenderUtils) RenderLabels(labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML { isPullRequest := issue != nil && issue.IsPull baseLink := fmt.Sprintf("%s/%s", repoLink, util.Iif(isPullRequest, "pulls", "issues")) htmlCode := `<span class="labels-list">` @@ -220,7 +227,7 @@ func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issu if label == nil { continue } - htmlCode += fmt.Sprintf(`<a href="%s?labels=%d">%s</a>`, baseLink, label.ID, renderLabel(ctx, locale, label)) + htmlCode += fmt.Sprintf(`<a href="%s?labels=%d">%s</a>`, baseLink, label.ID, ut.RenderLabel(label)) } htmlCode += "</span>" return template.HTML(htmlCode) diff --git a/modules/templates/util_render_legacy.go b/modules/templates/util_render_legacy.go new file mode 100644 index 0000000000..994f2fa064 --- /dev/null +++ b/modules/templates/util_render_legacy.go @@ -0,0 +1,52 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package templates + +import ( + "context" + "html/template" + + issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/modules/translation" +) + +func renderEmojiLegacy(ctx context.Context, text string) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderEmoji(text) +} + +func renderLabelLegacy(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderLabel(label) +} + +func renderLabelsLegacy(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderLabels(labels, repoLink, issue) +} + +func renderMarkdownToHtmlLegacy(ctx context.Context, input string) template.HTML { //nolint:revive + panicIfDevOrTesting() + return NewRenderUtils(ctx).MarkdownToHtml(input) +} + +func renderCommitMessageLegacy(ctx context.Context, msg string, metas map[string]string) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderCommitMessage(msg, metas) +} + +func renderCommitMessageLinkSubjectLegacy(ctx context.Context, msg, urlDefault string, metas map[string]string) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderCommitMessageLinkSubject(msg, urlDefault, metas) +} + +func renderIssueTitleLegacy(ctx context.Context, text string, metas map[string]string) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderIssueTitle(text, metas) +} + +func renderCommitBodyLegacy(ctx context.Context, msg string, metas map[string]string) template.HTML { + panicIfDevOrTesting() + return NewRenderUtils(ctx).RenderCommitBody(msg, metas) +} diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go index ba47c34efc..3e4ea04c63 100644 --- a/modules/templates/util_render_test.go +++ b/modules/templates/util_render_test.go @@ -65,9 +65,14 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func newTestRenderUtils() *RenderUtils { + ctx := context.Background() + ctx = context.WithValue(ctx, translation.ContextKey, &translation.MockLocale{}) + return NewRenderUtils(ctx) +} + func TestRenderCommitBody(t *testing.T) { type args struct { - ctx context.Context msg string metas map[string]string } @@ -79,7 +84,6 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines", args: args{ - ctx: context.Background(), msg: "first line\nsecond line", }, want: "second line", @@ -87,7 +91,6 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines with leading newlines", args: args{ - ctx: context.Background(), msg: "\n\n\n\nfirst line\nsecond line", }, want: "second line", @@ -95,15 +98,15 @@ func TestRenderCommitBody(t *testing.T) { { name: "multiple lines with trailing newlines", args: args{ - ctx: context.Background(), msg: "first line\nsecond line\n\n\n", }, want: "second line", }, } + ut := newTestRenderUtils() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, renderCommitBody(tt.args.ctx, tt.args.msg, tt.args.metas), "RenderCommitBody(%v, %v, %v)", tt.args.ctx, tt.args.msg, tt.args.metas) + assert.Equalf(t, tt.want, ut.RenderCommitBody(tt.args.msg, tt.args.metas), "RenderCommitBody(%v, %v)", tt.args.msg, tt.args.metas) }) } @@ -127,19 +130,19 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit <a href="/user13/repo11/issues/123" class="ref-issue">#123</a> space` - assert.EqualValues(t, expected, renderCommitBody(context.Background(), testInput(), testMetas)) + assert.EqualValues(t, expected, newTestRenderUtils().RenderCommitBody(testInput(), testMetas)) } func TestRenderCommitMessage(t *testing.T) { expected := `space <a href="/mention-user" class="mention">@mention-user</a> ` - assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput(), testMetas)) + assert.EqualValues(t, expected, newTestRenderUtils().RenderCommitMessage(testInput(), testMetas)) } func TestRenderCommitMessageLinkSubject(t *testing.T) { expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="/mention-user" class="mention">@mention-user</a>` - assert.EqualValues(t, expected, renderCommitMessageLinkSubject(context.Background(), testInput(), "https://example.com/link", testMetas)) + assert.EqualValues(t, expected, newTestRenderUtils().RenderCommitMessageLinkSubject(testInput(), "https://example.com/link", testMetas)) } func TestRenderIssueTitle(t *testing.T) { @@ -165,7 +168,7 @@ mail@domain.com space<SPACE><SPACE> ` expected = strings.ReplaceAll(expected, "<SPACE>", " ") - assert.EqualValues(t, expected, renderIssueTitle(context.Background(), testInput(), testMetas)) + assert.EqualValues(t, expected, newTestRenderUtils().RenderIssueTitle(testInput(), testMetas)) } func TestRenderMarkdownToHtml(t *testing.T) { @@ -190,25 +193,23 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit #123 space</p> ` - assert.Equal(t, expected, string(RenderMarkdownToHtml(context.Background(), testInput()))) + assert.Equal(t, expected, string(newTestRenderUtils().MarkdownToHtml(testInput()))) } func TestRenderLabels(t *testing.T) { - ctx := context.Background() - locale := &translation.MockLocale{} - + ut := newTestRenderUtils() label := &issues.Label{ID: 123, Name: "label-name", Color: "label-color"} issue := &issues.Issue{} expected := `/owner/repo/issues?labels=123` - assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected) + assert.Contains(t, ut.RenderLabels([]*issues.Label{label}, "/owner/repo", issue), expected) label = &issues.Label{ID: 123, Name: "label-name", Color: "label-color"} issue = &issues.Issue{IsPull: true} expected = `/owner/repo/pulls?labels=123` - assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected) + assert.Contains(t, ut.RenderLabels([]*issues.Label{label}, "/owner/repo", issue), expected) } func TestUserMention(t *testing.T) { - rendered := RenderMarkdownToHtml(context.Background(), "@no-such-user @mention-user @mention-user") + rendered := newTestRenderUtils().MarkdownToHtml("@no-such-user @mention-user @mention-user") assert.EqualValues(t, `<p>@no-such-user <a href="/mention-user" rel="nofollow">@mention-user</a> <a href="/mention-user" rel="nofollow">@mention-user</a></p>`, strings.TrimSpace(string(rendered))) } |