diff --git a/README.md b/README.md index 489f49d..e284246 100644 --- a/README.md +++ b/README.md @@ -1 +1,76 @@ -### SystemsEngineeringToolkit +# SystemsEngineeringToolkit + +## To run (regular way). + +- Download Node.js. +- Set up a Mongo Database (Atlas or Local). + +### Set up and run the server: + +- In cmd inside folder (./server/), run ```npm install```. +- In the config.json add the fields: + { + "db_url": (insert mongo db url), + "server_url": (insert server url), + "key": (insert key, preferably a strong one, this if for encryption of passwords), + "emailInfo": { (this is for forgot password, so preferably an email dedicated to that) + "service": (mail provider like gmail, outlook, hotmail), + "emailUsername": (email), + "emailPassword": (password) + } + } +- run in CMD ```npm start```. + +### Set up and run front end: + +- in cmd inside folder (./frontend/toolkit-webapp/), run: ```npm install```. +- In the config.json add the fields: + "server_url": (server url) +- run in CMD ```npm start```. + +### create an admin user. + +- first create a regular student user on the website by registering. +- once created go to mongo and update the user field roleID to 2 (int). + + + +## To run (docker way). + +- Download and run docker. + +### Server side changes: + +- In the config.json add the fields: + { + "db_url": (insert mongo db url for docker: "mongodb://mongo:27017/se_toolkit"), + "server_url": (insert server url), + "frontend_url": (insert front end url), + "key": (insert key, preferably a strong one, this if for encryption of passwords), + "emailInfo": { (this is for forgot password, so preferably an email dedicated to that) + "service": (mail provider like gmail, outlook, hotmail), + "emailUsername": (email), + "emailPassword": (password) + } + } + + +### Front end side changes: +- In the config.json add the fields: + "server_url": (server url). + +### Docker instructions: + +- on cmd inside folder (./SystemsEngineeringToolkit/). +- run ```docker-compose build``` this is to build the website, once finished continue. +- run ```docker-compose up``` this is to run the website, the front end might take a minute or two. + +### create an admin user: + +- first create a regular student user on the website by registering. +- once created go to the docker command line and run mongo ```mongo```. +- check that se_toolkit db was created by running ```show dbs```. +- select the se_tollkit db by running: ```use se_toolkit```. +- to change the role of the created user run this command: + ```db.users.update({ "email":(insert email of created user surrounded by "") }, { "roleID":2 })```. +- log in again and check if you have the creator and admin functionalities. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4904679 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +version: '3.7' + +services: + client: + image: myapp-frontend + build: ./frontend/toolkit-webapp + stdin_open: true + ports: + - "3000:3000" + networks: + - app-network + command: npm start + volumes: + - ./frontend/toolkit-webapp/:/usr/src/app + - /usr/src/app/node_modules + depends_on: + - server + server: + image: myapp-server + build: ./server + ports: + - "4000:4000" + networks: + - app-network + depends_on: + - mongo + volumes: + - ./server/:/usr/src/app + - /usr/src/app/node_modules + mongo: + image: mongo:4.4-bionic + ports: + - 27017:27017 + networks: + - app-network + volumes: + - mongo-data:/data/db + +networks: + app-network: + driver: bridge + +volumes: + mongo-data: + driver: local \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4ce6127..48e341a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,240 +1,3 @@ { - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@popperjs/core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.1.tgz", - "integrity": "sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==" - }, - "@restart/context": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", - "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==" - }, - "@restart/hooks": { - "version": "0.3.26", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.26.tgz", - "integrity": "sha512-7Hwk2ZMYm+JLWcb7R9qIXk1OoUg1Z+saKWqZXlrvFwT3w6UArVNWgxYOzf+PJoK9zZejp8okPAKTctthhXLt5g==", - "requires": { - "lodash": "^4.17.20", - "lodash-es": "^4.17.20" - } - }, - "@types/classnames": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz", - "integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw==" - }, - "@types/invariant": { - "version": "2.2.34", - "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.34.tgz", - "integrity": "sha512-lYUtmJ9BqUN688fGY1U1HZoWT1/Jrmgigx2loq4ZcJpICECm/Om3V314BxdzypO0u5PORKGMM6x0OXaljV1YFg==" - }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" - }, - "@types/react": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", - "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" - }, - "@types/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=" - }, - "bootstrap": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz", - "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==" - }, - "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" - }, - "csstype": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", - "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" - }, - "dom-helpers": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", - "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "requires": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - } - }, - "react-bootstrap": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.5.2.tgz", - "integrity": "sha512-mGKPY5+lLd7Vtkx2VFivoRkPT4xAHazuFfIhJLTEgHlDfIUSePn7qrmpZe5gXH9zvHV0RsBaQ9cLfXjxnZrOpA==", - "requires": { - "@babel/runtime": "^7.13.8", - "@restart/context": "^2.1.4", - "@restart/hooks": "^0.3.26", - "@types/classnames": "^2.2.10", - "@types/invariant": "^2.2.33", - "@types/prop-types": "^15.7.3", - "@types/react": ">=16.9.35", - "@types/react-transition-group": "^4.4.1", - "@types/warning": "^3.0.0", - "classnames": "^2.2.6", - "dom-helpers": "^5.1.2", - "invariant": "^2.2.4", - "prop-types": "^15.7.2", - "prop-types-extra": "^1.1.0", - "react-overlays": "^5.0.0", - "react-transition-group": "^4.4.1", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "react-overlays": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.0.0.tgz", - "integrity": "sha512-TKbqfAv23TFtCJ2lzISdx76p97G/DP8Rp4TOFdqM9n8GTruVYgE3jX7Zgb8+w7YJ18slTVcDTQ1/tFzdCqjVhA==", - "requires": { - "@babel/runtime": "^7.12.1", - "@popperjs/core": "^2.5.3", - "@restart/hooks": "^0.3.25", - "@types/warning": "^3.0.0", - "dom-helpers": "^5.2.0", - "prop-types": "^15.7.2", - "uncontrollable": "^7.0.0", - "warning": "^4.0.3" - } - }, - "react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "uncontrollable": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", - "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", - "requires": { - "@babel/runtime": "^7.6.3", - "@types/react": ">=16.9.11", - "invariant": "^2.2.4", - "react-lifecycles-compat": "^3.0.4" - } - }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } - } - } + "lockfileVersion": 1 } diff --git a/frontend/toolkit-webapp/.dockerignore b/frontend/toolkit-webapp/.dockerignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/frontend/toolkit-webapp/.dockerignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/frontend/toolkit-webapp/Dockerfile b/frontend/toolkit-webapp/Dockerfile new file mode 100644 index 0000000..0a2cf6a --- /dev/null +++ b/frontend/toolkit-webapp/Dockerfile @@ -0,0 +1,20 @@ +# Dockerfile for React client + +# Build react client +FROM node:14-slim + +# Working directory be app +WORKDIR /usr/src/app + +COPY package*.json ./ + +### Installing dependencies + +RUN npm install --silent + +# copy local files to app folder +COPY . . + +EXPOSE 3000 + +CMD ["npm","start"] \ No newline at end of file diff --git a/frontend/toolkit-webapp/README.md b/frontend/toolkit-webapp/README.md deleted file mode 100644 index 6679798..0000000 --- a/frontend/toolkit-webapp/README.md +++ /dev/null @@ -1,28 +0,0 @@ -### Front End - -### Instructions: - -# Installation -1. Download Node.js. -2. in cmd inside folder, run: - ```npm install``` - -3. Create a JSON file called ```config.json``` inside src folder containing: -{ - "server_url": "http://localhost:4000/api", - "paths": { - "login": "/v0/auth/login", - "registration": "/v0/auth/registration", - "dashboardCourses": "/v0/courses/info", - "course": "/v0/courses/course", - "createCourse": "/v0/courses/create", - "newModule": "/v0/courses/module/create", - "fileUpload": "/v0/upload/single", - "updateCourseInfo": "/v0/courses/course/update", - "sendScore": "/v0/courses/module/score", - "removeCourse": "/v0/courses/removeCourse" - } -} -run in CMD ```npm start```. - - diff --git a/frontend/toolkit-webapp/package-lock.json b/frontend/toolkit-webapp/package-lock.json index 2059a66..74dc39a 100644 --- a/frontend/toolkit-webapp/package-lock.json +++ b/frontend/toolkit-webapp/package-lock.json @@ -15989,7 +15989,8 @@ }, "ssri": { "version": "6.0.1", - "resolved": "", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "requires": { "figgy-pudding": "^3.5.1" } diff --git a/frontend/toolkit-webapp/public/favicon.ico b/frontend/toolkit-webapp/public/favicon.ico deleted file mode 100644 index a11777c..0000000 Binary files a/frontend/toolkit-webapp/public/favicon.ico and /dev/null differ diff --git a/frontend/toolkit-webapp/public/logo192.png b/frontend/toolkit-webapp/public/logo192.png deleted file mode 100644 index fc44b0a..0000000 Binary files a/frontend/toolkit-webapp/public/logo192.png and /dev/null differ diff --git a/frontend/toolkit-webapp/public/logo512.png b/frontend/toolkit-webapp/public/logo512.png deleted file mode 100644 index a4e47a6..0000000 Binary files a/frontend/toolkit-webapp/public/logo512.png and /dev/null differ diff --git a/frontend/toolkit-webapp/src/App.js b/frontend/toolkit-webapp/src/App.js index eb28e3f..d3e6920 100644 --- a/frontend/toolkit-webapp/src/App.js +++ b/frontend/toolkit-webapp/src/App.js @@ -5,12 +5,11 @@ import Registration from './pages/Registration' import ForgotPassword from './pages/ForgotPassword' import ResetPassword from './pages/ResetPassword' import CourseCreatorNewCourse from './pages/CourseCreatorNewCourse' +import EditCourse from './pages/EditCourse' import { BrowserRouter as Router, Route } from 'react-router-dom' import Course from './pages/Course' import ModuleCreator from './pages/ModuleCreator' import ModuleEditor from './pages/ModuleEditor' -// import background from "./img/image0.png"; -import videoSource from "./img/PEOSTRI.mp4" import VideoModule from "./components/VideoModule" import ManageMyCourses from './pages/ManageMyCourses' import MyCourses from './pages/MyCourses' @@ -19,14 +18,14 @@ import AdminDashboard from './pages/AdminDashboard' function App() { return ( - {/* these two lines should have 'Login' not 'Dashboard' */} - {/* should we make like a landing page, or the sanding page is login */} + + diff --git a/frontend/toolkit-webapp/src/components/AdminCategoriesTab.js b/frontend/toolkit-webapp/src/components/AdminCategoriesTab.js index ab18571..8192a3e 100644 --- a/frontend/toolkit-webapp/src/components/AdminCategoriesTab.js +++ b/frontend/toolkit-webapp/src/components/AdminCategoriesTab.js @@ -13,6 +13,8 @@ import Link from '@material-ui/core/Link'; import TextField from '@material-ui/core/TextField'; import InputAdornment from '@material-ui/core/InputAdornment'; import SearchIcon from '@material-ui/icons/Search'; +import dialogStyles from '../styles/dialogStyle' +import DialogComponent from '../components/DialogComponent' const columns = [ { id: '_id', label: 'Id' }, @@ -58,48 +60,59 @@ const useStyles = makeStyles({ const AdminCategoriesTab = (props) => { const classes = useStyles(); + const dialogClasses = dialogStyles() const [categories, setCategories] = useState([]); const [search, setSearch] = useState([]); + const [dialogText, setDialogText] = useState('') + const [openDialog, setOpenDialog] = useState(false); // function that will run when page is loaded useEffect(() => { + const getCategories = async () => { + const token = localStorage.getItem("token"); + + + const res = await fetch(config.server_url + config.paths.getCategories, { + method: 'POST', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify({ "token": token }) + }) + + const data = await res.json() + + if(data.newToken !== undefined) + localStorage.setItem("token", data.newToken) + + if (data.message === "unauthorized") { + props.isUnauthorized() + } else if (data.message === undefined) { + setCategories(data.categories) + } else if (data.message === "wrong token") { + localStorage.removeItem('token'); + props.history.push('login'); + + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() + } else { // this is to check if there are errors not being addressed already + console.log(data) + } + } getCategories() - }, []); - - const getCategories = async () => { - const token = localStorage.getItem("token"); - - // console.log(typeof(new URLSearchParams(window.location.search).get('tab'))) - - const res = await fetch(config.server_url + config.paths.getCategories, { - method: 'POST', - headers: { - 'Content-type': 'application/json' - }, - body: JSON.stringify({ "token": token }) - }) + }, [props]); - const data = await res.json() - - if(data.newToken != undefined) - localStorage.setItem("token", data.newToken) - - if (data.message === "unauthorized") { - props.isUnauthorized() - } else if (data.message === undefined) { - setCategories(data.categories) - } else if (data.message === "wrong token") { - localStorage.removeItem('token'); - props.history.push('login'); - // probably alert the user - } else { // this is to check if there are errors not being addressed already - console.log(data) + const handleOpenDialog = () => { + setOpenDialog(true); + } + const handleCloseDialog = () => { + setOpenDialog(false); } - } + const getSearch = async (query) => { setSearch(query) - // console.log(query) const token = localStorage.getItem("token"); const res = await fetch(config.server_url + config.paths.getCategoriesSearch, { @@ -112,7 +125,7 @@ const AdminCategoriesTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { @@ -122,7 +135,10 @@ const AdminCategoriesTab = (props) => { } else if (data.message === "wrong token") { localStorage.removeItem('token'); props.history.push('login'); - // probably alert the user + + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() } else { // this is to check if there are errors not being addressed already console.log(data) } @@ -141,17 +157,19 @@ const AdminCategoriesTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { props.isUnauthorized() } else if (data.message === undefined) { - // localStorage.setItem("tab", 2); } else if (data.message === "wrong token") { localStorage.removeItem('token'); props.history.push('login'); - // probably alert the user + + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() } else { // this is to check if there are errors not being addressed already console.log(data) } @@ -200,7 +218,6 @@ const AdminCategoriesTab = (props) => { return ( {columns.map((column) => { - const value = row[column.id]; return ( {(column.id === '_id' || @@ -224,6 +241,14 @@ const AdminCategoriesTab = (props) => { + ); } diff --git a/frontend/toolkit-webapp/src/components/AdminCoursesTab.js b/frontend/toolkit-webapp/src/components/AdminCoursesTab.js index deea2a5..296587a 100644 --- a/frontend/toolkit-webapp/src/components/AdminCoursesTab.js +++ b/frontend/toolkit-webapp/src/components/AdminCoursesTab.js @@ -13,6 +13,8 @@ import Link from '@material-ui/core/Link'; import TextField from '@material-ui/core/TextField'; import InputAdornment from '@material-ui/core/InputAdornment'; import SearchIcon from '@material-ui/icons/Search'; +import dialogStyles from '../styles/dialogStyle' +import DialogComponent from '../components/DialogComponent' const columns = [ { id: '_id', label: 'Id' }, @@ -62,47 +64,59 @@ const useStyles = makeStyles({ const AdminCoursesTab = (props) => { const classes = useStyles(); + const dialogClasses = dialogStyles() const [courses, setCourses] = useState([]); const [search, setSearch] = useState([]); + const [dialogText, setDialogText] = useState('') + const [openDialog, setOpenDialog] = useState(false); // function that will run when page is loaded useEffect(() => { + const getCourses = async () => { + const token = localStorage.getItem("token"); + + const res = await fetch(config.server_url + config.paths.getCourses, { + method: 'POST', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify({ "token": token }) + }) + + const data = await res.json() + + if(data.newToken !== undefined) + localStorage.setItem("token", data.newToken) + + if (data.message === "unauthorized") { + props.isUnauthorized() + } else if (data.message === undefined) { + setCourses(data.courses) + } else if (data.message === "wrong token") { + localStorage.removeItem('token'); + props.history.push('login'); + + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() + } else { // this is to check if there are errors not being addressed already + console.log(data) + } + } getCourses() - }, []); - - const getCourses = async () => { - const token = localStorage.getItem("token"); + }, [props]); - const res = await fetch(config.server_url + config.paths.getCourses, { - method: 'POST', - headers: { - 'Content-type': 'application/json' - }, - body: JSON.stringify({ "token": token }) - }) - - const data = await res.json() - - if(data.newToken != undefined) - localStorage.setItem("token", data.newToken) - - if (data.message === "unauthorized") { - props.isUnauthorized() - } else if (data.message === undefined) { - setCourses(data.courses) - } else if (data.message === "wrong token") { - localStorage.removeItem('token'); - props.history.push('login'); - // probably alert the user - } else { // this is to check if there are errors not being addressed already - console.log(data) + const handleOpenDialog = () => { + setOpenDialog(true); } - } + const handleCloseDialog = () => { + setOpenDialog(false); + } + const getSearch = async (query) => { setSearch(query) - // console.log(query) const token = localStorage.getItem("token"); const res = await fetch(config.server_url + config.paths.getCoursesSearch, { @@ -115,7 +129,7 @@ const AdminCoursesTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { @@ -125,7 +139,9 @@ const AdminCoursesTab = (props) => { } else if (data.message === "wrong token") { localStorage.removeItem('token'); props.history.push('login'); - // probably alert the user + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() } else { // this is to check if there are errors not being addressed already console.log(data) } @@ -144,17 +160,18 @@ const AdminCoursesTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { props.isUnauthorized() } else if (data.message === undefined) { - // localStorage.setItem("tab", 1); } else if (data.message === "wrong token") { localStorage.removeItem('token'); props.history.push('login'); - // probably alert the user + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() } else { // this is to check if there are errors not being addressed already console.log(data) } @@ -203,7 +220,6 @@ const AdminCoursesTab = (props) => { return ( {columns.map((column) => { - const value = row[column.id]; return ( {(column.id === '_id' || @@ -218,7 +234,7 @@ const AdminCoursesTab = (props) => { { window.confirm(`Are you sure you wish to Delete user: ${row.name}`) && handleDelete(row._id, row.author) }} + onClick={() => { window.confirm(`Are you sure you wish to Delete the Course: ${row.name}`) && handleDelete(row._id, row.author) }} > @@ -233,6 +249,14 @@ const AdminCoursesTab = (props) => { + ); } diff --git a/frontend/toolkit-webapp/src/components/AdminUsersTab.js b/frontend/toolkit-webapp/src/components/AdminUsersTab.js index b0e1c0e..fa141ef 100644 --- a/frontend/toolkit-webapp/src/components/AdminUsersTab.js +++ b/frontend/toolkit-webapp/src/components/AdminUsersTab.js @@ -16,6 +16,8 @@ import Link from '@material-ui/core/Link'; import TextField from '@material-ui/core/TextField'; import InputAdornment from '@material-ui/core/InputAdornment'; import SearchIcon from '@material-ui/icons/Search'; +import dialogStyles from '../styles/dialogStyle' +import DialogComponent from '../components/DialogComponent' const columns = [ { id: '_id', label: 'Id' }, @@ -59,46 +61,57 @@ const useStyles = makeStyles({ const AdminUsersTab = (props) => { const classes = useStyles(); + const dialogClasses = dialogStyles() const [users, setUsers] = useState([]); const [search, setSearch] = useState([]); + const [dialogText, setDialogText] = useState('') + const [openDialog, setOpenDialog] = useState(false); // function that will run when page is loaded useEffect(() => { + const getUsers = async () => { + const token = localStorage.getItem("token"); + + const res = await fetch(config.server_url + config.paths.getUsers, { + method: 'POST', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify({ "token": token }) + }) + + const data = await res.json() + + if(data.newToken !== undefined) + localStorage.setItem("token", data.newToken) + + if (data.message === "unauthorized") { + props.isUnauthorized() + } else if (data.message === undefined) { + setUsers(data.users) + } else if (data.message === "wrong token") { + localStorage.removeItem('token'); + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() + props.history.push('login'); + } else { // this is to check if there are errors not being addressed already + console.log(data) + } + } getUsers() - }, []); - - const getUsers = async () => { - const token = localStorage.getItem("token"); - - const res = await fetch(config.server_url + config.paths.getUsers, { - method: 'POST', - headers: { - 'Content-type': 'application/json' - }, - body: JSON.stringify({ "token": token }) - }) + }, [props]); - const data = await res.json() - - if(data.newToken != undefined) - localStorage.setItem("token", data.newToken) - - if (data.message === "unauthorized") { - props.isUnauthorized() - } else if (data.message === undefined) { - setUsers(data.users) - } else if (data.message === "wrong token") { - localStorage.removeItem('token'); - props.history.push('login'); - // probably alert the user - } else { // this is to check if there are errors not being addressed already - console.log(data) + const handleOpenDialog = () => { + setOpenDialog(true); + } + const handleCloseDialog = () => { + setOpenDialog(false); } - } + const getSearch = async (query) => { setSearch(query) - // console.log(query) const token = localStorage.getItem("token"); const res = await fetch(config.server_url + config.paths.getUsersSearch, { @@ -111,7 +124,7 @@ const AdminUsersTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { @@ -120,8 +133,10 @@ const AdminUsersTab = (props) => { setUsers(data.users) } else if (data.message === "wrong token") { localStorage.removeItem('token'); + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() props.history.push('login'); - // probably alert the user } else { // this is to check if there are errors not being addressed already console.log(data) } @@ -141,7 +156,7 @@ const AdminUsersTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { @@ -150,8 +165,10 @@ const AdminUsersTab = (props) => { // alert(`Successfully deleted user`) } else if (data.message === "wrong token") { localStorage.removeItem('token'); + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() props.history.push('login'); - // probably alert the user } else { // this is to check if there are errors not being addressed already console.log(data) } @@ -170,15 +187,17 @@ const AdminUsersTab = (props) => { const data = await res.json() - if(data.newToken != undefined) + if(data.newToken !== undefined) localStorage.setItem("token", data.newToken) if (data.message === "unauthorized") { props.isUnauthorized() } else if (data.message === "success") { - // localStorage.setItem("tab", 0); } else if (data.message === "wrong token") { localStorage.removeItem('token'); + // alert the user + setDialogText("Unauthorized access. Please contact your system administrator.") + handleOpenDialog() props.history.push('login'); // probably alert the user } else { // this is to check if there are errors not being addressed already @@ -229,7 +248,6 @@ const AdminUsersTab = (props) => { return ( {columns.map((column) => { - const value = row[column.id]; return ( {(column.id === '_id' || column.id === 'email') && row[column.id]} @@ -269,6 +287,14 @@ const AdminUsersTab = (props) => { + ); } diff --git a/frontend/toolkit-webapp/src/components/DialogComponent.js b/frontend/toolkit-webapp/src/components/DialogComponent.js new file mode 100644 index 0000000..070611b --- /dev/null +++ b/frontend/toolkit-webapp/src/components/DialogComponent.js @@ -0,0 +1,35 @@ +import { Dialog, DialogTitle, DialogContent, Button } from '@material-ui/core' +import dialogStyles from '../styles/dialogStyle' + +export default function DialogComponent(props) { + + const classes = dialogStyles() + + return ( + <> + {props.open === true ? + +
+ +
+ + {props.text} + +
+ + {props.buttons.map((obj) => { + return ( + + ) + })} + +
+
+ + : null} + + ) + +} \ No newline at end of file diff --git a/frontend/toolkit-webapp/src/components/FileCreatorModule.js b/frontend/toolkit-webapp/src/components/FileCreatorModule.js index 1f0487f..7038ccc 100644 --- a/frontend/toolkit-webapp/src/components/FileCreatorModule.js +++ b/frontend/toolkit-webapp/src/components/FileCreatorModule.js @@ -1,12 +1,11 @@ -import React, { useState } from 'react' -import { TextField } from '@material-ui/core' +import React from 'react' const FileCreator = (props) => { return (
props.setFile(e.target.files[0])} />
- ) + ) } export default FileCreator \ No newline at end of file diff --git a/frontend/toolkit-webapp/src/components/FileModule.js b/frontend/toolkit-webapp/src/components/FileModule.js index 2fef1e5..a612cf2 100644 --- a/frontend/toolkit-webapp/src/components/FileModule.js +++ b/frontend/toolkit-webapp/src/components/FileModule.js @@ -6,7 +6,7 @@ const fileStyles = makeStyles((theme) => ({ const FileModule = ({ fileUrl }) => { - const [part, setpart] = useState(fileUrl.split('/')) + const [part] = useState(fileUrl.split('/')) const classes = fileStyles() console.log(fileUrl) diff --git a/frontend/toolkit-webapp/src/components/ModuleInfoEditButton.js b/frontend/toolkit-webapp/src/components/ModuleInfoEditButton.js index 36c851c..d5e586a 100644 --- a/frontend/toolkit-webapp/src/components/ModuleInfoEditButton.js +++ b/frontend/toolkit-webapp/src/components/ModuleInfoEditButton.js @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from 'react' -import { Box, IconButton, makeStyles, Button } from "@material-ui/core"; +import React from 'react' +import { IconButton, makeStyles } from "@material-ui/core"; import CreateIcon from '@material-ui/icons/Create'; import { Link } from 'react-router-dom'; diff --git a/frontend/toolkit-webapp/src/components/PDFCreatorModule.js b/frontend/toolkit-webapp/src/components/PDFCreatorModule.js index 162cd87..7e36daf 100644 --- a/frontend/toolkit-webapp/src/components/PDFCreatorModule.js +++ b/frontend/toolkit-webapp/src/components/PDFCreatorModule.js @@ -1,5 +1,4 @@ -import React, { useState } from 'react' -import { TextField } from '@material-ui/core' +import React from 'react' const PDFCreator = (props) => { return ( diff --git a/frontend/toolkit-webapp/src/components/PdfModule.js b/frontend/toolkit-webapp/src/components/PdfModule.js index 9e51333..6a00eef 100644 --- a/frontend/toolkit-webapp/src/components/PdfModule.js +++ b/frontend/toolkit-webapp/src/components/PdfModule.js @@ -2,7 +2,7 @@ import React from 'react' import { makeStyles } from '@material-ui/core' const pdfStyles = makeStyles((theme) => ({ - div:{ + div: { width: '100%' } })) @@ -14,6 +14,7 @@ const PdfModule = ({ fileUrl }) => { return (