Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use relative links for commits, mentions, and issues in markdown #29427

Merged
merged 11 commits into from Mar 13, 2024
12 changes: 6 additions & 6 deletions modules/markup/html.go
Expand Up @@ -609,7 +609,7 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) {
if ok && strings.Contains(mention, "/") {
mentionOrgAndTeam := strings.Split(mention, "/")
if mentionOrgAndTeam[0][1:] == ctx.Metas["org"] && strings.Contains(teams, ","+strings.ToLower(mentionOrgAndTeam[1])+",") {
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, "org", ctx.Metas["org"], "teams", mentionOrgAndTeam[1]), mention, "mention"))
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), "org", ctx.Metas["org"], "teams", mentionOrgAndTeam[1]), mention, "mention"))
node = node.NextSibling.NextSibling
start = 0
continue
Expand All @@ -620,7 +620,7 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) {
mentionedUsername := mention[1:]

if DefaultProcessorHelper.IsUsernameMentionable != nil && DefaultProcessorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) {
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mentionedUsername), mention, "mention"))
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), mentionedUsername), mention, "mention"))
node = node.NextSibling.NextSibling
} else {
node = node.NextSibling
Expand Down Expand Up @@ -898,9 +898,9 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
path = "pulls"
}
if ref.Owner == "" {
link = createLink(util.URLJoin(setting.AppURL, ctx.Metas["user"], ctx.Metas["repo"], path, ref.Issue), reftext, "ref-issue")
link = createLink(util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], path, ref.Issue), reftext, "ref-issue")
} else {
link = createLink(util.URLJoin(setting.AppURL, ref.Owner, ref.Name, path, ref.Issue), reftext, "ref-issue")
link = createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, path, ref.Issue), reftext, "ref-issue")
}
}

Expand Down Expand Up @@ -939,7 +939,7 @@ func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) {
}

reftext := ref.Owner + "/" + ref.Name + "@" + base.ShortSha(ref.CommitSha)
link := createLink(util.URLJoin(setting.AppSubURL, ref.Owner, ref.Name, "commit", ref.CommitSha), reftext, "commit")
link := createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, "commit", ref.CommitSha), reftext, "commit")

replaceContent(node, ref.RefLocation.Start, ref.RefLocation.End, link)
node = node.NextSibling.NextSibling
Expand Down Expand Up @@ -1166,7 +1166,7 @@ func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
continue
}

link := util.URLJoin(setting.AppURL, ctx.Metas["user"], ctx.Metas["repo"], "commit", hash)
link := util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], "commit", hash)
replaceContent(node, m[2], m[3], createCodeLink(link, base.ShortSha(hash), "commit"))
start = 0
node = node.NextSibling.NextSibling
Expand Down
1 change: 1 addition & 0 deletions modules/markup/html_internal_test.go
Expand Up @@ -287,6 +287,7 @@ func TestRender_IssueIndexPattern_Document(t *testing.T) {
}

func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) {
ctx.Links.AbsolutePrefix = true
if ctx.Links.Base == "" {
ctx.Links.Base = TestRepoURL
}
Expand Down
9 changes: 6 additions & 3 deletions modules/markup/html_test.go
Expand Up @@ -43,7 +43,8 @@ func TestRender_Commits(t *testing.T) {
Ctx: git.DefaultContext,
RelativePath: ".md",
Links: markup.Links{
Base: markup.TestRepoURL,
AbsolutePrefix: true,
Base: markup.TestRepoURL,
},
Metas: localMetas,
}, input)
Expand Down Expand Up @@ -96,7 +97,8 @@ func TestRender_CrossReferences(t *testing.T) {
Ctx: git.DefaultContext,
RelativePath: "a.md",
Links: markup.Links{
Base: setting.AppSubURL,
AbsolutePrefix: true,
Base: setting.AppSubURL,
},
Metas: localMetas,
}, input)
Expand Down Expand Up @@ -588,7 +590,8 @@ func TestPostProcess_RenderDocument(t *testing.T) {
err := markup.PostProcess(&markup.RenderContext{
Ctx: git.DefaultContext,
Links: markup.Links{
Base: "https://example.com",
AbsolutePrefix: true,
Base: "https://example.com",
},
Metas: localMetas,
}, strings.NewReader(input), &res)
Expand Down
6 changes: 3 additions & 3 deletions modules/markup/markdown/markdown_test.go
Expand Up @@ -130,11 +130,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
<li><a href="` + baseURLContent + `/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li>
<li><a href="` + baseURLContent + `/Tips" rel="nofollow">Tips</a></li>
</ul>
<p>See commit <a href="http://localhost:3000/gogits/gogs/commit/65f1bf27bc" rel="nofollow"><code>65f1bf27bc</code></a></p>
<p>See commit <a href="/gogits/gogs/commit/65f1bf27bc" rel="nofollow"><code>65f1bf27bc</code></a></p>
<p>Ideas and codes</p>
<ul>
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" class="ref-issue" rel="nofollow">ocornut/imgui#786</a></li>
<li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/gogits/gogs/issues/786" class="ref-issue" rel="nofollow">#786</a></li>
<li>Bezier widget (by <a href="/r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" class="ref-issue" rel="nofollow">ocornut/imgui#786</a></li>
<li>Bezier widget (by <a href="/r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/gogits/gogs/issues/786" class="ref-issue" rel="nofollow">#786</a></li>
<li>Node graph editors <a href="https://github.com/ocornut/imgui/issues/306" rel="nofollow">https://github.com/ocornut/imgui/issues/306</a></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>
Expand Down
14 changes: 11 additions & 3 deletions modules/markup/renderer.go
Expand Up @@ -82,9 +82,17 @@ type RenderContext struct {
}

type Links struct {
Base string
BranchPath string
TreePath string
AbsolutePrefix bool
Base string
BranchPath string
TreePath string
}

func (l *Links) Prefix() string {
if l.AbsolutePrefix {
return setting.AppURL
}
return setting.AppSubURL
}

func (l *Links) HasBranchInfo() bool {
Expand Down
14 changes: 7 additions & 7 deletions modules/templates/util_render_test.go
Expand Up @@ -117,21 +117,21 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a582
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<span class="emoji" aria-label="thumbs up">👍</span>
<a href="mailto:mail@domain.com" class="mailto">mail@domain.com</a>
<a href="http://localhost:3000/mention-user" class="mention">@mention-user</a> test
<a href="http://localhost:3000/user13/repo11/issues/123" class="ref-issue">#123</a>
<a href="/mention-user" class="mention">@mention-user</a> test
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
space`

assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas))
}

func TestRenderCommitMessage(t *testing.T) {
expected := `space <a href="http://localhost:3000/mention-user" class="mention">@mention-user</a> `
expected := `space <a href="/mention-user" class="mention">@mention-user</a> `

assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas))
}

func TestRenderCommitMessageLinkSubject(t *testing.T) {
expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="http://localhost:3000/mention-user" class="mention">@mention-user</a>`
expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="/mention-user" class="mention">@mention-user</a>`

assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas))
}
Expand All @@ -155,14 +155,14 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<span class="emoji" aria-label="thumbs up">👍</span>
mail@domain.com
@mention-user test
<a href="http://localhost:3000/user13/repo11/issues/123" class="ref-issue">#123</a>
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a>
space
`
assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
}

func TestRenderMarkdownToHtml(t *testing.T) {
expected := `<p>space <a href="http://localhost:3000/mention-user" rel="nofollow">@mention-user</a><br/>
expected := `<p>space <a href="/mention-user" rel="nofollow">@mention-user</a><br/>
/just/a/path.bin
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a>
<a href="/file.bin" rel="nofollow">local link</a>
Expand All @@ -179,7 +179,7 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a582
com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
<span class="emoji" aria-label="thumbs up">👍</span>
<a href="mailto:mail@domain.com" rel="nofollow">mail@domain.com</a>
<a href="http://localhost:3000/mention-user" rel="nofollow">@mention-user</a> test
<a href="/mention-user" rel="nofollow">@mention-user</a> test
#123
space</p>
`
Expand Down
6 changes: 4 additions & 2 deletions routers/common/markup.go
Expand Up @@ -34,7 +34,8 @@ func RenderMarkup(ctx *context.Base, repo *context.Repository, mode, text, urlPr
if err := markdown.RenderRaw(&markup.RenderContext{
Ctx: ctx,
Links: markup.Links{
Base: urlPrefix,
AbsolutePrefix: true,
Base: urlPrefix,
},
}, strings.NewReader(text), ctx.Resp); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
Expand Down Expand Up @@ -79,7 +80,8 @@ func RenderMarkup(ctx *context.Base, repo *context.Repository, mode, text, urlPr
if err := markup.Render(&markup.RenderContext{
Ctx: ctx,
Links: markup.Links{
Base: urlPrefix,
AbsolutePrefix: true,
Base: urlPrefix,
},
Metas: meta,
IsWiki: wiki,
Expand Down
3 changes: 2 additions & 1 deletion services/mailer/mail.go
Expand Up @@ -222,7 +222,8 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
body, err := markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
Links: markup.Links{
Base: ctx.Issue.Repo.HTMLURL(),
AbsolutePrefix: true,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mail, maybe /routers/common/markup.go and/or rendered webhook messages should be the only places with AbsolutePrefix = true. Some tests have true too but that should be changed in another PR.

Base: ctx.Issue.Repo.HTMLURL(),
},
Metas: ctx.Issue.Repo.ComposeMetas(ctx),
}, ctx.Content)
Expand Down
26 changes: 25 additions & 1 deletion services/mailer/mail_test.go
Expand Up @@ -8,6 +8,8 @@ import (
"context"
"fmt"
"html/template"
"io"
"mime/quotedprintable"
"regexp"
"strings"
"testing"
Expand All @@ -19,6 +21,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -67,6 +70,12 @@ func prepareMailerTest(t *testing.T) (doer *user_model.User, repo *repo_model.Re
func TestComposeIssueCommentMessage(t *testing.T) {
doer, _, issue, comment := prepareMailerTest(t)

markup.Init(&markup.ProcessorHelper{
IsUsernameMentionable: func(ctx context.Context, username string) bool {
return username == doer.Name
},
})

setting.IncomingEmail.Enabled = true
defer func() { setting.IncomingEmail.Enabled = false }()

Expand All @@ -77,7 +86,8 @@ func TestComposeIssueCommentMessage(t *testing.T) {
msgs, err := composeIssueCommentMessages(&mailCommentContext{
Context: context.TODO(), // TODO: use a correct context
Issue: issue, Doer: doer, ActionType: activities_model.ActionCommentIssue,
Content: "test body", Comment: comment,
Content: fmt.Sprintf("test @%s %s#%d body", doer.Name, issue.Repo.FullName(), issue.Index),
Comment: comment,
}, "en-US", recipients, false, "issue comment")
assert.NoError(t, err)
assert.Len(t, msgs, 2)
Expand All @@ -96,6 +106,20 @@ func TestComposeIssueCommentMessage(t *testing.T) {
assert.Equal(t, "<user2/repo1/issues/1/comment/2@localhost>", gomailMsg.GetHeader("Message-ID")[0], "Message-ID header doesn't match")
assert.Equal(t, "<mailto:"+replyTo+">", gomailMsg.GetHeader("List-Post")[0])
assert.Len(t, gomailMsg.GetHeader("List-Unsubscribe"), 2) // url + mailto

var buf bytes.Buffer
gomailMsg.WriteTo(&buf)

b, err := io.ReadAll(quotedprintable.NewReader(&buf))
assert.NoError(t, err)

// text/plain
assert.Contains(t, string(b), fmt.Sprintf(`( %s )`, doer.HTMLURL()))
assert.Contains(t, string(b), fmt.Sprintf(`( %s )`, issue.HTMLURL()))

// text/html
assert.Contains(t, string(b), fmt.Sprintf(`href="%s"`, doer.HTMLURL()))
assert.Contains(t, string(b), fmt.Sprintf(`href="%s"`, issue.HTMLURL()))
}

func TestComposeIssueMessage(t *testing.T) {
Expand Down