teams: refactor so that you can only delete teams if you are team admin

This commit is contained in:
Hugo Häggmark 2019-03-14 14:24:13 +01:00 committed by Leonard Gram
parent a615b78f8a
commit 53c74fa2f5
8 changed files with 60 additions and 16 deletions

View File

@ -73,12 +73,13 @@ type SearchTeamsQuery struct {
}
type TeamDTO struct {
Id int64 `json:"id"`
OrgId int64 `json:"orgId"`
Name string `json:"name"`
Email string `json:"email"`
AvatarUrl string `json:"avatarUrl"`
MemberCount int64 `json:"memberCount"`
Id int64 `json:"id"`
OrgId int64 `json:"orgId"`
Name string `json:"name"`
Email string `json:"email"`
AvatarUrl string `json:"avatarUrl"`
MemberCount int64 `json:"memberCount"`
Permission PermissionType `json:"permission"`
}
type SearchTeamQueryResult struct {

View File

@ -23,13 +23,25 @@ func init() {
bus.AddHandler("sql", GetTeamMembers)
}
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 getTeamSelectSqlBase() 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
(SELECT COUNT(*) from team_member where team_member.team_id = team.id) as member_count
FROM team as team `
}
@ -146,10 +158,11 @@ func SearchTeams(query *m.SearchTeamsQuery) error {
var sql bytes.Buffer
params := make([]interface{}, 0)
sql.WriteString(getTeamSelectSqlBase())
if query.UserIdFilter > 0 {
sql.WriteString(`INNER JOIN team_member on team.id = team_member.team_id AND team_member.user_id = ?`)
sql.WriteString(getTeamSearchSqlBase())
params = append(params, query.UserIdFilter)
} else {
sql.WriteString(getTeamSelectSqlBase())
}
sql.WriteString(` WHERE team.org_id = ?`)

View File

@ -6,7 +6,7 @@ import { DeleteButton } from '@grafana/ui';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import { NavModel, Team, OrgRole } from 'app/types';
import { loadTeams, deleteTeam, setSearchQuery } from './state/actions';
import { getSearchQuery, getTeams, getTeamsCount } from './state/selectors';
import { getSearchQuery, getTeams, getTeamsCount, isPermissionTeamAdmin } from './state/selectors';
import { getNavModel } from 'app/core/selectors/navModel';
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
import { config } from 'app/core/config';
@ -43,7 +43,10 @@ export class TeamList extends PureComponent<Props, any> {
};
renderTeam(team: Team) {
const { editorsCanAdmin, signedInUser } = this.props;
const permission = team.permission;
const teamUrl = `org/teams/edit/${team.id}`;
const canDelete = isPermissionTeamAdmin({ permission, editorsCanAdmin, signedInUser });
return (
<tr key={team.id}>
@ -62,7 +65,7 @@ export class TeamList extends PureComponent<Props, any> {
<a href={teamUrl}>{team.memberCount}</a>
</td>
<td className="text-right">
<DeleteButton onConfirm={() => this.deleteTeam(team)} />
<DeleteButton onConfirm={() => this.deleteTeam(team)} disabled={!canDelete} />
</td>
</tr>
);

View File

@ -9,6 +9,7 @@ export const getMultipleMockTeams = (numberOfTeams: number): Team[] => {
avatarUrl: 'some/url/',
email: `test-${i}@test.com`,
memberCount: i,
permission: TeamPermissionLevel.Member,
});
}
@ -22,6 +23,7 @@ export const getMockTeam = (): Team => {
avatarUrl: 'some/url/',
email: 'test@test.com',
memberCount: 1,
permission: TeamPermissionLevel.Member,
};
};

View File

@ -133,6 +133,7 @@ exports[`Render should render teams table 1`] = `
className="text-right"
>
<DeleteButton
disabled={false}
onConfirm={[Function]}
/>
</td>
@ -183,6 +184,7 @@ exports[`Render should render teams table 1`] = `
className="text-right"
>
<DeleteButton
disabled={false}
onConfirm={[Function]}
/>
</td>
@ -233,6 +235,7 @@ exports[`Render should render teams table 1`] = `
className="text-right"
>
<DeleteButton
disabled={false}
onConfirm={[Function]}
/>
</td>
@ -283,6 +286,7 @@ exports[`Render should render teams table 1`] = `
className="text-right"
>
<DeleteButton
disabled={false}
onConfirm={[Function]}
/>
</td>
@ -333,6 +337,7 @@ exports[`Render should render teams table 1`] = `
className="text-right"
>
<DeleteButton
disabled={false}
onConfirm={[Function]}
/>
</td>
@ -458,6 +463,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on and signedin us
className="text-right"
>
<DeleteButton
disabled={true}
onConfirm={[Function]}
/>
</td>
@ -583,6 +589,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on and signedin us
className="text-right"
>
<DeleteButton
disabled={true}
onConfirm={[Function]}
/>
</td>

View File

@ -1,4 +1,4 @@
import { Team, NavModelItem, NavModel } from 'app/types';
import { Team, NavModelItem, NavModel, TeamPermissionLevel } from 'app/types';
import config from 'app/core/config';
export function buildNavModel(team: Team): NavModelItem {
@ -47,6 +47,7 @@ export function getTeamLoadingNav(pageName: string): NavModel {
name: 'Loading',
email: 'loading',
memberCount: 0,
permission: TeamPermissionLevel.Member,
});
let node: NavModelItem;

View File

@ -37,10 +37,24 @@ export interface Config {
}
export const isSignedInUserTeamAdmin = (config: Config): boolean => {
const userInMembers = config.members.find(m => m.userId === config.signedInUser.id);
const isAdmin = config.signedInUser.isGrafanaAdmin || config.signedInUser.orgRole === OrgRole.Admin;
const userIsTeamAdmin = userInMembers && userInMembers.permission === TeamPermissionLevel.Admin;
const { members, signedInUser, editorsCanAdmin } = config;
const userInMembers = members.find(m => m.userId === signedInUser.id);
const permission = userInMembers ? userInMembers.permission : TeamPermissionLevel.Member;
return isPermissionTeamAdmin({ permission, signedInUser, editorsCanAdmin });
};
export interface PermissionConfig {
permission: TeamPermissionLevel;
editorsCanAdmin: boolean;
signedInUser: User;
}
export const isPermissionTeamAdmin = (config: PermissionConfig): boolean => {
const { permission, signedInUser, editorsCanAdmin } = config;
const isAdmin = signedInUser.isGrafanaAdmin || signedInUser.orgRole === OrgRole.Admin;
const userIsTeamAdmin = permission === TeamPermissionLevel.Admin;
const isSignedInUserTeamAdmin = isAdmin || userIsTeamAdmin;
return isSignedInUserTeamAdmin || !config.editorsCanAdmin;
return isSignedInUserTeamAdmin || !editorsCanAdmin;
};

View File

@ -1,9 +1,12 @@
import { TeamPermissionLevel } from './acl';
export interface Team {
id: number;
name: string;
avatarUrl: string;
email: string;
memberCount: number;
permission: TeamPermissionLevel;
}
export interface TeamMember {