From ef8867658e0d87c48fee0edcecfd7bcf82a1f170 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 24 May 2024 13:44:42 -0700 Subject: [PATCH 01/22] Removed package-lock.json from root --- Server/controllers/monitorController.js | 35 +++++++++++++-------- Server/db/MongoDB.js | 5 +++ Server/index.js | 2 +- Server/middleware/verifyOwnership.js | 41 +++++++++++++++++++++++++ Server/models/user.js | 1 - Server/routes/monitorRoute.js | 14 +++++++-- package-lock.json | 6 ---- 7 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 Server/middleware/verifyOwnership.js delete mode 100644 package-lock.json diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index f004f98f3..b8e2e1ec7 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -5,6 +5,7 @@ const { } = require("../validation/joi"); const logger = require("../utils/logger"); +const SERVICE_NAME = "monitorController"; /** * Returns all monitors @@ -19,7 +20,7 @@ const getAllMonitors = async (req, res) => { const monitors = await req.db.getAllMonitors(); return res.json({ success: true, msg: "Monitors found", data: monitors }); } catch (error) { - logger.error(error.message, { service: "monitor" }); + logger.error(error.message, { service: SERVICE_NAME }); return res.status(500).json({ success: false, msg: error.message }); } }; @@ -42,9 +43,14 @@ const getMonitorById = async (req, res) => { try { const monitor = await req.db.getMonitorById(req, res); + if (!monitor) { + logger.error("Monitor not found", { service: SERVICE_NAME }); + return res.status(404).json({ success: false, msg: "Monitor not found" }); + } + return res.json({ success: true, msg: "Monitor found", data: monitor }); } catch (error) { - logger.error(error.message, { service: "monitor" }); + logger.error(error.message, { service: SERVICE_NAME }); return res.status(500).json({ success: false, msg: error.message }); } }; @@ -68,17 +74,20 @@ const getMonitorsByUserId = async (req, res) => { try { const userId = req.params.userId; const monitors = await req.db.getMonitorsByUserId(req, res); - logger.info(`Monitors for user ${userId} found`, { - service: "monitor", - userId: userId, - }); + + if (monitors && monitors.length === 0) { + return res + .status(404) + .json({ success: false, msg: "No monitors not found" }); + } + return res.json({ success: true, msg: `Monitors for user ${userId} found`, data: monitors, }); } catch (error) { - logger.error(error.message, { service: "monitor" }); + logger.error(error.message, { service: SERVICE_NAME }); return res.status(500).json({ success: false, msg: error.message }); } }; @@ -106,7 +115,7 @@ const createMonitor = async (req, res) => { .status(201) .json({ success: true, msg: "Monitor created", data: monitor }); } catch (error) { - logger.error(error.message, { service: "monitor" }); + logger.error(error.message, { service: SERVICE_NAME }); return res.status(500).json({ success: false, msg: error.message }); } }; @@ -137,7 +146,7 @@ const deleteMonitor = async (req, res) => { */ return res.status(200).json({ success: true, msg: "Monitor deleted" }); } catch (error) { - logger.error(error.message, { service: "monitor" }); + logger.error(error.message, { service: SERVICE_NAME }); return res.status(500).json({ success: false, msg: error.message }); } }; @@ -150,9 +159,9 @@ const deleteMonitor = async (req, res) => { * @returns {Promise} * @throws {Error} */ -const editMonitor = async (req, res) => { - let paramError = getMonitorByIdValidation.validate(req.params); - if (paramError.error) { +const editMonitor = async (req, res, next) => { + let { paramError } = getMonitorByIdValidation.validate(req.params); + if (paramError) { return res .status(422) .json({ success: false, msg: paramError.error.details[0].message }); @@ -171,7 +180,7 @@ const editMonitor = async (req, res) => { .status(200) .json({ success: true, msg: "Monitor edited", data: editedMonitor }); } catch (error) { - logger.error(error.message, { service: "monitor" }); + logger.error(error.message, { service: SERVICE_NAME }); return res.status(500).json({ success: false, msg: error.message }); } }; diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index 8fcc1dced..44b734954 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -2,6 +2,10 @@ const Monitor = require("../models/Monitor"); const mongoose = require("mongoose"); const UserModel = require("../models/user"); +const verifyId = (userId, monitorId) => { + return userId.toString() === monitorId.toString(); +}; + const connect = async () => { try { await mongoose.connect(process.env.DB_CONNECTION_STRING); @@ -113,6 +117,7 @@ const getMonitorsByUserId = async (req, res) => { const createMonitor = async (req, res) => { try { const monitor = new Monitor({ ...req.body }); + monitor.userId = req.user._id; await monitor.save(); return monitor; } catch (error) { diff --git a/Server/index.js b/Server/index.js index 5068c98d8..11e2b5b5b 100644 --- a/Server/index.js +++ b/Server/index.js @@ -6,7 +6,7 @@ const monitorRouter = require("./routes/monitorRoute"); const { connectDbAndRunServer } = require("./configs/db"); require("dotenv").config(); const logger = require("./utils/logger"); -var { verifyJWT } = require("./middleware/verifyJWT"); +const { verifyJWT } = require("./middleware/verifyJWT"); // const { sendEmail } = require('./utils/sendEmail') diff --git a/Server/middleware/verifyOwnership.js b/Server/middleware/verifyOwnership.js new file mode 100644 index 000000000..1b496fbce --- /dev/null +++ b/Server/middleware/verifyOwnership.js @@ -0,0 +1,41 @@ +const logger = require("../utils/logger"); +const SERVICE_NAME = "verifyOwnership"; + +const verifyOwnership = (Model, paramName) => { + return async (req, res, next) => { + const userId = req.user._id; + const documentId = req.params[paramName]; + try { + const doc = await Model.findById(documentId); + //If the document is not found, return a 404 error + if (!doc) { + logger.error("Document not found", { + service: SERVICE_NAME, + }); + return res + .status(404) + .json({ success: false, msg: "Document not found" }); + } + + // If the userID does not match the document's userID, return a 403 error + if (userId.toString() !== doc.userId.toString()) { + logger.error("Unauthorized access", { + service: SERVICE_NAME, + }); + + return res.status(403).json({ + success: false, + msg: "You are not authorized to perform this action", + }); + } + next(); + } catch (error) { + logger.error(error.message, { + service: SERVICE_NAME, + }); + return res.status(500).json({ success: false, msg: error.message }); + } + }; +}; + +module.exports = { verifyOwnership }; diff --git a/Server/models/user.js b/Server/models/user.js index 02d0d53b3..d90b484bb 100644 --- a/Server/models/user.js +++ b/Server/models/user.js @@ -50,7 +50,6 @@ UserSchema.pre("save", async function (next) { }); UserSchema.methods.comparePassword = function (submittedPassword) { - console.log(submittedPassword, this.password); return bcrypt.compare(submittedPassword, this.password); }; diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index 5f2ce4bb5..ffdce1d4d 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -1,11 +1,21 @@ const router = require("express").Router(); const monitorController = require("../controllers/monitorController"); +const { verifyOwnership } = require("../middleware/verifyOwnership"); +const Monitor = require("../models/Monitor"); router.get("/", monitorController.getAllMonitors); router.get("/:monitorId", monitorController.getMonitorById); router.get("/user/:userId", monitorController.getMonitorsByUserId); router.post("/", monitorController.createMonitor); -router.post("/delete/:monitorId", monitorController.deleteMonitor); -router.post("/edit/:monitorId", monitorController.editMonitor); +router.post( + "/delete/:monitorId", + verifyOwnership(Monitor, "monitorId"), + monitorController.deleteMonitor +); +router.post( + "/edit/:monitorId", + verifyOwnership(Monitor, "monitorId"), + monitorController.editMonitor +); module.exports = router; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index f71a78c1f..000000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "bluewave-uptime", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} From 75e007142fd112d431eeff618792a1cd19a0b60e Mon Sep 17 00:00:00 2001 From: Alvaro Torres <79110517+alvarotorrestx@users.noreply.github.com> Date: Sat, 25 May 2024 13:56:19 -0500 Subject: [PATCH 02/22] Add Server endpoints to ToC in README --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 44a30ea94..610f21f8e 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,14 @@ BlueWave uptime monitoring application 1. [Installation (Server)](#server) 1. [Configuration(Server)](#config-server) 1. [Endpoints](#endpoints) + - POST [/api/v1/auth/register](#post-register) + - POST [/api/v1/auth/login](#post-login) + - GET [/api/v1/monitors](#get-monitors) + - GET [/api/v1/monitor/{id}](#get-monitor-id) + - GET [/api/v1/monitors/user/{userId}](#get-monitors-user-userid) + - POST [/api/v1/monitors](#post-monitors) + - POST [/api/v1/monitors/delete/{monitorId}](#post-monitors-del-id) + - POST [/api/v1/monitors/edit/{monitorId}](#post-monitors-edit-id) --- @@ -111,7 +119,7 @@ Example: ---
-POST /api/v1/auth/register +POST /api/v1/auth/register ##### Method/Headers @@ -164,7 +172,7 @@ curl --request POST \ ---
-POST /api/v1/auth/login +POST /api/v1/auth/login ##### Method/Headers @@ -213,7 +221,7 @@ curl --request POST \ ---
-GET /api/v1/monitors +GET /api/v1/monitors ##### Method/Headers @@ -275,7 +283,7 @@ curl --request GET \ ---
-GET /api/v1/monitor/{id} +GET /api/v1/monitor/{id} ###### Method/Headers @@ -323,7 +331,7 @@ curl --request GET \ ---
-GET /api/v1/monitors/user/{userId} +GET /api/v1/monitors/user/{userId} ###### Method/Headers @@ -385,7 +393,7 @@ curl --request GET \ ---
-POST/api/v1/monitors +POST/api/v1/monitors ###### Method/Headers @@ -440,7 +448,7 @@ curl --request POST \ ---
-POST/api/v1/monitors/delete/{monitorId} +POST/api/v1/monitors/delete/{monitorId} ###### Method/Headers @@ -477,7 +485,7 @@ curl --request POST \ ---
-POST/api/v1/monitors/edit/{monitorId} +POST/api/v1/monitors/edit/{monitorId} ###### Method/Headers From 54f7f2d4048a7ceae9737b8ab43f27b6dd6a24ee Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 25 May 2024 20:14:06 -0700 Subject: [PATCH 03/22] Added missing details tag, contributors was hidden under the last endpoint --- README.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 610f21f8e..c7dc928f1 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,18 @@ BlueWave uptime monitoring application - Clone this repository to your local machine 1. [Installation (Client)](#client) -1. [Installation (Server)](#server) -1. [Configuration(Server)](#config-server) -1. [Endpoints](#endpoints) - - POST [/api/v1/auth/register](#post-register) - - POST [/api/v1/auth/login](#post-login) - - GET [/api/v1/monitors](#get-monitors) - - GET [/api/v1/monitor/{id}](#get-monitor-id) - - GET [/api/v1/monitors/user/{userId}](#get-monitors-user-userid) - - POST [/api/v1/monitors](#post-monitors) - - POST [/api/v1/monitors/delete/{monitorId}](#post-monitors-del-id) - - POST [/api/v1/monitors/edit/{monitorId}](#post-monitors-edit-id) +2. [Installation (Server)](#server) +3. [Configuration(Server)](#config-server) +4. [Endpoints](#endpoints) + - POST [/api/v1/auth/register](#post-register) + - POST [/api/v1/auth/login](#post-login) + - GET [/api/v1/monitors](#get-monitors) + - GET [/api/v1/monitor/{id}](#get-monitor-id) + - GET [/api/v1/monitors/user/{userId}](#get-monitors-user-userid) + - POST [/api/v1/monitors](#post-monitors) + - POST [/api/v1/monitors/delete/{monitorId}](#post-monitors-del-id) + - POST [/api/v1/monitors/edit/{monitorId}](#post-monitors-edit-id) +5. [Contributors](#contributors) --- @@ -539,6 +540,8 @@ curl --request POST \ } ``` +
+ ## Contributors From 3cb63919f014c57571765a739ec5f3e647d930f1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Sat, 25 May 2024 20:14:24 -0700 Subject: [PATCH 04/22] Added divider --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c7dc928f1..5440f0e7d 100644 --- a/README.md +++ b/README.md @@ -542,6 +542,8 @@ curl --request POST \
+--- + ## Contributors From 54220a6125f469e78cc21f8d31d9604aad3eeeb3 Mon Sep 17 00:00:00 2001 From: M M Date: Sat, 25 May 2024 21:35:37 -0700 Subject: [PATCH 05/22] Implemented the dashboard progress bars. --- Client/package-lock.json | 230 ++++++++++++++++++ Client/package.json | 1 + .../DashboardProgressBars/index.css | 0 .../DashboardProgressBars/index.jsx | 19 ++ Client/src/Layouts/HomeLayout/index.jsx | 4 +- 5 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 Client/src/Components/DashboardProgressBars/index.css create mode 100644 Client/src/Components/DashboardProgressBars/index.jsx diff --git a/Client/package-lock.json b/Client/package-lock.json index fe3d684f5..e4a8fd7a8 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -13,6 +13,7 @@ "@fontsource/roboto": "^5.0.13", "@mui/icons-material": "^5.15.17", "@mui/material": "^5.15.16", + "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.3.2", "@mui/x-date-pickers": "7.3.2", "dayjs": "1.11.11", @@ -989,6 +990,44 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, + "node_modules/@mui/x-charts": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.5.1.tgz", + "integrity": "sha512-8vMQyJL13cGXMbp+gm2QdABzFuOpP4hxEa/o6nL3ZpVNp7hja6h9F5bc0FNGR8h/eRN+4+swDnrEebnR0w4cbA==", + "dependencies": { + "@babel/runtime": "^7.24.5", + "@mui/base": "^5.0.0-beta.40", + "@mui/system": "^5.15.14", + "@mui/utils": "^5.15.14", + "@react-spring/rafz": "^9.7.3", + "@react-spring/web": "^9.7.3", + "clsx": "^2.1.1", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, "node_modules/@mui/x-data-grid": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.3.2.tgz", @@ -1123,6 +1162,71 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-spring/animated": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", + "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "dependencies": { + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", + "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.3.tgz", + "integrity": "sha512-9vzW1zJPcC4nS3aCV+GgcsK/WLaB520Iyvm55ARHfM5AuyBqycjvh1wbmWmgCyJuX4VPoWigzemq1CaaeRSHhQ==" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", + "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "dependencies": { + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", + "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.3", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", + "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "dependencies": { + "@react-spring/animated": "~9.7.3", + "@react-spring/core": "~9.7.3", + "@react-spring/shared": "~9.7.3", + "@react-spring/types": "~9.7.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@remix-run/router": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", @@ -1674,6 +1778,111 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -1787,6 +1996,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2739,6 +2956,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -3805,6 +4030,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/rollup": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", diff --git a/Client/package.json b/Client/package.json index cca88fb31..213119f38 100644 --- a/Client/package.json +++ b/Client/package.json @@ -15,6 +15,7 @@ "@fontsource/roboto": "^5.0.13", "@mui/icons-material": "^5.15.17", "@mui/material": "^5.15.16", + "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.3.2", "@mui/x-date-pickers": "7.3.2", "dayjs": "1.11.11", diff --git a/Client/src/Components/DashboardProgressBars/index.css b/Client/src/Components/DashboardProgressBars/index.css new file mode 100644 index 000000000..e69de29bb diff --git a/Client/src/Components/DashboardProgressBars/index.jsx b/Client/src/Components/DashboardProgressBars/index.jsx new file mode 100644 index 000000000..8215a0d17 --- /dev/null +++ b/Client/src/Components/DashboardProgressBars/index.jsx @@ -0,0 +1,19 @@ +import { BarChart } from '@mui/x-charts/BarChart'; + +const ChartsOverviewDemo = () => { + return ( + + ); +}; + +export default ChartsOverviewDemo; diff --git a/Client/src/Layouts/HomeLayout/index.jsx b/Client/src/Layouts/HomeLayout/index.jsx index 454f1452a..bb37d4768 100644 --- a/Client/src/Layouts/HomeLayout/index.jsx +++ b/Client/src/Layouts/HomeLayout/index.jsx @@ -1,8 +1,9 @@ -import React from 'react' import NavBar from '../../Components/NavBar' import { Outlet } from 'react-router' import Home from '../../Pages/Home' import './index.css' +import ChartsOverviewDemo from '../../Components/DashboardProgressBars' + const HomeLayout = () => { return ( @@ -10,6 +11,7 @@ const HomeLayout = () => { + ) } From 950222f94ec791bf144b5e38c5de53e046477b7d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 10:47:14 -0700 Subject: [PATCH 06/22] Implemented error handling middleware --- Server/controllers/authController.js | 35 ++++---- Server/controllers/monitorController.js | 110 +++++++++++++----------- Server/index.js | 7 ++ Server/middleware/handleErrors.js | 9 ++ Server/middleware/verifyJWT.js | 14 +-- Server/middleware/verifyOwnership.js | 23 ++--- 6 files changed, 106 insertions(+), 92 deletions(-) create mode 100644 Server/middleware/handleErrors.js diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 1285726e1..a3a43ba0d 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -21,35 +21,32 @@ const issueToken = (payload) => { * @param {express.Response} res * @returns {{success: Boolean, msg: String}} */ -const registerController = async (req, res) => { +const registerController = async (req, res, next) => { // joi validation try { await registerValidation.validateAsync(req.body); } catch (error) { - return res - .status(400) - .json({ success: false, msg: error.details[0].message }); + error.status = 400; + error.service = SERVICE_NAME; + error.message = error.details[0].message; + next(error); + return; } // Check if the user exists try { const isUser = await req.db.getUserByEmail(req, res); if (isUser) { - logger.error("User already exists", { - service: SERVICE_NAME, - userId: isUser._id, - }); - return res - .status(400) - .json({ success: false, msg: "User already exists" }); + throw new Error("User already exists"); } } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); + return; } + // Create a new user try { - // Create a new user const newUser = await req.db.insertUser(req, res); // TODO: Send an email to user // Will add this later @@ -63,8 +60,8 @@ const registerController = async (req, res) => { .status(200) .json({ success: true, msg: "User created", data: token }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; @@ -76,7 +73,7 @@ const registerController = async (req, res) => { * @returns {Promise} * @throws {Error} */ -const loginController = async (req, res) => { +const loginController = async (req, res, next) => { try { // Validate input await loginValidation.validateAsync(req.body); @@ -104,9 +101,9 @@ const loginController = async (req, res) => { .status(200) .json({ success: true, msg: "Found user", data: token }); } catch (error) { + error.status = 500; // Anything else should be an error - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + next(error); } }; diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index b8e2e1ec7..250dc55b8 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -4,7 +4,6 @@ const { monitorValidation, } = require("../validation/joi"); -const logger = require("../utils/logger"); const SERVICE_NAME = "monitorController"; /** @@ -15,13 +14,13 @@ const SERVICE_NAME = "monitorController"; * @returns {Promise} * @throws {Error} */ -const getAllMonitors = async (req, res) => { +const getAllMonitors = async (req, res, next) => { try { const monitors = await req.db.getAllMonitors(); return res.json({ success: true, msg: "Monitors found", data: monitors }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; @@ -33,25 +32,28 @@ const getAllMonitors = async (req, res) => { * @returns {Promise} * @throws {Error} */ -const getMonitorById = async (req, res) => { - const { error } = getMonitorByIdValidation.validate(req.params); - if (error) { - return res - .status(422) - .json({ success: false, msg: error.details[0].message }); +const getMonitorById = async (req, res, next) => { + try { + await getMonitorByIdValidation.validateAsync(req.params); + } catch (error) { + error.status = 422; + error.message = error.details[0].message; + next(error); + return; } try { const monitor = await req.db.getMonitorById(req, res); if (!monitor) { - logger.error("Monitor not found", { service: SERVICE_NAME }); - return res.status(404).json({ success: false, msg: "Monitor not found" }); + const error = new Error("Monitor not found"); + error.status = 404; + throw error; } return res.json({ success: true, msg: "Monitor found", data: monitor }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; @@ -63,7 +65,7 @@ const getMonitorById = async (req, res) => { * @returns {Promise} * @throws {Error} */ -const getMonitorsByUserId = async (req, res) => { +const getMonitorsByUserId = async (req, res, next) => { const { error } = getMonitorsByUserIdValidation.validate(req.params); if (error) { return res @@ -76,9 +78,9 @@ const getMonitorsByUserId = async (req, res) => { const monitors = await req.db.getMonitorsByUserId(req, res); if (monitors && monitors.length === 0) { - return res - .status(404) - .json({ success: false, msg: "No monitors not found" }); + const err = new Error("No monitors found"); + err.status = 404; + throw err; } return res.json({ @@ -87,8 +89,8 @@ const getMonitorsByUserId = async (req, res) => { data: monitors, }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; @@ -101,12 +103,15 @@ const getMonitorsByUserId = async (req, res) => { * @throws {Error} */ -const createMonitor = async (req, res) => { - const { error } = monitorValidation.validate(req.body); - if (error) { - return res - .status(422) - .json({ success: false, msg: error.details[0].message }); +const createMonitor = async (req, res, next) => { + try { + await monitorValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details[0].message; + next(error); + return; } try { @@ -115,8 +120,8 @@ const createMonitor = async (req, res) => { .status(201) .json({ success: true, msg: "Monitor created", data: monitor }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; @@ -129,15 +134,19 @@ const createMonitor = async (req, res) => { * @throws {Error} */ -const deleteMonitor = async (req, res) => { - const { error } = getMonitorByIdValidation.validate(req.params); - if (error) { - return res - .status(422) - .json({ success: false, msg: error.details[0].message }); - } +const deleteMonitor = async (req, res, next) => { try { - const monitor = await req.db.deleteMonitor(req, res); + await getMonitorByIdValidation.validateAsync(req.params); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details[0].message; + next(error); + return; + } + + try { + const monitor = await req.db.deleteMonitor(req, res, next); /** * TODO * We should remove all checks and alerts associated with this monitor @@ -146,8 +155,8 @@ const deleteMonitor = async (req, res) => { */ return res.status(200).json({ success: true, msg: "Monitor deleted" }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; @@ -160,18 +169,15 @@ const deleteMonitor = async (req, res) => { * @throws {Error} */ const editMonitor = async (req, res, next) => { - let { paramError } = getMonitorByIdValidation.validate(req.params); - if (paramError) { - return res - .status(422) - .json({ success: false, msg: paramError.error.details[0].message }); - } - - let { error } = monitorValidation.validate(req.body); - if (error) { - return res - .status(422) - .json({ success: false, msg: error.details[0].message }); + try { + await getMonitorByIdValidation.validateAsync(req.params); + await monitorValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details[0].message; + next(error); + return; } try { @@ -180,8 +186,8 @@ const editMonitor = async (req, res, next) => { .status(200) .json({ success: true, msg: "Monitor edited", data: editedMonitor }); } catch (error) { - logger.error(error.message, { service: SERVICE_NAME }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; diff --git a/Server/index.js b/Server/index.js index 11e2b5b5b..db3be459c 100644 --- a/Server/index.js +++ b/Server/index.js @@ -7,6 +7,7 @@ const { connectDbAndRunServer } = require("./configs/db"); require("dotenv").config(); const logger = require("./utils/logger"); const { verifyJWT } = require("./middleware/verifyJWT"); +const { handleErrors } = require("./middleware/handleErrors"); // const { sendEmail } = require('./utils/sendEmail') @@ -62,6 +63,12 @@ app.use((req, res, next) => { app.use("/api/v1/auth", authRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); +/** + * Error handler middleware + * MUST be called after all routes + */ +app.use(handleErrors); + // Testing email service // app.use('/sendEmail', async (req, res) => { // const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '

Testing Bluewavelabs

'); diff --git a/Server/middleware/handleErrors.js b/Server/middleware/handleErrors.js new file mode 100644 index 000000000..2febc6b31 --- /dev/null +++ b/Server/middleware/handleErrors.js @@ -0,0 +1,9 @@ +const logger = require("../utils/logger"); + +const handleErrors = (error, req, res, next) => { + error.status = error.status ? error.status : 500; + logger.error(error.message, { service: error.service }); + res.status(error.status).json({ success: false, msg: error.message }); +}; + +module.exports = { handleErrors }; diff --git a/Server/middleware/verifyJWT.js b/Server/middleware/verifyJWT.js index 53464c606..2e8895623 100644 --- a/Server/middleware/verifyJWT.js +++ b/Server/middleware/verifyJWT.js @@ -15,8 +15,11 @@ const verifyJWT = (req, res, next) => { const token = req.headers["authorization"]; // Make sure a token is provided if (!token) { - logger.error("No token provided", { service: SERVICE_NAME }); - return res.status(401).json({ success: false, msg: "No token provided" }); + const error = new Error("No token provided"); + error.status = 401; + error.service = SERVICE_NAME; + next(error); + return; } // Make sure it is properly formatted if (token.startsWith(TOKEN_PREFIX)) { @@ -32,10 +35,9 @@ const verifyJWT = (req, res, next) => { next(); }); } else { - logger.error("Invalid token format", { service: SERVICE_NAME }); - return res - .status(400) - .json({ success: false, msg: "Invalid token format" }); + error.status = 400; + error.service = SERVICE_NAME; + next(error); } }; diff --git a/Server/middleware/verifyOwnership.js b/Server/middleware/verifyOwnership.js index 1b496fbce..00f7b0787 100644 --- a/Server/middleware/verifyOwnership.js +++ b/Server/middleware/verifyOwnership.js @@ -12,28 +12,21 @@ const verifyOwnership = (Model, paramName) => { logger.error("Document not found", { service: SERVICE_NAME, }); - return res - .status(404) - .json({ success: false, msg: "Document not found" }); + const error = new Error("Document not found"); + error.status = 404; + throw error; } // If the userID does not match the document's userID, return a 403 error if (userId.toString() !== doc.userId.toString()) { - logger.error("Unauthorized access", { - service: SERVICE_NAME, - }); - - return res.status(403).json({ - success: false, - msg: "You are not authorized to perform this action", - }); + const error = new Error("Unauthorized access"); + error.status = 403; + throw error; } next(); } catch (error) { - logger.error(error.message, { - service: SERVICE_NAME, - }); - return res.status(500).json({ success: false, msg: error.message }); + error.service = SERVICE_NAME; + next(error); } }; }; From 5fa73a1f17f34af26b93c2b232e2c2cf386a04b5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 11:03:12 -0700 Subject: [PATCH 07/22] Added documentation for error handling --- README.md | 37 ++++++++++++++++++++++++++++++- Server/middleware/handleErrors.js | 9 +++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5440f0e7d..a8e1b1f32 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ BlueWave uptime monitoring application - POST [/api/v1/monitors](#post-monitors) - POST [/api/v1/monitors/delete/{monitorId}](#post-monitors-del-id) - POST [/api/v1/monitors/edit/{monitorId}](#post-monitors-edit-id) -5. [Contributors](#contributors) +5. [Error Handling](#error-handling) +6. [Contributors](#contributors) --- @@ -544,6 +545,40 @@ curl --request POST \ --- +### Error handling {#error-handling} + +Errors are returned in a standard format: + +`{"success": false, "msg": "No token provided"}` + +Errors are handled by error handling middleware and should be thrown with the following parameters + +| Name | Type | Default | Notes | +| ------- | --------- | ---------------------- | ------------------------------------ | +| status | `integer` | 500 | Standard HTTP codes | +| message | `string` | "Something went wrong" | An error message | +| service | `string` | "Unknown Service" | Name of service that threw the error | + +Example: + +``` +const myRoute = async(req, res, next) => { + try{ + const result = myRiskyOperationHere(); + } + catch(error){ + error.status = 404 + error.message = "Resource not found" + error.service = service name + next(error) + return; + } +} + +``` + +Errors should not be handled at the controller level and should be left to the middleware to handle. + ## Contributors
diff --git a/Server/middleware/handleErrors.js b/Server/middleware/handleErrors.js index 2febc6b31..78764c1e1 100644 --- a/Server/middleware/handleErrors.js +++ b/Server/middleware/handleErrors.js @@ -1,9 +1,12 @@ const logger = require("../utils/logger"); const handleErrors = (error, req, res, next) => { - error.status = error.status ? error.status : 500; - logger.error(error.message, { service: error.service }); - res.status(error.status).json({ success: false, msg: error.message }); + const status = error.status || 500; + const message = error.message || "Something went wrong"; + const service = error.errorService || "Unknown service"; + + logger.error(error.message, { service: service }); + res.status(status).json({ success: false, msg: message }); }; module.exports = { handleErrors }; From d84a0f9c87276c5d5376a3610663a1f793a583b7 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 11:57:25 -0700 Subject: [PATCH 08/22] Started update user route --- Server/controllers/authController.js | 42 +++++++++++++++- Server/db/MongoDB.js | 26 ++++++++++ Server/index.js | 12 ++--- Server/middleware/verifyOwnership.js | 1 + Server/models/user.js | 71 +++++++++++++--------------- Server/routes/authRoute.js | 6 +++ Server/validation/joi.js | 13 ++++- 7 files changed, 125 insertions(+), 46 deletions(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index a3a43ba0d..3d3dde796 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -1,5 +1,10 @@ const express = require("express"); -const { registerValidation, loginValidation } = require("../validation/joi"); +const { + registerValidation, + loginValidation, + editUserParamValidation, + editUserBodyValidation, +} = require("../validation/joi"); const logger = require("../utils/logger"); require("dotenv").config(); var jwt = require("jsonwebtoken"); @@ -107,4 +112,37 @@ const loginController = async (req, res, next) => { } }; -module.exports = { registerController, loginController }; +const userEditController = async (req, res, next) => { + try { + await editUserParamValidation.validateAsync(req.params); + await editUserBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.service = SERVICE_NAME; + error.message = error.details[0].message; + next(error); + return; + } + + if (req.params.userId !== req.user._id.toString()) { + const error = new Error("Unauthorized access"); + error.status = 401; + error.service = SERVICE_NAME; + next(error); + return; + } + + //Find and update user + try { + const updatedUser = await req.db.updateUser(req, res); + res + .status(200) + .json({ success: true, msg: "User updated", data: updatedUser }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + return; + } +}; + +module.exports = { registerController, loginController, userEditController }; diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index 44b734954..a2e45f5d6 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -55,6 +55,31 @@ const getUserByEmail = async (req, res) => { } }; +/** + * Update a user by ID + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {Promise} + * @throws {Error} + */ + +const updateUser = async (req, res) => { + const candidateUserId = req.params.userId; + const candidateUser = req.body; + + try { + const updatedUser = await user.findByIdAndUpdate( + candidateUserId, + candidateUser, + { new: true } // Returns updated user instead of pre-update user + ); + return updatedUser; + } catch (error) { + throw error; + } +}; + /** * Get all monitors * @async @@ -173,6 +198,7 @@ module.exports = { connect, insertUser, getUserByEmail, + updateUser, getAllMonitors, getMonitorById, getMonitorsByUserId, diff --git a/Server/index.js b/Server/index.js index db3be459c..63d919b8d 100644 --- a/Server/index.js +++ b/Server/index.js @@ -63,12 +63,6 @@ app.use((req, res, next) => { app.use("/api/v1/auth", authRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); -/** - * Error handler middleware - * MUST be called after all routes - */ -app.use(handleErrors); - // Testing email service // app.use('/sendEmail', async (req, res) => { // const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '

Testing Bluewavelabs

'); @@ -86,4 +80,10 @@ app.use("/api/v1/healthy", (req, res) => { } }); +/** + * Error handler middleware + * Should be called last + */ +app.use(handleErrors); + connectDbAndRunServer(app, db); diff --git a/Server/middleware/verifyOwnership.js b/Server/middleware/verifyOwnership.js index 00f7b0787..409303fa4 100644 --- a/Server/middleware/verifyOwnership.js +++ b/Server/middleware/verifyOwnership.js @@ -19,6 +19,7 @@ const verifyOwnership = (Model, paramName) => { // If the userID does not match the document's userID, return a 403 error if (userId.toString() !== doc.userId.toString()) { + console.log("boom"); const error = new Error("Unauthorized access"); error.status = 403; throw error; diff --git a/Server/models/user.js b/Server/models/user.js index d90b484bb..7f3945354 100644 --- a/Server/models/user.js +++ b/Server/models/user.js @@ -1,44 +1,41 @@ const mongoose = require("mongoose"); const bcrypt = require("bcrypt"); -const UserSchema = mongoose.Schema({ - firstname: { - type: String, - required: true, +const UserSchema = mongoose.Schema( + { + firstname: { + type: String, + required: true, + }, + lastname: { + type: String, + required: true, + }, + email: { + type: String, + required: true, + unique: true, + }, + password: { + type: String, + required: true, + }, + profilePicUrl: { + type: String, + }, + isActive: { + type: Boolean, + default: true, + }, + isVerified: { + type: Boolean, + default: false, + }, }, - lastname: { - type: String, - required: true, - }, - email: { - type: String, - required: true, - unique: true, - }, - password: { - type: String, - required: true, - }, - profilePicUrl: { - type: String, - }, - isActive: { - type: Boolean, - default: true, - }, - isVerified: { - type: Boolean, - default: false, - }, - updated_at: { - type: Date, - default: Date.now, - }, - created_at: { - type: Date, - default: Date.now, - }, -}); + { + timestamps: true, + } +); UserSchema.pre("save", async function (next) { if (!this.isModified("password")) { diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 48a173b92..94f0ce5cc 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -1,10 +1,16 @@ const router = require("express").Router(); +const user = require("../models/user"); +const { verifyJWT } = require("../middleware/verifyJWT"); +const { verifyOwnership } = require("../middleware/verifyOwnership"); + const { registerController, loginController, + userEditController, } = require("../controllers/authController"); router.post("/register", registerController); router.post("/login", loginController); +router.post("/user/:userId", verifyJWT, userEditController); module.exports = router; diff --git a/Server/validation/joi.js b/Server/validation/joi.js index ecc19253e..399c243dc 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -1,5 +1,4 @@ const joi = require("joi"); -const user = require("../models/user"); const loginValidation = joi.object({ email: joi.string().email().required(), @@ -30,10 +29,22 @@ const monitorValidation = joi.object({ interval: joi.number(), }); +const editUserParamValidation = joi.object({ + userId: joi.string().required(), +}); + +const editUserBodyValidation = joi.object({ + firstname: joi.string(), + lastname: joi.string(), + profilePicUrl: joi.string(), +}); + module.exports = { loginValidation, registerValidation, getMonitorByIdValidation, getMonitorsByUserIdValidation, monitorValidation, + editUserParamValidation, + editUserBodyValidation, }; From 78abdd7f704cf405d825e7b845da88e0a9304dbd Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 12:03:32 -0700 Subject: [PATCH 09/22] Fixed bug in error handler, finished implementing update user endpoint --- Server/controllers/authController.js | 1 - Server/db/MongoDB.js | 2 +- Server/middleware/handleErrors.js | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 3d3dde796..cc476ab54 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -132,7 +132,6 @@ const userEditController = async (req, res, next) => { return; } - //Find and update user try { const updatedUser = await req.db.updateUser(req, res); res diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index a2e45f5d6..b3b269600 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -69,7 +69,7 @@ const updateUser = async (req, res) => { const candidateUser = req.body; try { - const updatedUser = await user.findByIdAndUpdate( + const updatedUser = await UserModel.findByIdAndUpdate( candidateUserId, candidateUser, { new: true } // Returns updated user instead of pre-update user diff --git a/Server/middleware/handleErrors.js b/Server/middleware/handleErrors.js index 78764c1e1..a20db8571 100644 --- a/Server/middleware/handleErrors.js +++ b/Server/middleware/handleErrors.js @@ -3,7 +3,7 @@ const logger = require("../utils/logger"); const handleErrors = (error, req, res, next) => { const status = error.status || 500; const message = error.message || "Something went wrong"; - const service = error.errorService || "Unknown service"; + const service = error.service || "Unknown service"; logger.error(error.message, { service: service }); res.status(status).json({ success: false, msg: message }); From 36936266acf35392dc737a42bcb71ba44e1b9993 Mon Sep 17 00:00:00 2001 From: veyselboybay Date: Mon, 27 May 2024 15:07:34 -0400 Subject: [PATCH 10/22] Added Check and Alert models and updated ReadMe --- README.md | 29 +++++++++++++++++++++++++++++ Server/models/Alert.js | 28 ++++++++++++++++++++++++++++ Server/models/Check.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 Server/models/Alert.js create mode 100644 Server/models/Check.js diff --git a/README.md b/README.md index a8e1b1f32..039750dc1 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,35 @@ Example:
+
+Check + +| Name | Type | Notes | +| ----------- | --------- | ------------------------------------------------| +| monitorId | `string` | Unique ID for the monitor | +| status | `boolean` | Indicates the service is Up or Down | +| responseTime| `integer` | Indicates the response time of the service (ms) | +| statusCode | `integer` | Status Code returned from the service | +| message | `string` | Message returned from the service | +| updatedAt | `Date` | Last time the check was updated | +| CreatedAt | `Date` | When the check was created | + +
+ +
+Alert + +| Name | Type | Notes | +| ----------- | --------- | --------------------------------------------------| +| checkId | `string` | Unique ID for the check | +| status | `boolean` | Indicates the service is Up or Down | +| message | `string` | Message for the user about the down service | +| notifiedStatus | `boolean` | Indicates whether the user is notified | +| acknowledgeStatus | `boolean` | Indicates whether the user acknowledged the alert | +| updatedAt | `Date` | Last time the alert was updated | +| CreatedAt | `Date` | When the alert was created | + +
---
diff --git a/Server/models/Alert.js b/Server/models/Alert.js new file mode 100644 index 000000000..72705d947 --- /dev/null +++ b/Server/models/Alert.js @@ -0,0 +1,28 @@ +const mongoose = require('mongoose') + +const AlertSchema = mongoose.Schema( + { + checkId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Check', + immutable: true, + }, + status: { + type: Boolean, + }, + message: { + type: String, + }, + notifiedStatus: { + type: Boolean, + }, + acknowledgeStatus: { + type: Boolean, + } + }, + { + timestamps: true, + } +); + +module.exports = mongoose.model('Alert', AlertSchema); diff --git a/Server/models/Check.js b/Server/models/Check.js new file mode 100644 index 000000000..eedc2a28e --- /dev/null +++ b/Server/models/Check.js @@ -0,0 +1,28 @@ +const mongoose = require('mongoose') + +const CheckSchema = mongoose.Schema( + { + monitorId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Monitor', + immutable: true, + }, + status: { + type: Boolean, + }, + responseTime: { + type: Number, // milliseconds + }, + statusCode: { + type: Number, // 200, ... , 500 + }, + message: { + type: String, + } + }, + { + timestamps: true, + } +); + +module.exports = mongoose.model('Check', CheckSchema); From 7672cd55300ef6676d92fdd266c279e491a66470 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 12:27:57 -0700 Subject: [PATCH 11/22] Removed password from returned user, updated readme --- README.md | 62 ++++++++++++++++++++++++++++++++++++++ Server/db/MongoDB.js | 2 +- Server/routes/authRoute.js | 2 -- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a8e1b1f32..63f5625aa 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ BlueWave uptime monitoring application 4. [Endpoints](#endpoints) - POST [/api/v1/auth/register](#post-register) - POST [/api/v1/auth/login](#post-login) + - POST [/api/v1/auth/user/{userId}](#post-auth-user-edit-id) - GET [/api/v1/monitors](#get-monitors) - GET [/api/v1/monitor/{id}](#get-monitor-id) - GET [/api/v1/monitors/user/{userId}](#get-monitors-user-userid) @@ -222,6 +223,67 @@ curl --request POST \ --- +
+POST/api/v1/auth/user/{userId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +##### Body + +> | Name | Type | Notes | +> | ------------- | -------- | ----------- | +> | firstname | `string` | | +> | lastname | `string` | | +> | profilePicUrl | `string` | | +> | password | `string` | Min 8 chars | + +###### Response Payload + +> | Type | Notes | +> | ------ | ------------------------ | +> | `User` | Returns the updated user | + +##### Sample CURL request + +``` +curl --request POST \ + --url http://localhost:5000/api/v1/auth/user/6654d156634754f789e1f10e \ + --header 'Authorization: ' \ + --header 'Content-Type: application/json' \ + --data '{ + "firstname": "First Name", + "lastname: "Last Name" +}' +``` + +###### Sample Response + +```json +{ + "success": true, + "msg": "User updated", + "data": { + "_id": "6654d156634754f789e1f10e", + "firstname": "First Name", + "lastname": "Last Name", + "email": "me@gmail.com", + "isActive": true, + "isVerified": false, + "createdAt": "2024-05-27T18:30:46.358Z", + "updatedAt": "2024-05-27T19:21:51.747Z", + "__v": 0 + } +} +``` + +
+ +--- +
GET /api/v1/monitors diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index b3b269600..71b6fe44a 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -73,7 +73,7 @@ const updateUser = async (req, res) => { candidateUserId, candidateUser, { new: true } // Returns updated user instead of pre-update user - ); + ).select("-password"); return updatedUser; } catch (error) { throw error; diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 94f0ce5cc..637e4bf5e 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -1,7 +1,5 @@ const router = require("express").Router(); -const user = require("../models/user"); const { verifyJWT } = require("../middleware/verifyJWT"); -const { verifyOwnership } = require("../middleware/verifyOwnership"); const { registerController, From 1e398d9153357159674f07dd2736acd7946bdb61 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 13:51:51 -0700 Subject: [PATCH 12/22] Added route and DB scaffolds --- Server/controllers/checkController.js | 37 ++++++++++++++ Server/db/MongoDB.js | 74 +++++++++++++++++++++++++++ Server/index.js | 2 + Server/routes/checkRoute.js | 24 +++++++++ 4 files changed, 137 insertions(+) create mode 100644 Server/controllers/checkController.js create mode 100644 Server/routes/checkRoute.js diff --git a/Server/controllers/checkController.js b/Server/controllers/checkController.js new file mode 100644 index 000000000..ef1a1a071 --- /dev/null +++ b/Server/controllers/checkController.js @@ -0,0 +1,37 @@ +var jwt = require("jsonwebtoken"); +const SERVICE_NAME = "check"; + +const createCheck = (req, res, next) => { + try { + req.db.createCheck(req, res); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } +}; + +const getChecks = (req, res, next) => { + try { + req.db.getChecks(req, res); + // Return all checks for a monitor + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } +}; + +const deleteChecks = (req, res, next) => { + try { + req.db.deleteChecks(req, res); + // Delete all checks for a monitor + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } +}; + +module.exports = { + createCheck, + getChecks, + deleteChecks, +}; diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index 44b734954..f7f790e86 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -16,6 +16,10 @@ const connect = async () => { } }; +//**************************************** +// Users +//**************************************** + /** * Insert a User * @async @@ -55,6 +59,10 @@ const getUserByEmail = async (req, res) => { } }; +//**************************************** +// Monitors +//**************************************** + /** * Get all monitors * @async @@ -169,6 +177,69 @@ const editMonitor = async (req, res) => { } }; +//**************************************** +// Checks +//**************************************** + +/** + * Create a check for a monitor + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @throws {Error} + */ + +const createCheck = async (req, res) => { + try { + // Create check with monitor id + res + .status(200) + .json({ success: true, msg: "Create check", data: req.params.monitorId }); + } catch (error) { + throw error; + } +}; + +/** + * Get all checks for a monitor + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @throws {Error} + */ + +const getChecks = async (req, res) => { + try { + // TODO get all checks for a monitor from DB + res + .status(200) + .json({ success: true, msg: "Get checks", data: req.params.monitorId }); + } catch (error) { + throw error; + } +}; + +/** + * Delete all checks for a monitor + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @throws {Error} + */ + +const deleteChecks = async (req, res) => { + try { + // TODO Delete all checks for a monitor + res.status(200).json({ + success: true, + msg: "Deleted checks", + data: req.params.monitorId, + }); + } catch (error) { + throw error; + } +}; + module.exports = { connect, insertUser, @@ -179,4 +250,7 @@ module.exports = { createMonitor, deleteMonitor, editMonitor, + createCheck, + getChecks, + deleteChecks, }; diff --git a/Server/index.js b/Server/index.js index db3be459c..67813051e 100644 --- a/Server/index.js +++ b/Server/index.js @@ -3,6 +3,7 @@ const helmet = require("helmet"); const cors = require("cors"); const authRouter = require("./routes/authRoute"); const monitorRouter = require("./routes/monitorRoute"); +const checkRouter = require("./routes/checkRoute"); const { connectDbAndRunServer } = require("./configs/db"); require("dotenv").config(); const logger = require("./utils/logger"); @@ -62,6 +63,7 @@ app.use((req, res, next) => { //routes app.use("/api/v1/auth", authRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); +app.use("/api/v1/checks", verifyJWT, checkRouter); /** * Error handler middleware diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js new file mode 100644 index 000000000..6569dd49a --- /dev/null +++ b/Server/routes/checkRoute.js @@ -0,0 +1,24 @@ +const router = require("express").Router(); +const checkController = require("../controllers/checkController"); +const { verifyOwnership } = require("../middleware/verifyOwnership"); +const Monitor = require("../models/Monitor"); + +router.post( + "/:monitorId", + verifyOwnership(Monitor, "monitorId"), + checkController.createCheck +); + +router.get( + "/:monitorId", + verifyOwnership(Monitor, "monitorId"), + checkController.getChecks +); + +router.post( + "/delete/:monitorId", + verifyOwnership(Monitor, "monitorId"), + checkController.deleteChecks +); + +module.exports = router; From 9e3278b304a9020b5cd63c46d0f834dc000a4440 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 27 May 2024 16:04:44 -0700 Subject: [PATCH 13/22] Added placeholders to readme --- README.md | 142 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 8767a3633..2fb1d944c 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,21 @@ BlueWave uptime monitoring application 2. [Installation (Server)](#server) 3. [Configuration(Server)](#config-server) 4. [Endpoints](#endpoints) + ###### Auth - POST [/api/v1/auth/register](#post-register) - POST [/api/v1/auth/login](#post-login) - POST [/api/v1/auth/user/{userId}](#post-auth-user-edit-id) + ###### Monitors - GET [/api/v1/monitors](#get-monitors) - GET [/api/v1/monitor/{id}](#get-monitor-id) - GET [/api/v1/monitors/user/{userId}](#get-monitors-user-userid) - POST [/api/v1/monitors](#post-monitors) - POST [/api/v1/monitors/delete/{monitorId}](#post-monitors-del-id) - POST [/api/v1/monitors/edit/{monitorId}](#post-monitors-edit-id) + ###### Checks + - POST [/api/v1/checks/{monitorId}](#post-checks) + - GET [/api/v1/checks/{monitorId}](#get-checks) + - POST [/api/v1/checks/delete/{monitorId}](#delete-checks) 5. [Error Handling](#error-handling) 6. [Contributors](#contributors) @@ -122,15 +128,15 @@ Example:
Check -| Name | Type | Notes | -| ----------- | --------- | ------------------------------------------------| -| monitorId | `string` | Unique ID for the monitor | -| status | `boolean` | Indicates the service is Up or Down | -| responseTime| `integer` | Indicates the response time of the service (ms) | -| statusCode | `integer` | Status Code returned from the service | -| message | `string` | Message returned from the service | -| updatedAt | `Date` | Last time the check was updated | -| CreatedAt | `Date` | When the check was created | +| Name | Type | Notes | +| ------------ | --------- | ----------------------------------------------- | +| monitorId | `string` | Unique ID for the monitor | +| status | `boolean` | Indicates the service is Up or Down | +| responseTime | `integer` | Indicates the response time of the service (ms) | +| statusCode | `integer` | Status Code returned from the service | +| message | `string` | Message returned from the service | +| updatedAt | `Date` | Last time the check was updated | +| CreatedAt | `Date` | When the check was created |
@@ -138,9 +144,9 @@ Example: Alert | Name | Type | Notes | -| ----------- | --------- | --------------------------------------------------| +| ----------------- | --------- | ------------------------------------------------- | | checkId | `string` | Unique ID for the check | -| status | `boolean` | Indicates the service is Up or Down | +| status | `boolean` | Indicates the service is Up or Down | | message | `string` | Message for the user about the down service | | notifiedStatus | `boolean` | Indicates whether the user is notified | | acknowledgeStatus | `boolean` | Indicates whether the user acknowledged the alert | @@ -148,8 +154,11 @@ Example: | CreatedAt | `Date` | When the alert was created |
+ --- +###### Auth +
POST /api/v1/auth/register @@ -201,8 +210,6 @@ curl --request POST \
---- -
POST /api/v1/auth/login @@ -250,8 +257,6 @@ curl --request POST \
---- -
POST/api/v1/auth/user/{userId} @@ -313,6 +318,8 @@ curl --request POST \ --- +###### Monitors +
GET /api/v1/monitors @@ -373,8 +380,6 @@ curl --request GET \
---- -
GET /api/v1/monitor/{id} @@ -421,8 +426,6 @@ curl --request GET \
---- -
GET /api/v1/monitors/user/{userId} @@ -483,8 +486,6 @@ curl --request GET \
---- -
POST/api/v1/monitors @@ -538,8 +539,6 @@ curl --request POST \
---- -
POST/api/v1/monitors/delete/{monitorId} @@ -575,8 +574,6 @@ curl --request POST \ ##
---- -
POST/api/v1/monitors/edit/{monitorId} @@ -636,6 +633,101 @@ curl --request POST \ --- +###### Checks + +
+POST/api/v1/checks/{monitorId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +###### Response Payload + +> | Type | Notes | +> | ---- | ------------------- | +> | None | No payload returned | + +###### Body + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +
+GET/api/v1/checks/{monitorId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +###### Response Payload + +> | Type | Notes | +> | --------------- | ------------------------ | +> | `Array[Checks]` | Array of `Check` objects | + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +
+POST/api/v1/checks/delete/{monitorId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +###### Response Payload + +> | Type | Notes | +> | ---- | ------------------- | +> | None | No payload returned | + +###### Body + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +--- + ### Error handling {#error-handling} Errors are returned in a standard format: From a417662f68680b5fd60ede8156e6b470a0544bc6 Mon Sep 17 00:00:00 2001 From: M M Date: Mon, 27 May 2024 17:26:12 -0700 Subject: [PATCH 14/22] Implemented the dashboard settings icon with its dropdown menu. --- .../DashboardSettingsIcon/index.css | 0 .../DashboardSettingsIcon/index.jsx | 78 +++++++++++++++++++ Client/src/Layouts/HomeLayout/index.jsx | 2 + 3 files changed, 80 insertions(+) create mode 100644 Client/src/Components/DashboardSettingsIcon/index.css create mode 100644 Client/src/Components/DashboardSettingsIcon/index.jsx diff --git a/Client/src/Components/DashboardSettingsIcon/index.css b/Client/src/Components/DashboardSettingsIcon/index.css new file mode 100644 index 000000000..e69de29bb diff --git a/Client/src/Components/DashboardSettingsIcon/index.jsx b/Client/src/Components/DashboardSettingsIcon/index.jsx new file mode 100644 index 000000000..e1f1d59da --- /dev/null +++ b/Client/src/Components/DashboardSettingsIcon/index.jsx @@ -0,0 +1,78 @@ +import { useState } from 'react'; +import Box from '@mui/material/Box'; +import IconButton from '@mui/material/IconButton'; +import Menu from '@mui/material/Menu'; +import Tooltip from '@mui/material/Tooltip'; +import MenuItem from '@mui/material/MenuItem'; +import Typography from '@mui/material/Typography'; +import SvgIcon from '@mui/material/SvgIcon'; +import SettingsIcon from '@mui/icons-material/Settings'; +import { useTheme } from '@mui/material/styles'; + +const settings = ['Open Site', 'Detailed View', 'Incidents', 'Configure', 'Remove']; + +/** + * DashboardSettings component + * + * A component that provides a settings menu accessible from an icon. + * + * @component + * @example + * return ( + * + * ) + */ +function DashboardSettings() { + const theme = useTheme(); + const [anchorElUser, setAnchorElUser] = useState(null); + + /** + * Handles opening the user menu. + * + * @param {React.MouseEvent} event - The event triggered by clicking the user menu button. + */ + const handleOpenUserMenu = (event) => { + setAnchorElUser(event.currentTarget); + }; + + /** + * Handles closing the user menu. + */ + const handleCloseUserMenu = () => { + setAnchorElUser(null); + }; + + return ( + + + + + + + + {settings.map((setting) => ( + + {setting} + + ))} + + + ); +} + +export default DashboardSettings; diff --git a/Client/src/Layouts/HomeLayout/index.jsx b/Client/src/Layouts/HomeLayout/index.jsx index bb37d4768..e75863b3b 100644 --- a/Client/src/Layouts/HomeLayout/index.jsx +++ b/Client/src/Layouts/HomeLayout/index.jsx @@ -3,6 +3,7 @@ import { Outlet } from 'react-router' import Home from '../../Pages/Home' import './index.css' import ChartsOverviewDemo from '../../Components/DashboardProgressBars' +import DashboardSettings from '../../Components/DashboardSettings' const HomeLayout = () => { @@ -12,6 +13,7 @@ const HomeLayout = () => { + ) } From d24b5d8ada832342116bdb95f1477354a0697675 Mon Sep 17 00:00:00 2001 From: M M Date: Mon, 27 May 2024 23:11:23 -0700 Subject: [PATCH 15/22] Addressed comments and fixed the issue with the import statement. --- Client/src/Layouts/HomeLayout/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Layouts/HomeLayout/index.jsx b/Client/src/Layouts/HomeLayout/index.jsx index e75863b3b..ed1d06fe6 100644 --- a/Client/src/Layouts/HomeLayout/index.jsx +++ b/Client/src/Layouts/HomeLayout/index.jsx @@ -3,7 +3,7 @@ import { Outlet } from 'react-router' import Home from '../../Pages/Home' import './index.css' import ChartsOverviewDemo from '../../Components/DashboardProgressBars' -import DashboardSettings from '../../Components/DashboardSettings' +import DashboardSettings from '../../Components/DashboardSettingsIcon' const HomeLayout = () => { From 7430a6eb48e835ac0ebfdeeb2f9b70f2b0ea33e2 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 28 May 2024 11:17:03 -0700 Subject: [PATCH 16/22] Started work on alert routes and controller --- Server/controllers/alertController.js | 15 +++++++++++++++ Server/routes/alertRoute.js | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 Server/controllers/alertController.js create mode 100644 Server/routes/alertRoute.js diff --git a/Server/controllers/alertController.js b/Server/controllers/alertController.js new file mode 100644 index 000000000..6d7a493d4 --- /dev/null +++ b/Server/controllers/alertController.js @@ -0,0 +1,15 @@ +const createAlert = (req, res, next) => {}; +const getAlertsByUserId = (req, res, next) => {}; +const getAlertsByMonitorId = (req, res, next) => {}; +const getAlertById = (req, res, next) => {}; +const editAlert = (req, res, next) => {}; +const deleteAlert = (req, res, next) => {}; + +module.exports = { + createAlert, + getAlertsByUserId, + getAlertsByMonitorId, + getAlertById, + editAlert, + deleteAlert, +}; diff --git a/Server/routes/alertRoute.js b/Server/routes/alertRoute.js new file mode 100644 index 000000000..be252e8c4 --- /dev/null +++ b/Server/routes/alertRoute.js @@ -0,0 +1,27 @@ +const router = require("express").Router(); +const alertController = require("../controllers/alertController"); +const { verifyOwnership } = require("../middleware/verifyOwnership"); +const Alert = require("../models/Alert"); + +// Create alert +router.post("/:monitorId", alertController.createAlert); +// Get all alerts for a user +router.get("/user/:userId", alertController.getAlertsByUserId); +// Get all alerts for a monitor +router.get("/monitor/:monitorId", alertController.getAlertsByMonitorId); +// Get a single alert +router.get("/:alertId", alertController.getAlertById); +// Edit +router.post( + "/edit/:alertId", + verifyOwnership(Alert, "alertId"), + alertController.editAlert +); +//Delete +router.post( + "/delete/:alertId", + verifyOwnership(Alert, "alertId"), + alertController.deleteAlert +); + +module.exports = router; From 7e9f8d9d290f39ec9122f74940be493d02d1b2a7 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 28 May 2024 11:34:25 -0700 Subject: [PATCH 17/22] Implemented routes --- Server/controllers/alertController.js | 31 +++++++++++++++++++++------ Server/index.js | 2 ++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Server/controllers/alertController.js b/Server/controllers/alertController.js index 6d7a493d4..25edb1643 100644 --- a/Server/controllers/alertController.js +++ b/Server/controllers/alertController.js @@ -1,9 +1,28 @@ -const createAlert = (req, res, next) => {}; -const getAlertsByUserId = (req, res, next) => {}; -const getAlertsByMonitorId = (req, res, next) => {}; -const getAlertById = (req, res, next) => {}; -const editAlert = (req, res, next) => {}; -const deleteAlert = (req, res, next) => {}; +const express = require("express"); +const {} = require("../validation/joi"); +const logger = require("../utils/logger"); +require("dotenv").config(); + +const SERVICE_NAME = "alerts"; + +const createAlert = (req, res, next) => { + res.status(200).json({ success: true, msg: "Create Alert" }); +}; +const getAlertsByUserId = (req, res, next) => { + res.status(200).json({ success: true, msg: "Get Alerts By UserID" }); +}; +const getAlertsByMonitorId = (req, res, next) => { + res.status(200).json({ success: true, msg: "Get Alerts By MonitorID" }); +}; +const getAlertById = (req, res, next) => { + res.status(200).json({ success: true, msg: "Get Alert By alertID" }); +}; +const editAlert = (req, res, next) => { + res.status(200).json({ success: true, msg: "Edit alert" }); +}; +const deleteAlert = (req, res, next) => { + res.status(200).json({ success: true, msg: "Delete alert" }); +}; module.exports = { createAlert, diff --git a/Server/index.js b/Server/index.js index 1596e0862..96f7553fd 100644 --- a/Server/index.js +++ b/Server/index.js @@ -4,6 +4,7 @@ const cors = require("cors"); const authRouter = require("./routes/authRoute"); const monitorRouter = require("./routes/monitorRoute"); const checkRouter = require("./routes/checkRoute"); +const alertRouter = require("./routes/alertRoute"); const { connectDbAndRunServer } = require("./configs/db"); require("dotenv").config(); const logger = require("./utils/logger"); @@ -64,6 +65,7 @@ app.use((req, res, next) => { app.use("/api/v1/auth", authRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); +app.use("/api/v1/alerts", verifyJWT, alertRouter); // Testing email service // app.use('/sendEmail', async (req, res) => { From e90073da24d4b2ab83d789b5f7f0ca44830ceac1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 28 May 2024 11:39:55 -0700 Subject: [PATCH 18/22] Add validation to createAlert --- Server/controllers/alertController.js | 19 ++++++++++++++++--- Server/validation/joi.js | 5 +++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Server/controllers/alertController.js b/Server/controllers/alertController.js index 25edb1643..b7295b901 100644 --- a/Server/controllers/alertController.js +++ b/Server/controllers/alertController.js @@ -2,14 +2,27 @@ const express = require("express"); const {} = require("../validation/joi"); const logger = require("../utils/logger"); require("dotenv").config(); +const { createAlertParamValidation } = require("../validation/joi"); const SERVICE_NAME = "alerts"; -const createAlert = (req, res, next) => { - res.status(200).json({ success: true, msg: "Create Alert" }); +const createAlert = async (req, res, next) => { + try { + await createAlertParamValidation.validateAsync(req.params); + res + .status(200) + .json({ success: true, msg: "Create Alert", data: req.params.monitorId }); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } }; const getAlertsByUserId = (req, res, next) => { - res.status(200).json({ success: true, msg: "Get Alerts By UserID" }); + res.status(200).json({ + success: true, + msg: "Get Alerts By UserID", + data: req.params.userId, + }); }; const getAlertsByMonitorId = (req, res, next) => { res.status(200).json({ success: true, msg: "Get Alerts By MonitorID" }); diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 399c243dc..441e0ebc3 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -39,6 +39,10 @@ const editUserBodyValidation = joi.object({ profilePicUrl: joi.string(), }); +const createAlertParamValidation = joi.object({ + monitorId: joi.string().required(), +}); + module.exports = { loginValidation, registerValidation, @@ -47,4 +51,5 @@ module.exports = { monitorValidation, editUserParamValidation, editUserBodyValidation, + createAlertParamValidation, }; From 424bec1366431cac54b28984b14f8fb3c6669e15 Mon Sep 17 00:00:00 2001 From: veyselboybay Date: Tue, 28 May 2024 14:42:51 -0400 Subject: [PATCH 19/22] Updated the Alert model, ReadMe file --- README.md | 4 +++- Server/models/Alert.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2fb1d944c..2e1022c31 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,9 @@ Example: | Name | Type | Notes | | ----------------- | --------- | ------------------------------------------------- | -| checkId | `string` | Unique ID for the check | +| checkId | `string` | Unique ID for the associated check | +| monitorId | `string` | Unique ID for the associated monitor | +| userId | `string` | Unique ID for the associated user | | status | `boolean` | Indicates the service is Up or Down | | message | `string` | Message for the user about the down service | | notifiedStatus | `boolean` | Indicates whether the user is notified | diff --git a/Server/models/Alert.js b/Server/models/Alert.js index 72705d947..758a7eba2 100644 --- a/Server/models/Alert.js +++ b/Server/models/Alert.js @@ -7,6 +7,16 @@ const AlertSchema = mongoose.Schema( ref: 'Check', immutable: true, }, + monitorId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Monitor', + immutable: true, + }, + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + immutable: true, + }, status: { type: Boolean, }, From fdb8c6b20ac193d3b8c20ae93a055c65d747af61 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 28 May 2024 13:02:19 -0700 Subject: [PATCH 20/22] Finished routes, validation, and scaffold DB --- Server/controllers/alertController.js | 130 ++++++++++++++++++++++---- Server/controllers/authController.js | 4 +- Server/db/MongoDB.js | 123 ++++++++++++++++++++++++ Server/validation/joi.js | 44 +++++++++ 4 files changed, 280 insertions(+), 21 deletions(-) diff --git a/Server/controllers/alertController.js b/Server/controllers/alertController.js index b7295b901..91bb56971 100644 --- a/Server/controllers/alertController.js +++ b/Server/controllers/alertController.js @@ -1,40 +1,132 @@ const express = require("express"); -const {} = require("../validation/joi"); const logger = require("../utils/logger"); require("dotenv").config(); -const { createAlertParamValidation } = require("../validation/joi"); +const { + createAlertParamValidation, + createAlertBodyValidation, + getAlertsByUserIdParamValidation, + getAlertsByMonitorIdParamValidation, + getAlertByIdParamValidation, + editAlertParamValidation, + editAlertBodyValidation, + deleteAlertParamValidation, +} = require("../validation/joi"); const SERVICE_NAME = "alerts"; +/** + * Creates an alert for a monitor + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {Promise} + * @throws {Error} + */ const createAlert = async (req, res, next) => { try { await createAlertParamValidation.validateAsync(req.params); - res - .status(200) - .json({ success: true, msg: "Create Alert", data: req.params.monitorId }); + await createAlertBodyValidation.validateAsync(req.body); + } catch (error) { + error.status = 422; + error.message = error.details[0].message; + error.service = SERVICE_NAME; + next(error); + return; + } + + try { + req.db.createAlert(req, res); } catch (error) { error.service = SERVICE_NAME; next(error); } }; -const getAlertsByUserId = (req, res, next) => { - res.status(200).json({ - success: true, - msg: "Get Alerts By UserID", - data: req.params.userId, - }); + +/** + * Gets all alerts for a user + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {Promise} + * @throws {Error} + */ +const getAlertsByUserId = async (req, res, next) => { + try { + await getAlertsByUserIdParamValidation.validateAsync(req.params); + } catch (error) { + error.status = 422; + error.message = error.details[0].message; + error.service = SERVICE_NAME; + next(error); + return; + } + + try { + req.db.getAlertsByUserId(req, res); + } catch (error) { + error.service = SERVICE_NAME; + next(error); + } }; -const getAlertsByMonitorId = (req, res, next) => { - res.status(200).json({ success: true, msg: "Get Alerts By MonitorID" }); + +const getAlertsByMonitorId = async (req, res, next) => { + try { + await getAlertsByMonitorIdParamValidation.validateAsync(req.params); + res.status(200).json({ + success: true, + msg: "Get Alerts By MonitorID", + data: req.params.monitorId, + }); + } catch (error) { + error.status = 422; + res.status(200).json({ success: true, msg: "Edit alert" }); + + error.message = error.details[0].message; + error.service = SERVICE_NAME; + next(error); + return; + } }; -const getAlertById = (req, res, next) => { - res.status(200).json({ success: true, msg: "Get Alert By alertID" }); +const getAlertById = async (req, res, next) => { + try { + await getAlertByIdParamValidation.validateAsync(req.params); + res.status(200).json({ + success: true, + msg: "Get Alert By alertID", + data: req.params.alertId, + }); + } catch (error) { + error.status = 422; + error.message = error.details[0].message; + error.service = SERVICE_NAME; + next(error); + return; + } }; -const editAlert = (req, res, next) => { - res.status(200).json({ success: true, msg: "Edit alert" }); +const editAlert = async (req, res, next) => { + try { + await editAlertParamValidation(req.params); + await editAlertBodyValidation(req.body); + res.status(200).json({ success: true, msg: "Edit alert" }); + } catch (error) { + error.status = 422; + error.message = error.details[0].message; + error.service = SERVICE_NAME; + next(error); + return; + } }; -const deleteAlert = (req, res, next) => { - res.status(200).json({ success: true, msg: "Delete alert" }); +const deleteAlert = async (req, res, next) => { + try { + await deleteAlertParamValidation(req.params); + res.status(200).json({ success: true, msg: "Delete alert" }); + } catch (error) { + error.status = 422; + error.message = error.details[0].message; + error.service = SERVICE_NAME; + next(error); + return; + } }; module.exports = { diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index cc476ab54..257048937 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -17,7 +17,7 @@ const SERVICE_NAME = "auth"; * @returns {String} */ const issueToken = (payload) => { - return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: "1h" }); + return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: "99d" }); }; /** @@ -31,7 +31,7 @@ const registerController = async (req, res, next) => { try { await registerValidation.validateAsync(req.body); } catch (error) { - error.status = 400; + error.status = 422; error.service = SERVICE_NAME; error.message = error.details[0].message; next(error); diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js index a4c9422a3..32d5d33f7 100644 --- a/Server/db/MongoDB.js +++ b/Server/db/MongoDB.js @@ -265,6 +265,123 @@ const deleteChecks = async (req, res) => { } }; +//**************************************** +// Alerts +//**************************************** + +/** + * Creates an Alert associated with a Monitor and User + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {>} + * @throws {Error} + */ +const createAlert = async (req, res) => { + try { + res + .status(200) + .json({ success: true, msg: "Create Alert", data: req.params.monitorId }); + } catch (error) { + throw error; + } +}; + +/** + * Gets all alerts a User has set + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {>} + * @throws {Error} + */ +const getAlertsByUserId = async (req, res) => { + try { + res.status(200).json({ + success: true, + msg: "Get Alerts By UserID", + data: req.params.userId, + }); + } catch (error) { + throw error; + } +}; + +/** + * Gets all alerts a for an associated Monitor + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {>} + * @throws {Error} + */ +const getAlertsByMonitorId = async (req, res) => { + try { + res.status(200).json({ + success: true, + msg: "Get Alerts By MonitorID", + data: req.params.monitorId, + }); + } catch (error) { + throw error; + } +}; + +/** + * Gets an alert with specified ID + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {Promise} + * @throws {Error} + */ +const getAlertById = async (req, res) => { + try { + res.status(200).json({ + success: true, + msg: "Get Alert By alertID", + data: req.params.alertId, + }); + } catch (error) { + throw error; + } +}; + +/** + * Returns an edited monitor with the specified ID + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @returns {Promise>} + * @throws {Error} + */ +const editAlert = async (req, res) => { + try { + res + .status(200) + .json({ success: true, msg: "Edit alert", data: req.params.alertId }); + } catch (error) { + throw error; + } +}; + +/** + * Deletes a monitor with the specified ID + * @async + * @param {Express.Request} req + * @param {Express.Response} res + * @throws {Error} + */ +const deleteAlert = async (req, res) => { + try { + res + .status(200) + .json({ success: true, msg: "Delete alert", data: req.params.alertId }); + } catch (error) { + throw error; + } +}; + module.exports = { connect, insertUser, @@ -279,4 +396,10 @@ module.exports = { createCheck, getChecks, deleteChecks, + createAlert, + getAlertsByUserId, + getAlertsByMonitorId, + getAlertById, + editAlert, + deleteAlert, }; diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 441e0ebc3..01a0d0ada 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -43,6 +43,43 @@ const createAlertParamValidation = joi.object({ monitorId: joi.string().required(), }); +const createAlertBodyValidation = joi.object({ + checkId: joi.string().required(), + monitorId: joi.string().required(), + userId: joi.string().required(), + status: joi.boolean(), + message: joi.string(), + notifiedStatus: joi.boolean(), + acknowledgeStatus: joi.boolean(), +}); + +const getAlertsByUserIdParamValidation = joi.object({ + userId: joi.string().required(), +}); + +const getAlertsByMonitorIdParamValidation = joi.object({ + monitorId: joi.string().required(), +}); + +const getAlertByIdParamValidation = joi.object({ + alertId: joi.string().required(), +}); + +const editAlertParamValidation = joi.object({ + alertId: joi.string().required(), +}); + +const editAlertBodyValidation = joi.object({ + status: joi.boolean(), + message: joi.string(), + notifiedStatus: joi.boolean(), + acknowledgeStatus: joi.boolean(), +}); + +const deleteAlertParamValidation = joi.object({ + alertId: joi.string().required(), +}); + module.exports = { loginValidation, registerValidation, @@ -52,4 +89,11 @@ module.exports = { editUserParamValidation, editUserBodyValidation, createAlertParamValidation, + createAlertBodyValidation, + getAlertsByUserIdParamValidation, + getAlertsByMonitorIdParamValidation, + getAlertByIdParamValidation, + editAlertParamValidation, + editAlertBodyValidation, + deleteAlertParamValidation, }; From 476b6ff6d81c5a0c82ad011a175107e0e33f4ecc Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 28 May 2024 13:18:32 -0700 Subject: [PATCH 21/22] Added routes to readme --- README.md | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 199 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2e1022c31..dfc57064d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,13 @@ BlueWave uptime monitoring application - POST [/api/v1/checks/{monitorId}](#post-checks) - GET [/api/v1/checks/{monitorId}](#get-checks) - POST [/api/v1/checks/delete/{monitorId}](#delete-checks) + ###### Alerts + - POST [/api/v1/alerts/{monitorId}](#create-alert) + - GET [/api/v1/alerts/user/{userId}](#get-alerts-user-id) + - GET [/api/v1/alerts/monitor/{monitorId}](#get-alerts-monitor-id) + - GET [/api/v1/alerts/{alertId}](#get-alert-alert-id) + - POST [/api/v1/alerts/edit/{alertId}](#edit-alert) + - POST [/api/v1/alerts/delete/{alertId}](#delete-alert) 5. [Error Handling](#error-handling) 6. [Contributors](#contributors) @@ -333,9 +340,9 @@ curl --request POST \ ##### Response Payload -> | Type | Notes | -> | ---------------- | ----------------- | -> | `Array[Monitor]` | Array of monitors | +> | Type | Notes | +> | ---------------- | --------------------- | +> | `Array` | Array of all monitors | ###### Sample cURL Request @@ -439,9 +446,9 @@ curl --request GET \ ###### Response Payload -> | Type | Notes | -> | ---------------- | ------------------------------------------------------------------ | -> | `Array[Monitor]` | Array of monitors created by user with userId specified in request | +> | Type | Notes | +> | ---------------- | ------------------------------------------------------- | +> | `Array` | Array of monitors created by user with specified UserID | ###### Sample cURL Request @@ -499,9 +506,9 @@ curl --request GET \ ###### Response Payload -> | Type | Notes | -> | --------- | --------------------------------- | -> | `Monitor` | Newly created monitor is returned | +> | Type | Notes | +> | --------- | ------------------------------- | +> | `Monitor` | Returns newly created `Monitor` | ##### Sample CURL request @@ -681,7 +688,7 @@ curl --request POST \ > | Type | Notes | > | --------------- | ------------------------ | -> | `Array[Checks]` | Array of `Check` objects | +> | `Array` | Array of `Check` objects | ##### Sample CURL request @@ -730,6 +737,188 @@ curl --request POST \ --- +###### Alerts + +
+POST/api/v1/alerts/{monitorId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +###### Response Payload + +> | Type | Notes | +> | ------- | ----------------------------- | +> | `Alert` | Returns newly created `Alert` | + +###### Body + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +
+GET/api/v1/alerts/user/{userId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | GET | + +###### Response Payload + +> | Type | Notes | +> | -------------- | --------------------------------------- | +> | `Array` | Returns all `Alert` created by a `User` | + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+
+GET/api/v1/alerts/monitor/{monitorId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | GET | + +###### Response Payload + +> | Type | Notes | +> | -------------- | -------------------------------------------------------------- | +> | `Array` | Returns an array of `Alert` belonging to a specified `Monitor` | + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +
+GET/api/v1/alerts/{alertId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | GET | + +###### Response Payload + +> | Type | Notes | +> | ------- | ------------------------- | +> | `Alert` | Returns specified `Alert` | + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +
+POST/api/v1/alerts/edit/{alertId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +###### Response Payload + +> | Type | Notes | +> | ------- | -------------------- | +> | `Alert` | Returns edited alert | + +###### Body + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+
+POST/api/v1/alerts/delete/{alertId} + +###### Method/Headers + +> | Method/Headers | Value | +> | -------------- | ----- | +> | Method | POST | + +###### Response Payload + +> | Type | Notes | +> | ---- | ------------------- | +> | None | No payload returned | + +###### Body + +##### Sample CURL request + +``` + +``` + +###### Sample Response + +```json + +``` + +
+ +--- + ### Error handling {#error-handling} Errors are returned in a standard format: From aec859947bf747bd6c71baddae9e5ac9f5071d45 Mon Sep 17 00:00:00 2001 From: M M Date: Tue, 28 May 2024 15:52:55 -0700 Subject: [PATCH 22/22] Deleted unnecessary Vite timestamp files. --- ...config.js.timestamp-1714807476723-44482001f0038.mjs | 10 ---------- ...config.js.timestamp-1714807479464-cc660fde72923.mjs | 10 ---------- ...config.js.timestamp-1714807482127-bba3249973ca6.mjs | 0 ...config.js.timestamp-1714807487371-43b917cc75e26.mjs | 10 ---------- ....config.js.timestamp-1714807494135-d5aa25dec011.mjs | 0 ...config.js.timestamp-1714807590920-36497efd2dbd1.mjs | 10 ---------- ...config.js.timestamp-1714807965878-e54134a7db9a9.mjs | 10 ---------- ...config.js.timestamp-1714807967318-789fa77657938.mjs | 10 ---------- 8 files changed, 60 deletions(-) delete mode 100644 Client/vite.config.js.timestamp-1714807476723-44482001f0038.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807479464-cc660fde72923.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807482127-bba3249973ca6.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807487371-43b917cc75e26.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807494135-d5aa25dec011.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807590920-36497efd2dbd1.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807965878-e54134a7db9a9.mjs delete mode 100644 Client/vite.config.js.timestamp-1714807967318-789fa77657938.mjs diff --git a/Client/vite.config.js.timestamp-1714807476723-44482001f0038.mjs b/Client/vite.config.js.timestamp-1714807476723-44482001f0038.mjs deleted file mode 100644 index f54c5cbfe..000000000 --- a/Client/vite.config.js.timestamp-1714807476723-44482001f0038.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.js -import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js"; -import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/Client/vite.config.js.timestamp-1714807479464-cc660fde72923.mjs b/Client/vite.config.js.timestamp-1714807479464-cc660fde72923.mjs deleted file mode 100644 index f54c5cbfe..000000000 --- a/Client/vite.config.js.timestamp-1714807479464-cc660fde72923.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.js -import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js"; -import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/Client/vite.config.js.timestamp-1714807482127-bba3249973ca6.mjs b/Client/vite.config.js.timestamp-1714807482127-bba3249973ca6.mjs deleted file mode 100644 index e69de29bb..000000000 diff --git a/Client/vite.config.js.timestamp-1714807487371-43b917cc75e26.mjs b/Client/vite.config.js.timestamp-1714807487371-43b917cc75e26.mjs deleted file mode 100644 index f54c5cbfe..000000000 --- a/Client/vite.config.js.timestamp-1714807487371-43b917cc75e26.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.js -import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js"; -import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/Client/vite.config.js.timestamp-1714807494135-d5aa25dec011.mjs b/Client/vite.config.js.timestamp-1714807494135-d5aa25dec011.mjs deleted file mode 100644 index e69de29bb..000000000 diff --git a/Client/vite.config.js.timestamp-1714807590920-36497efd2dbd1.mjs b/Client/vite.config.js.timestamp-1714807590920-36497efd2dbd1.mjs deleted file mode 100644 index f54c5cbfe..000000000 --- a/Client/vite.config.js.timestamp-1714807590920-36497efd2dbd1.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.js -import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js"; -import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/Client/vite.config.js.timestamp-1714807965878-e54134a7db9a9.mjs b/Client/vite.config.js.timestamp-1714807965878-e54134a7db9a9.mjs deleted file mode 100644 index f54c5cbfe..000000000 --- a/Client/vite.config.js.timestamp-1714807965878-e54134a7db9a9.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.js -import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js"; -import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K diff --git a/Client/vite.config.js.timestamp-1714807967318-789fa77657938.mjs b/Client/vite.config.js.timestamp-1714807967318-789fa77657938.mjs deleted file mode 100644 index f54c5cbfe..000000000 --- a/Client/vite.config.js.timestamp-1714807967318-789fa77657938.mjs +++ /dev/null @@ -1,10 +0,0 @@ -// vite.config.js -import { defineConfig } from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/vite/dist/node/index.js"; -import react from "file:///c:/Users/cosmi/OneDrive/Desktop/BlueWave/Uptime-Monitor/bluewave-uptime/Client/node_modules/@vitejs/plugin-react/dist/index.mjs"; -var vite_config_default = defineConfig({ - plugins: [react()] -}); -export { - vite_config_default as default -}; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJjOlxcXFxVc2Vyc1xcXFxjb3NtaVxcXFxPbmVEcml2ZVxcXFxEZXNrdG9wXFxcXEJsdWVXYXZlXFxcXFVwdGltZS1Nb25pdG9yXFxcXGJsdWV3YXZlLXVwdGltZVxcXFxDbGllbnRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcImM6XFxcXFVzZXJzXFxcXGNvc21pXFxcXE9uZURyaXZlXFxcXERlc2t0b3BcXFxcQmx1ZVdhdmVcXFxcVXB0aW1lLU1vbml0b3JcXFxcYmx1ZXdhdmUtdXB0aW1lXFxcXENsaWVudFxcXFx2aXRlLmNvbmZpZy5qc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vYzovVXNlcnMvY29zbWkvT25lRHJpdmUvRGVza3RvcC9CbHVlV2F2ZS9VcHRpbWUtTW9uaXRvci9ibHVld2F2ZS11cHRpbWUvQ2xpZW50L3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHJlYWN0IGZyb20gJ0B2aXRlanMvcGx1Z2luLXJlYWN0J1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICBwbHVnaW5zOiBbcmVhY3QoKV0sXHJcbn0pXHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBOGEsU0FBUyxvQkFBb0I7QUFDM2MsT0FBTyxXQUFXO0FBR2xCLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDbkIsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K