mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 12:37:14 -04:00 
			
		
		
		
	Backport Iif (#31353)
This commit is contained in:
		| @@ -9,6 +9,7 @@ import ( | ||||
| 	"html" | ||||
| 	"html/template" | ||||
| 	"net/url" | ||||
| 	"reflect" | ||||
| 	"slices" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| @@ -237,8 +238,8 @@ func DotEscape(raw string) string { | ||||
|  | ||||
| // Iif is an "inline-if", similar util.Iif[T] but templates need the non-generic version, | ||||
| // and it could be simply used as "{{Iif expr trueVal}}" (omit the falseVal). | ||||
| func Iif(condition bool, vals ...any) any { | ||||
| 	if condition { | ||||
| func Iif(condition any, vals ...any) any { | ||||
| 	if isTemplateTruthy(condition) { | ||||
| 		return vals[0] | ||||
| 	} else if len(vals) > 1 { | ||||
| 		return vals[1] | ||||
| @@ -246,6 +247,32 @@ func Iif(condition bool, vals ...any) any { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func isTemplateTruthy(v any) bool { | ||||
| 	if v == nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	rv := reflect.ValueOf(v) | ||||
| 	switch rv.Kind() { | ||||
| 	case reflect.Bool: | ||||
| 		return rv.Bool() | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		return rv.Int() != 0 | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 		return rv.Uint() != 0 | ||||
| 	case reflect.Float32, reflect.Float64: | ||||
| 		return rv.Float() != 0 | ||||
| 	case reflect.Complex64, reflect.Complex128: | ||||
| 		return rv.Complex() != 0 | ||||
| 	case reflect.String, reflect.Slice, reflect.Array, reflect.Map: | ||||
| 		return rv.Len() > 0 | ||||
| 	case reflect.Struct: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return !rv.IsNil() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Eval the expression and return the result, see the comment of eval.Expr for details. | ||||
| // To use this helper function in templates, pass each token as a separate parameter. | ||||
| // | ||||
|   | ||||
| @@ -5,8 +5,11 @@ package templates | ||||
|  | ||||
| import ( | ||||
| 	"html/template" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| @@ -65,3 +68,41 @@ func TestHTMLFormat(t *testing.T) { | ||||
| func TestSanitizeHTML(t *testing.T) { | ||||
| 	assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`)) | ||||
| } | ||||
|  | ||||
| func TestTemplateTruthy(t *testing.T) { | ||||
| 	tmpl := template.New("test") | ||||
| 	tmpl.Funcs(template.FuncMap{"Iif": Iif}) | ||||
| 	template.Must(tmpl.Parse(`{{if .Value}}true{{else}}false{{end}}:{{Iif .Value "true" "false"}}`)) | ||||
|  | ||||
| 	cases := []any{ | ||||
| 		nil, false, true, "", "string", 0, 1, | ||||
| 		byte(0), byte(1), int64(0), int64(1), float64(0), float64(1), | ||||
| 		complex(0, 0), complex(1, 0), | ||||
| 		(chan int)(nil), make(chan int), | ||||
| 		(func())(nil), func() {}, | ||||
| 		util.ToPointer(0), util.ToPointer(util.ToPointer(0)), | ||||
| 		util.ToPointer(1), util.ToPointer(util.ToPointer(1)), | ||||
| 		[0]int{}, | ||||
| 		[1]int{0}, | ||||
| 		[]int(nil), | ||||
| 		[]int{}, | ||||
| 		[]int{0}, | ||||
| 		map[any]any(nil), | ||||
| 		map[any]any{}, | ||||
| 		map[any]any{"k": "v"}, | ||||
| 		(*struct{})(nil), | ||||
| 		struct{}{}, | ||||
| 		util.ToPointer(struct{}{}), | ||||
| 	} | ||||
| 	w := &strings.Builder{} | ||||
| 	truthyCount := 0 | ||||
| 	for i, v := range cases { | ||||
| 		w.Reset() | ||||
| 		assert.NoError(t, tmpl.Execute(w, struct{ Value any }{v}), "case %d (%T) %#v fails", i, v, v) | ||||
| 		out := w.String() | ||||
| 		truthyCount += util.Iif(out == "true:true", 1, 0) | ||||
| 		truthyMatches := out == "true:true" || out == "false:false" | ||||
| 		assert.True(t, truthyMatches, "case %d (%T) %#v fail: %s", i, v, v, out) | ||||
| 	} | ||||
| 	assert.True(t, truthyCount != 0 && truthyCount != len(cases)) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user