Skip to content

Commit 299270a

Browse files
committed
Fix rendering of external links
1 parent e90bbca commit 299270a

File tree

4 files changed

+56
-79
lines changed

4 files changed

+56
-79
lines changed

modules/markdown/markdown.go

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,29 @@ var (
6969
// AnySHA1Pattern allows to split url containing SHA into parts
7070
AnySHA1Pattern = regexp.MustCompile(`(http\S*)://(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?`)
7171

72-
// IssueFullPattern allows to split issue (and pull) URLs into parts
73-
IssueFullPattern = regexp.MustCompile(`(?:^|\s|\()(http\S*)://((?:[^\s/]+/)+)((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b`)
74-
7572
validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
7673
)
7774

75+
// regexp for full links to issues/pulls
76+
var issueFullPattern *regexp.Regexp
77+
78+
// InitMarkdown initialize regexps for markdown parsing
79+
func InitMarkdown() {
80+
getIssueFullPattern()
81+
}
82+
83+
func getIssueFullPattern() *regexp.Regexp {
84+
if issueFullPattern == nil {
85+
appURL := setting.AppURL
86+
if len(appURL) > 0 && appURL[len(appURL)-1] != '/' {
87+
appURL += "/"
88+
}
89+
issueFullPattern = regexp.MustCompile(appURL +
90+
`\w+/\w+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b`)
91+
}
92+
return issueFullPattern
93+
}
94+
7895
// isLink reports whether link fits valid format.
7996
func isLink(link []byte) bool {
8097
return validLinksPattern.Match(link)
@@ -323,32 +340,17 @@ func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte {
323340
return rawBytes
324341
}
325342

326-
// renderFullIssuePattern renders issues-like URLs
327-
func renderFullIssuePattern(rawBytes []byte, urlPrefix string) []byte {
328-
ms := IssueFullPattern.FindAllSubmatch(rawBytes, -1)
343+
// RenderFullIssuePattern renders issues-like URLs
344+
func RenderFullIssuePattern(rawBytes []byte) []byte {
345+
ms := getIssueFullPattern().FindAllSubmatch(rawBytes, -1)
329346
for _, m := range ms {
330347
all := m[0]
331-
protocol := string(m[1])
332-
paths := bytes.Split(m[2], []byte("/"))
333-
paths = paths[:len(paths)-1]
334-
if bytes.HasPrefix(paths[0], []byte("gist.")) {
335-
continue
336-
}
337-
path := protocol + "://" + string(m[2])
338-
id := string(m[3])
339-
path = URLJoin(path, id)
340-
var comment []byte
341-
if len(m) > 3 {
342-
comment = m[4]
343-
}
344-
urlSuffix := ""
348+
id := string(m[1])
345349
text := "#" + id
346-
if comment != nil {
347-
urlSuffix += string(comment)
348-
text += " <i class='comment icon'></i>"
349-
}
350+
// TODO if m[2] is not nil, then link is to a comment,
351+
// and we should indicate that in the text somehow
350352
rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf(
351-
`<a href="%s%s">%s</a>`, path, urlSuffix, text)), -1)
353+
`<a href="%s">%s</a>`, string(all), text)), -1)
352354
}
353355
return rawBytes
354356
}
@@ -550,12 +552,12 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]strin
550552
[]byte(fmt.Sprintf(`<a href="%s">%s</a>`, URLJoin(setting.AppURL, string(m[1:])), m)), -1)
551553
}
552554

555+
rawBytes = RenderFullIssuePattern(rawBytes)
553556
rawBytes = RenderShortLinks(rawBytes, urlPrefix, false, isWikiMarkdown)
554557
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
555558
rawBytes = RenderCrossReferenceIssueIndexPattern(rawBytes, urlPrefix, metas)
556559
rawBytes = renderFullSha1Pattern(rawBytes, urlPrefix)
557560
rawBytes = renderSha1CurrentPattern(rawBytes, urlPrefix)
558-
rawBytes = renderFullIssuePattern(rawBytes, urlPrefix)
559561
return rawBytes
560562
}
561563

modules/markdown/markdown_test.go

Lines changed: 26 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,15 @@ func TestRender_AutoLink(t *testing.T) {
209209
numericIssueLink(URLJoin(setting.AppSubURL, "issues"), 3333))
210210

211211
// render external issue URLs
212-
tmp := "http://1111/2222/ssss-issues/3333?param=blah&blahh=333"
213-
test(tmp, "<a href=\""+tmp+"\">#3333 <i class='comment icon'></i></a>")
214-
test("http://test.com/issues/33333", numericIssueLink("http://test.com/issues", 33333))
215-
test("https://issues/333", numericIssueLink("https://issues", 333))
212+
for _, externalURL := range []string{
213+
"http://1111/2222/ssss-issues/3333?param=blah&blahh=333",
214+
"http://test.com/issues/33333",
215+
"https://issues/333"} {
216+
test(externalURL, externalURL)
217+
}
216218

217219
// render valid commit URLs
218-
tmp = URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
220+
tmp := URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
219221
test(tmp, "<a href=\""+tmp+"\">d8a994ef24</a>")
220222
tmp += "#diff-2"
221223
test(tmp, "<a href=\""+tmp+"\">d8a994ef24 (diff-2)</a>")
@@ -368,6 +370,22 @@ func TestRender_CrossReferences(t *testing.T) {
368370
`<p><a href="`+URLJoin(AppURL, "gogits", "gogs", "issues", "12345")+`" rel="nofollow">gogits/gogs#12345</a></p>`)
369371
}
370372

373+
func TestRender_FullIssueURLs(t *testing.T) {
374+
setting.AppURL = AppURL
375+
setting.AppSubURL = AppSubURL
376+
377+
test := func(input, expected string) {
378+
result := RenderFullIssuePattern([]byte(input))
379+
assert.Equal(t, expected, string(result))
380+
}
381+
test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6",
382+
"Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6")
383+
test("Look here http://localhost:3000/person/repo/issues/4",
384+
`Look here <a href="http://localhost:3000/person/repo/issues/4">#4</a>`)
385+
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
386+
`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234">#4</a>`)
387+
}
388+
371389
func TestRegExp_MentionPattern(t *testing.T) {
372390
trueTestCases := []string{
373391
"@Unknwon",
@@ -558,50 +576,6 @@ func TestRegExp_AnySHA1Pattern(t *testing.T) {
558576
}
559577
}
560578

561-
func TestRegExp_IssueFullPattern(t *testing.T) {
562-
testCases := map[string][]string{
563-
"https://github.com/gogits/gogs/pull/3244": {
564-
"https",
565-
"github.com/gogits/gogs/pull/",
566-
"3244",
567-
"",
568-
"",
569-
},
570-
"https://github.com/gogits/gogs/issues/3247#issuecomment-231517079": {
571-
"https",
572-
"github.com/gogits/gogs/issues/",
573-
"3247",
574-
"#issuecomment-231517079",
575-
"",
576-
},
577-
"https://try.gogs.io/gogs/gogs/issues/4#issue-685": {
578-
"https",
579-
"try.gogs.io/gogs/gogs/issues/",
580-
"4",
581-
"#issue-685",
582-
"",
583-
},
584-
"https://youtrack.jetbrains.com/issue/JT-36485": {
585-
"https",
586-
"youtrack.jetbrains.com/issue/",
587-
"JT-36485",
588-
"",
589-
"",
590-
},
591-
"https://youtrack.jetbrains.com/issue/JT-36485#comment=27-1508676": {
592-
"https",
593-
"youtrack.jetbrains.com/issue/",
594-
"JT-36485",
595-
"#comment=27-1508676",
596-
"",
597-
},
598-
}
599-
600-
for k, v := range testCases {
601-
assert.Equal(t, IssueFullPattern.FindStringSubmatch(k)[1:], v)
602-
}
603-
}
604-
605579
func TestMisc_IsMarkdownFile(t *testing.T) {
606580
setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"}
607581
trueTestCases := []string{
@@ -645,7 +619,7 @@ var sameCases = []string{
645619
646620
Ideas and codes
647621
648-
- Bezier widget (by @r-lyeh) https://github.com/ocornut/imgui/issues/786
622+
- Bezier widget (by @r-lyeh) ` + AppURL + `ocornut/imgui/issues/786
649623
- Node graph editors https://github.com/ocornut/imgui/issues/306
650624
- [[Memory Editor|memory_editor_example]]
651625
- [[Plot var helper|plot_var_example]]`,
@@ -681,8 +655,8 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
681655
<p>Ideas and codes</p>
682656
683657
<ul>
684-
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>)<a href="https://github.com/ocornut/imgui/issues/786" rel="nofollow">#786</a></li>
685-
<li>Node graph editors<a href="https://github.com/ocornut/imgui/issues/306" rel="nofollow">#306</a></li>
658+
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" rel="nofollow">#786</a></li>
659+
<li>Node graph editors https://github.com/ocornut/imgui/issues/306</li>
686660
<li><a href="` + baseURLContent + `/memory_editor_example" rel="nofollow">Memory Editor</a></li>
687661
<li><a href="` + baseURLContent + `/plot_var_example" rel="nofollow">Plot var helper</a></li>
688662
</ul>

routers/api/v1/misc/markdown_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func TestAPI_RenderGFM(t *testing.T) {
7575
<ul>
7676
<li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
7777
<li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li>
78-
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>)<a href="https://github.com/ocornut/imgui/issues/786" rel="nofollow">#786</a></li>
78+
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) https://github.com/ocornut/imgui/issues/786</li>
7979
</ul>
8080
`,
8181
// wine-staging wiki home extract: special wiki syntax, images

routers/init.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func GlobalInit() {
5050

5151
if setting.InstallLock {
5252
highlight.NewContext()
53+
markdown.InitMarkdown()
5354
markdown.NewSanitizer()
5455
if err := models.NewEngine(migrations.Migrate); err != nil {
5556
log.Fatal(4, "Failed to initialize ORM engine: %v", err)

0 commit comments

Comments
 (0)