Skip to content

Commit db19c18

Browse files
committed
start using template ctx
1 parent fc6c3d6 commit db19c18

File tree

12 files changed

+91
-22
lines changed

12 files changed

+91
-22
lines changed

modules/context/context.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package context
66

77
import (
8+
"context"
89
"html"
910
"html/template"
1011
"io"
@@ -31,14 +32,16 @@ import (
3132

3233
// Render represents a template render
3334
type Render interface {
34-
TemplateLookup(tmpl string) (templates.TemplateExecutor, error)
35-
HTML(w io.Writer, status int, name string, data any) error
35+
TemplateLookup(tmpl string, templateCtx context.Context) (templates.TemplateExecutor, error)
36+
HTML(w io.Writer, status int, name string, data any, templateCtx context.Context) error
3637
}
3738

3839
// Context represents context of a request.
3940
type Context struct {
4041
*Base
4142

43+
TemplateContext TemplateContext
44+
4245
Render Render
4346
PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
4447

@@ -60,6 +63,8 @@ type Context struct {
6063
Package *Package
6164
}
6265

66+
type TemplateContext map[string]any
67+
6368
func init() {
6469
web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider {
6570
return req.Context().Value(WebContextKey).(*Context)
@@ -133,8 +138,12 @@ func Contexter() func(next http.Handler) http.Handler {
133138
}
134139
defer baseCleanUp()
135140

141+
// TODO: "install.go" also shares the same logic, which should be refactored to a general function
142+
ctx.TemplateContext = NewTemplateContext(ctx)
143+
ctx.TemplateContext["Locale"] = ctx.Locale
144+
136145
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
137-
ctx.Data["Context"] = &ctx
146+
ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this
138147
ctx.Data["CurrentURL"] = setting.AppSubURL + req.URL.RequestURI()
139148
ctx.Data["Link"] = ctx.Link
140149
ctx.Data["locale"] = ctx.Locale

modules/context/context_response.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
7575
return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
7676
}
7777

78-
err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data)
78+
err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext)
7979
if err == nil {
8080
return
8181
}
@@ -93,7 +93,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
9393
// RenderToString renders the template content to a string
9494
func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) {
9595
var buf strings.Builder
96-
err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data)
96+
err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data, ctx.TemplateContext)
9797
return buf.String(), err
9898
}
9999

modules/context/context_template.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package context
5+
6+
import (
7+
"context"
8+
"errors"
9+
"time"
10+
11+
"code.gitea.io/gitea/modules/log"
12+
)
13+
14+
var _ context.Context = TemplateContext(nil)
15+
16+
func NewTemplateContext(ctx context.Context) TemplateContext {
17+
return TemplateContext{"_ctx": ctx}
18+
}
19+
20+
func (c TemplateContext) parentContext() context.Context {
21+
return c["_ctx"].(context.Context)
22+
}
23+
24+
func (c TemplateContext) Deadline() (deadline time.Time, ok bool) {
25+
return c.parentContext().Deadline()
26+
}
27+
28+
func (c TemplateContext) Done() <-chan struct{} {
29+
return c.parentContext().Done()
30+
}
31+
32+
func (c TemplateContext) Err() error {
33+
return c.parentContext().Err()
34+
}
35+
36+
func (c TemplateContext) Value(key any) any {
37+
return c.parentContext().Value(key)
38+
}
39+
40+
// DataRaceCheck checks whether the template context function "ctx()" returns the consistent context
41+
// as the current template's rendering context (request context), to help to find data race issues as early as possible.
42+
// When the code is proven to be correct and stable, this function should be removed.
43+
func (c TemplateContext) DataRaceCheck(dataCtx context.Context) (string, error) {
44+
if c.parentContext() != dataCtx {
45+
log.Error("TemplateContext.DataRaceCheck: parent context mismatch\n%s", log.Stack(2))
46+
return "", errors.New("parent context mismatch")
47+
}
48+
return "", nil
49+
}

modules/templates/helper.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
// NewFuncMap returns functions for injecting to templates
2929
func NewFuncMap() template.FuncMap {
3030
return map[string]any{
31+
"ctx": func() any { return nil }, // template context function
32+
3133
"DumpVar": dumpVar,
3234

3335
// -----------------------------------------------------------------

modules/templates/htmlrenderer.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package templates
66
import (
77
"bufio"
88
"bytes"
9+
"context"
910
"errors"
1011
"fmt"
1112
"io"
@@ -39,27 +40,28 @@ var (
3940

4041
var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors")
4142

42-
func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any) error {
43+
func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any, ctx context.Context) error { //nolint:revive
4344
if respWriter, ok := w.(http.ResponseWriter); ok {
4445
if respWriter.Header().Get("Content-Type") == "" {
4546
respWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
4647
}
4748
respWriter.WriteHeader(status)
4849
}
49-
t, err := h.TemplateLookup(name)
50+
t, err := h.TemplateLookup(name, ctx)
5051
if err != nil {
5152
return texttemplate.ExecError{Name: name, Err: err}
5253
}
5354
return t.Execute(w, data)
5455
}
5556

56-
func (h *HTMLRender) TemplateLookup(name string) (TemplateExecutor, error) {
57+
func (h *HTMLRender) TemplateLookup(name string, ctx context.Context) (TemplateExecutor, error) { //nolint:revive
5758
tmpls := h.templates.Load()
5859
if tmpls == nil {
5960
return nil, ErrTemplateNotInitialized
6061
}
61-
62-
return tmpls.Executor(name, NewFuncMap())
62+
m := NewFuncMap()
63+
m["ctx"] = func() any { return ctx }
64+
return tmpls.Executor(name, m)
6365
}
6466

6567
func (h *HTMLRender) CompileTemplates() error {

modules/test/context_tests.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,11 @@ func LoadGitRepo(t *testing.T, ctx *context.Context) {
150150

151151
type mockRender struct{}
152152

153-
func (tr *mockRender) TemplateLookup(tmpl string) (templates.TemplateExecutor, error) {
153+
func (tr *mockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) {
154154
return nil, nil
155155
}
156156

157-
func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any) error {
157+
func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error {
158158
if resp, ok := w.(http.ResponseWriter); ok {
159159
resp.WriteHeader(status)
160160
}

routers/common/errpage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) {
4848
data["ErrorMsg"] = "PANIC: " + combinedErr
4949
}
5050

51-
err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data)
51+
err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data, nil)
5252
if err != nil {
5353
log.Error("Error occurs again when rendering error page: %v", err)
5454
w.WriteHeader(http.StatusInternalServerError)

routers/install/install.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ func Contexter() func(next http.Handler) http.Handler {
6868
}
6969
defer baseCleanUp()
7070

71+
ctx.TemplateContext = context.NewTemplateContext(ctx)
72+
ctx.TemplateContext["Locale"] = ctx.Locale
73+
7174
ctx.AppendContextValue(context.WebContextKey, ctx)
7275
ctx.Data.MergeFrom(middleware.CommonTemplateContextData())
7376
ctx.Data.MergeFrom(middleware.ContextData{
77+
"Context": ctx, // TODO: use "ctx" in template and remove this
7478
"locale": ctx.Locale,
7579
"Title": ctx.Locale.Tr("install.install"),
7680
"PageIsInstall": true,

routers/web/auth/oauth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ func GrantApplicationOAuth(ctx *context.Context) {
578578

579579
// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
580580
func OIDCWellKnown(ctx *context.Context) {
581-
t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown")
581+
t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown", nil)
582582
if err != nil {
583583
ctx.ServerError("unable to find template", err)
584584
return

routers/web/swagger_json.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const tplSwaggerV1Json base.TplName = "swagger/v1_json"
1313

1414
// SwaggerV1Json render swagger v1 json
1515
func SwaggerV1Json(ctx *context.Context) {
16-
t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json))
16+
t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json), nil)
1717
if err != nil {
1818
ctx.ServerError("unable to find template", err)
1919
return

templates/base/footer.tmpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
{{end}}
2727
{{end}}
2828
<script src="{{AssetUrlPrefix}}/js/index.js?v={{AssetVersion}}" onerror="alert('Failed to load asset files from ' + this.src + '. Please make sure the asset files can be accessed.')"></script>
29-
{{template "custom/footer" .}}
29+
30+
{{template "custom/footer" .}}
31+
{{ctx.DataRaceCheck $.Context}}
3032
</body>
3133
</html>

templates/base/head.tmpl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="{{.locale.Lang}}" class="theme-{{if .SignedUser.Theme}}{{.SignedUser.Theme}}{{else}}{{DefaultTheme}}{{end}}">
2+
<html lang="{{ctx.Locale.Lang}}" class="theme-{{if .SignedUser.Theme}}{{.SignedUser.Theme}}{{else}}{{DefaultTheme}}{{end}}">
33
<head>
44
<meta name="viewport" content="width=device-width, initial-scale=1">
55
<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
@@ -28,7 +28,7 @@
2828
{{if .PageIsUserProfile}}
2929
<meta property="og:title" content="{{.ContextUser.DisplayName}}">
3030
<meta property="og:type" content="profile">
31-
<meta property="og:image" content="{{.ContextUser.AvatarLink $.Context}}">
31+
<meta property="og:image" content="{{.ContextUser.AvatarLink ctx}}">
3232
<meta property="og:url" content="{{.ContextUser.HTMLURL}}">
3333
{{if .ContextUser.Description}}
3434
<meta property="og:description" content="{{.ContextUser.Description}}">
@@ -48,10 +48,10 @@
4848
{{end}}
4949
{{end}}
5050
<meta property="og:type" content="object">
51-
{{if (.Repository.AvatarLink $.Context)}}
52-
<meta property="og:image" content="{{.Repository.AvatarLink $.Context}}">
51+
{{if (.Repository.AvatarLink ctx)}}
52+
<meta property="og:image" content="{{.Repository.AvatarLink ctx}}">
5353
{{else}}
54-
<meta property="og:image" content="{{.Repository.Owner.AvatarLink $.Context}}">
54+
<meta property="og:image" content="{{.Repository.Owner.AvatarLink ctx}}">
5555
{{end}}
5656
{{else}}
5757
<meta property="og:title" content="{{AppName}}">
@@ -65,10 +65,11 @@
6565
{{template "custom/header" .}}
6666
</head>
6767
<body>
68+
{{ctx.DataRaceCheck $.Context}}
6869
{{template "custom/body_outer_pre" .}}
6970

7071
<div class="full height">
71-
<noscript>{{.locale.Tr "enable_javascript"}}</noscript>
72+
<noscript>{{ctx.Locale.Tr "enable_javascript"}}</noscript>
7273

7374
{{template "custom/body_inner_pre" .}}
7475

0 commit comments

Comments
 (0)