Skip to content

Commit

Permalink
Adds end-to-end feature for archiving and deleting user accounts (#1449)
Browse files Browse the repository at this point in the history
* adds db migration file

* adds backend feature to soft del and hard del users with their projects

* adds endpoints to client

* fixes broken endpoints

* adds functionality to prevent archived users logging in

* refactors migration and account service

* adds frontend user feedback for archived users on log in

* fixes functionality to retrieve all archived projects by security admin

* edits migration for selecting all archived projects

* adds db migration and service for unarchiving user

* adds route and controller for unarchive endpoint

* adds controller for unarchive endpoint

* fixes unarchiveUser service

* adds code to prevent self archive and self delete

* adds frontend functionality to archive and delete users

* updates migration reports

* small fix to address line endings issues when working on branches between windows and unix systems

* automatic linting fixes by lerna

* fixes lerna issues, refactors, lints
  • Loading branch information
agosmou authored Sep 13, 2023
1 parent e356700 commit e48ecb7
Show file tree
Hide file tree
Showing 21 changed files with 9,978 additions and 16 deletions.
1 change: 1 addition & 0 deletions client/.prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
module.exports = {
trailingComma: "none", // deafult changed in prettier 2+
arrowParens: "avoid", // default changed in prettier 2+
endOfLine: "auto"
};
16 changes: 16 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import Login from "./components/Authorization/Login";
import Unauthorized from "./components/Authorization/Unauthorized";
import Admin from "./components/Admin";
import Roles from "./components/Roles";
import ProjectsArchive from "./components/ArchiveDelete/ProjectsArchive";
import RolesArchive from "./components/ArchiveDelete/RolesArchive";
import FaqView from "./components/Faq/FaqView";
import ResetPassword from "./components/Authorization/ResetPassword";
import ForgotPassword from "./components/Authorization/ForgotPassword";
Expand Down Expand Up @@ -169,6 +171,20 @@ const App = ({
<Roles />
</ProtectedRoute>

<ProtectedRoute
path="/archivedaccounts"
isAuthorized={account && account.isSecurityAdmin}
>
<RolesArchive />
</ProtectedRoute>

<ProtectedRoute
path="/archivedprojects"
isAuthorized={account && account.isSecurityAdmin}
>
<ProjectsArchive />
</ProtectedRoute>

<Route path="/faqs/:showChecklist?">
<FaqView
isAdmin={account.isAdmin}
Expand Down
129 changes: 129 additions & 0 deletions client/src/components/ArchiveDelete/ProjectsArchive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { createUseStyles } from "react-jss";
import * as projectService from "../../services/project.service";
import { useToast } from "../../contexts/Toast";

const useStyles = createUseStyles({
main: {
display: "flex",
flexDirection: "column",
justifyContent: "flex-start",
alignItems: "center"
},
pageTitle: {
marginTop: "2em"
},
pageSubtitle: {
marginTop: "0.5em",
textAlign: "center",
fontSize: "20px",
fontWeight: "normal",
fontStyle: "normal"
},
table: {
minWidth: "80%",
margin: "20px"
},
tr: {
margin: "0.5em"
},
td: {
padding: "0.2em",
textAlign: "left"
},
thead: {
fontWeight: "bold",
backgroundColor: "#0f2940",
color: "white",
"& td": {
padding: ".4em"
}
},
tbody: {
"& tr td": {
padding: ".4em 0"
},
"& tr:hover": {
background: "#f0e300"
}
},
link: {
textDecoration: "underline"
}
});

const ProjectsArchive = () => {
const [archivedProjects, setArchivedProjects] = useState([]);

const classes = useStyles();
// const toast = useToast();
const { add } = useToast();

useEffect(() => {
const getArchivedProjects = async () => {
try {
const response = await projectService.getAllArchivedProjects();
if (response.status === 200) {
setArchivedProjects(response.data);
} else {
add("Failed to get archived projects.");
}
} catch (err) {
add("Error - Could not display archived projects.");
}
};
getArchivedProjects();
}, [add]);

return (
<div className={classes.main}>
<h1 className={classes.pageTitle}>Archived Projects</h1>
<div className={classes.pageSubtitle}>
<Link to="/roles" className={classes.link}>
Return to Active Roles
</Link>
</div>
<div className={classes.pageSubtitle}>
<Link to="/archivedaccounts" className={classes.link}>
See Archived Users
</Link>
</div>

<table className={classes.table}>
<thead className={classes.thead}>
<tr className={classes.tr}>
<td className={classes.td}>Name</td>
<td className={classes.td}>Address</td>
<td className={classes.td}>Created By</td>
<td className={classes.td}>Created On</td>
<td className={classes.td}>Last Modified</td>
<td className={classes.td}>Archive Date</td>
</tr>
</thead>
<tbody className={classes.tbody}>
{archivedProjects.map(project => (
<tr key={project.id}>
<td className={classes.td}>{project.name}</td>
<td className={classes.td}>{project.address}</td>
<td
className={classes.td}
>{`${project.lastName}, ${project.firstName}`}</td>
<td className={classes.td}>
{new Date(project.dateCreated).toLocaleDateString()}
</td>
<td className={classes.td}>
{new Date(project.dateModified).toLocaleDateString()}
</td>
<td className={classes.td}>
{new Date(project.archivedAt).toLocaleDateString()}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};

export default ProjectsArchive;
Loading

0 comments on commit e48ecb7

Please sign in to comment.