mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Backport #23281 This branch continues the work of #23092 and attempts to rid the codebase of any `nil` contexts when using a `RenderContext`. Anything that renders markdown or does post processing may call `markup.sha1CurrentPatternProcessor()`, and this runs `git.OpenRepository()`, which needs a context. It will panic if the context is `nil`. This branch attempts to _always_ include a context when creating a `RenderContext` to prevent future crashes. Co-authored-by: Jonathan Tran <jon@allspice.io>
This commit is contained in:
		@@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/markup"
 | 
						"code.gitea.io/gitea/modules/markup"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
@@ -229,7 +230,10 @@ John Doe	john@doe.com	This,note,had,a,lot,of,commas,to,test,delimiters`,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for n, c := range cases {
 | 
						for n, c := range cases {
 | 
				
			||||||
		delimiter := determineDelimiter(&markup.RenderContext{RelativePath: c.filename}, []byte(decodeSlashes(t, c.csv)))
 | 
							delimiter := determineDelimiter(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:          git.DefaultContext,
 | 
				
			||||||
 | 
								RelativePath: c.filename,
 | 
				
			||||||
 | 
							}, []byte(decodeSlashes(t, c.csv)))
 | 
				
			||||||
		assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
							assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/markup"
 | 
						"code.gitea.io/gitea/modules/markup"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
@@ -23,7 +24,8 @@ func TestRenderConsole(t *testing.T) {
 | 
				
			|||||||
		canRender := render.CanRender("test", strings.NewReader(k))
 | 
							canRender := render.CanRender("test", strings.NewReader(k))
 | 
				
			||||||
		assert.True(t, canRender)
 | 
							assert.True(t, canRender)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err := render.Render(&markup.RenderContext{}, strings.NewReader(k), &buf)
 | 
							err := render.Render(&markup.RenderContext{Ctx: git.DefaultContext},
 | 
				
			||||||
 | 
								strings.NewReader(k), &buf)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.EqualValues(t, v, buf.String())
 | 
							assert.EqualValues(t, v, buf.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/markup"
 | 
						"code.gitea.io/gitea/modules/markup"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
@@ -23,7 +24,8 @@ func TestRenderCSV(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for k, v := range kases {
 | 
						for k, v := range kases {
 | 
				
			||||||
		var buf strings.Builder
 | 
							var buf strings.Builder
 | 
				
			||||||
		err := render.Render(&markup.RenderContext{}, strings.NewReader(k), &buf)
 | 
							err := render.Render(&markup.RenderContext{Ctx: git.DefaultContext},
 | 
				
			||||||
 | 
								strings.NewReader(k), &buf)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.EqualValues(t, v, buf.String())
 | 
							assert.EqualValues(t, v, buf.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -291,9 +291,10 @@ func RenderDescriptionHTML(
 | 
				
			|||||||
// RenderEmoji for when we want to just process emoji and shortcodes
 | 
					// RenderEmoji for when we want to just process emoji and shortcodes
 | 
				
			||||||
// in various places it isn't already run through the normal markdown processor
 | 
					// in various places it isn't already run through the normal markdown processor
 | 
				
			||||||
func RenderEmoji(
 | 
					func RenderEmoji(
 | 
				
			||||||
 | 
						ctx *RenderContext,
 | 
				
			||||||
	content string,
 | 
						content string,
 | 
				
			||||||
) (string, error) {
 | 
					) (string, error) {
 | 
				
			||||||
	return renderProcessString(&RenderContext{}, emojiProcessors, content)
 | 
						return renderProcessString(ctx, emojiProcessors, content)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,8 +71,13 @@ var localMetas = map[string]string{
 | 
				
			|||||||
func TestRender_IssueIndexPattern(t *testing.T) {
 | 
					func TestRender_IssueIndexPattern(t *testing.T) {
 | 
				
			||||||
	// numeric: render inputs without valid mentions
 | 
						// numeric: render inputs without valid mentions
 | 
				
			||||||
	test := func(s string) {
 | 
						test := func(s string) {
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, s, &RenderContext{})
 | 
							testRenderIssueIndexPattern(t, s, s, &RenderContext{
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, s, &RenderContext{Metas: numericMetas})
 | 
								Ctx: git.DefaultContext,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							testRenderIssueIndexPattern(t, s, s, &RenderContext{
 | 
				
			||||||
 | 
								Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
								Metas: numericMetas,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// should not render anything when there are no mentions
 | 
						// should not render anything when there are no mentions
 | 
				
			||||||
@@ -119,7 +125,10 @@ func TestRender_IssueIndexPattern2(t *testing.T) {
 | 
				
			|||||||
			links[i] = numericIssueLink(util.URLJoin(TestRepoURL, path), "ref-issue", index, marker)
 | 
								links[i] = numericIssueLink(util.URLJoin(TestRepoURL, path), "ref-issue", index, marker)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		expectedNil := fmt.Sprintf(expectedFmt, links...)
 | 
							expectedNil := fmt.Sprintf(expectedFmt, links...)
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, expectedNil, &RenderContext{Metas: localMetas})
 | 
							testRenderIssueIndexPattern(t, s, expectedNil, &RenderContext{
 | 
				
			||||||
 | 
								Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
								Metas: localMetas,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		class := "ref-issue"
 | 
							class := "ref-issue"
 | 
				
			||||||
		if isExternal {
 | 
							if isExternal {
 | 
				
			||||||
@@ -130,7 +139,10 @@ func TestRender_IssueIndexPattern2(t *testing.T) {
 | 
				
			|||||||
			links[i] = numericIssueLink(prefix, class, index, marker)
 | 
								links[i] = numericIssueLink(prefix, class, index, marker)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		expectedNum := fmt.Sprintf(expectedFmt, links...)
 | 
							expectedNum := fmt.Sprintf(expectedFmt, links...)
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, expectedNum, &RenderContext{Metas: numericMetas})
 | 
							testRenderIssueIndexPattern(t, s, expectedNum, &RenderContext{
 | 
				
			||||||
 | 
								Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
								Metas: numericMetas,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// should render freestanding mentions
 | 
						// should render freestanding mentions
 | 
				
			||||||
@@ -164,7 +176,10 @@ func TestRender_IssueIndexPattern3(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// alphanumeric: render inputs without valid mentions
 | 
						// alphanumeric: render inputs without valid mentions
 | 
				
			||||||
	test := func(s string) {
 | 
						test := func(s string) {
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, s, &RenderContext{Metas: alphanumericMetas})
 | 
							testRenderIssueIndexPattern(t, s, s, &RenderContext{
 | 
				
			||||||
 | 
								Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
								Metas: alphanumericMetas,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	test("")
 | 
						test("")
 | 
				
			||||||
	test("this is a test")
 | 
						test("this is a test")
 | 
				
			||||||
@@ -194,7 +209,10 @@ func TestRender_IssueIndexPattern4(t *testing.T) {
 | 
				
			|||||||
			links[i] = externalIssueLink("https://someurl.com/someUser/someRepo/", "ref-issue ref-external-issue", name)
 | 
								links[i] = externalIssueLink("https://someurl.com/someUser/someRepo/", "ref-issue ref-external-issue", name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		expected := fmt.Sprintf(expectedFmt, links...)
 | 
							expected := fmt.Sprintf(expectedFmt, links...)
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, expected, &RenderContext{Metas: alphanumericMetas})
 | 
							testRenderIssueIndexPattern(t, s, expected, &RenderContext{
 | 
				
			||||||
 | 
								Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
								Metas: alphanumericMetas,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	test("OTT-1234 test", "%s test", "OTT-1234")
 | 
						test("OTT-1234 test", "%s test", "OTT-1234")
 | 
				
			||||||
	test("test T-12 issue", "test %s issue", "T-12")
 | 
						test("test T-12 issue", "test %s issue", "T-12")
 | 
				
			||||||
@@ -214,7 +232,10 @@ func TestRender_IssueIndexPattern5(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		expected := fmt.Sprintf(expectedFmt, links...)
 | 
							expected := fmt.Sprintf(expectedFmt, links...)
 | 
				
			||||||
		testRenderIssueIndexPattern(t, s, expected, &RenderContext{Metas: metas})
 | 
							testRenderIssueIndexPattern(t, s, expected, &RenderContext{
 | 
				
			||||||
 | 
								Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
								Metas: metas,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test("abc ISSUE-123 def", "abc %s def",
 | 
						test("abc ISSUE-123 def", "abc %s def",
 | 
				
			||||||
@@ -235,7 +256,10 @@ func TestRender_IssueIndexPattern5(t *testing.T) {
 | 
				
			|||||||
		[]string{"ISSUE-123"},
 | 
							[]string{"ISSUE-123"},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	testRenderIssueIndexPattern(t, "will not match", "will not match", &RenderContext{Metas: regexpMetas})
 | 
						testRenderIssueIndexPattern(t, "will not match", "will not match", &RenderContext{
 | 
				
			||||||
 | 
							Ctx:   git.DefaultContext,
 | 
				
			||||||
 | 
							Metas: regexpMetas,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) {
 | 
					func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) {
 | 
				
			||||||
@@ -255,6 +279,7 @@ func TestRender_AutoLink(t *testing.T) {
 | 
				
			|||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		var buffer strings.Builder
 | 
							var buffer strings.Builder
 | 
				
			||||||
		err := PostProcess(&RenderContext{
 | 
							err := PostProcess(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: TestRepoURL,
 | 
								URLPrefix: TestRepoURL,
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
		}, strings.NewReader(input), &buffer)
 | 
							}, strings.NewReader(input), &buffer)
 | 
				
			||||||
@@ -263,6 +288,7 @@ func TestRender_AutoLink(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		buffer.Reset()
 | 
							buffer.Reset()
 | 
				
			||||||
		err = PostProcess(&RenderContext{
 | 
							err = PostProcess(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: TestRepoURL,
 | 
								URLPrefix: TestRepoURL,
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
			IsWiki:    true,
 | 
								IsWiki:    true,
 | 
				
			||||||
@@ -292,6 +318,7 @@ func TestRender_FullIssueURLs(t *testing.T) {
 | 
				
			|||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		var result strings.Builder
 | 
							var result strings.Builder
 | 
				
			||||||
		err := postProcess(&RenderContext{
 | 
							err := postProcess(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: TestRepoURL,
 | 
								URLPrefix: TestRepoURL,
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
		}, []processor{fullIssuePatternProcessor}, strings.NewReader(input), &result)
 | 
							}, []processor{fullIssuePatternProcessor}, strings.NewReader(input), &result)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,6 +91,7 @@ func TestRender_CrossReferences(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		buffer, err := RenderString(&RenderContext{
 | 
							buffer, err := RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:          git.DefaultContext,
 | 
				
			||||||
			RelativePath: "a.md",
 | 
								RelativePath: "a.md",
 | 
				
			||||||
			URLPrefix:    setting.AppSubURL,
 | 
								URLPrefix:    setting.AppSubURL,
 | 
				
			||||||
			Metas:        localMetas,
 | 
								Metas:        localMetas,
 | 
				
			||||||
@@ -135,6 +136,7 @@ func TestRender_links(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		buffer, err := RenderString(&RenderContext{
 | 
							buffer, err := RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:          git.DefaultContext,
 | 
				
			||||||
			RelativePath: "a.md",
 | 
								RelativePath: "a.md",
 | 
				
			||||||
			URLPrefix:    TestRepoURL,
 | 
								URLPrefix:    TestRepoURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
@@ -234,6 +236,7 @@ func TestRender_email(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		res, err := RenderString(&RenderContext{
 | 
							res, err := RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:          git.DefaultContext,
 | 
				
			||||||
			RelativePath: "a.md",
 | 
								RelativePath: "a.md",
 | 
				
			||||||
			URLPrefix:    TestRepoURL,
 | 
								URLPrefix:    TestRepoURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
@@ -292,6 +295,7 @@ func TestRender_emoji(t *testing.T) {
 | 
				
			|||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		expected = strings.ReplaceAll(expected, "&", "&")
 | 
							expected = strings.ReplaceAll(expected, "&", "&")
 | 
				
			||||||
		buffer, err := RenderString(&RenderContext{
 | 
							buffer, err := RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:          git.DefaultContext,
 | 
				
			||||||
			RelativePath: "a.md",
 | 
								RelativePath: "a.md",
 | 
				
			||||||
			URLPrefix:    TestRepoURL,
 | 
								URLPrefix:    TestRepoURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
@@ -355,11 +359,13 @@ func TestRender_ShortLinks(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected, expectedWiki string) {
 | 
						test := func(input, expected, expectedWiki string) {
 | 
				
			||||||
		buffer, err := markdown.RenderString(&RenderContext{
 | 
							buffer, err := markdown.RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: tree,
 | 
								URLPrefix: tree,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
				
			||||||
		buffer, err = markdown.RenderString(&RenderContext{
 | 
							buffer, err = markdown.RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: TestRepoURL,
 | 
								URLPrefix: TestRepoURL,
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
			IsWiki:    true,
 | 
								IsWiki:    true,
 | 
				
			||||||
@@ -461,12 +467,14 @@ func TestRender_RelativeImages(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected, expectedWiki string) {
 | 
						test := func(input, expected, expectedWiki string) {
 | 
				
			||||||
		buffer, err := markdown.RenderString(&RenderContext{
 | 
							buffer, err := markdown.RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: tree,
 | 
								URLPrefix: tree,
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
				
			||||||
		buffer, err = markdown.RenderString(&RenderContext{
 | 
							buffer, err = markdown.RenderString(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: TestRepoURL,
 | 
								URLPrefix: TestRepoURL,
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
			IsWiki:    true,
 | 
								IsWiki:    true,
 | 
				
			||||||
@@ -501,6 +509,7 @@ func Test_ParseClusterFuzz(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var res strings.Builder
 | 
						var res strings.Builder
 | 
				
			||||||
	err := PostProcess(&RenderContext{
 | 
						err := PostProcess(&RenderContext{
 | 
				
			||||||
 | 
							Ctx:       git.DefaultContext,
 | 
				
			||||||
		URLPrefix: "https://example.com",
 | 
							URLPrefix: "https://example.com",
 | 
				
			||||||
		Metas:     localMetas,
 | 
							Metas:     localMetas,
 | 
				
			||||||
	}, strings.NewReader(data), &res)
 | 
						}, strings.NewReader(data), &res)
 | 
				
			||||||
@@ -511,6 +520,7 @@ func Test_ParseClusterFuzz(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	res.Reset()
 | 
						res.Reset()
 | 
				
			||||||
	err = PostProcess(&RenderContext{
 | 
						err = PostProcess(&RenderContext{
 | 
				
			||||||
 | 
							Ctx:       git.DefaultContext,
 | 
				
			||||||
		URLPrefix: "https://example.com",
 | 
							URLPrefix: "https://example.com",
 | 
				
			||||||
		Metas:     localMetas,
 | 
							Metas:     localMetas,
 | 
				
			||||||
	}, strings.NewReader(data), &res)
 | 
						}, strings.NewReader(data), &res)
 | 
				
			||||||
@@ -531,6 +541,7 @@ func TestIssue16020(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var res strings.Builder
 | 
						var res strings.Builder
 | 
				
			||||||
	err := PostProcess(&RenderContext{
 | 
						err := PostProcess(&RenderContext{
 | 
				
			||||||
 | 
							Ctx:       git.DefaultContext,
 | 
				
			||||||
		URLPrefix: "https://example.com",
 | 
							URLPrefix: "https://example.com",
 | 
				
			||||||
		Metas:     localMetas,
 | 
							Metas:     localMetas,
 | 
				
			||||||
	}, strings.NewReader(data), &res)
 | 
						}, strings.NewReader(data), &res)
 | 
				
			||||||
@@ -547,6 +558,7 @@ func BenchmarkEmojiPostprocess(b *testing.B) {
 | 
				
			|||||||
	for i := 0; i < b.N; i++ {
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
		var res strings.Builder
 | 
							var res strings.Builder
 | 
				
			||||||
		err := PostProcess(&RenderContext{
 | 
							err := PostProcess(&RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: "https://example.com",
 | 
								URLPrefix: "https://example.com",
 | 
				
			||||||
			Metas:     localMetas,
 | 
								Metas:     localMetas,
 | 
				
			||||||
		}, strings.NewReader(data), &res)
 | 
							}, strings.NewReader(data), &res)
 | 
				
			||||||
@@ -557,6 +569,7 @@ func BenchmarkEmojiPostprocess(b *testing.B) {
 | 
				
			|||||||
func TestFuzz(t *testing.T) {
 | 
					func TestFuzz(t *testing.T) {
 | 
				
			||||||
	s := "t/l/issues/8#/../../a"
 | 
						s := "t/l/issues/8#/../../a"
 | 
				
			||||||
	renderContext := RenderContext{
 | 
						renderContext := RenderContext{
 | 
				
			||||||
 | 
							Ctx:       git.DefaultContext,
 | 
				
			||||||
		URLPrefix: "https://example.com/go-gitea/gitea",
 | 
							URLPrefix: "https://example.com/go-gitea/gitea",
 | 
				
			||||||
		Metas: map[string]string{
 | 
							Metas: map[string]string{
 | 
				
			||||||
			"user": "go-gitea",
 | 
								"user": "go-gitea",
 | 
				
			||||||
@@ -574,6 +587,7 @@ func TestIssue18471(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var res strings.Builder
 | 
						var res strings.Builder
 | 
				
			||||||
	err := PostProcess(&RenderContext{
 | 
						err := PostProcess(&RenderContext{
 | 
				
			||||||
 | 
							Ctx:       git.DefaultContext,
 | 
				
			||||||
		URLPrefix: "https://example.com",
 | 
							URLPrefix: "https://example.com",
 | 
				
			||||||
		Metas:     localMetas,
 | 
							Metas:     localMetas,
 | 
				
			||||||
	}, strings.NewReader(data), &res)
 | 
						}, strings.NewReader(data), &res)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,12 +52,14 @@ func TestRender_StandardLinks(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected, expectedWiki string) {
 | 
						test := func(input, expected, expectedWiki string) {
 | 
				
			||||||
		buffer, err := RenderString(&markup.RenderContext{
 | 
							buffer, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: setting.AppSubURL,
 | 
								URLPrefix: setting.AppSubURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
							assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		buffer, err = RenderString(&markup.RenderContext{
 | 
							buffer, err = RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: setting.AppSubURL,
 | 
								URLPrefix: setting.AppSubURL,
 | 
				
			||||||
			IsWiki:    true,
 | 
								IsWiki:    true,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
@@ -81,6 +83,7 @@ func TestRender_Images(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		buffer, err := RenderString(&markup.RenderContext{
 | 
							buffer, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: setting.AppSubURL,
 | 
								URLPrefix: setting.AppSubURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
@@ -311,6 +314,7 @@ func TestTotal_RenderWiki(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for i := 0; i < len(testCases); i += 2 {
 | 
						for i := 0; i < len(testCases); i += 2 {
 | 
				
			||||||
		line, err := RenderString(&markup.RenderContext{
 | 
							line, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: AppSubURL,
 | 
								URLPrefix: AppSubURL,
 | 
				
			||||||
			IsWiki:    true,
 | 
								IsWiki:    true,
 | 
				
			||||||
		}, testCases[i])
 | 
							}, testCases[i])
 | 
				
			||||||
@@ -339,6 +343,7 @@ func TestTotal_RenderString(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for i := 0; i < len(testCases); i += 2 {
 | 
						for i := 0; i < len(testCases); i += 2 {
 | 
				
			||||||
		line, err := RenderString(&markup.RenderContext{
 | 
							line, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: AppSubURL,
 | 
								URLPrefix: AppSubURL,
 | 
				
			||||||
		}, testCases[i])
 | 
							}, testCases[i])
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
@@ -348,17 +353,17 @@ func TestTotal_RenderString(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestRender_RenderParagraphs(t *testing.T) {
 | 
					func TestRender_RenderParagraphs(t *testing.T) {
 | 
				
			||||||
	test := func(t *testing.T, str string, cnt int) {
 | 
						test := func(t *testing.T, str string, cnt int) {
 | 
				
			||||||
		res, err := RenderRawString(&markup.RenderContext{}, str)
 | 
							res, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, str)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for unix should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
 | 
							assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for unix should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mac := strings.ReplaceAll(str, "\n", "\r")
 | 
							mac := strings.ReplaceAll(str, "\n", "\r")
 | 
				
			||||||
		res, err = RenderRawString(&markup.RenderContext{}, mac)
 | 
							res, err = RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, mac)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for mac should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
 | 
							assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for mac should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dos := strings.ReplaceAll(str, "\n", "\r\n")
 | 
							dos := strings.ReplaceAll(str, "\n", "\r\n")
 | 
				
			||||||
		res, err = RenderRawString(&markup.RenderContext{}, dos)
 | 
							res, err = RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, dos)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
		assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for windows should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
 | 
							assert.Equal(t, cnt, strings.Count(res, "<p"), "Rendered result for windows should have %d paragraph(s) but has %d:\n%s\n", cnt, strings.Count(res, "<p"), res)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -386,7 +391,7 @@ func TestMarkdownRenderRaw(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, testcase := range testcases {
 | 
						for _, testcase := range testcases {
 | 
				
			||||||
		log.Info("Test markdown render error with fuzzy data: %x, the following errors can be recovered", testcase)
 | 
							log.Info("Test markdown render error with fuzzy data: %x, the following errors can be recovered", testcase)
 | 
				
			||||||
		_, err := RenderRawString(&markup.RenderContext{}, string(testcase))
 | 
							_, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, string(testcase))
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -398,7 +403,7 @@ func TestRenderSiblingImages_Issue12925(t *testing.T) {
 | 
				
			|||||||
	expected := `<p><a href="/image1" target="_blank" rel="nofollow noopener"><img src="/image1" alt="image1"></a><br>
 | 
						expected := `<p><a href="/image1" target="_blank" rel="nofollow noopener"><img src="/image1" alt="image1"></a><br>
 | 
				
			||||||
<a href="/image2" target="_blank" rel="nofollow noopener"><img src="/image2" alt="image2"></a></p>
 | 
					<a href="/image2" target="_blank" rel="nofollow noopener"><img src="/image2" alt="image2"></a></p>
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	res, err := RenderRawString(&markup.RenderContext{}, testcase)
 | 
						res, err := RenderRawString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Equal(t, expected, res)
 | 
						assert.Equal(t, expected, res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -407,7 +412,7 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) {
 | 
				
			|||||||
	testcase := `[Link with emoji :moon: in text](https://gitea.io)`
 | 
						testcase := `[Link with emoji :moon: in text](https://gitea.io)`
 | 
				
			||||||
	expected := `<p><a href="https://gitea.io" rel="nofollow">Link with emoji <span class="emoji" aria-label="waxing gibbous moon">🌔</span> in text</a></p>
 | 
						expected := `<p><a href="https://gitea.io" rel="nofollow">Link with emoji <span class="emoji" aria-label="waxing gibbous moon">🌔</span> in text</a></p>
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
	res, err := RenderString(&markup.RenderContext{}, testcase)
 | 
						res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Equal(t, expected, res)
 | 
						assert.Equal(t, expected, res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -441,7 +446,7 @@ func TestColorPreview(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, test := range positiveTests {
 | 
						for _, test := range positiveTests {
 | 
				
			||||||
		res, err := RenderString(&markup.RenderContext{}, test.testcase)
 | 
							res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
				
			||||||
		assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
							assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -461,7 +466,7 @@ func TestColorPreview(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, test := range negativeTests {
 | 
						for _, test := range negativeTests {
 | 
				
			||||||
		res, err := RenderString(&markup.RenderContext{}, test)
 | 
							res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %q", test)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %q", test)
 | 
				
			||||||
		assert.NotContains(t, res, `<span class="color-preview" style="background-color: `, "Unexpected result in testcase %q", test)
 | 
							assert.NotContains(t, res, `<span class="color-preview" style="background-color: `, "Unexpected result in testcase %q", test)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -508,7 +513,7 @@ func TestMathBlock(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, test := range testcases {
 | 
						for _, test := range testcases {
 | 
				
			||||||
		res, err := RenderString(&markup.RenderContext{}, test.testcase)
 | 
							res, err := RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase)
 | 
				
			||||||
		assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
							assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
 | 
				
			||||||
		assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
							assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/markup"
 | 
						"code.gitea.io/gitea/modules/markup"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
@@ -26,6 +27,7 @@ func TestRender_StandardLinks(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		buffer, err := RenderString(&markup.RenderContext{
 | 
							buffer, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: setting.AppSubURL,
 | 
								URLPrefix: setting.AppSubURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
@@ -46,6 +48,7 @@ func TestRender_Images(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		buffer, err := RenderString(&markup.RenderContext{
 | 
							buffer, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: setting.AppSubURL,
 | 
								URLPrefix: setting.AppSubURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
@@ -65,6 +68,7 @@ func TestRender_Source(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	test := func(input, expected string) {
 | 
						test := func(input, expected string) {
 | 
				
			||||||
		buffer, err := RenderString(&markup.RenderContext{
 | 
							buffer, err := RenderString(&markup.RenderContext{
 | 
				
			||||||
 | 
								Ctx:       git.DefaultContext,
 | 
				
			||||||
			URLPrefix: setting.AppSubURL,
 | 
								URLPrefix: setting.AppSubURL,
 | 
				
			||||||
		}, input)
 | 
							}, input)
 | 
				
			||||||
		assert.NoError(t, err)
 | 
							assert.NoError(t, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -385,10 +385,10 @@ func NewFuncMap() []template.FuncMap {
 | 
				
			|||||||
			// the table is NOT sorted with this header
 | 
								// the table is NOT sorted with this header
 | 
				
			||||||
			return ""
 | 
								return ""
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"RenderLabel": func(label *issues_model.Label) template.HTML {
 | 
							"RenderLabel": func(ctx context.Context, label *issues_model.Label) template.HTML {
 | 
				
			||||||
			return template.HTML(RenderLabel(label))
 | 
								return template.HTML(RenderLabel(ctx, label))
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"RenderLabels": func(labels []*issues_model.Label, repoLink string) template.HTML {
 | 
							"RenderLabels": func(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML {
 | 
				
			||||||
			htmlCode := `<span class="labels-list">`
 | 
								htmlCode := `<span class="labels-list">`
 | 
				
			||||||
			for _, label := range labels {
 | 
								for _, label := range labels {
 | 
				
			||||||
				// Protect against nil value in labels - shouldn't happen but would cause a panic if so
 | 
									// Protect against nil value in labels - shouldn't happen but would cause a panic if so
 | 
				
			||||||
@@ -396,7 +396,7 @@ func NewFuncMap() []template.FuncMap {
 | 
				
			|||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				htmlCode += fmt.Sprintf("<a href='%s/issues?labels=%d'>%s</a> ",
 | 
									htmlCode += fmt.Sprintf("<a href='%s/issues?labels=%d'>%s</a> ",
 | 
				
			||||||
					repoLink, label.ID, RenderLabel(label))
 | 
										repoLink, label.ID, RenderLabel(ctx, label))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			htmlCode += "</span>"
 | 
								htmlCode += "</span>"
 | 
				
			||||||
			return template.HTML(htmlCode)
 | 
								return template.HTML(htmlCode)
 | 
				
			||||||
@@ -808,7 +808,7 @@ func RenderIssueTitle(ctx context.Context, text, urlPrefix string, metas map[str
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RenderLabel renders a label
 | 
					// RenderLabel renders a label
 | 
				
			||||||
func RenderLabel(label *issues_model.Label) string {
 | 
					func RenderLabel(ctx context.Context, label *issues_model.Label) string {
 | 
				
			||||||
	labelScope := label.ExclusiveScope()
 | 
						labelScope := label.ExclusiveScope()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	textColor := "#111"
 | 
						textColor := "#111"
 | 
				
			||||||
@@ -821,12 +821,12 @@ func RenderLabel(label *issues_model.Label) string {
 | 
				
			|||||||
	if labelScope == "" {
 | 
						if labelScope == "" {
 | 
				
			||||||
		// Regular label
 | 
							// Regular label
 | 
				
			||||||
		return fmt.Sprintf("<div class='ui label' style='color: %s !important; background-color: %s !important' title='%s'>%s</div>",
 | 
							return fmt.Sprintf("<div class='ui label' style='color: %s !important; background-color: %s !important' title='%s'>%s</div>",
 | 
				
			||||||
			textColor, label.Color, description, RenderEmoji(label.Name))
 | 
								textColor, label.Color, description, RenderEmoji(ctx, label.Name))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Scoped label
 | 
						// Scoped label
 | 
				
			||||||
	scopeText := RenderEmoji(labelScope)
 | 
						scopeText := RenderEmoji(ctx, labelScope)
 | 
				
			||||||
	itemText := RenderEmoji(label.Name[len(labelScope)+1:])
 | 
						itemText := RenderEmoji(ctx, label.Name[len(labelScope)+1:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	itemColor := label.Color
 | 
						itemColor := label.Color
 | 
				
			||||||
	scopeColor := label.Color
 | 
						scopeColor := label.Color
 | 
				
			||||||
@@ -869,8 +869,9 @@ func RenderLabel(label *issues_model.Label) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RenderEmoji renders html text with emoji post processors
 | 
					// RenderEmoji renders html text with emoji post processors
 | 
				
			||||||
func RenderEmoji(text string) template.HTML {
 | 
					func RenderEmoji(ctx context.Context, text string) template.HTML {
 | 
				
			||||||
	renderedText, err := markup.RenderEmoji(template.HTMLEscapeString(text))
 | 
						renderedText, err := markup.RenderEmoji(&markup.RenderContext{Ctx: ctx},
 | 
				
			||||||
 | 
							template.HTMLEscapeString(text))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error("RenderEmoji: %v", err)
 | 
							log.Error("RenderEmoji: %v", err)
 | 
				
			||||||
		return template.HTML("")
 | 
							return template.HTML("")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -234,7 +234,7 @@
 | 
				
			|||||||
						{{if or .Labels .Assignees}}
 | 
											{{if or .Labels .Assignees}}
 | 
				
			||||||
						<div class="extra content labels-list gt-p-0 gt-pt-2">
 | 
											<div class="extra content labels-list gt-p-0 gt-pt-2">
 | 
				
			||||||
							{{range .Labels}}
 | 
												{{range .Labels}}
 | 
				
			||||||
								<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel .}}</a>
 | 
													<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel $.Context .}}</a>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
							<div class="right floated">
 | 
												<div class="right floated">
 | 
				
			||||||
								{{range .Assignees}}
 | 
													{{range .Assignees}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -129,7 +129,7 @@
 | 
				
			|||||||
						<span class="ui green label">{{$.locale.Tr "repo.activity.published_release_label"}}</span>
 | 
											<span class="ui green label">{{$.locale.Tr "repo.activity.published_release_label"}}</span>
 | 
				
			||||||
						{{.TagName}}
 | 
											{{.TagName}}
 | 
				
			||||||
						{{if not .IsTag}}
 | 
											{{if not .IsTag}}
 | 
				
			||||||
							<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji}}</a>
 | 
												<a class="title" href="{{$.RepoLink}}/src/{{.TagName | PathEscapeSegments}}">{{.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{TimeSinceUnix .CreatedUnix $.locale}}
 | 
											{{TimeSinceUnix .CreatedUnix $.locale}}
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
@@ -149,7 +149,7 @@
 | 
				
			|||||||
				{{range .Activity.MergedPRs}}
 | 
									{{range .Activity.MergedPRs}}
 | 
				
			||||||
					<p class="desc">
 | 
										<p class="desc">
 | 
				
			||||||
						<span class="ui purple label">{{$.locale.Tr "repo.activity.merged_prs_label"}}</span>
 | 
											<span class="ui purple label">{{$.locale.Tr "repo.activity.merged_prs_label"}}</span>
 | 
				
			||||||
						#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a>
 | 
											#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{TimeSinceUnix .MergedUnix $.locale}}
 | 
											{{TimeSinceUnix .MergedUnix $.locale}}
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
@@ -168,7 +168,7 @@
 | 
				
			|||||||
				{{range .Activity.OpenedPRs}}
 | 
									{{range .Activity.OpenedPRs}}
 | 
				
			||||||
					<p class="desc">
 | 
										<p class="desc">
 | 
				
			||||||
						<span class="ui green label">{{$.locale.Tr "repo.activity.opened_prs_label"}}</span>
 | 
											<span class="ui green label">{{$.locale.Tr "repo.activity.opened_prs_label"}}</span>
 | 
				
			||||||
						#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji}}</a>
 | 
											#{{.Index}} <a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Issue.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{TimeSinceUnix .Issue.CreatedUnix $.locale}}
 | 
											{{TimeSinceUnix .Issue.CreatedUnix $.locale}}
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
@@ -187,7 +187,7 @@
 | 
				
			|||||||
				{{range .Activity.ClosedIssues}}
 | 
									{{range .Activity.ClosedIssues}}
 | 
				
			||||||
					<p class="desc">
 | 
										<p class="desc">
 | 
				
			||||||
						<span class="ui red label">{{$.locale.Tr "repo.activity.closed_issue_label"}}</span>
 | 
											<span class="ui red label">{{$.locale.Tr "repo.activity.closed_issue_label"}}</span>
 | 
				
			||||||
						#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
 | 
											#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{TimeSinceUnix .ClosedUnix $.locale}}
 | 
											{{TimeSinceUnix .ClosedUnix $.locale}}
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
@@ -206,7 +206,7 @@
 | 
				
			|||||||
				{{range .Activity.OpenedIssues}}
 | 
									{{range .Activity.OpenedIssues}}
 | 
				
			||||||
					<p class="desc">
 | 
										<p class="desc">
 | 
				
			||||||
						<span class="ui green label">{{$.locale.Tr "repo.activity.new_issue_label"}}</span>
 | 
											<span class="ui green label">{{$.locale.Tr "repo.activity.new_issue_label"}}</span>
 | 
				
			||||||
						#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
 | 
											#{{.Index}} <a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{TimeSinceUnix .CreatedUnix $.locale}}
 | 
											{{TimeSinceUnix .CreatedUnix $.locale}}
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
@@ -227,9 +227,9 @@
 | 
				
			|||||||
						<span class="ui green label">{{$.locale.Tr "repo.activity.unresolved_conv_label"}}</span>
 | 
											<span class="ui green label">{{$.locale.Tr "repo.activity.unresolved_conv_label"}}</span>
 | 
				
			||||||
						#{{.Index}}
 | 
											#{{.Index}}
 | 
				
			||||||
						{{if .IsPull}}
 | 
											{{if .IsPull}}
 | 
				
			||||||
						<a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Title | RenderEmoji}}</a>
 | 
											<a class="title" href="{{$.RepoLink}}/pulls/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{else}}
 | 
											{{else}}
 | 
				
			||||||
						<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji}}</a>
 | 
											<a class="title" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title | RenderEmoji $.Context}}</a>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{TimeSinceUnix .UpdatedUnix $.locale}}
 | 
											{{TimeSinceUnix .UpdatedUnix $.locale}}
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,7 @@
 | 
				
			|||||||
						<td class="message">
 | 
											<td class="message">
 | 
				
			||||||
							<span class="message-wrapper">
 | 
												<span class="message-wrapper">
 | 
				
			||||||
							{{if $.PageIsWiki}}
 | 
												{{if $.PageIsWiki}}
 | 
				
			||||||
								<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji}}</span>
 | 
													<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | RenderEmoji $.Context}}</span>
 | 
				
			||||||
							{{else}}
 | 
												{{else}}
 | 
				
			||||||
								{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}}
 | 
													{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}}
 | 
				
			||||||
								<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitRepoLink $commitLink $.Repository.ComposeMetas}}</span>
 | 
													<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{RenderCommitMessageLinkSubject $.Context .Message $commitRepoLink $commitLink $.Repository.ComposeMetas}}</span>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,5 +3,5 @@
 | 
				
			|||||||
	id="label_{{.label.ID}}"
 | 
						id="label_{{.label.ID}}"
 | 
				
			||||||
	href="{{.root.RepoLink}}/{{if or .root.IsPull .root.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.label.ID}}"{{/* FIXME: use .root.Issue.Link or create .root.Link */}}
 | 
						href="{{.root.RepoLink}}/{{if or .root.IsPull .root.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.label.ID}}"{{/* FIXME: use .root.Issue.Link or create .root.Link */}}
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
	{{RenderLabel .label}}
 | 
						{{RenderLabel $.Context .label}}
 | 
				
			||||||
</a>
 | 
					</a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,8 +31,8 @@
 | 
				
			|||||||
			<li class="item">
 | 
								<li class="item">
 | 
				
			||||||
			<div class="ui grid middle aligned">
 | 
								<div class="ui grid middle aligned">
 | 
				
			||||||
				<div class="nine wide column">
 | 
									<div class="nine wide column">
 | 
				
			||||||
					{{RenderLabel .}}
 | 
										{{RenderLabel $.Context .}}
 | 
				
			||||||
					{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}
 | 
										{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
				<div class="four wide column">
 | 
									<div class="four wide column">
 | 
				
			||||||
					{{if $.PageIsOrgSettingsLabels}}
 | 
										{{if $.PageIsOrgSettingsLabels}}
 | 
				
			||||||
@@ -70,8 +70,8 @@
 | 
				
			|||||||
					<li class="item">
 | 
										<li class="item">
 | 
				
			||||||
					<div class="ui grid middle aligned">
 | 
										<div class="ui grid middle aligned">
 | 
				
			||||||
						<div class="nine wide column">
 | 
											<div class="nine wide column">
 | 
				
			||||||
							{{RenderLabel .}}
 | 
												{{RenderLabel $.Context .}}
 | 
				
			||||||
							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}
 | 
												{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
						<div class="four wide column">
 | 
											<div class="four wide column">
 | 
				
			||||||
							<a class="ui left open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.locale.Tr "repo.issues.label_open_issues" .NumOpenRepoIssues}}</a>
 | 
												<a class="ui left open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.locale.Tr "repo.issues.label_open_issues" .NumOpenRepoIssues}}</a>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@
 | 
				
			|||||||
									<div class="ui divider"></div>
 | 
														<div class="ui divider"></div>
 | 
				
			||||||
								{{end}}
 | 
													{{end}}
 | 
				
			||||||
								{{$previousExclusiveScope = $exclusiveScope}}
 | 
													{{$previousExclusiveScope = $exclusiveScope}}
 | 
				
			||||||
								<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if .IsSelected}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel .}}</a>
 | 
													<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&project={{$.ProjectID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if .IsSelected}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context .}}</a>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
@@ -231,7 +231,7 @@
 | 
				
			|||||||
								{{end}}
 | 
													{{end}}
 | 
				
			||||||
								{{$previousExclusiveScope = $exclusiveScope}}
 | 
													{{$previousExclusiveScope = $exclusiveScope}}
 | 
				
			||||||
								<div class="item issue-action" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels">
 | 
													<div class="item issue-action" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels">
 | 
				
			||||||
									{{if contain $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel .}}
 | 
														{{if contain $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context .}}
 | 
				
			||||||
								</div>
 | 
													</div>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@
 | 
				
			|||||||
							<span class="info">{{.locale.Tr "repo.issues.filter_label_exclude" | Safe}}</span>
 | 
												<span class="info">{{.locale.Tr "repo.issues.filter_label_exclude" | Safe}}</span>
 | 
				
			||||||
							<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_label_no_select"}}</a>
 | 
												<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_label_no_select"}}</a>
 | 
				
			||||||
							{{range .Labels}}
 | 
												{{range .Labels}}
 | 
				
			||||||
								<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel .}}</a>
 | 
													<a class="item label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}" data-label-id="{{.ID}}">{{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel $.Context .}}</a>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
@@ -161,7 +161,7 @@
 | 
				
			|||||||
						<div class="menu">
 | 
											<div class="menu">
 | 
				
			||||||
							{{range .Labels}}
 | 
												{{range .Labels}}
 | 
				
			||||||
								<div class="item issue-action" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels">
 | 
													<div class="item issue-action" data-action="toggle" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/labels">
 | 
				
			||||||
									{{if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel .}}
 | 
														{{if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{RenderLabel $.Context .}}
 | 
				
			||||||
								</div>
 | 
													</div>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,8 +60,8 @@
 | 
				
			|||||||
								<div class="ui divider"></div>
 | 
													<div class="ui divider"></div>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
							{{$previousExclusiveScope = $exclusiveScope}}
 | 
												{{$previousExclusiveScope = $exclusiveScope}}
 | 
				
			||||||
							<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}}
 | 
												<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}}
 | 
				
			||||||
							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a>
 | 
												{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						<div class="ui divider"></div>
 | 
											<div class="ui divider"></div>
 | 
				
			||||||
@@ -72,8 +72,8 @@
 | 
				
			|||||||
								<div class="ui divider"></div>
 | 
													<div class="ui divider"></div>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
							{{$previousExclusiveScope = $exclusiveScope}}
 | 
												{{$previousExclusiveScope = $exclusiveScope}}
 | 
				
			||||||
							<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}}
 | 
												<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}}
 | 
				
			||||||
							{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a>
 | 
												{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
					{{else}}
 | 
										{{else}}
 | 
				
			||||||
						<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
 | 
											<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -180,11 +180,11 @@
 | 
				
			|||||||
					<span class="text grey muted-links">
 | 
										<span class="text grey muted-links">
 | 
				
			||||||
						{{template "shared/user/authorlink" .Poster}}
 | 
											{{template "shared/user/authorlink" .Poster}}
 | 
				
			||||||
						{{if and .AddedLabels (not .RemovedLabels)}}
 | 
											{{if and .AddedLabels (not .RemovedLabels)}}
 | 
				
			||||||
							{{$.locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels .AddedLabels $.RepoLink) $createdStr | Safe}}
 | 
												{{$.locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) $createdStr | Safe}}
 | 
				
			||||||
						{{else if and (not .AddedLabels) .RemovedLabels}}
 | 
											{{else if and (not .AddedLabels) .RemovedLabels}}
 | 
				
			||||||
							{{$.locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels .RemovedLabels $.RepoLink) $createdStr | Safe}}
 | 
												{{$.locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr | Safe}}
 | 
				
			||||||
						{{else}}
 | 
											{{else}}
 | 
				
			||||||
							{{$.locale.Tr "repo.issues.add_remove_labels" (RenderLabels .AddedLabels $.RepoLink) (RenderLabels .RemovedLabels $.RepoLink) $createdStr | Safe}}
 | 
												{{$.locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr | Safe}}
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
					</span>
 | 
										</span>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
@@ -231,7 +231,7 @@
 | 
				
			|||||||
				{{template "shared/user/avatarlink" Dict "Context" $.Context "user" .Poster}}
 | 
									{{template "shared/user/avatarlink" Dict "Context" $.Context "user" .Poster}}
 | 
				
			||||||
				<span class="text grey muted-links">
 | 
									<span class="text grey muted-links">
 | 
				
			||||||
					{{template "shared/user/authorlink" .Poster}}
 | 
										{{template "shared/user/authorlink" .Poster}}
 | 
				
			||||||
					{{$.locale.Tr "repo.issues.change_title_at" (.OldTitle|RenderEmoji) (.NewTitle|RenderEmoji) $createdStr | Safe}}
 | 
										{{$.locale.Tr "repo.issues.change_title_at" (.OldTitle|RenderEmoji $.Context) (.NewTitle|RenderEmoji $.Context) $createdStr | Safe}}
 | 
				
			||||||
				</span>
 | 
									</span>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
		{{else if eq .Type 11}}
 | 
							{{else if eq .Type 11}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,8 +130,8 @@
 | 
				
			|||||||
							<div class="ui divider"></div>
 | 
												<div class="ui divider"></div>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{$previousExclusiveScope = $exclusiveScope}}
 | 
											{{$previousExclusiveScope = $exclusiveScope}}
 | 
				
			||||||
						<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}}
 | 
											<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}}
 | 
				
			||||||
						{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a>
 | 
											{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					<div class="ui divider"></div>
 | 
										<div class="ui divider"></div>
 | 
				
			||||||
					{{$previousExclusiveScope := "_no_scope"}}
 | 
										{{$previousExclusiveScope := "_no_scope"}}
 | 
				
			||||||
@@ -141,8 +141,8 @@
 | 
				
			|||||||
							<div class="ui divider"></div>
 | 
												<div class="ui divider"></div>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
						{{$previousExclusiveScope = $exclusiveScope}}
 | 
											{{$previousExclusiveScope = $exclusiveScope}}
 | 
				
			||||||
						<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel .}}
 | 
											<a class="{{if .IsChecked}}checked{{end}} item" href="#" data-id="{{.ID}}" data-id-selector="#label_{{.ID}}" data-scope="{{$exclusiveScope}}"><span class="octicon-check {{if not .IsChecked}}invisible{{end}}">{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}</span>  {{RenderLabel $.Context .}}
 | 
				
			||||||
						{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji}}</small>{{end}}</a>
 | 
											{{if .Description}}<br><small class="desc">{{.Description | RenderEmoji $.Context}}</small>{{end}}</a>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
				{{else}}
 | 
									{{else}}
 | 
				
			||||||
					<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
 | 
										<div class="header" style="text-transform: none;font-size:14px;">{{.locale.Tr "repo.issues.new.no_items"}}</div>
 | 
				
			||||||
@@ -487,8 +487,8 @@
 | 
				
			|||||||
						{{range .BlockingDependencies}}
 | 
											{{range .BlockingDependencies}}
 | 
				
			||||||
							<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
 | 
												<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
 | 
				
			||||||
								<div class="item-left gt-df gt-jc gt-fc gt-f1">
 | 
													<div class="item-left gt-df gt-jc gt-fc gt-f1">
 | 
				
			||||||
									<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}">
 | 
														<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
 | 
				
			||||||
										#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}
 | 
															#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
 | 
				
			||||||
									</a>
 | 
														</a>
 | 
				
			||||||
									<div class="text small">
 | 
														<div class="text small">
 | 
				
			||||||
										{{.Repository.OwnerName}}/{{.Repository.Name}}
 | 
															{{.Repository.OwnerName}}/{{.Repository.Name}}
 | 
				
			||||||
@@ -514,8 +514,8 @@
 | 
				
			|||||||
						{{range .BlockedByDependencies}}
 | 
											{{range .BlockedByDependencies}}
 | 
				
			||||||
							<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
 | 
												<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} gt-df gt-ac gt-sb">
 | 
				
			||||||
								<div class="item-left gt-df gt-jc gt-fc gt-f1">
 | 
													<div class="item-left gt-df gt-jc gt-fc gt-f1">
 | 
				
			||||||
									<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}">
 | 
														<a class="title tooltip" href="{{.Issue.Link}}" data-content="#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}">
 | 
				
			||||||
										#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}
 | 
															#{{.Issue.Index}} {{.Issue.Title | RenderEmoji $.Context}}
 | 
				
			||||||
									</a>
 | 
														</a>
 | 
				
			||||||
									<div class="text small">
 | 
														<div class="text small">
 | 
				
			||||||
										{{.Repository.OwnerName}}/{{.Repository.Name}}
 | 
															{{.Repository.OwnerName}}/{{.Repository.Name}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -245,7 +245,7 @@
 | 
				
			|||||||
						{{if or .Labels .Assignees}}
 | 
											{{if or .Labels .Assignees}}
 | 
				
			||||||
						<div class="extra content labels-list gt-p-0 gt-pt-2">
 | 
											<div class="extra content labels-list gt-p-0 gt-pt-2">
 | 
				
			||||||
							{{range .Labels}}
 | 
												{{range .Labels}}
 | 
				
			||||||
								<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel .}}</a>
 | 
													<a target="_blank" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{RenderLabel $.Context .}}</a>
 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
							<div class="right floated">
 | 
												<div class="right floated">
 | 
				
			||||||
								{{range .Assignees}}
 | 
													{{range .Assignees}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@
 | 
				
			|||||||
							<td class="message">
 | 
												<td class="message">
 | 
				
			||||||
								<span class="truncate">
 | 
													<span class="truncate">
 | 
				
			||||||
									<a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{.Summary | RenderEmojiPlain}}">
 | 
														<a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{.Summary | RenderEmojiPlain}}">
 | 
				
			||||||
										{{.Summary | RenderEmoji}}
 | 
															{{.Summary | RenderEmoji $.Context}}
 | 
				
			||||||
									</a>
 | 
														</a>
 | 
				
			||||||
								</span>
 | 
													</span>
 | 
				
			||||||
							</td>
 | 
												</td>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@
 | 
				
			|||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<div class="issue-item-main gt-f1 gt-fc gt-df">
 | 
								<div class="issue-item-main gt-f1 gt-fc gt-df">
 | 
				
			||||||
				<div class="issue-item-top-row">
 | 
									<div class="issue-item-top-row">
 | 
				
			||||||
					<a class="title gt-tdn issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji .Title | RenderCodeBlock}}</a>
 | 
										<a class="title gt-tdn issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji $.Context .Title | RenderCodeBlock}}</a>
 | 
				
			||||||
					{{if .IsPull}}
 | 
										{{if .IsPull}}
 | 
				
			||||||
						{{if (index $.CommitStatuses .PullRequest.ID)}}
 | 
											{{if (index $.CommitStatuses .PullRequest.ID)}}
 | 
				
			||||||
							{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}}
 | 
												{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}}
 | 
				
			||||||
@@ -42,7 +42,7 @@
 | 
				
			|||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					<span class="labels-list gt-ml-2">
 | 
										<span class="labels-list gt-ml-2">
 | 
				
			||||||
						{{range .Labels}}
 | 
											{{range .Labels}}
 | 
				
			||||||
							<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{RenderLabel .}}</a>
 | 
												<a href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}{{if ne $.listType "milestone"}}&milestone={{$.MilestoneID}}{{end}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{RenderLabel $.Context .}}</a>
 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
					</span>
 | 
										</span>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,7 +72,7 @@
 | 
				
			|||||||
							{{$index := index .GetIssueInfos 0}}
 | 
												{{$index := index .GetIssueInfos 0}}
 | 
				
			||||||
							{{$.locale.Tr "action.comment_pull" ((printf "%s/pulls/%s" .GetRepoLink $index) |Escape) $index (.ShortRepoPath|Escape) | Str2html}}
 | 
												{{$.locale.Tr "action.comment_pull" ((printf "%s/pulls/%s" .GetRepoLink $index) |Escape) $index (.ShortRepoPath|Escape) | Str2html}}
 | 
				
			||||||
						{{else if eq .GetOpType 24}}
 | 
											{{else if eq .GetOpType 24}}
 | 
				
			||||||
							{{$linkText := .Content | RenderEmoji}}
 | 
												{{$linkText := .Content | RenderEmoji $.Context}}
 | 
				
			||||||
							{{$.locale.Tr "action.publish_release" (.GetRepoLink|Escape) ((printf "%s/releases/tag/%s" .GetRepoLink .GetTag)|Escape) (.ShortRepoPath|Escape) $linkText | Str2html}}
 | 
												{{$.locale.Tr "action.publish_release" (.GetRepoLink|Escape) ((printf "%s/releases/tag/%s" .GetRepoLink .GetTag)|Escape) (.ShortRepoPath|Escape) $linkText | Str2html}}
 | 
				
			||||||
						{{else if eq .GetOpType 25}}
 | 
											{{else if eq .GetOpType 25}}
 | 
				
			||||||
							{{$index := index .GetIssueInfos 0}}
 | 
												{{$index := index .GetIssueInfos 0}}
 | 
				
			||||||
@@ -99,20 +99,20 @@
 | 
				
			|||||||
							</ul>
 | 
												</ul>
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					{{else if eq .GetOpType 6}}
 | 
										{{else if eq .GetOpType 6}}
 | 
				
			||||||
						<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji | RenderCodeBlock}}</span>
 | 
											<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span>
 | 
				
			||||||
					{{else if eq .GetOpType 7}}
 | 
										{{else if eq .GetOpType 7}}
 | 
				
			||||||
						<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji | RenderCodeBlock}}</span>
 | 
											<span class="text truncate issue title">{{index .GetIssueInfos 1 | RenderEmoji $.Context | RenderCodeBlock}}</span>
 | 
				
			||||||
					{{else if or (eq .GetOpType 10) (eq .GetOpType 21) (eq .GetOpType 22) (eq .GetOpType 23)}}
 | 
										{{else if or (eq .GetOpType 10) (eq .GetOpType 21) (eq .GetOpType 22) (eq .GetOpType 23)}}
 | 
				
			||||||
						<a href="{{.GetCommentLink}}" class="text truncate issue title">{{.GetIssueTitle | RenderEmoji | RenderCodeBlock}}</a>
 | 
											<a href="{{.GetCommentLink}}" class="text truncate issue title">{{.GetIssueTitle | RenderEmoji $.Context | RenderCodeBlock}}</a>
 | 
				
			||||||
						{{$comment := index .GetIssueInfos 1}}
 | 
											{{$comment := index .GetIssueInfos 1}}
 | 
				
			||||||
						{{if gt (len $comment) 0}}<p class="text light grey">{{$comment | RenderEmoji}}</p>{{end}}
 | 
											{{if gt (len $comment) 0}}<p class="text light grey">{{$comment | RenderEmoji $.Context}}</p>{{end}}
 | 
				
			||||||
					{{else if eq .GetOpType 11}}
 | 
										{{else if eq .GetOpType 11}}
 | 
				
			||||||
						<p class="text light grey">{{index .GetIssueInfos 1}}</p>
 | 
											<p class="text light grey">{{index .GetIssueInfos 1}}</p>
 | 
				
			||||||
					{{else if or (eq .GetOpType 12) (eq .GetOpType 13) (eq .GetOpType 14) (eq .GetOpType 15)}}
 | 
										{{else if or (eq .GetOpType 12) (eq .GetOpType 13) (eq .GetOpType 14) (eq .GetOpType 15)}}
 | 
				
			||||||
						<span class="text truncate issue title">{{.GetIssueTitle | RenderEmoji | RenderCodeBlock}}</span>
 | 
											<span class="text truncate issue title">{{.GetIssueTitle | RenderEmoji $.Context | RenderCodeBlock}}</span>
 | 
				
			||||||
					{{else if eq .GetOpType 25}}
 | 
										{{else if eq .GetOpType 25}}
 | 
				
			||||||
					<p class="text light grey">{{$.locale.Tr "action.review_dismissed_reason"}}</p>
 | 
										<p class="text light grey">{{$.locale.Tr "action.review_dismissed_reason"}}</p>
 | 
				
			||||||
						<p class="text light grey">{{index .GetIssueInfos 2 | RenderEmoji}}</p>
 | 
											<p class="text light grey">{{index .GetIssueInfos 2 | RenderEmoji $.Context}}</p>
 | 
				
			||||||
					{{end}}
 | 
										{{end}}
 | 
				
			||||||
					<p class="text italic light grey">{{TimeSince .GetCreate $.locale}}</p>
 | 
										<p class="text italic light grey">{{TimeSince .GetCreate $.locale}}</p>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user