From c5e88fb03d01b929cfcf17c0a817d75572d44023 Mon Sep 17 00:00:00 2001
From: 6543 <6543@obermui.de>
Date: Mon, 19 Sep 2022 14:02:29 +0200
Subject: [PATCH] [API] teamSearch show teams with no members if user is admin
 (#21204)

close #21176
---
 build/generate-go-licenses.go           |  4 +--
 models/organization/team.go             | 24 +++--------------
 modules/markup/markdown/meta.go         |  1 +
 modules/markup/markdown/renderconfig.go |  1 +
 routers/api/v1/org/team.go              |  6 ++++-
 tests/integration/api_org_test.go       | 36 +++++++++++++++++++++++++
 6 files changed, 48 insertions(+), 24 deletions(-)

diff --git a/build/generate-go-licenses.go b/build/generate-go-licenses.go
index fedfdc315e..87c773ed8b 100644
--- a/build/generate-go-licenses.go
+++ b/build/generate-go-licenses.go
@@ -64,8 +64,8 @@ func main() {
 		}
 
 		entries = append(entries, LicenseEntry{
-			Name: name,
-			Path: path,
+			Name:        name,
+			Path:        path,
 			LicenseText: string(licenseText),
 		})
 	}
diff --git a/models/organization/team.go b/models/organization/team.go
index 2d5ee17272..bd80b1a8c7 100644
--- a/models/organization/team.go
+++ b/models/organization/team.go
@@ -129,29 +129,11 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
 	if opts.UserID > 0 {
 		sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
 	}
-
-	count, err := sess.
-		Where(cond).
-		Count(new(Team))
-	if err != nil {
-		return nil, 0, err
-	}
-
-	if opts.UserID > 0 {
-		sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
-	}
-
-	if opts.PageSize == -1 {
-		opts.PageSize = int(count)
-	} else {
-		sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
-	}
+	sess = db.SetSessionPagination(sess, opts)
 
 	teams := make([]*Team, 0, opts.PageSize)
-	if err = sess.
-		Where(cond).
-		OrderBy("lower_name").
-		Find(&teams); err != nil {
+	count, err := sess.Where(cond).OrderBy("lower_name").FindAndCount(&teams)
+	if err != nil {
 		return nil, 0, err
 	}
 
diff --git a/modules/markup/markdown/meta.go b/modules/markup/markdown/meta.go
index 28913fd684..b08121e868 100644
--- a/modules/markup/markdown/meta.go
+++ b/modules/markup/markdown/meta.go
@@ -11,6 +11,7 @@ import (
 	"unicode/utf8"
 
 	"code.gitea.io/gitea/modules/log"
+
 	"gopkg.in/yaml.v3"
 )
 
diff --git a/modules/markup/markdown/renderconfig.go b/modules/markup/markdown/renderconfig.go
index 6a3b3a1bde..003579115f 100644
--- a/modules/markup/markdown/renderconfig.go
+++ b/modules/markup/markdown/renderconfig.go
@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/modules/log"
+
 	"github.com/yuin/goldmark/ast"
 	"gopkg.in/yaml.v3"
 )
diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go
index c891d0e122..f3e7834a49 100644
--- a/routers/api/v1/org/team.go
+++ b/routers/api/v1/org/team.go
@@ -759,13 +759,17 @@ func SearchTeam(ctx *context.APIContext) {
 	listOptions := utils.GetListOptions(ctx)
 
 	opts := &organization.SearchTeamOptions{
-		UserID:      ctx.Doer.ID,
 		Keyword:     ctx.FormTrim("q"),
 		OrgID:       ctx.Org.Organization.ID,
 		IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"),
 		ListOptions: listOptions,
 	}
 
+	// Only admin is allowd to search for all teams
+	if !ctx.Doer.IsAdmin {
+		opts.UserID = ctx.Doer.ID
+	}
+
 	teams, maxResults, err := organization.SearchTeam(opts)
 	if err != nil {
 		log.Error("SearchTeam failed: %v", err)
diff --git a/tests/integration/api_org_test.go b/tests/integration/api_org_test.go
index 70bb17bee2..4b8c5c97a8 100644
--- a/tests/integration/api_org_test.go
+++ b/tests/integration/api_org_test.go
@@ -5,6 +5,7 @@
 package integration
 
 import (
+	"fmt"
 	"net/http"
 	"net/url"
 	"strings"
@@ -151,3 +152,38 @@ func TestAPIGetAll(t *testing.T) {
 	assert.Equal(t, "org25", apiOrgList[0].FullName)
 	assert.Equal(t, "public", apiOrgList[0].Visibility)
 }
+
+func TestAPIOrgSearchEmptyTeam(t *testing.T) {
+	onGiteaRun(t, func(*testing.T, *url.URL) {
+		token := getUserToken(t, "user1")
+		orgName := "org_with_empty_team"
+
+		// create org
+		req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &api.CreateOrgOption{
+			UserName: orgName,
+		})
+		MakeRequest(t, req, http.StatusCreated)
+
+		// create team with no member
+		req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams?token=%s", orgName, token), &api.CreateTeamOption{
+			Name:                    "Empty",
+			IncludesAllRepositories: true,
+			Permission:              "read",
+			Units:                   []string{"repo.code", "repo.issues", "repo.ext_issues", "repo.wiki", "repo.pulls"},
+		})
+		MakeRequest(t, req, http.StatusCreated)
+
+		// case-insensitive search for teams that have no members
+		req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/%s/teams/search?q=%s&token=%s", orgName, "empty", token))
+		resp := MakeRequest(t, req, http.StatusOK)
+		data := struct {
+			Ok   bool
+			Data []*api.Team
+		}{}
+		DecodeJSON(t, resp, &data)
+		assert.True(t, data.Ok)
+		if assert.Len(t, data.Data, 1) {
+			assert.EqualValues(t, "Empty", data.Data[0].Name)
+		}
+	})
+}