Add an option to hide certain users in the UI (#28942)

* Add an option to hide certain users in the UI

* revert changes for admin users routes

* fix sqlstore function name

* Improve slice management

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Hidden users: convert slice to map

* filter with user logins instead of IDs

* put HiddenUsers in Cfg struct

* hide hidden users from dashboards/folders permissions list

* Update conf/defaults.ini

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>

* fix params order

* fix tests

* fix dashboard/folder update with hidden user

* add team tests

* add dashboard and folder permissions tests

* fixes after merge

* fix tests

* API: add test for org users endpoints

* update hidden users management for dashboard / folder permissions

* improve dashboard / folder permissions tests

* fixes after merge

* Guardian: add hidden acl tests

* API: add team members tests

* fix team sql syntax for postgres

* api tests update

* fix linter error

* fix tests errors after merge

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
Co-authored-by: Leonard Gram <leo@xlson.com>
This commit is contained in:
Agnès Toulet
2020-11-24 12:10:32 +01:00
committed by GitHub
co-authored by Emil Tullstedt Torkel Ödegaard Leonard Gram
parent 4c47fc56bb
commit 22788d1d86
21 changed files with 852 additions and 133 deletions
+63 -20
View File
@@ -3,6 +3,7 @@ package sqlstore
import (
"bytes"
"fmt"
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
@@ -24,26 +25,54 @@ func init() {
bus.AddHandler("sql", IsAdminOfTeams)
}
func getTeamSearchSQLBase() string {
return `SELECT
team.id as id,
team.org_id,
team.name as name,
team.email as email,
(SELECT COUNT(*) from team_member where team_member.team_id = team.id) as member_count,
team_member.permission
FROM team as team
INNER JOIN team_member on team.id = team_member.team_id AND team_member.user_id = ? `
func getFilteredUsers(signedInUser *models.SignedInUser, hiddenUsers map[string]struct{}) []string {
filteredUsers := make([]string, 0, len(hiddenUsers))
if signedInUser == nil || signedInUser.IsGrafanaAdmin {
return filteredUsers
}
for u := range hiddenUsers {
if u == signedInUser.Login {
continue
}
filteredUsers = append(filteredUsers, u)
}
return filteredUsers
}
func getTeamSelectSQLBase() string {
func getTeamMemberCount(filteredUsers []string) string {
if len(filteredUsers) > 0 {
return `(SELECT COUNT(*) FROM team_member
INNER JOIN ` + dialect.Quote("user") + ` ON team_member.user_id = ` + dialect.Quote("user") + `.id
WHERE team_member.team_id = team.id AND ` + dialect.Quote("user") + `.login NOT IN (?` +
strings.Repeat(",?", len(filteredUsers)-1) + ")" +
`) AS member_count `
}
return "(SELECT COUNT(*) FROM team_member WHERE team_member.team_id = team.id) AS member_count "
}
func getTeamSearchSQLBase(filteredUsers []string) string {
return `SELECT
team.id AS id,
team.org_id,
team.name AS name,
team.email AS email,
team_member.permission, ` +
getTeamMemberCount(filteredUsers) +
` FROM team AS team
INNER JOIN team_member ON team.id = team_member.team_id AND team_member.user_id = ? `
}
func getTeamSelectSQLBase(filteredUsers []string) string {
return `SELECT
team.id as id,
team.org_id,
team.name as name,
team.email as email,
(SELECT COUNT(*) from team_member where team_member.team_id = team.id) as member_count
FROM team as team `
team.email as email, ` +
getTeamMemberCount(filteredUsers) +
` FROM team as team `
}
func CreateTeam(cmd *models.CreateTeamCommand) error {
@@ -157,14 +186,21 @@ func SearchTeams(query *models.SearchTeamsQuery) error {
var sql bytes.Buffer
params := make([]interface{}, 0)
filteredUsers := getFilteredUsers(query.SignedInUser, query.HiddenUsers)
if query.UserIdFilter > 0 {
sql.WriteString(getTeamSearchSQLBase())
sql.WriteString(getTeamSearchSQLBase(filteredUsers))
for _, user := range filteredUsers {
params = append(params, user)
}
params = append(params, query.UserIdFilter)
} else {
sql.WriteString(getTeamSelectSQLBase())
sql.WriteString(getTeamSelectSQLBase(filteredUsers))
for _, user := range filteredUsers {
params = append(params, user)
}
}
sql.WriteString(` WHERE team.org_id = ?`)
sql.WriteString(` WHERE team.org_id = ?`)
params = append(params, query.OrgId)
if query.Query != "" {
@@ -206,12 +242,19 @@ func SearchTeams(query *models.SearchTeamsQuery) error {
func GetTeamById(query *models.GetTeamByIdQuery) error {
var sql bytes.Buffer
params := make([]interface{}, 0)
filteredUsers := getFilteredUsers(query.SignedInUser, query.HiddenUsers)
sql.WriteString(getTeamSelectSQLBase(filteredUsers))
for _, user := range filteredUsers {
params = append(params, user)
}
sql.WriteString(getTeamSelectSQLBase())
sql.WriteString(` WHERE team.org_id = ? and team.id = ?`)
params = append(params, query.OrgId, query.Id)
var team models.TeamDTO
exists, err := x.SQL(sql.String(), query.OrgId, query.Id).Get(&team)
exists, err := x.SQL(sql.String(), params...).Get(&team)
if err != nil {
return err
@@ -231,7 +274,7 @@ func GetTeamsByUser(query *models.GetTeamsByUserQuery) error {
var sql bytes.Buffer
sql.WriteString(getTeamSelectSQLBase())
sql.WriteString(getTeamSelectSQLBase([]string{}))
sql.WriteString(` INNER JOIN team_member on team.id = team_member.team_id`)
sql.WriteString(` WHERE team.org_id = ? and team_member.user_id = ?`)
+47
View File
@@ -48,6 +48,7 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(team1.Name, ShouldEqual, "group1 name")
So(team1.Email, ShouldEqual, "test1@test.com")
So(team1.OrgId, ShouldEqual, testOrgId)
So(team1.MemberCount, ShouldEqual, 0)
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: team1.Id, UserId: userIds[0]})
So(err, ShouldBeNil)
@@ -74,6 +75,20 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(q2.Result[0].Login, ShouldEqual, "loginuser1")
So(q2.Result[0].OrgId, ShouldEqual, testOrgId)
So(q2.Result[0].External, ShouldEqual, true)
err = SearchTeams(query)
So(err, ShouldBeNil)
team1 = query.Result.Teams[0]
So(team1.MemberCount, ShouldEqual, 2)
getTeamQuery := &models.GetTeamByIdQuery{OrgId: testOrgId, Id: team1.Id}
err = GetTeamById(getTeamQuery)
So(err, ShouldBeNil)
team1 = getTeamQuery.Result
So(team1.Name, ShouldEqual, "group1 name")
So(team1.Email, ShouldEqual, "test1@test.com")
So(team1.OrgId, ShouldEqual, testOrgId)
So(team1.MemberCount, ShouldEqual, 2)
})
Convey("Should return latest auth module for users when getting team members", func() {
@@ -275,6 +290,38 @@ func TestTeamCommandsAndQueries(t *testing.T) {
So(err, ShouldBeNil)
So(query.Result, ShouldBeTrue)
})
Convey("Should not return hidden users in team member count", func() {
signedInUser := &models.SignedInUser{Login: "loginuser0"}
hiddenUsers := map[string]struct{}{"loginuser0": {}, "loginuser1": {}}
teamId := group1.Result.Id
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: teamId, UserId: userIds[0]})
So(err, ShouldBeNil)
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: teamId, UserId: userIds[1]})
So(err, ShouldBeNil)
err = AddTeamMember(&models.AddTeamMemberCommand{OrgId: testOrgId, TeamId: teamId, UserId: userIds[2]})
So(err, ShouldBeNil)
searchQuery := &models.SearchTeamsQuery{OrgId: testOrgId, Page: 1, Limit: 10, SignedInUser: signedInUser, HiddenUsers: hiddenUsers}
err = SearchTeams(searchQuery)
So(err, ShouldBeNil)
So(searchQuery.Result.Teams, ShouldHaveLength, 2)
team1 := searchQuery.Result.Teams[0]
So(team1.MemberCount, ShouldEqual, 2)
searchQueryFilteredByUser := &models.SearchTeamsQuery{OrgId: testOrgId, Page: 1, Limit: 10, UserIdFilter: userIds[0], SignedInUser: signedInUser, HiddenUsers: hiddenUsers}
err = SearchTeams(searchQueryFilteredByUser)
So(err, ShouldBeNil)
So(searchQueryFilteredByUser.Result.Teams, ShouldHaveLength, 1)
team1 = searchQuery.Result.Teams[0]
So(team1.MemberCount, ShouldEqual, 2)
getTeamQuery := &models.GetTeamByIdQuery{OrgId: testOrgId, Id: teamId, SignedInUser: signedInUser, HiddenUsers: hiddenUsers}
err = GetTeamById(getTeamQuery)
So(err, ShouldBeNil)
So(getTeamQuery.Result.MemberCount, ShouldEqual, 2)
})
})
})
}