mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-06 18:00:18 +09:00
Backport #39436 by @breken-ai The `org` render meta is lower-cased (`Repository.composeCommonMetas` sets `metas["org"] = strings.ToLower(repo.OwnerName)`), but `mentionProcessor` compares it with the org part of the mention exactly as typed, while the team part is lower-cased before its lookup. So in a repository of the org `MyOrg`, `@MyOrg/developers` stays plain text, although `ResolveIssueMentionsByVisibility` lower-cases the name and still notifies that team. This compares the org part case-insensitively and adds a render test for team mentions. The code is the same on `release/v1.27`, so it could be backported. ### Verification - `go test ./modules/markup/ -run TestRender_TeamMention -count=1`: the `@Org1/Developers` case renders as plain text on current main and as the team link with this change; `go test ./modules/markup/...` passes. - `golangci-lint run ./modules/markup/` (v2.13.2): 0 issues. ### AI assistance This contribution was prepared with AI assistance. The behavior, the metas and mention-resolution code paths, the patch and the test were reviewed manually. > Built by breken, your AI support engineer - breken.ai - this one's on us. Co-authored-by: breken <support@brekfuz.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -5,6 +5,7 @@ package markup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/references"
|
"gitea.dev/modules/references"
|
||||||
@@ -26,12 +27,13 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
loc.Start += start
|
loc.Start += start
|
||||||
loc.End += start
|
loc.End += start
|
||||||
mention := node.Data[loc.Start:loc.End]
|
mention := node.Data[loc.Start:loc.End]
|
||||||
teams, ok := ctx.RenderOptions.Metas["teams"]
|
orgLowerTeams, checkOrgTeams := ctx.RenderOptions.Metas["teams"] // in format ",team1,team2,...,team-n,", always lowercase
|
||||||
|
|
||||||
if ok && strings.Contains(mention, "/") {
|
if checkOrgTeams && strings.Contains(mention, "/") {
|
||||||
mentionOrgAndTeam := strings.Split(mention, "/")
|
mentionOrg, teamName, _ := strings.Cut(mention, "/")
|
||||||
if mentionOrgAndTeam[0][1:] == ctx.RenderOptions.Metas["org"] && strings.Contains(teams, ","+strings.ToLower(mentionOrgAndTeam[1])+",") {
|
orgName := mentionOrg[1:] // remove the '@' prefix
|
||||||
link := fmt.Sprintf("/:root/org/%s/teams/%s", ctx.RenderOptions.Metas["org"], mentionOrgAndTeam[1])
|
if strings.EqualFold(orgName, ctx.RenderOptions.Metas["org"]) && strings.Contains(orgLowerTeams, ","+strings.ToLower(teamName)+",") {
|
||||||
|
link := fmt.Sprintf("/:root/org/%s/teams/%s", url.PathEscape(orgName), url.PathEscape(teamName))
|
||||||
replaceContent(node, loc.Start, loc.End, createLink(ctx, link, mention, "" /*mention*/))
|
replaceContent(node, loc.Start, loc.End, createLink(ctx, link, mention, "" /*mention*/))
|
||||||
node = node.NextSibling.NextSibling
|
node = node.NextSibling.NextSibling
|
||||||
start = 0
|
start = 0
|
||||||
@@ -43,7 +45,7 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) {
|
|||||||
mentionedUsername := mention[1:]
|
mentionedUsername := mention[1:]
|
||||||
|
|
||||||
if DefaultRenderHelperFuncs != nil && DefaultRenderHelperFuncs.IsUsernameMentionable(ctx, mentionedUsername) {
|
if DefaultRenderHelperFuncs != nil && DefaultRenderHelperFuncs.IsUsernameMentionable(ctx, mentionedUsername) {
|
||||||
link := "/:root/" + mentionedUsername
|
link := "/:root/" + url.PathEscape(mentionedUsername)
|
||||||
replaceContent(node, loc.Start, loc.End, createLink(ctx, link, mention, "" /*mention*/))
|
replaceContent(node, loc.Start, loc.End, createLink(ctx, link, mention, "" /*mention*/))
|
||||||
node = node.NextSibling.NextSibling
|
node = node.NextSibling.NextSibling
|
||||||
start = 0
|
start = 0
|
||||||
|
|||||||
@@ -605,3 +605,18 @@ func TestIssue18471(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, `<a href="`+markup.TestAppURL+`org/repo/compare/783b039...da951ce" class="compare"><code>783b039...da951ce</code></a>`, res.String())
|
assert.Equal(t, `<a href="`+markup.TestAppURL+`org/repo/compare/783b039...da951ce" class="compare"><code>783b039...da951ce</code></a>`, res.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRender_TeamMention(t *testing.T) {
|
||||||
|
// the "org" meta is lower-cased, see Repository.composeCommonMetas
|
||||||
|
metas := map[string]string{"user": "Org1", "repo": "repo1", "org": "org1", "teams": ",developers,"}
|
||||||
|
test := func(input, expected string) {
|
||||||
|
rctx := markup.NewTestRenderContext(markup.TestAppURL, metas).WithRelativePath("a.md")
|
||||||
|
buffer, err := testRenderString(rctx, input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||||
|
}
|
||||||
|
test("@org1/developers", `<p><a href="/org/org1/teams/developers" rel="nofollow">@org1/developers</a></p>`)
|
||||||
|
test("@Org1/Developers", `<p><a href="/org/Org1/teams/Developers" rel="nofollow">@Org1/Developers</a></p>`)
|
||||||
|
test("@org2/developers", `<p>@org2/developers</p>`)
|
||||||
|
test("@org1/testers", `<p>@org1/testers</p>`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ func FindAllMentionsBytes(content []byte) []RefSpan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindFirstMentionBytes matches the first mention in then given content
|
// FindFirstMentionBytes matches the first mention in then given content
|
||||||
// and returns the location of the unvalidated user name, including the @ prefix.
|
// and returns the location of the unvalidated username, including the @ prefix.
|
||||||
func FindFirstMentionBytes(content []byte) (bool, RefSpan) {
|
func FindFirstMentionBytes(content []byte) (bool, RefSpan) {
|
||||||
mention := mentionPattern.FindSubmatchIndex(content)
|
mention := mentionPattern.FindSubmatchIndex(content)
|
||||||
if mention == nil {
|
if mention == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user