From f25fd5c8ebc83c664b5ac1752e1c4dd11edc02a2 Mon Sep 17 00:00:00 2001
From: guillep2k <18600385+guillep2k@users.noreply.github.com>
Date: Sun, 24 Nov 2019 13:34:44 -0300
Subject: [PATCH] Fix team links in HTML rendering (#9127)

* Fix team links in HTML rendering

* Fix check and lint
---
 models/repo.go         | 38 +++++++++++++++++++++++++-------------
 models/repo_test.go    | 15 +++++++++++++--
 modules/markup/html.go | 10 ++++++++--
 3 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/models/repo.go b/models/repo.go
index eecc36377b..1f544f1e8c 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -173,8 +173,8 @@ type Repository struct {
 	*Mirror    `xorm:"-"`
 	Status     RepositoryStatus `xorm:"NOT NULL DEFAULT 0"`
 
-	ExternalMetas map[string]string `xorm:"-"`
-	Units         []*RepoUnit       `xorm:"-"`
+	RenderingMetas map[string]string `xorm:"-"`
+	Units          []*RepoUnit       `xorm:"-"`
 
 	IsFork                          bool               `xorm:"INDEX NOT NULL DEFAULT false"`
 	ForkID                          int64              `xorm:"INDEX"`
@@ -559,27 +559,39 @@ func (repo *Repository) mustOwnerName(e Engine) string {
 
 // ComposeMetas composes a map of metas for properly rendering issue links and external issue trackers.
 func (repo *Repository) ComposeMetas() map[string]string {
-	if repo.ExternalMetas == nil {
-		repo.ExternalMetas = map[string]string{
+	if repo.RenderingMetas == nil {
+		metas := map[string]string{
 			"user":     repo.MustOwner().Name,
 			"repo":     repo.Name,
 			"repoPath": repo.RepoPath(),
 		}
+
 		unit, err := repo.GetUnit(UnitTypeExternalTracker)
-		if err != nil {
-			return repo.ExternalMetas
+		if err == nil {
+			metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat
+			switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
+			case markup.IssueNameStyleAlphanumeric:
+				metas["style"] = markup.IssueNameStyleAlphanumeric
+			default:
+				metas["style"] = markup.IssueNameStyleNumeric
+			}
 		}
 
-		repo.ExternalMetas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat
-		switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
-		case markup.IssueNameStyleAlphanumeric:
-			repo.ExternalMetas["style"] = markup.IssueNameStyleAlphanumeric
-		default:
-			repo.ExternalMetas["style"] = markup.IssueNameStyleNumeric
+		if repo.Owner.IsOrganization() {
+			teams := make([]string, 0, 5)
+			_ = x.Table("team_repo").
+				Join("INNER", "team", "team.id = team_repo.team_id").
+				Where("team_repo.repo_id = ?", repo.ID).
+				Select("team.lower_name").
+				OrderBy("team.lower_name").
+				Find(&teams)
+			metas["teams"] = "," + strings.Join(teams, ",") + ","
+			metas["org"] = repo.Owner.LowerName
 		}
 
+		repo.RenderingMetas = metas
 	}
-	return repo.ExternalMetas
+	return repo.RenderingMetas
 }
 
 // DeleteWiki removes the actual and local copy of repository wiki.
diff --git a/models/repo_test.go b/models/repo_test.go
index 72a2959eb7..7a2227c820 100644
--- a/models/repo_test.go
+++ b/models/repo_test.go
@@ -17,7 +17,9 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestRepo(t *testing.T) {
+func TestMetas(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
 	repo := &Repository{Name: "testRepo"}
 	repo.Owner = &User{Name: "testOwner"}
 
@@ -36,7 +38,7 @@ func TestRepo(t *testing.T) {
 
 	testSuccess := func(expectedStyle string) {
 		repo.Units = []*RepoUnit{&externalTracker}
-		repo.ExternalMetas = nil
+		repo.RenderingMetas = nil
 		metas := repo.ComposeMetas()
 		assert.Equal(t, expectedStyle, metas["style"])
 		assert.Equal(t, "testRepo", metas["repo"])
@@ -51,6 +53,15 @@ func TestRepo(t *testing.T) {
 
 	externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markup.IssueNameStyleNumeric
 	testSuccess(markup.IssueNameStyleNumeric)
+
+	repo, err := GetRepositoryByID(3)
+	assert.NoError(t, err)
+
+	metas = repo.ComposeMetas()
+	assert.Contains(t, metas, "org")
+	assert.Contains(t, metas, "teams")
+	assert.Equal(t, metas["org"], "user3")
+	assert.Equal(t, metas["teams"], ",owners,team1,")
 }
 
 func TestGetRepositoryCount(t *testing.T) {
diff --git a/modules/markup/html.go b/modules/markup/html.go
index 924d0089a5..e5a475aff8 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -432,14 +432,20 @@ func replaceContentList(node *html.Node, i, j int, newNodes []*html.Node) {
 	}
 }
 
-func mentionProcessor(_ *postProcessCtx, node *html.Node) {
+func mentionProcessor(ctx *postProcessCtx, node *html.Node) {
 	// We replace only the first mention; other mentions will be addressed later
 	found, loc := references.FindFirstMentionBytes([]byte(node.Data))
 	if !found {
 		return
 	}
 	mention := node.Data[loc.Start:loc.End]
-	replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention"))
+	var teams string
+	teams, ok := ctx.metas["teams"]
+	if ok && strings.Contains(teams, ","+strings.ToLower(mention[1:])+",") {
+		replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, "org", ctx.metas["org"], "teams", mention[1:]), mention, "mention"))
+	} else {
+		replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mention[1:]), mention, "mention"))
+	}
 }
 
 func shortLinkProcessor(ctx *postProcessCtx, node *html.Node) {