Skip to content

Commit 33d40b7

Browse files
authored
Fix/aah 329 disable self delete (#300)
* Fix error where failing to delete a user throws a failed and a success message. * Prevent users from deleting themselves or admins. * Fix isUserSelfOrAdmin function.
1 parent fc18bd0 commit 33d40b7

File tree

4 files changed

+42
-12
lines changed

4 files changed

+42
-12
lines changed

src/containers/user-management/delete-user-modal.tsx

+32-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import * as React from 'react';
22
import { Modal, Button, Spinner } from '@patternfly/react-core';
33
import { ExclamationTriangleIcon } from '@patternfly/react-icons';
44
import { UserType, UserAPI } from '../../api';
5+
import { mapErrorMessages } from '../../utilities';
6+
import { AppContext } from '../../loaders/app-context';
57

68
interface IState {
79
isWaitingForResponse: boolean;
@@ -11,10 +13,12 @@ interface IProps {
1113
isOpen: boolean;
1214
user?: UserType;
1315
closeModal: (didDelete: boolean) => void;
14-
addAlert: (message, variant) => void;
16+
addAlert: (message, variant, description?) => void;
1517
}
1618

1719
export class DeleteUserModal extends React.Component<IProps, IState> {
20+
static contextType = AppContext;
21+
1822
constructor(props) {
1923
super(props);
2024

@@ -47,7 +51,7 @@ export class DeleteUserModal extends React.Component<IProps, IState> {
4751
}
4852
actions={[
4953
<Button
50-
isDisabled={isWaitingForResponse}
54+
isDisabled={isWaitingForResponse || this.isUserSelfOrAdmin(user)}
5155
key='delete'
5256
variant='danger'
5357
onClick={() => this.deleteUser()}
@@ -59,23 +63,45 @@ export class DeleteUserModal extends React.Component<IProps, IState> {
5963
</Button>,
6064
]}
6165
>
62-
{user.username} will be permanently deleted.
66+
{this.getActionDescription(user)}
6367
</Modal>
6468
);
6569
}
6670

71+
private getActionDescription(user: UserType) {
72+
if (user.is_superuser) {
73+
return 'Deleting super users is not allowed.';
74+
} else if (user.id === this.context.user.id) {
75+
return 'Deleting yourself is not allowed.';
76+
}
77+
78+
return `${user.username} will be permanently deleted.`;
79+
}
80+
81+
private isUserSelfOrAdmin = (user: UserType): boolean => {
82+
return user.is_superuser || user.id === this.context.user.id;
83+
};
84+
6785
private deleteUser = () => {
6886
this.setState({ isWaitingForResponse: true }, () =>
6987
UserAPI.delete(this.props.user.id)
70-
.then(this.waitForDeleteConfirm(this.props.user.id))
71-
.catch(() => this.props.addAlert('Error deleting user.', 'danger')),
88+
.then(() => this.waitForDeleteConfirm(this.props.user.id))
89+
.catch(err => {
90+
this.props.addAlert(
91+
'Error deleting user.',
92+
'danger',
93+
mapErrorMessages(err)['__nofield'],
94+
);
95+
this.props.closeModal(false);
96+
})
97+
.finally(() => this.setState({ isWaitingForResponse: false })),
7298
);
7399
};
74100

75101
// Wait for the user to actually get removed from the database before closing the
76102
// modal
77103
private waitForDeleteConfirm(user) {
78-
UserAPI.get(user.id)
104+
UserAPI.get(user)
79105
.then(async result => {
80106
// wait half a second
81107
await new Promise(r => setTimeout(r, 500));

src/containers/user-management/user-detail.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ class UserDetail extends React.Component<RouteComponentProps, IState> {
6969
isOpen={showDeleteModal}
7070
closeModal={this.closeModal}
7171
user={userDetail}
72-
addAlert={(text, variant) =>
72+
addAlert={(text, variant, description = undefined) =>
7373
this.setState({
74-
alerts: alerts.concat([{ title: text, variant: variant }]),
74+
alerts: alerts.concat([
75+
{ title: text, variant: variant, description: description },
76+
]),
7577
})
7678
}
7779
></DeleteUserModal>

src/containers/user-management/user-list.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,11 @@ class UserList extends React.Component<RouteComponentProps, IState> {
123123
isOpen={showDeleteModal}
124124
closeModal={this.closeModal}
125125
user={deleteUser}
126-
addAlert={(text, variant) =>
126+
addAlert={(text, variant, description = undefined) =>
127127
this.setState({
128-
alerts: alerts.concat([{ title: text, variant: variant }]),
128+
alerts: alerts.concat([
129+
{ title: text, variant: variant, description: description },
130+
]),
129131
})
130132
}
131133
></DeleteUserModal>
@@ -329,7 +331,7 @@ class UserList extends React.Component<RouteComponentProps, IState> {
329331
<td>{user.first_name}</td>
330332
<td>
331333
{user.groups.map(g => (
332-
<Label>{g.name}</Label>
334+
<Label key={g.id}>{g.name}</Label>
333335
))}
334336
</td>
335337
<td>{moment(user.date_joined).fromNow()}</td>

src/utilities/map-error-messages.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function mapErrorMessages(err) {
99
} else {
1010
// some error responses are too cool to have a
1111
// parameter set on them >:(
12-
messages['__nofield'] = e.detail;
12+
messages['__nofield'] = e.detail || e.title;
1313
}
1414
}
1515
return messages;

0 commit comments

Comments
 (0)