mirror of
https://github.com/grafana/grafana.git
synced 2024-12-28 01:41:24 -06:00
teams: refactor so that you can only delete teams if you are team admin
This commit is contained in:
parent
a615b78f8a
commit
53c74fa2f5
@ -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 {
|
||||
|
@ -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 = ?`)
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user