Login: Remove single admin team restriction (#54534)

* Remove single member team restriction

* Add label when permissions list is empty

* Fix unit tests

* Add co-author.

Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
linoman 2022-09-02 18:16:39 +02:00 committed by GitHub
parent 4bba3223a0
commit d2bb72fb3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 20 additions and 49 deletions

View File

@ -433,12 +433,6 @@ func updateTeamMember(sess *DBSession, orgID, teamID, userID int64, permission m
if permission != models.PERMISSION_ADMIN {
permission = 0 // make sure we don't get invalid permission levels in store
// protect the last team admin
_, err := isLastAdmin(sess, orgID, teamID, userID)
if err != nil {
return err
}
}
member.Permission = permission
@ -464,11 +458,6 @@ func removeTeamMember(sess *DBSession, cmd *models.RemoveTeamMemberCommand) erro
return err
}
_, err := isLastAdmin(sess, cmd.OrgId, cmd.TeamId, cmd.UserId)
if err != nil {
return err
}
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 {
@ -482,29 +471,6 @@ func removeTeamMember(sess *DBSession, cmd *models.RemoveTeamMemberCommand) erro
return err
}
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, models.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, models.ErrLastTeamAdmin
}
return false, err
}
// GetUserTeamMemberships return a list of memberships to teams granted to a user
// If external is specified, only memberships provided by an external auth provider will be listed
// This function doesn't perform any accesscontrol filtering.

View File

@ -251,25 +251,18 @@ func TestIntegrationTeamCommandsAndQueries(t *testing.T) {
require.Equal(t, len(q2.Result), 0)
})
t.Run("Should never remove the last admin of a team", func(t *testing.T) {
t.Run("Should have empty teams", func(t *testing.T) {
err = sqlStore.AddTeamMember(userIds[0], testOrgID, team1.Id, false, models.PERMISSION_ADMIN)
require.NoError(t, err)
t.Run("A user should not be able to remove the last admin", func(t *testing.T) {
err = sqlStore.RemoveTeamMember(context.Background(), &models.RemoveTeamMemberCommand{OrgId: testOrgID, TeamId: team1.Id, UserId: userIds[0]})
require.Equal(t, err, models.ErrLastTeamAdmin)
})
t.Run("A user should be able to remove an admin if there are other admins", func(t *testing.T) {
err = sqlStore.AddTeamMember(userIds[1], testOrgID, team1.Id, false, models.PERMISSION_ADMIN)
require.NoError(t, err)
err = sqlStore.RemoveTeamMember(context.Background(), &models.RemoveTeamMemberCommand{OrgId: testOrgID, TeamId: team1.Id, UserId: userIds[1]})
require.NoError(t, err)
})
t.Run("A user should not be able to remove the admin permission for the last admin", func(t *testing.T) {
t.Run("A user should be able to remove the admin permission for the last admin", func(t *testing.T) {
err = sqlStore.UpdateTeamMember(context.Background(), &models.UpdateTeamMemberCommand{OrgId: testOrgID, TeamId: team1.Id, UserId: userIds[0], Permission: 0})
require.Error(t, err, models.ErrLastTeamAdmin)
require.NoError(t, err)
})
t.Run("A user should be able to remove the last member", func(t *testing.T) {
err = sqlStore.RemoveTeamMember(context.Background(), &models.RemoveTeamMemberCommand{OrgId: testOrgID, TeamId: team1.Id, UserId: userIds[0]})
require.NoError(t, err)
})
t.Run("A user should be able to remove the admin permission if there are other admins", func(t *testing.T) {

View File

@ -26,6 +26,7 @@ type Type = 'users' | 'teams' | 'builtInRoles';
export type Props = {
title?: string;
buttonLabel?: string;
emptyLabel?: string;
addPermissionTitle?: string;
resource: string;
resourceId: ResourceId;
@ -35,6 +36,7 @@ export type Props = {
export const Permissions = ({
title = 'Permissions',
buttonLabel = 'Add a permission',
emptyLabel = 'There are no permissions',
resource,
resourceId,
canSetPermissions,
@ -145,6 +147,15 @@ export const Permissions = ({
onCancel={() => setIsAdding(false)}
/>
</SlideDown>
{items.length === 0 && (
<table className="filter-table gf-form-group">
<tbody>
<tr>
<th>{emptyLabel}</th>
</tr>
</tbody>
</table>
)}
<PermissionList
title="Role"
items={builtInRoles}

View File

@ -21,6 +21,7 @@ const TeamPermissions = (props: TeamPermissionsProps) => {
title=""
addPermissionTitle="Add member"
buttonLabel="Add member"
emptyLabel="There are no members in this team or you do not have the permissions to list the current members."
resource="teams"
resourceId={props.team.id}
canSetPermissions={canSetPermissions}