Previously mentioning a user would link to its profile, regardless of whether the user existed. This change tests if the user exists and only if it does - a link to its profile is added. * Fixes #3444 Signed-off-by: Yarden Shoham <hrsi88@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>tags/v1.18.0-rc0
@@ -33,6 +33,7 @@ import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/util" | |||
"code.gitea.io/gitea/routers" | |||
markup_service "code.gitea.io/gitea/services/markup" | |||
"github.com/go-git/go-git/v5" | |||
"github.com/go-git/go-git/v5/config" | |||
@@ -112,7 +113,7 @@ func runPR() { | |||
log.Printf("[PR] Setting up router\n") | |||
// routers.GlobalInit() | |||
external.RegisterRenderers() | |||
markup.Init() | |||
markup.Init(markup_service.ProcessorHelper()) | |||
c := routers.NormalRoutes(graceful.GetManager().HammerContext()) | |||
log.Printf("[PR] Ready for testing !\n") |
@@ -603,8 +603,14 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) { | |||
start = loc.End | |||
continue | |||
} | |||
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention")) | |||
node = node.NextSibling.NextSibling | |||
mentionedUsername := mention[1:] | |||
if processorHelper.IsUsernameMentionable != nil && processorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) { | |||
replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mentionedUsername), mention, "mention")) | |||
node = node.NextSibling.NextSibling | |||
} else { | |||
node = node.NextSibling | |||
} | |||
start = 0 | |||
} | |||
} |
@@ -38,6 +38,11 @@ func TestMain(m *testing.M) { | |||
if err := git.InitSimple(context.Background()); err != nil { | |||
log.Fatal("git init failed, err: %v", err) | |||
} | |||
markup.Init(&markup.ProcessorHelper{ | |||
IsUsernameMentionable: func(ctx context.Context, username string) bool { | |||
return username == "r-lyeh" | |||
}, | |||
}) | |||
os.Exit(m.Run()) | |||
} | |||
@@ -19,8 +19,18 @@ import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
) | |||
type ProcessorHelper struct { | |||
IsUsernameMentionable func(ctx context.Context, username string) bool | |||
} | |||
var processorHelper ProcessorHelper | |||
// Init initialize regexps for markdown parsing | |||
func Init() { | |||
func Init(ph *ProcessorHelper) { | |||
if ph != nil { | |||
processorHelper = *ph | |||
} | |||
NewSanitizer() | |||
if len(setting.Markdown.CustomURLSchemes) > 0 { | |||
CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes) |
@@ -5,6 +5,7 @@ | |||
package misc | |||
import ( | |||
go_context "context" | |||
"io" | |||
"net/http" | |||
"net/http/httptest" | |||
@@ -13,6 +14,7 @@ import ( | |||
"testing" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/markup" | |||
"code.gitea.io/gitea/modules/setting" | |||
api "code.gitea.io/gitea/modules/structs" | |||
"code.gitea.io/gitea/modules/templates" | |||
@@ -50,6 +52,11 @@ func wrap(ctx *context.Context) *context.APIContext { | |||
func TestAPI_RenderGFM(t *testing.T) { | |||
setting.AppURL = AppURL | |||
markup.Init(&markup.ProcessorHelper{ | |||
IsUsernameMentionable: func(ctx go_context.Context, username string) bool { | |||
return username == "r-lyeh" | |||
}, | |||
}) | |||
options := api.MarkdownOption{ | |||
Mode: "gfm", |
@@ -41,6 +41,7 @@ import ( | |||
"code.gitea.io/gitea/services/automerge" | |||
"code.gitea.io/gitea/services/cron" | |||
"code.gitea.io/gitea/services/mailer" | |||
markup_service "code.gitea.io/gitea/services/markup" | |||
repo_migrations "code.gitea.io/gitea/services/migrations" | |||
mirror_service "code.gitea.io/gitea/services/mirror" | |||
pull_service "code.gitea.io/gitea/services/pull" | |||
@@ -123,7 +124,7 @@ func GlobalInitInstalled(ctx context.Context) { | |||
highlight.NewContext() | |||
external.RegisterRenderers() | |||
markup.Init() | |||
markup.Init(markup_service.ProcessorHelper()) | |||
if setting.EnableSQLite3 { | |||
log.Info("SQLite3 support is enabled") |
@@ -0,0 +1,19 @@ | |||
// Copyright 2022 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package markup | |||
import ( | |||
"path/filepath" | |||
"testing" | |||
"code.gitea.io/gitea/models/unittest" | |||
) | |||
func TestMain(m *testing.M) { | |||
unittest.MainTest(m, &unittest.TestOptions{ | |||
GiteaRootPath: filepath.Join("..", ".."), | |||
FixtureFiles: []string{"user.yml"}, | |||
}) | |||
} |
@@ -0,0 +1,29 @@ | |||
// Copyright 2022 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package markup | |||
import ( | |||
"context" | |||
"code.gitea.io/gitea/models/user" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/markup" | |||
) | |||
func ProcessorHelper() *markup.ProcessorHelper { | |||
return &markup.ProcessorHelper{ | |||
IsUsernameMentionable: func(ctx context.Context, username string) bool { | |||
// TODO: cast ctx to modules/context.Context and use IsUserVisibleToViewer | |||
// Only link if the user actually exists | |||
userExists, err := user.IsUserExist(ctx, 0, username) | |||
if err != nil { | |||
log.Error("Failed to validate user in mention %q exists, assuming it does", username) | |||
userExists = true | |||
} | |||
return userExists | |||
}, | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
// Copyright 2022 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package markup | |||
import ( | |||
"context" | |||
"testing" | |||
"code.gitea.io/gitea/models/unittest" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func TestProcessorHelper(t *testing.T) { | |||
assert.NoError(t, unittest.PrepareTestDatabase()) | |||
assert.True(t, ProcessorHelper().IsUsernameMentionable(context.Background(), "user10")) | |||
assert.False(t, ProcessorHelper().IsUsernameMentionable(context.Background(), "no-such-user")) | |||
} |