Skip to content

Commit 5fff9eb

Browse files
authored
Warn if deleting user with associated Service Account (#2022)
Created api to check if users have service accounts before deleting, UI to display warning and users with associated accounts
1 parent 795497a commit 5fff9eb

12 files changed

+947
-13
lines changed

models/user_service_account_item.go

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

models/user_service_account_summary.go

Lines changed: 136 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

portal-ui/src/screens/Console/Users/DeleteUser.tsx

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,64 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

17-
import React from "react";
18-
import { useDispatch } from "react-redux";
17+
import React, { useEffect, useState, Fragment } from "react";
18+
import { connect } from "react-redux";
1919
import { DialogContentText } from "@mui/material";
20+
import { setErrorSnackMessage } from "../../../systemSlice";
2021
import useApi from "../Common/Hooks/useApi";
2122
import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog";
2223
import { ErrorResponseHandler } from "../../../common/types";
2324
import { ConfirmDeleteIcon } from "../../../icons";
2425
import { encodeURLString } from "../../../common/utils";
25-
import { setErrorSnackMessage } from "../../../systemSlice";
26-
26+
import WarningMessage from "../Common/WarningMessage/WarningMessage";
27+
import TableWrapper from "../Common/TableWrapper/TableWrapper";
28+
import api from "../../../common/api";
29+
import { IAM_PAGES } from "../../../common/SecureComponent/permissions";
30+
import Loader from "../Common/Loader/Loader";
2731
interface IDeleteUserProps {
2832
closeDeleteModalAndRefresh: (refresh: boolean) => void;
2933
deleteOpen: boolean;
3034
selectedUsers: string[] | null;
35+
setErrorSnackMessage: typeof setErrorSnackMessage;
36+
history: any;
3137
}
3238

3339
const DeleteUser = ({
3440
closeDeleteModalAndRefresh,
3541
deleteOpen,
3642
selectedUsers,
43+
setErrorSnackMessage,
44+
history,
3745
}: IDeleteUserProps) => {
38-
const dispatch = useDispatch();
3946
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
40-
const onDelError = (err: ErrorResponseHandler) =>
41-
dispatch(setErrorSnackMessage(err));
47+
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
4248
const onClose = () => closeDeleteModalAndRefresh(false);
4349

4450
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
51+
const [loadingSA, setLoadingSA] = useState<boolean>(true);
52+
const [hasSA, setHasSA] = useState<boolean>(false);
53+
const [userSAList, setUserSAList] = useState<userSACount[]>([]);
4554

4655
const userLoggedIn = localStorage.getItem("userLoggedIn") || "";
56+
57+
useEffect(() => {
58+
59+
if(selectedUsers) {
60+
api
61+
.invoke("POST", `/api/v1/users/service-accounts`, selectedUsers)
62+
.then((res) => {
63+
setUserSAList(res.userServiceAccountList) ;
64+
if (res.hasSA) {
65+
setHasSA(true)
66+
}
67+
setLoadingSA(false);
68+
})
69+
.catch((err: ErrorResponseHandler) => {
70+
setErrorSnackMessage(err);
71+
setLoadingSA(false);
72+
});
73+
}
74+
}, [selectedUsers, setErrorSnackMessage]);
4775

4876
if (!selectedUsers) {
4977
return null;
@@ -52,7 +80,18 @@ const DeleteUser = ({
5280
<div key={user}>
5381
<b>{user}</b>
5482
</div>
55-
));
83+
));
84+
const viewAction = (selectionElement: any): void => {
85+
history.push(
86+
`${IAM_PAGES.USERS}/${encodeURLString(selectionElement.userName)}`
87+
);
88+
};
89+
const tableActions = [
90+
{
91+
type: "view",
92+
onClick: viewAction,
93+
},
94+
];
5695

5796
const onConfirmDelete = () => {
5897
for (let user of selectedUsers) {
@@ -68,7 +107,18 @@ const DeleteUser = ({
68107
}
69108
};
70109

110+
interface userSACount {
111+
userName: string;
112+
numSAs: number;
113+
}
114+
115+
const noSAtext = "Are you sure you want to delete the following " + selectedUsers.length+" "+
116+
"user"+ (selectedUsers.length > 1 ? "s?" : "?")
117+
71118
return (
119+
loadingSA ?
120+
<Loader />
121+
:
72122
<ConfirmDialog
73123
title={`Delete User${selectedUsers.length > 1 ? "s" : ""}`}
74124
confirmText={"Delete"}
@@ -78,14 +128,42 @@ const DeleteUser = ({
78128
onConfirm={onConfirmDelete}
79129
onClose={onClose}
80130
confirmationContent={
81-
<DialogContentText>
82-
Are you sure you want to delete the following {selectedUsers.length}{" "}
83-
user{selectedUsers.length > 1 ? "s?" : "?"}
84-
<b>{renderUsers}</b>
131+
<DialogContentText>
132+
133+
{hasSA ?
134+
<Fragment>
135+
<WarningMessage
136+
label = "Click on a user to view the full listing of asociated Service Accounts. All Service Accounts associated with a user will be deleted along with the user. Are you sure you want to continue?"
137+
title = "Warning: One or more users selected has associated Service Accounts. "
138+
/>
139+
<TableWrapper
140+
itemActions={tableActions}
141+
columns={[
142+
{ label: "Username", elementKey: "userName" },
143+
{ label: "# Associated Service Accounts", elementKey: "numSAs" },
144+
]}
145+
isLoading={loadingSA}
146+
records={userSAList}
147+
entityName="User Service Accounts"
148+
idField="userName"
149+
customPaperHeight="250"
150+
/>
151+
</Fragment>
152+
: <Fragment>
153+
{noSAtext}
154+
{renderUsers}
155+
</Fragment>
156+
}
85157
</DialogContentText>
86158
}
87159
/>
88160
);
89161
};
90162

91-
export default DeleteUser;
163+
const mapDispatchToProps = {
164+
setErrorSnackMessage,
165+
};
166+
167+
const connector = connect(null, mapDispatchToProps);
168+
169+
export default connector(DeleteUser);

portal-ui/src/screens/Console/Users/ListUsers.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ const ListUsers = ({ classes, history }: IUsersProps) => {
186186
closeDeleteModalAndRefresh={(refresh: boolean) => {
187187
closeDeleteModalAndRefresh(refresh);
188188
}}
189+
history={history}
189190
/>
190191
)}
191192
{addGroupOpen && (

0 commit comments

Comments
 (0)