This PR fixes the possible ambiguity of rendered inline permalinks across repos by adding it as a suffix to the title element if the permalink refers to a file not inside the current repository. Closes #2965 ![grafik](/attachments/e70e37b8-24c7-4f7b-ab52-92f1e8dfb009) Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/3042 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: Mai-Lapyst <mai-lapyst@noreply.codeberg.org> Co-committed-by: Mai-Lapyst <mai-lapyst@noreply.codeberg.org> (cherry picked from commit 1d1c0131bb1bbd117d5aaac48d7dd32f4638c648)
This commit is contained in:
parent
caa6b4a34d
commit
dbf1d06ff6
|
@ -27,10 +27,9 @@ var filePreviewPattern = regexp.MustCompile(`https?://((?:\S+/){3})src/commit/([
|
||||||
|
|
||||||
type FilePreview struct {
|
type FilePreview struct {
|
||||||
fileContent []template.HTML
|
fileContent []template.HTML
|
||||||
|
title template.HTML
|
||||||
subTitle template.HTML
|
subTitle template.HTML
|
||||||
lineOffset int
|
lineOffset int
|
||||||
urlFull string
|
|
||||||
filePath string
|
|
||||||
start int
|
start int
|
||||||
end int
|
end int
|
||||||
isTruncated bool
|
isTruncated bool
|
||||||
|
@ -54,39 +53,65 @@ func NewFilePreview(ctx *RenderContext, node *html.Node, locale translation.Loca
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
preview.urlFull = node.Data[m[0]:m[1]]
|
urlFull := node.Data[m[0]:m[1]]
|
||||||
|
|
||||||
// Ensure that we only use links to local repositories
|
// Ensure that we only use links to local repositories
|
||||||
if !strings.HasPrefix(preview.urlFull, setting.AppURL+setting.AppSubURL) {
|
if !strings.HasPrefix(urlFull, setting.AppURL+setting.AppSubURL) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
projPath := strings.TrimSuffix(node.Data[m[2]:m[3]], "/")
|
projPath := strings.TrimSuffix(node.Data[m[2]:m[3]], "/")
|
||||||
|
|
||||||
commitSha := node.Data[m[4]:m[5]]
|
commitSha := node.Data[m[4]:m[5]]
|
||||||
preview.filePath = node.Data[m[6]:m[7]]
|
filePath := node.Data[m[6]:m[7]]
|
||||||
hash := node.Data[m[8]:m[9]]
|
hash := node.Data[m[8]:m[9]]
|
||||||
|
|
||||||
preview.start = m[0]
|
preview.start = m[0]
|
||||||
preview.end = m[1]
|
preview.end = m[1]
|
||||||
|
|
||||||
projPathSegments := strings.Split(projPath, "/")
|
projPathSegments := strings.Split(projPath, "/")
|
||||||
|
ownerName := projPathSegments[len(projPathSegments)-2]
|
||||||
|
repoName := projPathSegments[len(projPathSegments)-1]
|
||||||
|
|
||||||
var language string
|
var language string
|
||||||
fileBlob, err := DefaultProcessorHelper.GetRepoFileBlob(
|
fileBlob, err := DefaultProcessorHelper.GetRepoFileBlob(
|
||||||
ctx.Ctx,
|
ctx.Ctx,
|
||||||
projPathSegments[len(projPathSegments)-2],
|
ownerName,
|
||||||
projPathSegments[len(projPathSegments)-1],
|
repoName,
|
||||||
commitSha, preview.filePath,
|
commitSha, filePath,
|
||||||
&language,
|
&language,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
titleBuffer := new(bytes.Buffer)
|
||||||
|
|
||||||
|
isExternRef := ownerName != ctx.Metas["user"] || repoName != ctx.Metas["repo"]
|
||||||
|
if isExternRef {
|
||||||
|
err = html.Render(titleBuffer, createLink(node.Data[m[0]:m[3]], ownerName+"/"+repoName, ""))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to render repoLink: %v", err)
|
||||||
|
}
|
||||||
|
titleBuffer.WriteString(" – ")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = html.Render(titleBuffer, createLink(urlFull, filePath, "muted"))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to render filepathLink: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
preview.title = template.HTML(titleBuffer.String())
|
||||||
|
|
||||||
lineSpecs := strings.Split(hash, "-")
|
lineSpecs := strings.Split(hash, "-")
|
||||||
|
|
||||||
commitLinkBuffer := new(bytes.Buffer)
|
commitLinkBuffer := new(bytes.Buffer)
|
||||||
err = html.Render(commitLinkBuffer, createLink(node.Data[m[0]:m[5]], commitSha[0:7], "text black"))
|
commitLinkText := commitSha[0:7]
|
||||||
|
if isExternRef {
|
||||||
|
commitLinkText = ownerName + "/" + repoName + "@" + commitLinkText
|
||||||
|
}
|
||||||
|
|
||||||
|
err = html.Render(commitLinkBuffer, createLink(node.Data[m[0]:m[5]], commitLinkText, "text black"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to render commitLink: %v", err)
|
log.Error("failed to render commitLink: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -272,19 +297,16 @@ func (p *FilePreview) CreateHTML(locale translation.Locale) *html.Node {
|
||||||
Data: atom.Div.String(),
|
Data: atom.Div.String(),
|
||||||
Attr: []html.Attribute{{Key: "class", Val: "header"}},
|
Attr: []html.Attribute{{Key: "class", Val: "header"}},
|
||||||
}
|
}
|
||||||
afilepath := &html.Node{
|
|
||||||
|
ptitle := &html.Node{
|
||||||
Type: html.ElementNode,
|
Type: html.ElementNode,
|
||||||
Data: atom.A.String(),
|
Data: atom.Div.String(),
|
||||||
Attr: []html.Attribute{
|
|
||||||
{Key: "href", Val: p.urlFull},
|
|
||||||
{Key: "class", Val: "muted"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
afilepath.AppendChild(&html.Node{
|
ptitle.AppendChild(&html.Node{
|
||||||
Type: html.TextNode,
|
Type: html.RawNode,
|
||||||
Data: p.filePath,
|
Data: string(p.title),
|
||||||
})
|
})
|
||||||
header.AppendChild(afilepath)
|
header.AppendChild(ptitle)
|
||||||
|
|
||||||
psubtitle := &html.Node{
|
psubtitle := &html.Node{
|
||||||
Type: html.ElementNode,
|
Type: html.ElementNode,
|
||||||
|
|
|
@ -1056,7 +1056,7 @@ func comparePatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func filePreviewPatternProcessor(ctx *RenderContext, node *html.Node) {
|
func filePreviewPatternProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
if ctx.Metas == nil {
|
if ctx.Metas == nil || ctx.Metas["user"] == "" || ctx.Metas["repo"] == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if DefaultProcessorHelper.GetRepoFileBlob == nil {
|
if DefaultProcessorHelper.GetRepoFileBlob == nil {
|
||||||
|
|
|
@ -705,11 +705,11 @@ func TestRender_FilePreview(t *testing.T) {
|
||||||
sha := "190d9492934af498c3f669d6a2431dc5459e5b20"
|
sha := "190d9492934af498c3f669d6a2431dc5459e5b20"
|
||||||
commitFilePreview := util.URLJoin(markup.TestRepoURL, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3"
|
commitFilePreview := util.URLJoin(markup.TestRepoURL, "src", "commit", sha, "path", "to", "file.go") + "#L2-L3"
|
||||||
|
|
||||||
test := func(input, expected string) {
|
test := func(input, expected string, metas map[string]string) {
|
||||||
buffer, err := markup.RenderString(&markup.RenderContext{
|
buffer, err := markup.RenderString(&markup.RenderContext{
|
||||||
Ctx: git.DefaultContext,
|
Ctx: git.DefaultContext,
|
||||||
RelativePath: ".md",
|
RelativePath: ".md",
|
||||||
Metas: localMetas,
|
Metas: metas,
|
||||||
}, 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))
|
||||||
|
@ -720,7 +720,9 @@ func TestRender_FilePreview(t *testing.T) {
|
||||||
`<p></p>`+
|
`<p></p>`+
|
||||||
`<div class="file-preview-box">`+
|
`<div class="file-preview-box">`+
|
||||||
`<div class="header">`+
|
`<div class="header">`+
|
||||||
|
`<div>`+
|
||||||
`<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+
|
`<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+
|
||||||
|
`</div>`+
|
||||||
`<span class="text small grey">`+
|
`<span class="text small grey">`+
|
||||||
`Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+
|
`Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">190d949</a>`+
|
||||||
`</span>`+
|
`</span>`+
|
||||||
|
@ -741,5 +743,41 @@ func TestRender_FilePreview(t *testing.T) {
|
||||||
`</div>`+
|
`</div>`+
|
||||||
`</div>`+
|
`</div>`+
|
||||||
`<p></p>`,
|
`<p></p>`,
|
||||||
|
localMetas,
|
||||||
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
commitFilePreview,
|
||||||
|
`<p></p>`+
|
||||||
|
`<div class="file-preview-box">`+
|
||||||
|
`<div class="header">`+
|
||||||
|
`<div>`+
|
||||||
|
`<a href="http://localhost:3000/gogits/gogs/" rel="nofollow">gogits/gogs</a> – `+
|
||||||
|
`<a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" class="muted" rel="nofollow">path/to/file.go</a>`+
|
||||||
|
`</div>`+
|
||||||
|
`<span class="text small grey">`+
|
||||||
|
`Lines 2 to 3 in <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20" class="text black" rel="nofollow">gogits/gogs@190d949</a>`+
|
||||||
|
`</span>`+
|
||||||
|
`</div>`+
|
||||||
|
`<div class="ui table">`+
|
||||||
|
`<table class="file-preview">`+
|
||||||
|
`<tbody>`+
|
||||||
|
`<tr>`+
|
||||||
|
`<td class="lines-num"><span data-line-number="2"></span></td>`+
|
||||||
|
`<td class="lines-code chroma"><code class="code-inner"><span class="nx">B</span>`+"\n"+`</code></td>`+
|
||||||
|
`</tr>`+
|
||||||
|
`<tr>`+
|
||||||
|
`<td class="lines-num"><span data-line-number="3"></span></td>`+
|
||||||
|
`<td class="lines-code chroma"><code class="code-inner"><span class="nx">C</span>`+"\n"+`</code></td>`+
|
||||||
|
`</tr>`+
|
||||||
|
`</tbody>`+
|
||||||
|
`</table>`+
|
||||||
|
`</div>`+
|
||||||
|
`</div>`+
|
||||||
|
`<p></p>`,
|
||||||
|
map[string]string{
|
||||||
|
"user": "gogits",
|
||||||
|
"repo": "gogs2",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue