teams: editors can't remove the last admin from a team.

This commit is contained in:
Leonard Gram 2019-03-12 16:59:39 +01:00
parent 8593668ab2
commit 21d3d27452
6 changed files with 65 additions and 6 deletions

View File

@ -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)

View File

@ -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)
}

View File

@ -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")
)

View File

@ -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:"-"`
}
// ----------------------

View File

@ -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)

View File

@ -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]})