mirror of
https://github.com/grafana/grafana.git
synced 2024-12-28 01:41:24 -06:00
teams: editors can't remove the last admin from a team.
This commit is contained in:
parent
8593668ab2
commit
21d3d27452
@ -160,7 +160,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
teamsRoute.Get("/:teamId/members", Wrap(GetTeamMembers))
|
||||
teamsRoute.Post("/:teamId/members", bind(m.AddTeamMemberCommand{}), Wrap(AddTeamMember))
|
||||
teamsRoute.Put("/:teamId/members/:userId", bind(m.UpdateTeamMemberCommand{}), Wrap(UpdateTeamMember))
|
||||
teamsRoute.Delete("/:teamId/members/:userId", Wrap(RemoveTeamMember))
|
||||
teamsRoute.Delete("/:teamId/members/:userId", Wrap(hs.RemoveTeamMember))
|
||||
teamsRoute.Get("/:teamId/preferences", Wrap(GetTeamPreferences))
|
||||
teamsRoute.Put("/:teamId/preferences", bind(dtos.UpdatePrefsCmd{}), Wrap(UpdateTeamPreferences))
|
||||
}, reqAdminOrEditorCanAdmin)
|
||||
|
@ -81,7 +81,7 @@ func UpdateTeamMember(c *m.ReqContext, cmd m.UpdateTeamMemberCommand) Response {
|
||||
}
|
||||
|
||||
// DELETE /api/teams/:teamId/members/:userId
|
||||
func RemoveTeamMember(c *m.ReqContext) Response {
|
||||
func (hs *HTTPServer) RemoveTeamMember(c *m.ReqContext) Response {
|
||||
orgId := c.OrgId
|
||||
teamId := c.ParamsInt64(":teamId")
|
||||
userId := c.ParamsInt64(":userId")
|
||||
@ -90,7 +90,12 @@ func RemoveTeamMember(c *m.ReqContext) Response {
|
||||
return Error(403, "Not allowed to remove team member", err)
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&m.RemoveTeamMemberCommand{OrgId: orgId, TeamId: teamId, UserId: userId}); err != nil {
|
||||
protectLastAdmin := false
|
||||
if c.OrgRole == m.ROLE_EDITOR {
|
||||
protectLastAdmin = true
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&m.RemoveTeamMemberCommand{OrgId: orgId, TeamId: teamId, UserId: userId, ProtectLastAdmin: protectLastAdmin}); err != nil {
|
||||
if err == m.ErrTeamNotFound {
|
||||
return Error(404, "Team not found", nil)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ var (
|
||||
ErrTeamNotFound = errors.New("Team not found")
|
||||
ErrTeamNameTaken = errors.New("Team name is taken")
|
||||
ErrTeamMemberNotFound = errors.New("Team member not found")
|
||||
ErrLastTeamAdmin = errors.New("Not allowed to remove last admin")
|
||||
ErrNotAllowedToUpdateTeam = errors.New("User not allowed to update team")
|
||||
ErrNotAllowedToUpdateTeamInDifferentOrg = errors.New("User not allowed to update team in another org")
|
||||
)
|
||||
|
@ -42,9 +42,10 @@ type UpdateTeamMemberCommand struct {
|
||||
}
|
||||
|
||||
type RemoveTeamMemberCommand struct {
|
||||
OrgId int64 `json:"-"`
|
||||
UserId int64
|
||||
TeamId int64
|
||||
OrgId int64 `json:"-"`
|
||||
UserId int64
|
||||
TeamId int64
|
||||
ProtectLastAdmin bool `json:"-"`
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
|
@ -285,6 +285,18 @@ func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if cmd.ProtectLastAdmin {
|
||||
lastAdmin, err := isLastAdmin(sess, cmd.OrgId, cmd.TeamId, cmd.UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if lastAdmin {
|
||||
return m.ErrLastTeamAdmin
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
@ -299,6 +311,29 @@ func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error {
|
||||
})
|
||||
}
|
||||
|
||||
func isLastAdmin(sess *DBSession, orgId int64, teamId int64, userId int64) (bool, error) {
|
||||
rawSql := "SELECT user_id FROM team_member WHERE org_id=? and team_id=? and permission=?"
|
||||
userIds := []*int64{}
|
||||
err := sess.SQL(rawSql, orgId, teamId, m.PERMISSION_ADMIN).Find(&userIds)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
isAdmin := false
|
||||
for _, adminId := range userIds {
|
||||
if userId == *adminId {
|
||||
isAdmin = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isAdmin && len(userIds) == 1 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// GetTeamMembers return a list of members for the specified team
|
||||
func GetTeamMembers(query *m.GetTeamMembersQuery) error {
|
||||
query.Result = make([]*m.TeamMemberDTO, 0)
|
||||
|
@ -152,6 +152,23 @@ func TestTeamCommandsAndQueries(t *testing.T) {
|
||||
So(len(q2.Result), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("When ProtectLastAdmin is set to true", func() {
|
||||
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], Permission: int64(m.PERMISSION_ADMIN)})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("A user should not be able to remove the last admin", func() {
|
||||
err = RemoveTeamMember(&m.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], ProtectLastAdmin: true})
|
||||
So(err, ShouldEqual, m.ErrLastTeamAdmin)
|
||||
})
|
||||
|
||||
Convey("A user should be able to remove an admin if there are other admins", func() {
|
||||
err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[1], Permission: int64(m.PERMISSION_ADMIN)})
|
||||
err = RemoveTeamMember(&m.RemoveTeamMemberCommand{OrgId: testOrgId, TeamId: group1.Result.Id, UserId: userIds[0], ProtectLastAdmin: true})
|
||||
So(err, ShouldEqual, nil)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
Convey("Should be able to remove a group with users and permissions", func() {
|
||||
groupId := group2.Result.Id
|
||||
err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: testOrgId, TeamId: groupId, UserId: userIds[1]})
|
||||
|
Loading…
Reference in New Issue
Block a user