Skip to content

Commit 19a08c7

Browse files
authored
Fix orgmode link resolving (#29024) (#29076)
Backport #29024 Also backport #27968 (remove unnecessary titles) Fix #28974 Add some new tests and fix some legacy unclear tests.
1 parent f0d34cd commit 19a08c7

File tree

2 files changed

+43
-41
lines changed

2 files changed

+43
-41
lines changed

modules/markup/orgmode/orgmode.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,18 @@ type Writer struct {
133133
Ctx *markup.RenderContext
134134
}
135135

136-
const mailto = "mailto:"
137-
138-
func (r *Writer) resolveLink(l org.RegularLink) string {
139-
link := html.EscapeString(l.URL)
140-
if l.Protocol == "file" {
141-
link = link[len("file:"):]
142-
}
143-
if len(link) > 0 && !markup.IsLinkStr(link) &&
144-
link[0] != '#' && !strings.HasPrefix(link, mailto) {
136+
func (r *Writer) resolveLink(kind, link string) string {
137+
link = strings.TrimPrefix(link, "file:")
138+
if !strings.HasPrefix(link, "#") && // not a URL fragment
139+
!markup.IsLinkStr(link) && // not an absolute URL
140+
!strings.HasPrefix(link, "mailto:") {
141+
if kind == "regular" {
142+
// orgmode reports the link kind as "regular" for "[[ImageLink.svg][The Image Desc]]"
143+
// so we need to try to guess the link kind again here
144+
kind = org.RegularLink{URL: link}.Kind()
145+
}
145146
base := r.Ctx.Links.Base
146-
switch l.Kind() {
147-
case "image", "video":
147+
if kind == "image" || kind == "video" {
148148
base = r.Ctx.Links.ResolveMediaLink(r.Ctx.IsWiki)
149149
}
150150
link = util.URLJoin(base, link)
@@ -154,29 +154,29 @@ func (r *Writer) resolveLink(l org.RegularLink) string {
154154

155155
// WriteRegularLink renders images, links or videos
156156
func (r *Writer) WriteRegularLink(l org.RegularLink) {
157-
link := r.resolveLink(l)
157+
link := r.resolveLink(l.Kind(), l.URL)
158158

159159
// Inspired by https://github.com/niklasfasching/go-org/blob/6eb20dbda93cb88c3503f7508dc78cbbc639378f/org/html_writer.go#L406-L427
160160
switch l.Kind() {
161161
case "image":
162162
if l.Description == nil {
163-
fmt.Fprintf(r, `<img src="%s" alt="%s" />`, link, link)
163+
_, _ = fmt.Fprintf(r, `<img src="%s" alt="%s" />`, link, link)
164164
} else {
165-
imageSrc := r.resolveLink(l.Description[0].(org.RegularLink))
166-
fmt.Fprintf(r, `<a href="%s"><img src="%s" alt="%s" /></a>`, link, imageSrc, imageSrc)
165+
imageSrc := r.resolveLink(l.Kind(), org.String(l.Description...))
166+
_, _ = fmt.Fprintf(r, `<a href="%s"><img src="%s" alt="%s" /></a>`, link, imageSrc, imageSrc)
167167
}
168168
case "video":
169169
if l.Description == nil {
170-
fmt.Fprintf(r, `<video src="%s">%s</video>`, link, link)
170+
_, _ = fmt.Fprintf(r, `<video src="%s">%s</video>`, link, link)
171171
} else {
172-
videoSrc := r.resolveLink(l.Description[0].(org.RegularLink))
173-
fmt.Fprintf(r, `<a href="%s"><video src="%s">%s</video></a>`, link, videoSrc, videoSrc)
172+
videoSrc := r.resolveLink(l.Kind(), org.String(l.Description...))
173+
_, _ = fmt.Fprintf(r, `<a href="%s"><video src="%s">%s</video></a>`, link, videoSrc, videoSrc)
174174
}
175175
default:
176176
description := link
177177
if l.Description != nil {
178178
description = r.WriteNodesAsString(l.Description...)
179179
}
180-
fmt.Fprintf(r, `<a href="%s" title="%s">%s</a>`, link, description, description)
180+
_, _ = fmt.Fprintf(r, `<a href="%s">%s</a>`, link, description)
181181
}
182182
}

modules/markup/orgmode/orgmode_test.go

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,60 +10,53 @@ import (
1010
"code.gitea.io/gitea/modules/git"
1111
"code.gitea.io/gitea/modules/markup"
1212
"code.gitea.io/gitea/modules/setting"
13-
"code.gitea.io/gitea/modules/util"
1413

1514
"github.com/stretchr/testify/assert"
1615
)
1716

18-
const (
19-
AppURL = "http://localhost:3000/"
20-
Repo = "gogits/gogs"
21-
AppSubURL = AppURL + Repo + "/"
22-
)
17+
const AppURL = "http://localhost:3000/"
2318

2419
func TestRender_StandardLinks(t *testing.T) {
2520
setting.AppURL = AppURL
26-
setting.AppSubURL = AppSubURL
2721

2822
test := func(input, expected string) {
2923
buffer, err := RenderString(&markup.RenderContext{
3024
Ctx: git.DefaultContext,
3125
Links: markup.Links{
32-
Base: setting.AppSubURL,
26+
Base: "/relative-path",
27+
BranchPath: "branch/main",
3328
},
3429
}, input)
3530
assert.NoError(t, err)
3631
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
3732
}
3833

39-
googleRendered := "<p><a href=\"https://google.com/\" title=\"https://google.com/\">https://google.com/</a></p>"
40-
test("[[https://google.com/]]", googleRendered)
41-
42-
lnk := util.URLJoin(AppSubURL, "WikiPage")
43-
test("[[WikiPage][WikiPage]]",
44-
"<p><a href=\""+lnk+"\" title=\"WikiPage\">WikiPage</a></p>")
34+
test("[[https://google.com/]]",
35+
`<p><a href="https://google.com/">https://google.com/</a></p>`)
36+
test("[[WikiPage][The WikiPage Desc]]",
37+
`<p><a href="/relative-path/WikiPage">The WikiPage Desc</a></p>`)
38+
test("[[ImageLink.svg][The Image Desc]]",
39+
`<p><a href="/relative-path/media/branch/main/ImageLink.svg">The Image Desc</a></p>`)
4540
}
4641

4742
func TestRender_Media(t *testing.T) {
4843
setting.AppURL = AppURL
49-
setting.AppSubURL = AppSubURL
5044

5145
test := func(input, expected string) {
5246
buffer, err := RenderString(&markup.RenderContext{
5347
Ctx: git.DefaultContext,
5448
Links: markup.Links{
55-
Base: setting.AppSubURL,
49+
Base: "./relative-path",
5650
},
5751
}, input)
5852
assert.NoError(t, err)
5953
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
6054
}
6155

62-
url := "../../.images/src/02/train.jpg"
63-
result := util.URLJoin(AppSubURL, url)
64-
65-
test("[[file:"+url+"]]",
66-
"<p><img src=\""+result+"\" alt=\""+result+"\" /></p>")
56+
test("[[file:../../.images/src/02/train.jpg]]",
57+
`<p><img src=".images/src/02/train.jpg" alt=".images/src/02/train.jpg" /></p>`)
58+
test("[[file:train.jpg]]",
59+
`<p><img src="relative-path/train.jpg" alt="relative-path/train.jpg" /></p>`)
6760

6861
// With description.
6962
test("[[https://example.com][https://example.com/example.svg]]",
@@ -76,11 +69,20 @@ func TestRender_Media(t *testing.T) {
7669
`<p><img src="https://example.com/example.svg" alt="https://example.com/example.svg" /></p>`)
7770
test("[[https://example.com/example.mp4]]",
7871
`<p><video src="https://example.com/example.mp4">https://example.com/example.mp4</video></p>`)
72+
73+
// test [[LINK][DESCRIPTION]] syntax with "file:" prefix
74+
test(`[[https://example.com/][file:https://example.com/foo%20bar.svg]]`,
75+
`<p><a href="https://example.com/"><img src="https://example.com/foo%20bar.svg" alt="https://example.com/foo%20bar.svg" /></a></p>`)
76+
test(`[[file:https://example.com/foo%20bar.svg][Goto Image]]`,
77+
`<p><a href="https://example.com/foo%20bar.svg">Goto Image</a></p>`)
78+
test(`[[file:https://example.com/link][https://example.com/image.jpg]]`,
79+
`<p><a href="https://example.com/link"><img src="https://example.com/image.jpg" alt="https://example.com/image.jpg" /></a></p>`)
80+
test(`[[file:https://example.com/link][file:https://example.com/image.jpg]]`,
81+
`<p><a href="https://example.com/link"><img src="https://example.com/image.jpg" alt="https://example.com/image.jpg" /></a></p>`)
7982
}
8083

8184
func TestRender_Source(t *testing.T) {
8285
setting.AppURL = AppURL
83-
setting.AppSubURL = AppSubURL
8486

8587
test := func(input, expected string) {
8688
buffer, err := RenderString(&markup.RenderContext{

0 commit comments

Comments
 (0)