mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-22 20:53:40 +09:00
fix(markup): make RenderString never fail (#37779)
Fix #37778 --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Nicolas <bircni@icloud.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
wxiaoguang
wxiaoguang
Nicolas
parent
621aa67e7d
commit
7e436972f9
@@ -5,12 +5,19 @@ package renderhelper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func testRenderString(ctx *markup.RenderContext, content string) (string, error) {
|
||||||
|
var buf strings.Builder
|
||||||
|
err := markup.Render(ctx, strings.NewReader(content), &buf)
|
||||||
|
return buf.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
unittest.MainTest(m, &unittest.TestOptions{
|
unittest.MainTest(m, &unittest.TestOptions{
|
||||||
FixtureFiles: []string{"repository.yml", "user.yml"},
|
FixtureFiles: []string{"repository.yml", "user.yml"},
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -21,7 +20,7 @@ func TestRepoComment(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("AutoLink", func(t *testing.T) {
|
t.Run("AutoLink", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoComment(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextRepoComment(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
||||||
#1
|
#1
|
||||||
@user2
|
@user2
|
||||||
@@ -39,7 +38,7 @@ func TestRepoComment(t *testing.T) {
|
|||||||
|
|
||||||
// It is Gitea's old behavior, the relative path is resolved to the repo path
|
// It is Gitea's old behavior, the relative path is resolved to the repo path
|
||||||
// It is different from GitHub, GitHub resolves relative links to current page's path
|
// It is different from GitHub, GitHub resolves relative links to current page's path
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
[/test](/test)
|
[/test](/test)
|
||||||
[./test](./test)
|
[./test](./test)
|
||||||

|

|
||||||
@@ -59,7 +58,7 @@ func TestRepoComment(t *testing.T) {
|
|||||||
WithMarkupType(markdown.MarkupName)
|
WithMarkupType(markdown.MarkupName)
|
||||||
|
|
||||||
// the ref path is only used to render commit message: a commit message is rendered at the commit page with its commit ID path
|
// the ref path is only used to render commit message: a commit message is rendered at the commit page with its commit ID path
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
[/test](/test)
|
[/test](/test)
|
||||||
[./test](./test)
|
[./test](./test)
|
||||||

|

|
||||||
@@ -75,7 +74,7 @@ func TestRepoComment(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("NoRepo", func(t *testing.T) {
|
t.Run("NoRepo", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoComment(t.Context(), nil).WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextRepoComment(t.Context(), nil).WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, "any")
|
rendered, err := testRenderString(rctx, "any")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "<p>any</p>\n", rendered)
|
assert.Equal(t, "<p>any</p>\n", rendered)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
|
|
||||||
_ "code.gitea.io/gitea/modules/markup/orgmode"
|
_ "code.gitea.io/gitea/modules/markup/orgmode"
|
||||||
@@ -22,7 +21,7 @@ func TestRepoFile(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("AutoLink", func(t *testing.T) {
|
t.Run("AutoLink", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoFile(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextRepoFile(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
||||||
#1
|
#1
|
||||||
@user2
|
@user2
|
||||||
@@ -38,7 +37,7 @@ func TestRepoFile(t *testing.T) {
|
|||||||
t.Run("AbsoluteAndRelative", func(t *testing.T) {
|
t.Run("AbsoluteAndRelative", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefSubURL: "branch/main"}).
|
rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefSubURL: "branch/main"}).
|
||||||
WithMarkupType(markdown.MarkupName)
|
WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
[/test](/test)
|
[/test](/test)
|
||||||
[./test](./test)
|
[./test](./test)
|
||||||

|

|
||||||
@@ -56,7 +55,7 @@ func TestRepoFile(t *testing.T) {
|
|||||||
t.Run("WithCurrentRefSubURL", func(t *testing.T) {
|
t.Run("WithCurrentRefSubURL", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefSubURL: "/commit/1234"}).
|
rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{CurrentRefSubURL: "/commit/1234"}).
|
||||||
WithMarkupType(markdown.MarkupName)
|
WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
[/test](/test)
|
[/test](/test)
|
||||||

|

|
||||||
`)
|
`)
|
||||||
@@ -72,7 +71,7 @@ func TestRepoFile(t *testing.T) {
|
|||||||
CurrentTreePath: "my-dir",
|
CurrentTreePath: "my-dir",
|
||||||
}).
|
}).
|
||||||
WithMarkupType(markdown.MarkupName)
|
WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
<img src="LINK">
|
<img src="LINK">
|
||||||
<video src="LINK">
|
<video src="LINK">
|
||||||
`)
|
`)
|
||||||
@@ -93,7 +92,7 @@ func TestRepoFileOrgMode(t *testing.T) {
|
|||||||
CurrentTreePath: "my-dir",
|
CurrentTreePath: "my-dir",
|
||||||
}).WithRelativePath("my-dir/a.org")
|
}).WithRelativePath("my-dir/a.org")
|
||||||
|
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
[[https://google.com/]]
|
[[https://google.com/]]
|
||||||
[[ImageLink.svg][The Image Desc]]
|
[[ImageLink.svg][The Image Desc]]
|
||||||
`)
|
`)
|
||||||
@@ -107,7 +106,7 @@ func TestRepoFileOrgMode(t *testing.T) {
|
|||||||
t.Run("CodeHighlight", func(t *testing.T) {
|
t.Run("CodeHighlight", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{}).WithRelativePath("my-dir/a.org")
|
rctx := NewRenderContextRepoFile(t.Context(), repo1, RepoFileOptions{}).WithRelativePath("my-dir/a.org")
|
||||||
|
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
#+begin_src c
|
#+begin_src c
|
||||||
int a = 1;
|
int a = 1;
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -20,7 +19,7 @@ func TestRepoWiki(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("AutoLink", func(t *testing.T) {
|
t.Run("AutoLink", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
||||||
#1
|
#1
|
||||||
@user2
|
@user2
|
||||||
@@ -35,7 +34,7 @@ func TestRepoWiki(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("AbsoluteAndRelative", func(t *testing.T) {
|
t.Run("AbsoluteAndRelative", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
[/test](/test)
|
[/test](/test)
|
||||||
[./test](./test)
|
[./test](./test)
|
||||||

|

|
||||||
@@ -52,7 +51,7 @@ func TestRepoWiki(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("PathInTag", func(t *testing.T) {
|
t.Run("PathInTag", func(t *testing.T) {
|
||||||
rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextRepoWiki(t.Context(), repo1).WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
<img src="LINK">
|
<img src="LINK">
|
||||||
<video src="LINK">
|
<video src="LINK">
|
||||||
`)
|
`)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
func TestSimpleDocument(t *testing.T) {
|
func TestSimpleDocument(t *testing.T) {
|
||||||
unittest.PrepareTestEnv(t)
|
unittest.PrepareTestEnv(t)
|
||||||
rctx := NewRenderContextSimpleDocument(t.Context(), "/base").WithMarkupType(markdown.MarkupName)
|
rctx := NewRenderContextSimpleDocument(t.Context(), "/base").WithMarkupType(markdown.MarkupName)
|
||||||
rendered, err := markup.RenderString(rctx, `
|
rendered, err := testRenderString(rctx, `
|
||||||
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
||||||
#1
|
#1
|
||||||
@user2
|
@user2
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func TestRenderCodePreview(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
buffer, err := markup.RenderString(markup.NewTestRenderContext().WithMarkupType(markdown.MarkupName), input)
|
buffer, err := testRenderString(markup.NewTestRenderContext().WithMarkupType(markdown.MarkupName), 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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,16 @@ var (
|
|||||||
localMetas = map[string]string{"user": testRepoOwnerName, "repo": testRepoName}
|
localMetas = map[string]string{"user": testRepoOwnerName, "repo": testRepoName}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func testRenderString(ctx *markup.RenderContext, content string) (string, error) {
|
||||||
|
var buf strings.Builder
|
||||||
|
err := markup.Render(ctx, strings.NewReader(content), &buf)
|
||||||
|
return buf.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
func TestRender_Commits(t *testing.T) {
|
func TestRender_Commits(t *testing.T) {
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
rctx := markup.NewTestRenderContext(markup.TestAppURL, localMetas).WithRelativePath("a.md")
|
rctx := markup.NewTestRenderContext(markup.TestAppURL, localMetas).WithRelativePath("a.md")
|
||||||
buffer, err := markup.RenderString(rctx, input)
|
buffer, err := testRenderString(rctx, 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))
|
||||||
}
|
}
|
||||||
@@ -75,7 +81,7 @@ func TestRender_CrossReferences(t *testing.T) {
|
|||||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
rctx := markup.NewTestRenderContext(markup.TestAppURL, localMetas).WithRelativePath("a.md")
|
rctx := markup.NewTestRenderContext(markup.TestAppURL, localMetas).WithRelativePath("a.md")
|
||||||
buffer, err := markup.RenderString(rctx, input)
|
buffer, err := testRenderString(rctx, 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))
|
||||||
}
|
}
|
||||||
@@ -119,7 +125,7 @@ func TestRender_links(t *testing.T) {
|
|||||||
setting.AppURL = markup.TestAppURL
|
setting.AppURL = markup.TestAppURL
|
||||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
buffer, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
buffer, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), 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))
|
||||||
}
|
}
|
||||||
@@ -234,7 +240,7 @@ func TestRender_email(t *testing.T) {
|
|||||||
setting.AppURL = markup.TestAppURL
|
setting.AppURL = markup.TestAppURL
|
||||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string) {
|
||||||
res, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
res, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res), "input: %s", input)
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res), "input: %s", input)
|
||||||
}
|
}
|
||||||
@@ -321,7 +327,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 := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
buffer, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), 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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/htmlutil"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/markup/common"
|
"code.gitea.io/gitea/modules/markup/common"
|
||||||
@@ -266,7 +267,9 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
|
|||||||
func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) {
|
func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) {
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
||||||
return "", err
|
log.Warn("Unable to RenderString: %v, content: %s", err, giteautil.TruncateRunes(content, 200))
|
||||||
|
err = nil
|
||||||
|
return htmlutil.EscapeString(content), err
|
||||||
}
|
}
|
||||||
return template.HTML(buf.String()), nil
|
return template.HTML(buf.String()), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,15 +198,6 @@ func Render(rctx *RenderContext, origInput io.Reader, output io.Writer) error {
|
|||||||
return RenderWithRenderer(rctx, renderer, input, output)
|
return RenderWithRenderer(rctx, renderer, input, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderString renders Markup string to HTML with all specific handling stuff and return string
|
|
||||||
func RenderString(ctx *RenderContext, content string) (string, error) {
|
|
||||||
var buf strings.Builder
|
|
||||||
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return buf.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RenderIFrame(ctx *RenderContext, opts *ExternalRendererOptions, output io.Writer) error {
|
func RenderIFrame(ctx *RenderContext, opts *ExternalRendererOptions, output io.Writer) error {
|
||||||
ownerName, repoName := ctx.RenderOptions.Metas["user"], ctx.RenderOptions.Metas["repo"]
|
ownerName, repoName := ctx.RenderOptions.Metas["user"], ctx.RenderOptions.Metas["repo"]
|
||||||
refSubURL := ctx.RenderOptions.Metas["RefTypeNameSubURL"]
|
refSubURL := ctx.RenderOptions.Metas["RefTypeNameSubURL"]
|
||||||
|
|||||||
Reference in New Issue
Block a user