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: diff --git a/Server/controllers/alertController.js b/Server/controllers/alertController.js new file mode 100644 index 000000000..91bb56971 --- /dev/null +++ b/Server/controllers/alertController.js @@ -0,0 +1,139 @@ +const express = require("express"); +const logger = require("../utils/logger"); +require("dotenv").config(); +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); + 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); + } +}; + +/** + * 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 = 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 = 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 = 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 = 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 = { + createAlert, + getAlertsByUserId, + getAlertsByMonitorId, + getAlertById, + editAlert, + deleteAlert, +}; 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/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) => { 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; diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 399c243dc..01a0d0ada 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -39,6 +39,47 @@ const editUserBodyValidation = joi.object({ profilePicUrl: joi.string(), }); +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, @@ -47,4 +88,12 @@ module.exports = { monitorValidation, editUserParamValidation, editUserBodyValidation, + createAlertParamValidation, + createAlertBodyValidation, + getAlertsByUserIdParamValidation, + getAlertsByMonitorIdParamValidation, + getAlertByIdParamValidation, + editAlertParamValidation, + editAlertBodyValidation, + deleteAlertParamValidation, };