mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 11:28:24 +00:00 
			
		
		
		
	Refactor template helper (#34819)
FIx abuses and remove unused code --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
		| @@ -7,6 +7,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"slices" | 	"slices" | ||||||
|  | 	"strings" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ParseSizeAndClass get size and class from string with default values | // ParseSizeAndClass get size and class from string with default values | ||||||
| @@ -31,6 +32,9 @@ func ParseSizeAndClass(defaultSize int, defaultClass string, others ...any) (int | |||||||
| } | } | ||||||
|  |  | ||||||
| func HTMLFormat(s template.HTML, rawArgs ...any) template.HTML { | func HTMLFormat(s template.HTML, rawArgs ...any) template.HTML { | ||||||
|  | 	if !strings.Contains(string(s), "%") || len(rawArgs) == 0 { | ||||||
|  | 		panic("HTMLFormat requires one or more arguments") | ||||||
|  | 	} | ||||||
| 	args := slices.Clone(rawArgs) | 	args := slices.Clone(rawArgs) | ||||||
| 	for i, v := range args { | 	for i, v := range args { | ||||||
| 		switch v := v.(type) { | 		switch v := v.(type) { | ||||||
|   | |||||||
| @@ -51,8 +51,8 @@ func (r *BlockRenderer) writeLines(w util.BufWriter, source []byte, n gast.Node) | |||||||
| func (r *BlockRenderer) renderBlock(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { | func (r *BlockRenderer) renderBlock(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { | ||||||
| 	n := node.(*Block) | 	n := node.(*Block) | ||||||
| 	if entering { | 	if entering { | ||||||
| 		code := giteaUtil.Iif(n.Inline, "", `<pre class="code-block is-loading">`) + `<code class="language-math display">` | 		codeHTML := giteaUtil.Iif[template.HTML](n.Inline, "", `<pre class="code-block is-loading">`) + `<code class="language-math display">` | ||||||
| 		_ = r.renderInternal.FormatWithSafeAttrs(w, template.HTML(code)) | 		_, _ = w.WriteString(string(r.renderInternal.ProtectSafeAttrs(codeHTML))) | ||||||
| 		r.writeLines(w, source, n) | 		r.writeLines(w, source, n) | ||||||
| 	} else { | 	} else { | ||||||
| 		_, _ = w.WriteString(`</code>` + giteaUtil.Iif(n.Inline, "", `</pre>`) + "\n") | 		_, _ = w.WriteString(`</code>` + giteaUtil.Iif(n.Inline, "", `</pre>`) + "\n") | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ func NewInlineRenderer(renderInternal *internal.RenderInternal) renderer.NodeRen | |||||||
|  |  | ||||||
| func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { | func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { | ||||||
| 	if entering { | 	if entering { | ||||||
| 		_ = r.renderInternal.FormatWithSafeAttrs(w, `<code class="language-math">`) | 		_, _ = w.WriteString(string(r.renderInternal.ProtectSafeAttrs(`<code class="language-math">`))) | ||||||
| 		for c := n.FirstChild(); c != nil; c = c.NextSibling() { | 		for c := n.FirstChild(); c != nil; c = c.NextSibling() { | ||||||
| 			segment := c.(*ast.Text).Segment | 			segment := c.(*ast.Text).Segment | ||||||
| 			value := util.EscapeHTML(segment.Value(source)) | 			value := util.EscapeHTML(segment.Value(source)) | ||||||
|   | |||||||
| @@ -6,7 +6,6 @@ package templates | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"html" |  | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| @@ -38,9 +37,7 @@ func NewFuncMap() template.FuncMap { | |||||||
| 		"dict":         dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names. | 		"dict":         dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names. | ||||||
| 		"Iif":          iif, | 		"Iif":          iif, | ||||||
| 		"Eval":         evalTokens, | 		"Eval":         evalTokens, | ||||||
| 		"SafeHTML":     safeHTML, |  | ||||||
| 		"HTMLFormat":   htmlFormat, | 		"HTMLFormat":   htmlFormat, | ||||||
| 		"HTMLEscape":   htmlEscape, |  | ||||||
| 		"QueryEscape":  queryEscape, | 		"QueryEscape":  queryEscape, | ||||||
| 		"QueryBuild":   QueryBuild, | 		"QueryBuild":   QueryBuild, | ||||||
| 		"JSEscape":     jsEscapeSafe, | 		"JSEscape":     jsEscapeSafe, | ||||||
| @@ -165,32 +162,11 @@ func NewFuncMap() template.FuncMap { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // safeHTML render raw as HTML |  | ||||||
| func safeHTML(s any) template.HTML { |  | ||||||
| 	switch v := s.(type) { |  | ||||||
| 	case string: |  | ||||||
| 		return template.HTML(v) |  | ||||||
| 	case template.HTML: |  | ||||||
| 		return v |  | ||||||
| 	} |  | ||||||
| 	panic(fmt.Sprintf("unexpected type %T", s)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // SanitizeHTML sanitizes the input by default sanitization rules. | // SanitizeHTML sanitizes the input by default sanitization rules. | ||||||
| func SanitizeHTML(s string) template.HTML { | func SanitizeHTML(s string) template.HTML { | ||||||
| 	return markup.Sanitize(s) | 	return markup.Sanitize(s) | ||||||
| } | } | ||||||
|  |  | ||||||
| func htmlEscape(s any) template.HTML { |  | ||||||
| 	switch v := s.(type) { |  | ||||||
| 	case string: |  | ||||||
| 		return template.HTML(html.EscapeString(v)) |  | ||||||
| 	case template.HTML: |  | ||||||
| 		return v |  | ||||||
| 	} |  | ||||||
| 	panic(fmt.Sprintf("unexpected type %T", s)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func htmlFormat(s any, args ...any) template.HTML { | func htmlFormat(s any, args ...any) template.HTML { | ||||||
| 	if len(args) == 0 { | 	if len(args) == 0 { | ||||||
| 		// to prevent developers from calling "HTMLFormat $userInput" by mistake which will lead to XSS | 		// to prevent developers from calling "HTMLFormat $userInput" by mistake which will lead to XSS | ||||||
|   | |||||||
| @@ -90,7 +90,7 @@ | |||||||
| 		{{ctx.Locale.Tr "packages.settings.delete"}} | 		{{ctx.Locale.Tr "packages.settings.delete"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		{{ctx.Locale.Tr "packages.settings.delete.notice" (`<span class="name"></span>`|SafeHTML) (`<span class="dataVersion"></span>`|SafeHTML)}} | 		{{ctx.Locale.Tr "packages.settings.delete.notice" (HTMLFormat `<span class="%s"></span>` "name") (HTMLFormat `<span class="%s"></span>` "dataVersion")}} | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -103,7 +103,7 @@ | |||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p> | 		<p>{{ctx.Locale.Tr "repo.settings.delete_desc"}}</p> | ||||||
| 		{{ctx.Locale.Tr "repo.settings.delete_notices_2" (`<span class="name"></span>`|SafeHTML)}}<br> | 		{{ctx.Locale.Tr "repo.settings.delete_notices_2" (HTMLFormat `<span class="%s"></span>` "name")}}<br> | ||||||
| 		{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}<br> | 		{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}<br> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ | |||||||
| 		{{ctx.Locale.Tr "org.members.leave"}} | 		{{ctx.Locale.Tr "org.members.leave"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|SafeHTML)}}</p> | 		<p>{{ctx.Locale.Tr "org.members.leave.detail" (HTMLFormat `<span class="%s"></span>` "dataOrganizationName")}}</p> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
| @@ -82,7 +82,7 @@ | |||||||
| 		{{ctx.Locale.Tr "org.members.remove"}} | 		{{ctx.Locale.Tr "org.members.remove"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|SafeHTML) (`<span class="dataOrganizationName"></span>`|SafeHTML)}}</p> | 		<p>{{ctx.Locale.Tr "org.members.remove.detail" (HTMLFormat `<span class="%s"></span>` "name") (HTMLFormat `<span class="%s"></span>` "dataOrganizationName")}}</p> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -81,7 +81,7 @@ | |||||||
| 		{{ctx.Locale.Tr "org.members.remove"}} | 		{{ctx.Locale.Tr "org.members.remove"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "org.members.remove.detail" (`<span class="name"></span>`|SafeHTML) (`<span class="dataTeamName"></span>`|SafeHTML)}}</p> | 		<p>{{ctx.Locale.Tr "org.members.remove.detail" (HTMLFormat `<span class="%s"></span>` "name") (HTMLFormat `<span class="%s"></span>` "dataTeamName")}}</p> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -90,7 +90,7 @@ | |||||||
| 		{{ctx.Locale.Tr "org.teams.leave"}} | 		{{ctx.Locale.Tr "org.teams.leave"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|SafeHTML)}}</p> | 		<p>{{ctx.Locale.Tr "org.teams.leave.detail" (HTMLFormat `<span class="%s"></span>` "name")}}</p> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -49,7 +49,7 @@ | |||||||
| 		{{ctx.Locale.Tr "org.teams.leave"}} | 		{{ctx.Locale.Tr "org.teams.leave"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "org.teams.leave.detail" (`<span class="name"></span>`|SafeHTML)}}</p> | 		<p>{{ctx.Locale.Tr "org.teams.leave.detail" (HTMLFormat `<span class="%s"></span>` "name")}}</p> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -75,7 +75,7 @@ | |||||||
| 												{{.CsrfTokenHtml}} | 												{{.CsrfTokenHtml}} | ||||||
| 												<div class="field"> | 												<div class="field"> | ||||||
| 													<label> | 													<label> | ||||||
| 														{{ctx.Locale.Tr "repo.branch.new_branch_from" (`<span class="text" id="modal-create-branch-from-span"></span>`|SafeHTML)}} | 														{{ctx.Locale.Tr "repo.branch.new_branch_from" (HTMLFormat `<span class="%s" id="%s"></span>` "text" "modal-create-branch-from-span")}} | ||||||
| 													</label> | 													</label> | ||||||
| 												</div> | 												</div> | ||||||
| 												<div class="required field"> | 												<div class="required field"> | ||||||
| @@ -100,7 +100,7 @@ | |||||||
| 												<input type="hidden" name="create_tag" value="true"> | 												<input type="hidden" name="create_tag" value="true"> | ||||||
| 												<div class="field"> | 												<div class="field"> | ||||||
| 													<label> | 													<label> | ||||||
| 														{{ctx.Locale.Tr "repo.tag.create_tag_from" (`<span class="text" id="modal-create-tag-from-span"></span>`|SafeHTML)}} | 														{{ctx.Locale.Tr "repo.tag.create_tag_from" (HTMLFormat `<span class="%s" id="%s"></span>` "text" "modal-create-tag-from-span")}} | ||||||
| 													</label> | 													</label> | ||||||
| 												</div> | 												</div> | ||||||
| 												<div class="required field"> | 												<div class="required field"> | ||||||
|   | |||||||
| @@ -163,6 +163,7 @@ | |||||||
| 				</span> | 				</span> | ||||||
| 				<div class="detail flex-text-block"> | 				<div class="detail flex-text-block"> | ||||||
| 					{{svg "octicon-git-commit"}} | 					{{svg "octicon-git-commit"}} | ||||||
|  | 					{{/* the content is a link like <a href="{RepoLink}/commit/{CommitID}">message title</a> (from CreateRefComment) */}} | ||||||
| 					<span class="text grey muted-links">{{.Content | SanitizeHTML}}</span> | 					<span class="text grey muted-links">{{.Content | SanitizeHTML}}</span> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|   | |||||||
| @@ -298,7 +298,7 @@ | |||||||
| 	<label for="authorization_header">{{ctx.Locale.Tr "repo.settings.authorization_header"}}</label> | 	<label for="authorization_header">{{ctx.Locale.Tr "repo.settings.authorization_header"}}</label> | ||||||
| 	<input id="authorization_header" name="authorization_header" type="text" value="{{.Webhook.HeaderAuthorization}}"{{if eq .HookType "matrix"}} placeholder="Bearer $access_token" required{{end}}> | 	<input id="authorization_header" name="authorization_header" type="text" value="{{.Webhook.HeaderAuthorization}}"{{if eq .HookType "matrix"}} placeholder="Bearer $access_token" required{{end}}> | ||||||
| 	{{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}} | 	{{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}} | ||||||
| 		<span class="help">{{ctx.Locale.Tr "repo.settings.authorization_header_desc" ("<code>Bearer token123456</code>, <code>Basic YWxhZGRpbjpvcGVuc2VzYW1l</code>" | SafeHTML)}}</span> | 		<span class="help">{{ctx.Locale.Tr "repo.settings.authorization_header_desc" (HTMLFormat "<code>%s</code>, <code>%s</code>" "Bearer token123456" "Basic YWxhZGRpbjpvcGVuc2VzYW1l")}}</span> | ||||||
| 	{{end}} | 	{{end}} | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ | |||||||
| 						</label> | 						</label> | ||||||
| 					</div> | 					</div> | ||||||
| 					<div> | 					<div> | ||||||
| 						<div class="tw-my-2">{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (`href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`|SafeHTML)}}</div> | 						<div class="tw-my-2">{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (HTMLFormat `href="%s" target="_blank"` "https://docs.gitea.com/development/oauth2-provider#scopes")}}</div> | ||||||
| 						<table class="ui table unstackable tw-my-2"> | 						<table class="ui table unstackable tw-my-2"> | ||||||
| 						{{range $category := .TokenCategories}} | 						{{range $category := .TokenCategories}} | ||||||
| 							<tr> | 							<tr> | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ | |||||||
| 		{{ctx.Locale.Tr "org.members.leave"}} | 		{{ctx.Locale.Tr "org.members.leave"}} | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="content"> | 	<div class="content"> | ||||||
| 		<p>{{ctx.Locale.Tr "org.members.leave.detail" (`<span class="dataOrganizationName"></span>`|SafeHTML)}}</p> | 		<p>{{ctx.Locale.Tr "org.members.leave.detail" (HTMLFormat `<span class="%s"></span>` "dataOrganizationName")}}</p> | ||||||
| 	</div> | 	</div> | ||||||
| 	{{template "base/modal_actions_confirm" .}} | 	{{template "base/modal_actions_confirm" .}} | ||||||
| </div> | </div> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user