diff --git a/Client/src/Components/Integrations/index.css b/Client/src/Components/Integrations/index.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/Client/src/Components/Integrations/index.jsx b/Client/src/Components/Integrations/index.jsx
new file mode 100644
index 000000000..b0e00bdfe
--- /dev/null
+++ b/Client/src/Components/Integrations/index.jsx
@@ -0,0 +1,56 @@
+import { Box, Typography, useTheme } from '@mui/material';
+import Button from '../Button';
+
+/**
+ * Integrations component
+ * @returns {JSX.Element}
+ */
+const Integrations = () => {
+ const theme = useTheme();
+
+ return (
+
+
+
+
+
+ Header
+
+
+ This is a paragraph that provides more detail about the header.
+
+
+
+
+
+ );
+};
+
+export default Integrations;
diff --git a/Client/src/Pages/Home/index.jsx b/Client/src/Pages/Home/index.jsx
index ff5cb454e..a1ad8e314 100644
--- a/Client/src/Pages/Home/index.jsx
+++ b/Client/src/Pages/Home/index.jsx
@@ -2,6 +2,7 @@ import DropdownTeamMember from "../../Components/DropdownTeamMember";
import Search from "../../Components/Search";
import "./index.css";
import DashboardMenu from "../../Components/DashboardMenu";
+import Integrations from "../../Components/Integrations";
const Home = () => {
return (
@@ -10,6 +11,7 @@ const Home = () => {
+
>
);
};
diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js
index 793542cbf..8b2f72ab1 100644
--- a/Server/controllers/monitorController.js
+++ b/Server/controllers/monitorController.js
@@ -1,8 +1,11 @@
const {
- getMonitorsByIdValidation,
+ getMonitorByIdValidation,
getMonitorsByUserIdValidation,
+ monitorValidation,
} = require("../validation/joi");
+
const logger = require("../utils/logger");
+const Monitor = require("../models/Monitor");
/**
* Returns all monitors
@@ -31,10 +34,10 @@ const getAllMonitors = async (req, res) => {
* @throws {Error}
*/
const getMonitorById = async (req, res) => {
- const { error } = getMonitorsByIdValidation.validate(req.params);
+ const { error } = getMonitorByIdValidation.validate(req.params);
if (error) {
return res
- .status(400)
+ .status(422)
.json({ success: false, msg: error.details[0].message });
}
@@ -60,7 +63,7 @@ const getMonitorsByUserId = async (req, res) => {
const { error } = getMonitorsByUserIdValidation.validate(req.params);
if (error) {
return res
- .status(400)
+ .status(422)
.json({ success: false, msg: error.details[0].message });
}
@@ -82,4 +85,104 @@ const getMonitorsByUserId = async (req, res) => {
}
};
-module.exports = { getAllMonitors, getMonitorById, getMonitorsByUserId };
+/**
+ * Creates a new monitor
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @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 });
+ }
+
+ try {
+ const monitor = await req.db.createMonitor(req, res);
+ return res
+ .status(201)
+ .json({ success: true, msg: "Monitor created", data: monitor });
+ } catch (error) {
+ logger.error(error.message, { service: "monitor" });
+ return res.status(500).json({ success: false, msg: error.message });
+ }
+};
+
+/**
+ * Delete a monitor by ID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @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 });
+ }
+ try {
+ const monitor = await req.db.deleteMonitor(req, res);
+ /**
+ * TODO
+ * We should remove all checks and alerts associated with this monitor
+ * when it is deleted so there is no orphaned data
+ * We also need to make sure to stop all running services for this monitor
+ */
+ return res.status(204).json({ success: true, msg: "Monitor deleted" });
+ } catch (error) {
+ logger.error(error.message, { service: "monitor" });
+ return res.status(500).json({ success: false, msg: error.message });
+ }
+};
+
+/**
+ * Edit a monitor by ID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
+const editMonitor = async (req, res) => {
+ let paramError = getMonitorByIdValidation.validate(req.params);
+ if (paramError.error) {
+ 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 {
+ const editedMonitor = await req.db.editMonitor(req, res);
+ return res
+ .status(200)
+ .json({ success: true, msg: "Monitor edited", data: editedMonitor });
+ } catch (error) {
+ logger.error(error.message, { service: "monitor" });
+ return res.status(500).json({ success: false, msg: error.message });
+ }
+};
+
+module.exports = {
+ getAllMonitors,
+ getMonitorById,
+ getMonitorsByUserId,
+ createMonitor,
+ deleteMonitor,
+ editMonitor,
+};
diff --git a/Server/db/FakeDb.js b/Server/db/FakeDb.js
index a21b66ffd..b2abd919e 100644
--- a/Server/db/FakeDb.js
+++ b/Server/db/FakeDb.js
@@ -24,24 +24,9 @@ const Monitor = require("../models/Monitor");
const UserModel = require("../models/user");
const bcrypt = require("bcrypt");
-const FAKE_MONITOR_DATA = [];
+let FAKE_MONITOR_DATA = [];
const USERS = [];
-for (let i = 0; i < 10; i++) {
- FAKE_MONITOR_DATA.push(
- new Monitor({
- userId: i % 2 === 0 ? 1 : 2,
- name: `Monitor ${i}`,
- description: `Description for Monitor ${i}`,
- url: `https://monitor${i}.com`,
- isActive: true,
- interval: 60000,
- updated_at: new Date(),
- created_at: new Date(),
- })
- );
-}
-
const connect = async () => {
try {
await console.log("Connected to FakeDB");
@@ -99,10 +84,45 @@ const getMonitorsByUserId = async (userId) => {
if (userMonitors.length === 0) {
throw new Error(`Monitors for user ${userId} not found`);
}
-
return userMonitors;
};
+const createMonitor = async (req, res) => {
+ const monitor = new Monitor(req.body);
+ monitor.createdAt = Date.now();
+ monitor.updatedAt = Date.now();
+ FAKE_MONITOR_DATA.push(monitor);
+ return monitor;
+};
+
+const deleteMonitor = async (req, res) => {
+ const monitorId = req.params.monitorId;
+ try {
+ const monitor = getMonitorById(monitorId);
+ FAKE_MONITOR_DATA = FAKE_MONITOR_DATA.filter((monitor) => {
+ return monitor.id !== monitorId;
+ });
+ return monitor;
+ } catch (error) {
+ throw error;
+ }
+};
+
+const editMonitor = async (req, res) => {
+ const monitorId = req.params.monitorId;
+ const idx = FAKE_MONITOR_DATA.findIndex((monitor) => {
+ return monitor._id.toString() === monitorId;
+ });
+ const oldMonitor = FAKE_MONITOR_DATA[idx];
+ const editedMonitor = new Monitor({ ...req.body });
+ editedMonitor._id = oldMonitor._id;
+ editedMonitor.userId = oldMonitor.userId;
+ editedMonitor.updatedAt = Date.now();
+ editedMonitor.createdAt = oldMonitor.createdAt;
+ FAKE_MONITOR_DATA[idx] = editedMonitor;
+ return FAKE_MONITOR_DATA[idx];
+};
+
module.exports = {
connect,
insertUser,
@@ -110,4 +130,7 @@ module.exports = {
getAllMonitors,
getMonitorById,
getMonitorsByUserId,
+ createMonitor,
+ deleteMonitor,
+ editMonitor,
};
diff --git a/Server/db/MongoDB.js b/Server/db/MongoDB.js
index b6a126ab8..8fcc1dced 100644
--- a/Server/db/MongoDB.js
+++ b/Server/db/MongoDB.js
@@ -1,7 +1,6 @@
const Monitor = require("../models/Monitor");
const mongoose = require("mongoose");
const UserModel = require("../models/user");
-const user = require("../models/user");
const connect = async () => {
try {
@@ -13,6 +12,14 @@ const connect = async () => {
}
};
+/**
+ * Insert a User
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
const insertUser = async (req, res) => {
try {
const newUser = new UserModel({ ...req.body });
@@ -23,8 +30,16 @@ const insertUser = async (req, res) => {
}
};
-// Gets a user by Email. Not sure if we'll ever need this except for login.
-// If not needed except for login, we can move password comparison here
+/**
+ * Get User by Email
+ * Gets a user by Email. Not sure if we'll ever need this except for login.
+ * If not needed except for login, we can move password comparison here
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
const getUserByEmail = async (req, res) => {
try {
// Returns null if no user is found
@@ -36,17 +51,31 @@ const getUserByEmail = async (req, res) => {
}
};
-// Gets all monitors
+/**
+ * Get all monitors
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise>}
+ * @throws {Error}
+ */
const getAllMonitors = async (req, res) => {
try {
- const monitors = await Monitor.find();
+ const monitors = await Monitor.find({ isActive: true });
return monitors;
} catch (error) {
throw error;
}
};
-// Get a monitor by ID
+/**
+ * Get a monitor by ID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
const getMonitorById = async (req, res) => {
try {
const monitor = await Monitor.findById(req.params.monitorId);
@@ -56,7 +85,14 @@ const getMonitorById = async (req, res) => {
}
};
-// Gets a monitor by user ID
+/**
+ * Get monitors by UserID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise>}
+ * @throws {Error}
+ */
const getMonitorsByUserId = async (req, res) => {
try {
const monitors = await Monitor.find({ userId: req.params.userId });
@@ -66,6 +102,68 @@ const getMonitorsByUserId = async (req, res) => {
}
};
+/**
+ * Create a monitor
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
+const createMonitor = async (req, res) => {
+ try {
+ const monitor = new Monitor({ ...req.body });
+ await monitor.save();
+ return monitor;
+ } catch (error) {
+ throw error;
+ }
+};
+
+/**
+ * Delete a monitor by ID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
+const deleteMonitor = async (req, res) => {
+ const monitorId = req.params.monitorId;
+ try {
+ const monitor = await Monitor.findByIdAndDelete(monitorId);
+ if (!monitor) {
+ throw new Error(`Monitor with id ${monitorId} not found`);
+ }
+ return monitor;
+ } catch (error) {
+ throw error;
+ }
+};
+
+/**
+ * Edit a monitor by ID
+ * @async
+ * @param {Express.Request} req
+ * @param {Express.Response} res
+ * @returns {Promise}
+ * @throws {Error}
+ */
+const editMonitor = async (req, res) => {
+ const candidateId = req.params.monitorId;
+ const candidateMonitor = req.body;
+ try {
+ const editedMonitor = await Monitor.findByIdAndUpdate(
+ candidateId,
+ candidateMonitor,
+ { new: true }
+ );
+ return editedMonitor;
+ } catch (error) {
+ throw error;
+ }
+};
+
module.exports = {
connect,
insertUser,
@@ -73,4 +171,7 @@ module.exports = {
getAllMonitors,
getMonitorById,
getMonitorsByUserId,
+ createMonitor,
+ deleteMonitor,
+ editMonitor,
};
diff --git a/Server/models/Monitor.js b/Server/models/Monitor.js
index 513d4e2be..4aaad1497 100644
--- a/Server/models/Monitor.js
+++ b/Server/models/Monitor.js
@@ -1,37 +1,36 @@
const mongoose = require("mongoose");
-const MonitorSchema = mongoose.Schema({
- userId: {
- type: String,
+const MonitorSchema = mongoose.Schema(
+ {
+ userId: {
+ type: mongoose.Schema.Types.ObjectId,
+ ref: "User",
+ immutable: true,
+ },
+ name: {
+ type: String,
+ required: true,
+ },
+ description: {
+ type: String,
+ },
+ url: {
+ type: String,
+ required: true,
+ },
+ isActive: {
+ type: Boolean,
+ default: true,
+ },
+ interval: {
+ // in milliseconds
+ type: Number,
+ default: 60000,
+ },
},
- name: {
- type: String,
- required: true,
- },
- description: {
- type: String,
- },
- url: {
- type: String,
- required: true,
- },
- isActive: {
- type: Boolean,
- default: true,
- },
- interval: {
- // in milliseconds
- type: Number,
- default: 60000,
- },
- updated_at: {
- type: Date,
- default: Date.now,
- },
- created_at: {
- type: Date,
- default: Date.now,
- },
-});
+ {
+ timestamps: true,
+ }
+);
module.exports = mongoose.model("Monitor", MonitorSchema);
diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js
index e12982905..5f2ce4bb5 100644
--- a/Server/routes/monitorRoute.js
+++ b/Server/routes/monitorRoute.js
@@ -1,7 +1,11 @@
const router = require("express").Router();
const monitorController = require("../controllers/monitorController");
+
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);
module.exports = router;
diff --git a/Server/validation/joi.js b/Server/validation/joi.js
index 874daff93..ecc19253e 100644
--- a/Server/validation/joi.js
+++ b/Server/validation/joi.js
@@ -12,7 +12,7 @@ const registerValidation = joi.object({
password: joi.string().min(8).required(),
});
-const getMonitorsByIdValidation = joi.object({
+const getMonitorByIdValidation = joi.object({
monitorId: joi.string().required(),
});
@@ -20,9 +20,20 @@ const getMonitorsByUserIdValidation = joi.object({
userId: joi.string().required(),
});
+const monitorValidation = joi.object({
+ _id: joi.string(),
+ userId: joi.string().required(),
+ name: joi.string().required(),
+ description: joi.string().required(),
+ url: joi.string().uri().required(),
+ isActive: joi.boolean(),
+ interval: joi.number(),
+});
+
module.exports = {
loginValidation,
registerValidation,
- getMonitorsByIdValidation,
+ getMonitorByIdValidation,
getMonitorsByUserIdValidation,
+ monitorValidation,
};