]> source.dussan.org Git - gitea.git/commitdiff
Fix rendering of external links (#2292)
authorEthan Koenig <etk39@cornell.edu>
Sun, 13 Aug 2017 22:30:28 +0000 (15:30 -0700)
committerAndrey Nering <andrey.nering@gmail.com>
Sun, 13 Aug 2017 22:30:27 +0000 (19:30 -0300)
modules/markdown/markdown.go
modules/markdown/markdown_test.go
routers/api/v1/misc/markdown_test.go
routers/init.go

index 898df59292f2d576c9e014c76fea839e637f16f6..ed673f2056c2cc8b1f02aa0762e067ae7220bf4c 100644 (file)
@@ -69,12 +69,29 @@ var (
        // AnySHA1Pattern allows to split url containing SHA into parts
        AnySHA1Pattern = regexp.MustCompile(`(http\S*)://(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?`)
 
-       // IssueFullPattern allows to split issue (and pull) URLs into parts
-       IssueFullPattern = regexp.MustCompile(`(?:^|\s|\()(http\S*)://((?:[^\s/]+/)+)((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b`)
-
        validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`)
 )
 
+// regexp for full links to issues/pulls
+var issueFullPattern *regexp.Regexp
+
+// InitMarkdown initialize regexps for markdown parsing
+func InitMarkdown() {
+       getIssueFullPattern()
+}
+
+func getIssueFullPattern() *regexp.Regexp {
+       if issueFullPattern == nil {
+               appURL := setting.AppURL
+               if len(appURL) > 0 && appURL[len(appURL)-1] != '/' {
+                       appURL += "/"
+               }
+               issueFullPattern = regexp.MustCompile(appURL +
+                       `\w+/\w+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b`)
+       }
+       return issueFullPattern
+}
+
 // isLink reports whether link fits valid format.
 func isLink(link []byte) bool {
        return validLinksPattern.Match(link)
@@ -323,32 +340,17 @@ func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte {
        return rawBytes
 }
 
-// renderFullIssuePattern renders issues-like URLs
-func renderFullIssuePattern(rawBytes []byte, urlPrefix string) []byte {
-       ms := IssueFullPattern.FindAllSubmatch(rawBytes, -1)
+// RenderFullIssuePattern renders issues-like URLs
+func RenderFullIssuePattern(rawBytes []byte) []byte {
+       ms := getIssueFullPattern().FindAllSubmatch(rawBytes, -1)
        for _, m := range ms {
                all := m[0]
-               protocol := string(m[1])
-               paths := bytes.Split(m[2], []byte("/"))
-               paths = paths[:len(paths)-1]
-               if bytes.HasPrefix(paths[0], []byte("gist.")) {
-                       continue
-               }
-               path := protocol + "://" + string(m[2])
-               id := string(m[3])
-               path = URLJoin(path, id)
-               var comment []byte
-               if len(m) > 3 {
-                       comment = m[4]
-               }
-               urlSuffix := ""
+               id := string(m[1])
                text := "#" + id
-               if comment != nil {
-                       urlSuffix += string(comment)
-                       text += " <i class='comment icon'></i>"
-               }
+               // TODO if m[2] is not nil, then link is to a comment,
+               // and we should indicate that in the text somehow
                rawBytes = bytes.Replace(rawBytes, all, []byte(fmt.Sprintf(
-                       `<a href="%s%s">%s</a>`, path, urlSuffix, text)), -1)
+                       `<a href="%s">%s</a>`, string(all), text)), -1)
        }
        return rawBytes
 }
@@ -550,12 +552,12 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string, metas map[string]strin
                        []byte(fmt.Sprintf(`<a href="%s">%s</a>`, URLJoin(setting.AppURL, string(m[1:])), m)), -1)
        }
 
+       rawBytes = RenderFullIssuePattern(rawBytes)
        rawBytes = RenderShortLinks(rawBytes, urlPrefix, false, isWikiMarkdown)
        rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix, metas)
        rawBytes = RenderCrossReferenceIssueIndexPattern(rawBytes, urlPrefix, metas)
        rawBytes = renderFullSha1Pattern(rawBytes, urlPrefix)
        rawBytes = renderSha1CurrentPattern(rawBytes, urlPrefix)
-       rawBytes = renderFullIssuePattern(rawBytes, urlPrefix)
        return rawBytes
 }
 
index cfe9c5421a76f5f6effdd69d5c387469a122537e..4506a29b1eb361faac0f9303aad44e4f0efaef29 100644 (file)
@@ -209,13 +209,15 @@ func TestRender_AutoLink(t *testing.T) {
                numericIssueLink(URLJoin(setting.AppSubURL, "issues"), 3333))
 
        // render external issue URLs
-       tmp := "http://1111/2222/ssss-issues/3333?param=blah&blahh=333"
-       test(tmp, "<a href=\""+tmp+"\">#3333 <i class='comment icon'></i></a>")
-       test("http://test.com/issues/33333", numericIssueLink("http://test.com/issues", 33333))
-       test("https://issues/333", numericIssueLink("https://issues", 333))
+       for _, externalURL := range []string{
+               "http://1111/2222/ssss-issues/3333?param=blah&blahh=333",
+               "http://test.com/issues/33333",
+               "https://issues/333"} {
+               test(externalURL, externalURL)
+       }
 
        // render valid commit URLs
-       tmp = URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
+       tmp := URLJoin(AppSubURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
        test(tmp, "<a href=\""+tmp+"\">d8a994ef24</a>")
        tmp += "#diff-2"
        test(tmp, "<a href=\""+tmp+"\">d8a994ef24 (diff-2)</a>")
@@ -368,6 +370,22 @@ func TestRender_CrossReferences(t *testing.T) {
                `<p><a href="`+URLJoin(AppURL, "gogits", "gogs", "issues", "12345")+`" rel="nofollow">gogits/gogs#12345</a></p>`)
 }
 
+func TestRender_FullIssueURLs(t *testing.T) {
+       setting.AppURL = AppURL
+       setting.AppSubURL = AppSubURL
+
+       test := func(input, expected string) {
+               result := RenderFullIssuePattern([]byte(input))
+               assert.Equal(t, expected, string(result))
+       }
+       test("Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6",
+               "Here is a link https://git.osgeo.org/gogs/postgis/postgis/pulls/6")
+       test("Look here http://localhost:3000/person/repo/issues/4",
+               `Look here <a href="http://localhost:3000/person/repo/issues/4">#4</a>`)
+       test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
+               `<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234">#4</a>`)
+}
+
 func TestRegExp_MentionPattern(t *testing.T) {
        trueTestCases := []string{
                "@Unknwon",
@@ -558,50 +576,6 @@ func TestRegExp_AnySHA1Pattern(t *testing.T) {
        }
 }
 
-func TestRegExp_IssueFullPattern(t *testing.T) {
-       testCases := map[string][]string{
-               "https://github.com/gogits/gogs/pull/3244": {
-                       "https",
-                       "github.com/gogits/gogs/pull/",
-                       "3244",
-                       "",
-                       "",
-               },
-               "https://github.com/gogits/gogs/issues/3247#issuecomment-231517079": {
-                       "https",
-                       "github.com/gogits/gogs/issues/",
-                       "3247",
-                       "#issuecomment-231517079",
-                       "",
-               },
-               "https://try.gogs.io/gogs/gogs/issues/4#issue-685": {
-                       "https",
-                       "try.gogs.io/gogs/gogs/issues/",
-                       "4",
-                       "#issue-685",
-                       "",
-               },
-               "https://youtrack.jetbrains.com/issue/JT-36485": {
-                       "https",
-                       "youtrack.jetbrains.com/issue/",
-                       "JT-36485",
-                       "",
-                       "",
-               },
-               "https://youtrack.jetbrains.com/issue/JT-36485#comment=27-1508676": {
-                       "https",
-                       "youtrack.jetbrains.com/issue/",
-                       "JT-36485",
-                       "#comment=27-1508676",
-                       "",
-               },
-       }
-
-       for k, v := range testCases {
-               assert.Equal(t, IssueFullPattern.FindStringSubmatch(k)[1:], v)
-       }
-}
-
 func TestMisc_IsMarkdownFile(t *testing.T) {
        setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"}
        trueTestCases := []string{
@@ -645,7 +619,7 @@ var sameCases = []string{
 
 Ideas and codes
 
-- Bezier widget (by @r-lyeh) https://github.com/ocornut/imgui/issues/786
+- Bezier widget (by @r-lyeh) ` + AppURL + `ocornut/imgui/issues/786
 - Node graph editors https://github.com/ocornut/imgui/issues/306
 - [[Memory Editor|memory_editor_example]]
 - [[Plot var helper|plot_var_example]]`,
@@ -681,8 +655,8 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
 <p>Ideas and codes</p>
 
 <ul>
-<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>
-<li>Node graph editors<a href="https://github.com/ocornut/imgui/issues/306" rel="nofollow">#306</a></li>
+<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>
+<li>Node graph editors https://github.com/ocornut/imgui/issues/306</li>
 <li><a href="` + baseURLContent + `/memory_editor_example" rel="nofollow">Memory Editor</a></li>
 <li><a href="` + baseURLContent + `/plot_var_example" rel="nofollow">Plot var helper</a></li>
 </ul>
index 182b147820b0140afef8f53641ad2567210c22b3..d6e619347802416beef5e4932506c1e9cf68fbf0 100644 (file)
@@ -75,7 +75,7 @@ func TestAPI_RenderGFM(t *testing.T) {
 <ul>
 <li><a href="` + AppSubURL + `wiki/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
 <li><a href="` + AppSubURL + `wiki/Tips" rel="nofollow">Tips</a></li>
-<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>
+<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) https://github.com/ocornut/imgui/issues/786</li>
 </ul>
 `,
                // wine-staging wiki home extract: special wiki syntax, images
index ad624d3b7ad9216f6491b135ed3eec20962fa5a8..bd46abdf94e8321893363485e878d35d17b23934 100644 (file)
@@ -50,6 +50,7 @@ func GlobalInit() {
 
        if setting.InstallLock {
                highlight.NewContext()
+               markdown.InitMarkdown()
                markdown.NewSanitizer()
                if err := models.NewEngine(migrations.Migrate); err != nil {
                        log.Fatal(4, "Failed to initialize ORM engine: %v", err)