2017-04-08 17:55:07 -05:00
package sqlstore
import (
2017-12-14 10:22:45 -06:00
"bytes"
2021-03-17 10:06:10 -05:00
"context"
2017-04-08 17:55:07 -05:00
"fmt"
2020-11-24 05:10:32 -06:00
"strings"
2017-04-08 17:55:07 -05:00
"time"
"github.com/grafana/grafana/pkg/bus"
2019-08-12 13:03:48 -05:00
"github.com/grafana/grafana/pkg/models"
2017-04-08 17:55:07 -05:00
)
func init ( ) {
2017-12-08 09:25:45 -06:00
bus . AddHandler ( "sql" , UpdateTeam )
bus . AddHandler ( "sql" , DeleteTeam )
bus . AddHandler ( "sql" , SearchTeams )
bus . AddHandler ( "sql" , GetTeamById )
bus . AddHandler ( "sql" , GetTeamsByUser )
2019-03-06 08:37:37 -06:00
bus . AddHandler ( "sql" , UpdateTeamMember )
2017-12-08 09:25:45 -06:00
bus . AddHandler ( "sql" , RemoveTeamMember )
bus . AddHandler ( "sql" , GetTeamMembers )
2019-08-12 13:03:48 -05:00
bus . AddHandler ( "sql" , IsAdminOfTeams )
2017-04-08 17:55:07 -05:00
}
2020-11-24 05:10:32 -06:00
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 getTeamMemberCount ( filteredUsers [ ] string ) string {
if len ( filteredUsers ) > 0 {
2021-03-17 10:06:10 -05:00
return ` ( SELECT COUNT ( * ) FROM team_member
2020-11-24 05:10:32 -06:00
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 {
2019-03-14 08:24:13 -05:00
return ` SELECT
2020-11-24 05:10:32 -06:00
team . id AS id ,
2019-03-14 08:24:13 -05:00
team . org_id ,
2020-11-24 05:10:32 -06:00
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 = ? `
2019-03-14 08:24:13 -05:00
}
2020-11-24 05:10:32 -06:00
func getTeamSelectSQLBase ( filteredUsers [ ] string ) string {
2018-07-11 13:23:07 -05:00
return ` SELECT
team . id as id ,
team . org_id ,
team . name as name ,
2020-11-24 05:10:32 -06:00
team . email as email , ` +
getTeamMemberCount ( filteredUsers ) +
` FROM team as team `
2018-07-11 13:23:07 -05:00
}
2021-03-17 10:06:10 -05:00
func ( ss * SQLStore ) CreateTeam ( name , email string , orgID int64 ) ( models . Team , error ) {
team := models . Team {
Name : name ,
Email : email ,
OrgId : orgID ,
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
}
err := ss . WithTransactionalDbSession ( context . Background ( ) , func ( sess * DBSession ) error {
if isNameTaken , err := isTeamNameTaken ( orgID , name , 0 , sess ) ; err != nil {
2017-04-08 17:55:07 -05:00
return err
} else if isNameTaken {
2019-08-12 13:03:48 -05:00
return models . ErrTeamNameTaken
2017-04-08 17:55:07 -05:00
}
2017-12-08 09:25:45 -06:00
_ , err := sess . Insert ( & team )
2017-04-08 17:55:07 -05:00
return err
} )
2021-03-17 10:06:10 -05:00
return team , err
2017-04-08 17:55:07 -05:00
}
2019-08-12 13:03:48 -05:00
func UpdateTeam ( cmd * models . UpdateTeamCommand ) error {
2017-05-24 09:19:21 -05:00
return inTransaction ( func ( sess * DBSession ) error {
2018-02-09 10:26:15 -06:00
if isNameTaken , err := isTeamNameTaken ( cmd . OrgId , cmd . Name , cmd . Id , sess ) ; err != nil {
2017-04-18 08:01:05 -05:00
return err
} else if isNameTaken {
2019-08-12 13:03:48 -05:00
return models . ErrTeamNameTaken
2017-04-18 08:01:05 -05:00
}
2019-08-12 13:03:48 -05:00
team := models . Team {
2017-04-18 08:01:05 -05:00
Name : cmd . Name ,
2017-12-20 14:20:12 -06:00
Email : cmd . Email ,
2017-04-18 08:01:05 -05:00
Updated : time . Now ( ) ,
}
2017-12-20 14:20:12 -06:00
sess . MustCols ( "email" )
2018-09-16 05:37:08 -05:00
affectedRows , err := sess . ID ( cmd . Id ) . Update ( & team )
2017-04-18 08:01:05 -05:00
if err != nil {
return err
}
if affectedRows == 0 {
2019-08-12 13:03:48 -05:00
return models . ErrTeamNotFound
2017-04-18 08:01:05 -05:00
}
return nil
} )
}
2018-02-16 04:45:53 -06:00
// DeleteTeam will delete a team, its member and any permissions connected to the team
2019-08-12 13:03:48 -05:00
func DeleteTeam ( cmd * models . DeleteTeamCommand ) error {
2017-05-24 09:19:21 -05:00
return inTransaction ( func ( sess * DBSession ) error {
2019-03-11 09:48:05 -05:00
if _ , err := teamExists ( cmd . OrgId , cmd . Id , sess ) ; err != nil {
2017-04-08 17:55:07 -05:00
return err
}
deletes := [ ] string {
2018-02-09 10:26:15 -06:00
"DELETE FROM team_member WHERE org_id=? and team_id = ?" ,
"DELETE FROM team WHERE org_id=? and id = ?" ,
"DELETE FROM dashboard_acl WHERE org_id=? and team_id = ?" ,
2017-04-08 17:55:07 -05:00
}
for _ , sql := range deletes {
2018-02-09 10:26:15 -06:00
_ , err := sess . Exec ( sql , cmd . OrgId , cmd . Id )
2017-04-08 17:55:07 -05:00
if err != nil {
return err
}
}
return nil
} )
}
2021-03-17 10:06:10 -05:00
func teamExists ( orgID int64 , teamID int64 , sess * DBSession ) ( bool , error ) {
if res , err := sess . Query ( "SELECT 1 from team WHERE org_id=? and id=?" , orgID , teamID ) ; err != nil {
2018-02-16 04:45:53 -06:00
return false , err
} else if len ( res ) != 1 {
2019-08-12 13:03:48 -05:00
return false , models . ErrTeamNotFound
2018-02-16 04:45:53 -06:00
}
return true , nil
}
2018-02-09 10:26:15 -06:00
func isTeamNameTaken ( orgId int64 , name string , existingId int64 , sess * DBSession ) ( bool , error ) {
2019-08-12 13:03:48 -05:00
var team models . Team
2018-02-09 10:26:15 -06:00
exists , err := sess . Where ( "org_id=? and name=?" , orgId , name ) . Get ( & team )
2017-04-08 17:55:07 -05:00
if err != nil {
return false , nil
}
2017-12-08 09:25:45 -06:00
if exists && existingId != team . Id {
2017-04-08 17:55:07 -05:00
return true , nil
}
return false , nil
}
2019-08-12 13:03:48 -05:00
func SearchTeams ( query * models . SearchTeamsQuery ) error {
query . Result = models . SearchTeamQueryResult {
Teams : make ( [ ] * models . TeamDTO , 0 ) ,
2017-04-09 18:24:16 -05:00
}
queryWithWildcards := "%" + query . Query + "%"
2017-12-14 10:22:45 -06:00
var sql bytes . Buffer
params := make ( [ ] interface { } , 0 )
2020-11-24 05:10:32 -06:00
filteredUsers := getFilteredUsers ( query . SignedInUser , query . HiddenUsers )
2019-03-11 08:40:57 -05:00
if query . UserIdFilter > 0 {
2020-11-24 05:10:32 -06:00
sql . WriteString ( getTeamSearchSQLBase ( filteredUsers ) )
for _ , user := range filteredUsers {
params = append ( params , user )
}
2019-03-11 08:40:57 -05:00
params = append ( params , query . UserIdFilter )
2019-03-14 08:24:13 -05:00
} else {
2020-11-24 05:10:32 -06:00
sql . WriteString ( getTeamSelectSQLBase ( filteredUsers ) )
for _ , user := range filteredUsers {
params = append ( params , user )
}
2019-03-11 08:40:57 -05:00
}
2017-12-14 10:22:45 -06:00
2020-11-24 05:10:32 -06:00
sql . WriteString ( ` WHERE team.org_id = ? ` )
2017-12-14 10:22:45 -06:00
params = append ( params , query . OrgId )
2017-06-23 13:55:53 -05:00
2017-04-08 17:55:07 -05:00
if query . Query != "" {
2017-12-14 10:22:45 -06:00
sql . WriteString ( ` and team.name ` + dialect . LikeStr ( ) + ` ? ` )
params = append ( params , queryWithWildcards )
2017-04-08 17:55:07 -05:00
}
2017-12-14 10:22:45 -06:00
2017-04-08 17:55:07 -05:00
if query . Name != "" {
2017-12-14 10:22:45 -06:00
sql . WriteString ( ` and team.name = ? ` )
params = append ( params , query . Name )
2017-04-08 17:55:07 -05:00
}
2017-06-23 13:55:53 -05:00
2017-12-14 10:22:45 -06:00
sql . WriteString ( ` order by team.name asc ` )
if query . Limit != 0 {
offset := query . Limit * ( query . Page - 1 )
2018-05-10 09:54:21 -05:00
sql . WriteString ( dialect . LimitOffset ( int64 ( query . Limit ) , int64 ( offset ) ) )
2017-12-14 10:22:45 -06:00
}
2018-09-16 05:26:05 -05:00
if err := x . SQL ( sql . String ( ) , params ... ) . Find ( & query . Result . Teams ) ; err != nil {
2017-04-09 18:24:16 -05:00
return err
}
2019-08-12 13:03:48 -05:00
team := models . Team { }
2017-12-08 09:25:45 -06:00
countSess := x . Table ( "team" )
2017-04-09 18:24:16 -05:00
if query . Query != "" {
2017-12-14 10:22:45 -06:00
countSess . Where ( ` name ` + dialect . LikeStr ( ) + ` ? ` , queryWithWildcards )
2017-04-09 18:24:16 -05:00
}
2017-12-14 10:22:45 -06:00
2017-04-09 18:24:16 -05:00
if query . Name != "" {
countSess . Where ( "name=?" , query . Name )
}
2017-12-14 10:22:45 -06:00
2017-12-08 09:25:45 -06:00
count , err := countSess . Count ( & team )
2017-04-09 18:24:16 -05:00
query . Result . TotalCount = count
2017-04-08 17:55:07 -05:00
return err
}
2019-08-12 13:03:48 -05:00
func GetTeamById ( query * models . GetTeamByIdQuery ) error {
2018-07-11 13:23:07 -05:00
var sql bytes . Buffer
2020-11-24 05:10:32 -06:00
params := make ( [ ] interface { } , 0 )
filteredUsers := getFilteredUsers ( query . SignedInUser , query . HiddenUsers )
sql . WriteString ( getTeamSelectSQLBase ( filteredUsers ) )
for _ , user := range filteredUsers {
params = append ( params , user )
}
2018-07-11 13:23:07 -05:00
sql . WriteString ( ` WHERE team.org_id = ? and team.id = ? ` )
2020-11-24 05:10:32 -06:00
params = append ( params , query . OrgId , query . Id )
2018-07-11 13:23:07 -05:00
2019-08-12 13:03:48 -05:00
var team models . TeamDTO
2020-11-24 05:10:32 -06:00
exists , err := x . SQL ( sql . String ( ) , params ... ) . Get ( & team )
2018-07-11 13:23:07 -05:00
2017-04-08 17:55:07 -05:00
if err != nil {
return err
}
if ! exists {
2019-08-12 13:03:48 -05:00
return models . ErrTeamNotFound
2017-04-08 17:55:07 -05:00
}
2017-12-08 09:25:45 -06:00
query . Result = & team
2017-04-08 17:55:07 -05:00
return nil
}
2018-02-16 04:45:53 -06:00
// GetTeamsByUser is used by the Guardian when checking a users' permissions
2019-08-12 13:03:48 -05:00
func GetTeamsByUser ( query * models . GetTeamsByUserQuery ) error {
query . Result = make ( [ ] * models . TeamDTO , 0 )
2018-07-11 13:23:07 -05:00
var sql bytes . Buffer
2017-05-22 03:33:17 -05:00
2020-11-24 05:10:32 -06:00
sql . WriteString ( getTeamSelectSQLBase ( [ ] string { } ) )
2018-07-11 13:23:07 -05:00
sql . WriteString ( ` INNER JOIN team_member on team.id = team_member.team_id ` )
sql . WriteString ( ` WHERE team.org_id = ? and team_member.user_id = ? ` )
2017-05-22 03:33:17 -05:00
2018-09-16 05:26:05 -05:00
err := x . SQL ( sql . String ( ) , query . OrgId , query . UserId ) . Find ( & query . Result )
2018-04-16 12:54:23 -05:00
return err
2017-05-22 03:33:17 -05:00
}
2018-02-16 04:45:53 -06:00
// AddTeamMember adds a user to a team
2021-03-17 10:06:10 -05:00
func ( ss * SQLStore ) AddTeamMember ( userID , orgID , teamID int64 , isExternal bool , permission models . PermissionType ) error {
return ss . WithTransactionalDbSession ( context . Background ( ) , func ( sess * DBSession ) error {
if res , err := sess . Query ( "SELECT 1 from team_member WHERE org_id=? and team_id=? and user_id=?" ,
orgID , teamID , userID ) ; err != nil {
2017-04-08 17:55:07 -05:00
return err
} else if len ( res ) == 1 {
2019-08-12 13:03:48 -05:00
return models . ErrTeamMemberAlreadyAdded
2017-04-08 17:55:07 -05:00
}
2021-03-17 10:06:10 -05:00
if _ , err := teamExists ( orgID , teamID , sess ) ; err != nil {
2017-04-08 17:55:07 -05:00
return err
}
2019-08-12 13:03:48 -05:00
entity := models . TeamMember {
2021-03-17 10:06:10 -05:00
OrgId : orgID ,
TeamId : teamID ,
UserId : userID ,
External : isExternal ,
2019-03-06 04:47:18 -06:00
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
2021-03-17 10:06:10 -05:00
Permission : permission ,
2017-04-08 17:55:07 -05:00
}
_ , err := sess . Insert ( & entity )
return err
} )
}
2019-08-12 13:03:48 -05:00
func getTeamMember ( sess * DBSession , orgId int64 , teamId int64 , userId int64 ) ( models . TeamMember , error ) {
2020-11-10 23:21:08 -06:00
rawSQL := ` SELECT * FROM team_member WHERE org_id=? and team_id=? and user_id=? `
2019-08-12 13:03:48 -05:00
var member models . TeamMember
2020-11-10 23:21:08 -06:00
exists , err := sess . SQL ( rawSQL , orgId , teamId , userId ) . Get ( & member )
2019-03-14 03:37:56 -05:00
if err != nil {
return member , err
}
if ! exists {
2019-08-12 13:03:48 -05:00
return member , models . ErrTeamMemberNotFound
2019-03-14 03:37:56 -05:00
}
return member , nil
}
2019-03-06 08:37:37 -06:00
// UpdateTeamMember updates a team member
2019-08-12 13:03:48 -05:00
func UpdateTeamMember ( cmd * models . UpdateTeamMemberCommand ) error {
2019-03-06 08:37:37 -06:00
return inTransaction ( func ( sess * DBSession ) error {
2019-03-14 03:37:56 -05:00
member , err := getTeamMember ( sess , cmd . OrgId , cmd . TeamId , cmd . UserId )
2019-03-06 08:37:37 -06:00
if err != nil {
return err
}
2019-03-13 04:11:53 -05:00
if cmd . ProtectLastAdmin {
2019-03-14 03:14:35 -05:00
_ , err := isLastAdmin ( sess , cmd . OrgId , cmd . TeamId , cmd . UserId )
2019-03-13 04:11:53 -05:00
if err != nil {
return err
}
}
2019-08-12 13:03:48 -05:00
if cmd . Permission != models . PERMISSION_ADMIN { // make sure we don't get invalid permission levels in store
2019-03-13 01:18:57 -05:00
cmd . Permission = 0
}
2019-03-06 08:37:37 -06:00
member . Permission = cmd . Permission
2019-03-08 06:53:42 -06:00
_ , err = sess . Cols ( "permission" ) . Where ( "org_id=? and team_id=? and user_id=?" , cmd . OrgId , cmd . TeamId , cmd . UserId ) . Update ( member )
2019-03-06 08:37:37 -06:00
return err
} )
}
2018-02-16 04:45:53 -06:00
// RemoveTeamMember removes a member from a team
2019-08-12 13:03:48 -05:00
func RemoveTeamMember ( cmd * models . RemoveTeamMemberCommand ) error {
2017-05-24 09:19:21 -05:00
return inTransaction ( func ( sess * DBSession ) error {
2019-03-11 09:48:05 -05:00
if _ , err := teamExists ( cmd . OrgId , cmd . TeamId , sess ) ; err != nil {
2018-02-16 04:45:53 -06:00
return err
}
2019-03-12 10:59:39 -05:00
if cmd . ProtectLastAdmin {
2019-03-14 03:14:35 -05:00
_ , err := isLastAdmin ( sess , cmd . OrgId , cmd . TeamId , cmd . UserId )
2019-03-12 10:59:39 -05:00
if err != nil {
return err
}
}
2020-11-10 23:21:08 -06:00
var rawSQL = "DELETE FROM team_member WHERE org_id=? and team_id=? and user_id=?"
res , err := sess . Exec ( rawSQL , cmd . OrgId , cmd . TeamId , cmd . UserId )
2017-04-08 17:55:07 -05:00
if err != nil {
return err
}
2018-02-16 04:45:53 -06:00
rows , err := res . RowsAffected ( )
if rows == 0 {
2019-08-12 13:03:48 -05:00
return models . ErrTeamMemberNotFound
2018-02-16 04:45:53 -06:00
}
2017-04-08 17:55:07 -05:00
return err
} )
}
2019-03-12 10:59:39 -05:00
func isLastAdmin ( sess * DBSession , orgId int64 , teamId int64 , userId int64 ) ( bool , error ) {
2020-11-10 23:21:08 -06:00
rawSQL := "SELECT user_id FROM team_member WHERE org_id=? and team_id=? and permission=?"
2019-03-12 10:59:39 -05:00
userIds := [ ] * int64 { }
2020-11-10 23:21:08 -06:00
err := sess . SQL ( rawSQL , orgId , teamId , models . PERMISSION_ADMIN ) . Find ( & userIds )
2019-03-12 10:59:39 -05:00
if err != nil {
return false , err
}
isAdmin := false
for _ , adminId := range userIds {
if userId == * adminId {
isAdmin = true
break
}
}
if isAdmin && len ( userIds ) == 1 {
2019-08-12 13:03:48 -05:00
return true , models . ErrLastTeamAdmin
2019-03-12 10:59:39 -05:00
}
return false , err
}
2018-02-16 04:45:53 -06:00
// GetTeamMembers return a list of members for the specified team
2019-08-12 13:03:48 -05:00
func GetTeamMembers ( query * models . GetTeamMembersQuery ) error {
query . Result = make ( [ ] * models . TeamMemberDTO , 0 )
2017-12-08 09:25:45 -06:00
sess := x . Table ( "team_member" )
2019-03-04 09:57:29 -06:00
sess . Join ( "INNER" , x . Dialect ( ) . Quote ( "user" ) , fmt . Sprintf ( "team_member.user_id=%s.id" , x . Dialect ( ) . Quote ( "user" ) ) )
2019-07-03 08:52:10 -05:00
// Join with only most recent auth module
authJoinCondition := ` (
SELECT id from user_auth
WHERE user_auth . user_id = team_member . user_id
ORDER BY user_auth . created DESC `
authJoinCondition = "user_auth.id=" + authJoinCondition + dialect . Limit ( 1 ) + ")"
sess . Join ( "LEFT" , "user_auth" , authJoinCondition )
2018-07-01 09:01:43 -05:00
if query . OrgId != 0 {
sess . Where ( "team_member.org_id=?" , query . OrgId )
}
if query . TeamId != 0 {
sess . Where ( "team_member.team_id=?" , query . TeamId )
}
if query . UserId != 0 {
sess . Where ( "team_member.user_id=?" , query . UserId )
}
2018-09-14 10:27:36 -05:00
if query . External {
sess . Where ( "team_member.external=?" , dialect . BooleanStr ( true ) )
}
2019-11-21 04:44:46 -06:00
sess . Cols (
"team_member.org_id" ,
"team_member.team_id" ,
"team_member.user_id" ,
"user.email" ,
"user.name" ,
"user.login" ,
"team_member.external" ,
"team_member.permission" ,
"user_auth.auth_module" ,
)
2017-06-23 13:55:53 -05:00
sess . Asc ( "user.login" , "user.email" )
2017-04-08 17:55:07 -05:00
err := sess . Find ( & query . Result )
return err
}
2019-08-12 13:03:48 -05:00
func IsAdminOfTeams ( query * models . IsAdminOfTeamsQuery ) error {
2020-11-10 23:21:08 -06:00
builder := & SQLBuilder { }
2019-08-12 13:03:48 -05:00
builder . Write ( "SELECT COUNT(team.id) AS count FROM team INNER JOIN team_member ON team_member.team_id = team.id WHERE team.org_id = ? AND team_member.user_id = ? AND team_member.permission = ?" , query . SignedInUser . OrgId , query . SignedInUser . UserId , models . PERMISSION_ADMIN )
type teamCount struct {
Count int64
}
resp := make ( [ ] * teamCount , 0 )
2020-11-10 23:21:08 -06:00
if err := x . SQL ( builder . GetSQLString ( ) , builder . params ... ) . Find ( & resp ) ; err != nil {
2019-08-12 13:03:48 -05:00
return err
}
query . Result = len ( resp ) > 0 && resp [ 0 ] . Count > 0
return nil
}