Skip to content

Commit 0ccc3ae

Browse files
committed
fix
1 parent 376396a commit 0ccc3ae

16 files changed

+162
-171
lines changed

modules/templates/helper.go

+5-80
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"bytes"
99
"context"
1010
"encoding/hex"
11-
"errors"
1211
"fmt"
1312
"html"
1413
"html/template"
@@ -265,20 +264,6 @@ func NewFuncMap() []template.FuncMap {
265264
"DisableImportLocal": func() bool {
266265
return !setting.ImportLocalPaths
267266
},
268-
"Dict": func(values ...interface{}) (map[string]interface{}, error) {
269-
if len(values)%2 != 0 {
270-
return nil, errors.New("invalid dict call")
271-
}
272-
dict := make(map[string]interface{}, len(values)/2)
273-
for i := 0; i < len(values); i += 2 {
274-
key, ok := values[i].(string)
275-
if !ok {
276-
return nil, errors.New("dict keys must be strings")
277-
}
278-
dict[key] = values[i+1]
279-
}
280-
return dict, nil
281-
},
282267
"Printf": fmt.Sprintf,
283268
"Escape": Escape,
284269
"Sec2Time": util.SecToTime,
@@ -288,28 +273,7 @@ func NewFuncMap() []template.FuncMap {
288273
"DefaultTheme": func() string {
289274
return setting.UI.DefaultTheme
290275
},
291-
// pass key-value pairs to a partial template which receives them as a dict
292-
"dict": func(values ...interface{}) (map[string]interface{}, error) {
293-
if len(values) == 0 {
294-
return nil, errors.New("invalid dict call")
295-
}
296-
297-
dict := make(map[string]interface{})
298-
return util.MergeInto(dict, values...)
299-
},
300-
/* like dict but merge key-value pairs into the first dict and return it */
301-
"mergeinto": func(root map[string]interface{}, values ...interface{}) (map[string]interface{}, error) {
302-
if len(values) == 0 {
303-
return nil, errors.New("invalid mergeinto call")
304-
}
305-
306-
dict := make(map[string]interface{})
307-
for key, value := range root {
308-
dict[key] = value
309-
}
310-
311-
return util.MergeInto(dict, values...)
312-
},
276+
"dict": dict,
313277
"percentage": func(n int, values ...int) float32 {
314278
sum := 0
315279
for i := 0; i < len(values); i++ {
@@ -483,52 +447,13 @@ func NewTextFuncMap() []texttmpl.FuncMap {
483447
},
484448
"EllipsisString": base.EllipsisString,
485449
"URLJoin": util.URLJoin,
486-
"Dict": func(values ...interface{}) (map[string]interface{}, error) {
487-
if len(values)%2 != 0 {
488-
return nil, errors.New("invalid dict call")
489-
}
490-
dict := make(map[string]interface{}, len(values)/2)
491-
for i := 0; i < len(values); i += 2 {
492-
key, ok := values[i].(string)
493-
if !ok {
494-
return nil, errors.New("dict keys must be strings")
495-
}
496-
dict[key] = values[i+1]
497-
}
498-
return dict, nil
499-
},
500-
"Printf": fmt.Sprintf,
501-
"Escape": Escape,
502-
"Sec2Time": util.SecToTime,
450+
"Printf": fmt.Sprintf,
451+
"Escape": Escape,
452+
"Sec2Time": util.SecToTime,
503453
"ParseDeadline": func(deadline string) []string {
504454
return strings.Split(deadline, "|")
505455
},
506-
"dict": func(values ...interface{}) (map[string]interface{}, error) {
507-
if len(values) == 0 {
508-
return nil, errors.New("invalid dict call")
509-
}
510-
511-
dict := make(map[string]interface{})
512-
513-
for i := 0; i < len(values); i++ {
514-
switch key := values[i].(type) {
515-
case string:
516-
i++
517-
if i == len(values) {
518-
return nil, errors.New("specify the key for non array values")
519-
}
520-
dict[key] = values[i]
521-
case map[string]interface{}:
522-
m := values[i].(map[string]interface{})
523-
for i, v := range m {
524-
dict[i] = v
525-
}
526-
default:
527-
return nil, errors.New("dict values must be maps")
528-
}
529-
}
530-
return dict, nil
531-
},
456+
"dict": dict,
532457
"percentage": func(n int, values ...int) float32 {
533458
sum := 0
534459
for i := 0; i < len(values); i++ {

modules/templates/util.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package templates
5+
6+
import (
7+
"fmt"
8+
"reflect"
9+
)
10+
11+
func dictMerge(base map[string]any, arg any) bool {
12+
if arg == nil {
13+
return true
14+
}
15+
rv := reflect.ValueOf(arg)
16+
if rv.Kind() == reflect.Map {
17+
for _, k := range rv.MapKeys() {
18+
base[k.String()] = rv.MapIndex(k).Interface()
19+
}
20+
return true
21+
}
22+
return false
23+
}
24+
25+
// dict is a helper function for creating a map[string]any from a list of key-value pairs.
26+
// If the key is dot ".", the value is merged into the base map, just like Golang template's dot syntax: dot means current
27+
// The dot syntax is highly discouraged, because it might case unclear key conflicts. It's always good use explicit keys.
28+
func dict(args ...any) (map[string]any, error) {
29+
if len(args)%2 != 0 {
30+
return nil, fmt.Errorf("invalid dict constructor syntax: must have key-value pairs")
31+
}
32+
m := make(map[string]any, len(args)/2)
33+
for i := 0; i < len(args); i += 2 {
34+
key, ok := args[i].(string)
35+
if !ok {
36+
return nil, fmt.Errorf("invalid dict constructor syntax: unable to merge args[%d]", i)
37+
}
38+
if key == "." {
39+
if ok = dictMerge(m, args[i+1]); !ok {
40+
return nil, fmt.Errorf("invalid dict constructor syntax: dot arg[%d] must be followed by a dict", i)
41+
}
42+
} else {
43+
m[key] = args[i+1]
44+
}
45+
}
46+
return m, nil
47+
}

modules/templates/util_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package templates
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestDict(t *testing.T) {
13+
type M map[string]any
14+
cases := []struct {
15+
args []any
16+
want map[string]any
17+
}{
18+
{[]any{"a", 1, "b", 2}, M{"a": 1, "b": 2}},
19+
{[]any{".", M{"base": 1}, "b", 2}, M{"base": 1, "b": 2}},
20+
{[]any{"a", 1, ".", M{"extra": 2}}, M{"a": 1, "extra": 2}},
21+
{[]any{"a", 1, ".", map[string]int{"int": 2}}, M{"a": 1, "int": 2}},
22+
{[]any{".", nil, "b", 2}, M{"b": 2}},
23+
}
24+
25+
for _, c := range cases {
26+
got, err := dict(c.args...)
27+
if assert.NoError(t, err) {
28+
assert.EqualValues(t, c.want, got)
29+
}
30+
}
31+
32+
bads := []struct {
33+
args []any
34+
}{
35+
{[]any{"a", 1, "b"}},
36+
{[]any{1}},
37+
{[]any{struct{}{}}},
38+
}
39+
for _, c := range bads {
40+
_, err := dict(c.args...)
41+
assert.Error(t, err)
42+
}
43+
}

modules/util/util.go

-24
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package util
66
import (
77
"bytes"
88
"crypto/rand"
9-
"errors"
109
"fmt"
1110
"math/big"
1211
"os"
@@ -118,29 +117,6 @@ func NormalizeEOL(input []byte) []byte {
118117
return tmp[:pos]
119118
}
120119

121-
// MergeInto merges pairs of values into a "dict"
122-
func MergeInto(dict map[string]interface{}, values ...interface{}) (map[string]interface{}, error) {
123-
for i := 0; i < len(values); i++ {
124-
switch key := values[i].(type) {
125-
case string:
126-
i++
127-
if i == len(values) {
128-
return nil, errors.New("specify the key for non array values")
129-
}
130-
dict[key] = values[i]
131-
case map[string]interface{}:
132-
m := values[i].(map[string]interface{})
133-
for i, v := range m {
134-
dict[i] = v
135-
}
136-
default:
137-
return nil, errors.New("dict values must be maps")
138-
}
139-
}
140-
141-
return dict, nil
142-
}
143-
144120
// CryptoRandomInt returns a crypto random integer between 0 and limit, inclusive
145121
func CryptoRandomInt(limit int64) (int64, error) {
146122
rInt, err := rand.Int(rand.Reader, big.NewInt(limit))

templates/org/team/teams.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
</div>
3333
<div class="ui attached segment members">
3434
{{range .Members}}
35-
{{template "shared/user/avatarlink" Dict "Context" $.Context "user" .}}
35+
{{template "shared/user/avatarlink" dict "Context" $.Context "user" .}}
3636
{{end}}
3737
</div>
3838
<div class="ui bottom attached header">

templates/repo/diff/comments.tmpl

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{{if .OriginalAuthor}}
66
<span class="avatar"><img src="{{AppSubUrl}}/assets/img/avatar_default.png"></span>
77
{{else}}
8-
{{template "shared/user/avatarlink" Dict "Context" $.root.Context "user" .Poster}}
8+
{{template "shared/user/avatarlink" dict "Context" $.root.Context "user" .Poster}}
99
{{end}}
1010
<div class="content comment-container">
1111
<div class="ui top attached header comment-header gt-df gt-ac gt-sb">
@@ -42,8 +42,8 @@
4242
</div>
4343
{{end}}
4444
{{end}}
45-
{{template "repo/issue/view_content/add_reaction" Dict "ctxData" $.root "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}}
46-
{{template "repo/issue/view_content/context_menu" Dict "ctxData" $.root "item" . "delete" true "issue" false "diff" true "IsCommentPoster" (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}
45+
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $.root "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}}
46+
{{template "repo/issue/view_content/context_menu" dict "ctxData" $.root "item" . "delete" true "issue" false "diff" true "IsCommentPoster" (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}
4747
</div>
4848
</div>
4949
<div class="ui attached segment comment-body">
@@ -60,7 +60,7 @@
6060
{{$reactions := .Reactions.GroupByType}}
6161
{{if $reactions}}
6262
<div class="ui attached segment reactions">
63-
{{template "repo/issue/view_content/reactions" Dict "ctxData" $.root "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}}
63+
{{template "repo/issue/view_content/reactions" dict "ctxData" $.root "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}}
6464
</div>
6565
{{end}}
6666
</div>

templates/repo/diff/section_split.tmpl

+6-6
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,22 @@
111111
<td class="add-comment-left" colspan="4">
112112
{{if gt (len $line.Comments) 0}}
113113
{{if eq $line.GetCommentSide "previous"}}
114-
{{template "repo/diff/conversation" mergeinto $.root "comments" $line.Comments}}
114+
{{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}}
115115
{{end}}
116116
{{end}}
117117
{{if gt (len $match.Comments) 0}}
118118
{{if eq $match.GetCommentSide "previous"}}
119-
{{template "repo/diff/conversation" mergeinto $.root "comments" $match.Comments}}
119+
{{template "repo/diff/conversation" dict "." $.root "comments" $match.Comments}}
120120
{{end}}
121121
{{end}}
122122
</td>
123123
<td class="add-comment-right" colspan="4">
124124
{{if eq $line.GetCommentSide "proposed"}}
125-
{{template "repo/diff/conversation" mergeinto $.root "comments" $line.Comments}}
125+
{{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}}
126126
{{end}}
127127
{{if gt (len $match.Comments) 0}}
128128
{{if eq $match.GetCommentSide "proposed"}}
129-
{{template "repo/diff/conversation" mergeinto $.root "comments" $match.Comments}}
129+
{{template "repo/diff/conversation" dict "." $.root "comments" $match.Comments}}
130130
{{end}}
131131
{{end}}
132132
</td>
@@ -137,13 +137,13 @@
137137
<td class="add-comment-left" colspan="4">
138138
{{if gt (len $line.Comments) 0}}
139139
{{if eq $line.GetCommentSide "previous"}}
140-
{{template "repo/diff/conversation" mergeinto $.root "comments" $line.Comments}}
140+
{{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}}
141141
{{end}}
142142
{{end}}
143143
</td>
144144
<td class="add-comment-right" colspan="4">
145145
{{if eq $line.GetCommentSide "proposed"}}
146-
{{template "repo/diff/conversation" mergeinto $.root "comments" $line.Comments}}
146+
{{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}}
147147
{{end}}
148148
</td>
149149
</tr>

templates/repo/diff/section_unified.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
{{if gt (len $line.Comments) 0}}
5858
<tr class="add-comment" data-line-type="{{DiffLineTypeToStr .GetType}}">
5959
<td class="add-comment-left add-comment-right" colspan="5">
60-
{{template "repo/diff/conversation" mergeinto $.root "comments" $line.Comments}}
60+
{{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}}
6161
</td>
6262
</tr>
6363
{{end}}

templates/repo/issue/list.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@
308308
</div>
309309
</div>
310310
</div>
311-
{{template "shared/issuelist" mergeinto . "listType" "repo"}}
311+
{{template "shared/issuelist" dict "." . "listType" "repo"}}
312312
</div>
313313
</div>
314314
{{template "base/footer" .}}

templates/repo/issue/milestone_issues.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@
199199
</div>
200200
</div>
201201
</div>
202-
{{template "shared/issuelist" mergeinto . "listType" "milestone"}}
202+
{{template "shared/issuelist" dict "." . "listType" "milestone"}}
203203
</div>
204204
</div>
205205
{{template "base/footer" .}}

templates/repo/issue/new_form.tmpl

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<div class="twelve wide column">
99
<div class="ui comments">
1010
<div class="comment">
11-
{{template "shared/user/avatarlink" Dict "Context" $.Context "user" .SignedUser}}
11+
{{template "shared/user/avatarlink" dict "Context" $.Context "user" .SignedUser}}
1212
<div class="ui segment content">
1313
<div class="field">
1414
<input name="title" id="issue_title" placeholder="{{.locale.Tr "repo.milestones.title"}}" value="{{if .TitleQuery}}{{.TitleQuery}}{{else if .IssueTemplateTitle}}{{.IssueTemplateTitle}}{{else}}{{.title}}{{end}}" tabindex="3" autofocus required maxlength="255" autocomplete="off">
@@ -20,15 +20,15 @@
2020
<input type="hidden" name="template-file" value="{{.TemplateFile}}">
2121
{{range .Fields}}
2222
{{if eq .Type "input"}}
23-
{{template "repo/issue/fields/input" Dict "Context" $.Context "item" .}}
23+
{{template "repo/issue/fields/input" dict "Context" $.Context "item" .}}
2424
{{else if eq .Type "markdown"}}
25-
{{template "repo/issue/fields/markdown" Dict "Context" $.Context "item" .}}
25+
{{template "repo/issue/fields/markdown" dict "Context" $.Context "item" .}}
2626
{{else if eq .Type "textarea"}}
27-
{{template "repo/issue/fields/textarea" Dict "Context" $.Context "item" .}}
27+
{{template "repo/issue/fields/textarea" dict "Context" $.Context "item" .}}
2828
{{else if eq .Type "dropdown"}}
29-
{{template "repo/issue/fields/dropdown" Dict "Context" $.Context "item" .}}
29+
{{template "repo/issue/fields/dropdown" dict "Context" $.Context "item" .}}
3030
{{else if eq .Type "checkboxes"}}
31-
{{template "repo/issue/fields/checkboxes" Dict "Context" $.Context "item" .}}
31+
{{template "repo/issue/fields/checkboxes" dict "Context" $.Context "item" .}}
3232
{{end}}
3333
{{end}}
3434
{{if .IsAttachmentEnabled}}

0 commit comments

Comments
 (0)