From d2ab33492a08d9e90e66d89f07a0539cc5b2fe43 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 13:56:58 +0800 Subject: [PATCH 01/23] Update auth endpoints --- Server/controllers/authController.js | 17 --- Server/index.js | 12 ++- Server/openapi.json | 156 ++++++++++++++++----------- 3 files changed, 104 insertions(+), 81 deletions(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index a3e245ef3..f39ffb019 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -49,23 +49,6 @@ const registerController = async (req, res, next) => { next(error); return; } - - // TODO Can there be more than one admin? - // // Check if an admin user exists, if so, error - // try { - // const admin = await req.db.checkAdmin(req, res); - // console.log(admin); - // if (admin === true) { - // throw new Error(errorMessages.AUTH_ADMIN_EXISTS); - // } - // } catch (error) { - // console.log("WEEEEEEE", error.message); - // error.service = SERVICE_NAME; - // error.status = 403; - // next(error); - // return; - // } - // Create a new user try { const newUser = await req.db.insertUser({ ...req.body }, req.file); diff --git a/Server/index.js b/Server/index.js index 846b11e3d..672aa4882 100644 --- a/Server/index.js +++ b/Server/index.js @@ -1,3 +1,7 @@ +const path = require("path"); +const fs = require("fs"); +const swaggerUi = require("swagger-ui-express"); + const express = require("express"); const helmet = require("helmet"); const cors = require("cors"); @@ -21,8 +25,11 @@ const NetworkService = require("./service/networkService"); const EmailService = require("./service/emailService"); const PageSpeedService = require("./service/pageSpeedService"); const SERVICE_NAME = "Server"; -let cleaningUp = false; +let cleaningUp = false; +const openApiSpec = JSON.parse( + fs.readFileSync(path.join(__dirname, "openapi.json"), "utf8") +); // Need to wrap server setup in a function to handle async nature of JobQueue const startApp = async () => { // ************************** @@ -70,6 +77,9 @@ const startApp = async () => { next(); }); + // Swagger UI + app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(openApiSpec)); + //routes app.use("/api/v1/auth", authRouter); app.use("/api/v1/invite", inviteRouter); diff --git a/Server/openapi.json b/Server/openapi.json index 23c16521d..1f7294be3 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -81,7 +81,14 @@ "application/json": { "schema": { "type": "object", - "required": ["firstName", "lastName", "email", "password", "role", "teamId"], + "required": [ + "firstName", + "lastName", + "email", + "password", + "role", + "teamId" + ], "properties": { "firstName": { "type": "string" @@ -103,7 +110,7 @@ }, "role": { "type": "array", - "enum": [["user"], ["admin"], ["superadmin"]], + "enum": [["user"], ["admin"], ["superadmin"], ["Demo"]], "default": ["superadmin"] }, "teamId": { @@ -207,78 +214,54 @@ } } }, - "/auth/user/:userId": { + "/auth/user/{userId}": { "put": { "tags": ["auth"], - "description": "Change user informations", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" - } - } + "description": "Change user information", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" } - }, - "422": { - "description": "Unprocessable Content", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserUpdateRequest" } } } - } + }, + "security": [ + { + "bearerAuth": [] + } + ] }, "delete": { "tags": ["auth"], "description": "Delete user", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" - } - } - } - }, - "422": { - "description": "Unprocessable Content", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" } } - } + ], + "security": [ + { + "bearerAuth": [] + } + ] } }, "/auth/users/admin": { @@ -587,12 +570,20 @@ } }, "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + }, "schemas": { "ErrorResponse": { "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "default": false }, "msg": { "type": "string" @@ -613,6 +604,45 @@ } } }, + "UserUpdateRequest": { + "type": "object", + "required": [ + "firstName", + "lastName", + "email", + "password", + "role", + "teamId" + ], + "properties": { + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "password": { + "type": "string", + "format": "password" + }, + "newPassword": { + "type": "string", + "format": "password" + }, + "profileImage": { + "type": "file", + "format": "file" + }, + "role": { + "type": "array", + "enum": [["user"], ["admin"], ["superadmin"], ["Demo"]], + "default": ["superadmin"] + }, + "deleteProfileImage": { + "type": "boolean" + } + } + }, "UserSuccessResponse": { "type": "object", "properties": { From 7582dfdcc3e3e90e4536a9834784b78191bddb6a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 14:58:46 +0800 Subject: [PATCH 02/23] Update auth endpoints --- Server/openapi.json | 495 +++++++++++++------------------------------- 1 file changed, 144 insertions(+), 351 deletions(-) diff --git a/Server/openapi.json b/Server/openapi.json index 1f7294be3..b0cb8ebf8 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -128,7 +128,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -186,7 +186,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -238,6 +238,38 @@ } } }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, "security": [ { "bearerAuth": [] @@ -257,24 +289,13 @@ } } ], - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/auth/users/admin": { - "get": { - "tags": ["auth"], - "description": "Checks to see if an admin account exists", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -299,7 +320,55 @@ } } } - } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/auth/users/superadmin": { + "get": { + "tags": ["auth"], + "description": "Checks to see if an admin account exists", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] } }, "/auth/users": { @@ -312,7 +381,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -337,96 +406,41 @@ } } } - } - } - }, - "/auth/invite": { - "post": { - "tags": ["auth"], - "description": "Invite people to application", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" - } - } - } - }, - "422": { - "description": "Unprocessable Content", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } + }, + "security": [ + { + "bearerAuth": [] } - } - } - }, - "/auth/invite/verify": { - "post": { - "tags": ["auth"], - "description": "Verify the invite", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" - } - } - } - }, - "422": { - "description": "Unprocessable Content", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - } + ] } }, "/auth/recovery/request": { "post": { "tags": ["auth"], "description": "Request a recovery token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["email"], + "properties": { + "email": { + "type": "string", + "format": "email" + } + } + } + } + } + }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -458,13 +472,28 @@ "post": { "tags": ["auth"], "description": "Validate recovery token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["recoveryToken"], + "properties": { + "recoveryToken": { + "type": "string" + } + } + } + } + } + }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -496,13 +525,31 @@ "post": { "tags": ["auth"], "description": "Password reset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["recoveryToken", "password"], + "properties": { + "recoveryToken": { + "type": "string" + }, + "password": { + "type": "string" + } + } + } + } + } + }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/UserSuccessResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } @@ -529,44 +576,6 @@ } } } - }, - "/healthy": { - "get": { - "tags": ["healthy"], - "description": "Health check", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - } - } } }, "components": { @@ -594,7 +603,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "default": true }, "msg": { "type": "string" @@ -642,223 +652,6 @@ "type": "boolean" } } - }, - "UserSuccessResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean" - }, - "msg": { - "type": "string" - }, - "data": { - "type": "object", - "$ref": "#/components/schemas/UserDataType" - } - } - }, - "MonitorSuccessResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean" - }, - "msg": { - "type": "string" - }, - "data": { - "type": "object", - "$ref": "#/components/schemas/MonitorDataType" - } - } - }, - "CheckDataSuccessResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean" - }, - "msg": { - "type": "string" - }, - "data": { - "type": "object", - "$ref": "#/components/schemas/CheckDataType" - } - } - }, - "AlertDataSuccessResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean" - }, - "msg": { - "type": "string" - }, - "data": { - "type": "object", - "$ref": "#/components/schemas/AlertDataType" - } - } - }, - "UserDataType": { - "type": "object", - "required": [ - "firstname", - "lastname", - "email", - "profilePicUrl", - "isActive", - "isVerified", - "updatedAt", - "createdAt" - ], - "properties": { - "firstname": { - "type": "string" - }, - "lastname": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" - }, - "profilePicUrl": { - "type": "string" - }, - "isActive": { - "type": "boolean" - }, - "isVerified": { - "type": "boolean" - }, - "updatedAt": { - "type": "string" - }, - "createdAt": { - "type": "string" - } - } - }, - "MonitorDataType": { - "type": "object", - "required": [ - "userId", - "name", - "description", - "url", - "isActive", - "interval", - "updatedAt", - "createdAt" - ], - "properties": { - "userId": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "url": { - "type": "string" - }, - "isActive": { - "type": "boolean" - }, - "interval": { - "type": "integer" - }, - "updatedAt": { - "type": "string" - }, - "createdAt": { - "type": "string" - } - } - }, - "CheckDataType": { - "type": "object", - "required": [ - "monitorId", - "status", - "responseTime", - "statusCode", - "message", - "updatedAt", - "createdAt" - ], - "properties": { - "monitorId": { - "type": "string" - }, - "status": { - "type": "string" - }, - "responseTime": { - "type": "integer" - }, - "statusCode": { - "type": "integer" - }, - "message": { - "type": "string" - }, - "updatedAt": { - "type": "string" - }, - "createdAt": { - "type": "string" - } - } - }, - "AlertDataType": { - "type": "object", - "required": [ - "checkId", - "monitorId", - "userId", - "status", - "message", - "notifiedStatus", - "acknowledgedStatus", - "updatedAt", - "createdAt" - ], - "properties": { - "checkId": { - "type": "string" - }, - "monitorId": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "status": { - "type": "string" - }, - "message": { - "type": "string" - }, - "notifiedStatus": { - "type": "boolean" - }, - "acknowledgedStatus": { - "type": "boolean" - }, - "updatedAt": { - "type": "string" - }, - "createdAt": { - "type": "string" - } - } } } } From 0a49a070dbf3efdd69d31b672b34a53b5af08341 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:06:24 +0800 Subject: [PATCH 03/23] Add invite to swagger docs --- Server/openapi.json | 109 +++++++++++++++++++++++++++++++++++++++ Server/validation/joi.js | 1 - 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/Server/openapi.json b/Server/openapi.json index b0cb8ebf8..e76fcfe5e 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -576,6 +576,115 @@ } } } + }, + "/invite": { + "post": { + "tags": ["invite"], + "description": "Request an invitation", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["email", "role"], + "properties": { + "email": { + "type": "string" + }, + "role": { + "type": "array" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/invite/verify": { + "post": { + "tags": ["invite"], + "description": "Request an invitation", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["token"], + "properties": { + "token": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } } }, "components": { diff --git a/Server/validation/joi.js b/Server/validation/joi.js index dc82dc73e..60356332e 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -137,7 +137,6 @@ const inviteBodyValidation = joi.object({ "string.email": "Must be a valid email address", }), role: joi.array().required(), - teamId: joi.string().required(), }); const inviteVerifciationBodyValidation = joi.object({ From c9ab3d9fdef5313ce99824dbaf91d5a210fb977c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:09:05 +0800 Subject: [PATCH 04/23] Add security to invite docs --- Server/openapi.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Server/openapi.json b/Server/openapi.json index e76fcfe5e..f9afeb03f 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -630,7 +630,12 @@ } } } - } + }, + "security": [ + { + "bearerAuth": [] + } + ] } }, "/invite/verify": { @@ -683,7 +688,12 @@ } } } - } + }, + "security": [ + { + "bearerAuth": [] + } + ] } } }, From 53f2361a1058dedac18d9d39cc0d416f2d930581 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:12:38 +0800 Subject: [PATCH 05/23] add get all monitors to docs --- Server/openapi.json | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index f9afeb03f..da4ba7d53 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -695,6 +695,49 @@ } ] } + }, + "/monitors": { + "get": { + "tags": ["monitors"], + "description": "Get all monitors", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, "components": { From bd03964ab6b66eb088ff46d54e6aecedb2f78b36 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:20:45 +0800 Subject: [PATCH 06/23] Add get monitor stats by ID to docs --- Server/controllers/monitorController.js | 43 -------------------- Server/openapi.json | 54 +++++++++++++++++++++++++ Server/routes/monitorRoute.js | 1 - Server/validation/joi.js | 9 ----- 4 files changed, 54 insertions(+), 53 deletions(-) diff --git a/Server/controllers/monitorController.js b/Server/controllers/monitorController.js index f5bd98b74..e534e0f60 100644 --- a/Server/controllers/monitorController.js +++ b/Server/controllers/monitorController.js @@ -44,48 +44,6 @@ const getAllMonitors = async (req, res, next) => { } }; -/** - * Returns agregate stats for a monitor - * @async - * @param {Express.Request} req - * @param {Express.Response} res - * @returns {Promise} - * @throws {Error} - */ - -const getMonitorAggregateStats = async (req, res, next) => { - try { - await getMonitorAggregateStatsParamValidation.validateAsync(req.params); - await getMonitorAggregateStatsQueryValidation.validateAsync(req.query); - } catch (error) { - error.status = 422; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - - try { - const { monitorId } = req.params; - const dateRange = req.query.dateRange; - const aggregateStats = await req.db.getMonitorAggregateStats( - monitorId, - dateRange - ); - return res.json({ - success: true, - msg: successMessages.MONTIOR_STATS_BY_ID, - data: aggregateStats, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined - ? (error.method = "getMonitorAggregateStats") - : null; - next(error); - } -}; - /** * Returns monitor stats for monitor with matching ID * @async @@ -516,7 +474,6 @@ const addDemoMonitors = async (req, res, next) => { module.exports = { getAllMonitors, - getMonitorAggregateStats, getMonitorStatsById, getMonitorCertificate, getMonitorById, diff --git a/Server/openapi.json b/Server/openapi.json index da4ba7d53..a4129a8ba 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -738,8 +738,62 @@ } ] } + }, + "/monitors/stats/{monitorId}": { + "get": { + "tags": ["monitors"], + "description": "Get monitor stats", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, + "components": { "securitySchemes": { "bearerAuth": { diff --git a/Server/routes/monitorRoute.js b/Server/routes/monitorRoute.js index c6bec5f0f..aaa9c10e9 100644 --- a/Server/routes/monitorRoute.js +++ b/Server/routes/monitorRoute.js @@ -3,7 +3,6 @@ const monitorController = require("../controllers/monitorController"); const { isAllowed } = require("../middleware/isAllowed"); router.get("/", monitorController.getAllMonitors); -router.get("/aggregate/:monitorId", monitorController.getMonitorAggregateStats); router.get("/stats/:monitorId", monitorController.getMonitorStatsById); router.get("/certificate/:monitorId", monitorController.getMonitorCertificate); router.get("/:monitorId", monitorController.getMonitorById); diff --git a/Server/validation/joi.js b/Server/validation/joi.js index 60356332e..f61432595 100644 --- a/Server/validation/joi.js +++ b/Server/validation/joi.js @@ -235,13 +235,6 @@ const pauseMonitorParamValidation = joi.object({ monitorId: joi.string().required(), }); -const getMonitorAggregateStatsParamValidation = joi.object({ - monitorId: joi.string().required(), -}); -const getMonitorAggregateStatsQueryValidation = joi.object({ - dateRange: joi.string().valid("day", "week", "month"), -}); - //**************************************** // Alerts //**************************************** @@ -407,8 +400,6 @@ module.exports = { getMonitorStatsByIdParamValidation, getMonitorStatsByIdQueryValidation, getCertificateParamValidation, - getMonitorAggregateStatsParamValidation, - getMonitorAggregateStatsQueryValidation, editMonitorBodyValidation, pauseMonitorParamValidation, editUserParamValidation, From fd483b1857560d070f4b6a29ed0e692105c0987f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:23:40 +0800 Subject: [PATCH 07/23] Add get certificate by monitor ID to docs --- Server/openapi.json | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index a4129a8ba..7956c2f75 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -791,6 +791,59 @@ } ] } + }, + "/monitors/certificate/{monitorId}": { + "get": { + "tags": ["monitors"], + "description": "Get monitor certificate", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, From 1697e853e64114fe41f9b708f95008bd6d5ce85d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:27:01 +0800 Subject: [PATCH 08/23] Add getMonitorById to docs --- Server/openapi.json | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index 7956c2f75..595f2a0ce 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -739,6 +739,59 @@ ] } }, + "/monitors/{monitorId}": { + "get": { + "tags": ["monitors"], + "description": "Get monitor by id", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, "/monitors/stats/{monitorId}": { "get": { "tags": ["monitors"], From db4dbc6a5f6be5a4aeee8f7388477deaecfdacef Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Sep 2024 15:38:27 +0800 Subject: [PATCH 09/23] Add getMonitorsAndSummaryByTeamID to docs --- Server/openapi.json | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index 595f2a0ce..ef6a8ae2c 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -897,6 +897,68 @@ } ] } + }, + "/monitors/team/summary/{teamId}": { + "get": { + "tags": ["monitors"], + "description": "Get monitors and summary by teamId", + "parameters": [ + { + "name": "teamId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "type": "array", + "enum": ["http", "ping", "pagespeed"] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, From fe97390e53de865ffc85f9fb6ef8fc961593a458 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 10:54:56 +0800 Subject: [PATCH 10/23] Added put and delete to monitors docs --- Server/openapi.json | 266 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index ef6a8ae2c..8e71d07a0 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -737,6 +737,97 @@ "bearerAuth": [] } ] + }, + "post": { + "tags": ["monitors"], + "description": "Create a new monitor", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMonitorBody" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": ["monitors"], + "description": "Delete all monitors", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] } }, "/monitors/{monitorId}": { @@ -959,6 +1050,141 @@ } ] } + }, + "/monitors/team/{teamId}": { + "get": { + "tags": ["monitors"], + "description": "Get monitors by teamId", + "parameters": [ + { + "name": "teamId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "description": "Status of monitor, true for up, false for down", + "in": "query", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "name": "checkOrder", + "description": "Order of checks", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": ["asc", "desc"] + } + }, + { + "name": "limit", + "description": "Number of checks to return with monitor", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "type", + "description": "Type of monitor", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": ["http", "ping", "pagespeed"] + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "rowsPerPage", + "in": "query", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "filter", + "description": "Value to filter by", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "field", + "description": "Field to filter on", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "order", + "description": "Sort order of results", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": ["http", "ping", "pagespeed"] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, @@ -1036,6 +1262,46 @@ "type": "boolean" } } + }, + "CreateMonitorBody": { + "type": "object", + "required": ["userId", "teamId", "name", "description", "type", "url"], + "properties": { + "_id": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "teamId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["http", "ping", "pagespeed"] + }, + "url": { + "type": "string" + }, + "isActive": { + "type": "boolean" + }, + "interval": { + "type": "integer" + }, + "notifications": { + "type": "array", + "items": { + "type": "string" + } + } + } } } } From 17f2039fc221b69befcc6e731fa91917cf769378 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 10:57:44 +0800 Subject: [PATCH 11/23] Add delete to monitors/:monitorId doc --- Server/openapi.json | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index 8e71d07a0..e03ca93ac 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -881,6 +881,57 @@ "bearerAuth": [] } ] + }, + "delete": { + "tags": ["monitors"], + "description": "Delete monitor by id", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] } }, "/monitors/stats/{monitorId}": { From 24863a2fb72cc8d516fac95126a117ccb1a2d811 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:03:50 +0800 Subject: [PATCH 12/23] Add put to monitors/:monitorId doc --- Server/openapi.json | 80 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index e03ca93ac..0d07292e6 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -882,6 +882,66 @@ } ] }, + "put": { + "tags": ["monitors"], + "description": "Update monitor by id", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMonitorBody" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, "delete": { "tags": ["monitors"], "description": "Delete monitor by id", @@ -1353,6 +1413,26 @@ } } } + }, + "UpdateMonitorBody": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "interval": { + "type": "integer" + }, + "notifications": { + "type": "array", + "items": { + "type": "string" + } + } + } } } } From 7a78a6d6b0d02c6e0691e94ab748714f3379d454 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:10:05 +0800 Subject: [PATCH 13/23] Add pause and add demo routes to docs --- Server/openapi.json | 105 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index 0d07292e6..0117c8b0f 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -1296,6 +1296,111 @@ } ] } + }, + "/monitors/pause/{monitorId}": { + "post": { + "tags": ["monitors"], + "description": "Pause monitor", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/monitors/demo": { + "post": { + "tags": ["monitors"], + "description": "Create a demo monitor", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMonitorBody" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, From 05f1b2b6b463895d41c10b3135bfea95f4f9d457 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:23:36 +0800 Subject: [PATCH 14/23] Add getCheck createCheck routes to docs --- Server/openapi.json | 140 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index 0117c8b0f..28718098f 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -1401,6 +1401,119 @@ } ] } + }, + "/checks/{monitorId}": { + "get": { + "tags": ["checks"], + "description": "Get all checks for a monitor", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": ["checks"], + "description": "Create a new check", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCheckBody" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, @@ -1538,6 +1651,33 @@ } } } + }, + "CreateCheckBody": { + "type": "object", + "required": [ + "monitorId", + "status", + "responseTime", + "statusCode", + "message" + ], + "properties": { + "monitorId": { + "type": "string" + }, + "status": { + "type": "boolean" + }, + "responseTime": { + "type": "integer" + }, + "statusCode": { + "type": "integer" + }, + "message": { + "type": "string" + } + } } } } From 885a89e36b6b8a01e656a231bfef1465fe1f691b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:29:20 +0800 Subject: [PATCH 15/23] Add getChecksByTeam route --- Server/openapi.json | 104 ++++++++++++++++++++++++++++++++++++ Server/routes/checkRoute.js | 8 ++- 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/Server/openapi.json b/Server/openapi.json index 28718098f..d33fb03e1 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -1513,6 +1513,110 @@ "bearerAuth": [] } ] + }, + "delete": { + "tags": ["checks"], + "description": "Delete all checks for a monitor", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/checks/team/{teamId}": { + "get": { + "tags": ["checks"], + "description": "Get all checks for a team", + "parameters": [ + { + "name": "teamId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] } } }, diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index a26e9eb94..84e7f47a8 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -4,22 +4,20 @@ const { verifyOwnership } = require("../middleware/verifyOwnership"); const { isAllowed } = require("../middleware/isAllowed"); const Monitor = require("../models/Monitor"); +router.get("/:monitorId", checkController.getChecks); router.post( "/:monitorId", verifyOwnership(Monitor, "monitorId"), checkController.createCheck ); - -router.get("/:monitorId", checkController.getChecks); - -router.get("/team/:teamId", checkController.getTeamChecks); - router.delete( "/:monitorId", verifyOwnership(Monitor, "monitorId"), checkController.deleteChecks ); +router.get("/team/:teamId", checkController.getTeamChecks); + router.delete( "/team/:teamId", isAllowed(["admin", "superadmin"]), From c44152de93ea4812bc9fe4f84b2b0833f7f999d1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:30:59 +0800 Subject: [PATCH 16/23] Add deleteChecksByTeam route --- Server/openapi.json | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/Server/openapi.json b/Server/openapi.json index d33fb03e1..b1b23ce4b 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -1617,6 +1617,57 @@ "bearerAuth": [] } ] + }, + "delete": { + "tags": ["checks"], + "description": "Delete all checks for a team", + "parameters": [ + { + "name": "teamId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] } } }, From 36014fada2b4c185feeaa48c05ebd34faafa5a25 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:37:52 +0800 Subject: [PATCH 17/23] refactor ttl endpoint path, add /team/ttl to docs --- Client/src/Utils/NetworkService.js | 2 +- Server/openapi.json | 61 ++++++++++++++++++++++++++++++ Server/routes/checkRoute.js | 2 +- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Client/src/Utils/NetworkService.js b/Client/src/Utils/NetworkService.js index c087fb73a..905385e70 100644 --- a/Client/src/Utils/NetworkService.js +++ b/Client/src/Utils/NetworkService.js @@ -609,7 +609,7 @@ class NetworkService { */ async updateChecksTTL(config) { return this.axiosInstance.put( - `/checks/ttl`, + `/checks/team/ttl`, { ttl: config.ttl }, { headers: { diff --git a/Server/openapi.json b/Server/openapi.json index b1b23ce4b..dd9a3ae8b 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -1669,6 +1669,58 @@ } ] } + }, + "/checks/team/ttl": { + "put": { + "tags": ["checks"], + "description": "Update check TTL", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCheckTTLBody" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, @@ -1833,6 +1885,15 @@ "type": "string" } } + }, + "UpdateCheckTTLBody": { + "type": "object", + "required": ["ttl"], + "properties": { + "ttl": { + "type": "integer" + } + } } } } diff --git a/Server/routes/checkRoute.js b/Server/routes/checkRoute.js index 84e7f47a8..fe99e7271 100644 --- a/Server/routes/checkRoute.js +++ b/Server/routes/checkRoute.js @@ -25,7 +25,7 @@ router.delete( ); router.put( - "/ttl", + "/team/ttl", isAllowed(["admin", "superadmin"]), checkController.updateChecksTTL ); From 115831ca34f49725ba9d74e6673d002757e1aa77 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:41:50 +0800 Subject: [PATCH 18/23] Remove unsued alert module --- Server/controllers/alertController.js | 192 ------------------------- Server/db/mongo/MongoDB.js | 21 --- Server/db/mongo/modules/alertModule.js | 140 ------------------ Server/index.js | 2 - Server/models/Alert.js | 38 ----- Server/routes/alertRoute.js | 44 ------ 6 files changed, 437 deletions(-) delete mode 100644 Server/controllers/alertController.js delete mode 100644 Server/db/mongo/modules/alertModule.js delete mode 100644 Server/models/Alert.js delete mode 100644 Server/routes/alertRoute.js diff --git a/Server/controllers/alertController.js b/Server/controllers/alertController.js deleted file mode 100644 index cd31db565..000000000 --- a/Server/controllers/alertController.js +++ /dev/null @@ -1,192 +0,0 @@ -const logger = require("../utils/logger"); -require("dotenv").config(); -const { - createAlertParamValidation, - createAlertBodyValidation, - getAlertsByUserIdParamValidation, - getAlertsByMonitorIdParamValidation, - getAlertByIdParamValidation, - editAlertParamValidation, - editAlertBodyValidation, - deleteAlertParamValidation, -} = require("../validation/joi"); -const { successMessages } = require("../utils/messages"); -const SERVICE_NAME = "alertController"; - -/** - * 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.message || "Validation Error"; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - const alertData = { ...req.body }; - const alert = await req.db.createAlert(alertData); - return res - .status(200) - .json({ success: true, msg: successMessages.ALERT_CREATE, data: alert }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "createAlert") : null; - 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.message || "Validation Error"; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - const alerts = await req.db.getAlertsByUserId(req.params.userId); - return res.status(200).json({ - success: true, - msg: successMessages.ALERT_GET_BY_USER, - data: alerts, - }); - } catch (error) { - error.service = SERVICE_NAME; - next(error); - } -}; - -const getAlertsByMonitorId = async (req, res, next) => { - try { - await getAlertsByMonitorIdParamValidation.validateAsync(req.params); - } catch (error) { - error.status = 422; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - const alerts = await req.db.getAlertsByMonitorId(req.params.monitorId); - return res.status(200).json({ - success: true, - msg: successMessages.ALERT_GET_BY_MONITOR, - data: alerts, - }); - } catch (error) { - error.service = SERVICE_NAME; - next(error); - } -}; - -const getAlertById = async (req, res, next) => { - try { - await getAlertByIdParamValidation.validateAsync(req.params); - } catch (error) { - error.status = 422; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - const alert = await req.db.getAlertById(req.params.alertId); - return res.status(200).json({ - success: true, - msg: successMessages.ALERT_GET_BY_ID, - data: alert, - }); - } catch (error) { - error.service = SERVICE_NAME; - next(error); - } -}; - -const editAlert = async (req, res, next) => { - try { - await editAlertParamValidation.validateAsync(req.params); - await editAlertBodyValidation.validateAsync(req.body); - } catch (error) { - console.log(error); - error.status = 422; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - const alertData = { ...req.body }; - const alert = await req.db.editAlert(req.params.alertId, alertData); - return res.status(200).json({ - success: true, - msg: successMessages.ALERT_EDIT, - data: alert, - }); - } catch (error) { - error.service = SERVICE_NAME; - next(error); - } -}; -const deleteAlert = async (req, res, next) => { - try { - await deleteAlertParamValidation.validateAsync(req.params); - } catch (error) { - error.status = 422; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - error.service = SERVICE_NAME; - next(error); - return; - } - - try { - const deleted = await req.db.deleteAlert(req.params.alertId); - return res.status(200).json({ - success: true, - msg: successMessages.ALERT_DELETE, - data: deleted, - }); - } catch (error) { - error.service = SERVICE_NAME; - next(error); - } -}; - -module.exports = { - createAlert, - getAlertsByUserId, - getAlertsByMonitorId, - getAlertById, - editAlert, - deleteAlert, -}; diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index ebc50f7da..c5fcff08c 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -100,20 +100,6 @@ const { updateChecksTTL, } = require("./modules/checkModule"); -//**************************************** -// Alerts -//**************************************** - -const { - createAlert, - getAlertsByUserId, - getAlertsByMonitorId, - getAlertById, - editAlert, - deleteAlert, - deleteAlertByMonitorId, -} = require("./modules/alertModule"); - //**************************************** // Maintenance Window //**************************************** @@ -163,13 +149,6 @@ module.exports = { deleteChecks, deleteChecksByTeamId, updateChecksTTL, - createAlert, - getAlertsByUserId, - getAlertsByMonitorId, - getAlertById, - editAlert, - deleteAlert, - deleteAlertByMonitorId, deleteMonitorsByUserId, createPageSpeedCheck, getPageSpeedChecks, diff --git a/Server/db/mongo/modules/alertModule.js b/Server/db/mongo/modules/alertModule.js deleted file mode 100644 index b9e65647b..000000000 --- a/Server/db/mongo/modules/alertModule.js +++ /dev/null @@ -1,140 +0,0 @@ -const Alert = require("../../../models/Alert"); - -/** - * Creates an Alert associated with a Monitor and User - * @async - * @param {Object} alertData - * @param {string} alertData.checkId - * @param {string} alert.monitorId - * @param {string} alert.userId - * @param {boolean} alert.status - * @param {string} alert.message - * @param {boolean} alert.notifiedStatus - * @param {boolean} alert.acknowledgeStatus - * @returns {>} - * @throws {Error} - */ -const createAlert = async (alertData) => { - try { - const alert = await new Alert({ ...alertData }).save(); - return alert; - } catch (error) { - throw error; - } -}; - -/** - * Gets all alerts a User has set - * @async - * @param {string} userId - * @returns {>} - * @throws {Error} - */ -const getAlertsByUserId = async (userId) => { - try { - const alerts = await Alert.find({ userId }); - return alerts; - } catch (error) { - throw error; - } -}; - -/** - * Gets all alerts a for an associated Monitor - * @async - * @param {string} monitorId - * @returns {>} - * @throws {Error} - */ -const getAlertsByMonitorId = async (monitorId) => { - try { - const alerts = await Alert.find({ monitorId }); - return alerts; - } catch (error) { - throw error; - } -}; - -/** - * Returns an alert with specified ID - * @async - * @param {string} alertId - * @returns {Promise} - * @throws {Error} - */ -const getAlertById = async (alertId) => { - try { - const alert = await Alert.findById(alertId); - return alert; - } catch (error) { - throw error; - } -}; - -/** - * Returns an edited alert with the specified ID - * @async - * @param {string} alertId - * @param {Object} alertData - * @param {string} alertData.checkId - * @param {string} alertData.monitorId - * @param {string} alertData.userId - * @param {boolean} alertData.status - * @param {string} alertData.message - * @param {boolean} alertData.notifiedStatus - * @param {boolean} alertData.acknowledgeStatus - * @param {Express.Response} res - * @returns {Promise>} - * @throws {Error} - */ -const editAlert = async (alertId, alertData) => { - try { - const editedAlert = await Alert.findByIdAndUpdate(alertId, alertData, { - new: true, - }); - return editedAlert; - } catch (error) { - throw error; - } -}; - -/** - * Deletes an alert with the specified ID - * @async - * @param {string} alertId - * @throws {Error} - */ -const deleteAlert = async (alertId) => { - try { - const result = await Alert.findByIdAndDelete(alertId); - return result; - } catch (error) { - throw error; - } -}; - -/** - * Deletes alerts by monitor ID. - * - * @param {string} monitorId - The ID of the monitor. - * @returns {Promise} A promise that resolves to the result of the delete operation. - * @throws {Error} If an error occurs while deleting the alerts. - */ -const deleteAlertByMonitorId = async (monitorId) => { - try { - const result = await Alert.deleteMany({ monitorId }); - return result; - } catch (error) { - throw error; - } -}; - -module.exports = { - createAlert, - getAlertsByUserId, - getAlertsByMonitorId, - getAlertById, - editAlert, - deleteAlert, - deleteAlertByMonitorId, -}; diff --git a/Server/index.js b/Server/index.js index 672aa4882..e665f21d2 100644 --- a/Server/index.js +++ b/Server/index.js @@ -14,7 +14,6 @@ const authRouter = require("./routes/authRoute"); const inviteRouter = require("./routes/inviteRoute"); const monitorRouter = require("./routes/monitorRoute"); const checkRouter = require("./routes/checkRoute"); -const alertRouter = require("./routes/alertRoute"); const pageSpeedCheckRouter = require("./routes/pageSpeedCheckRoute"); const maintenanceWindowRouter = require("./routes/maintenanceWindowRoute"); @@ -85,7 +84,6 @@ const startApp = async () => { app.use("/api/v1/invite", inviteRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); - app.use("/api/v1/alerts", verifyJWT, alertRouter); app.use("/api/v1/pagespeed", verifyJWT, pageSpeedCheckRouter); app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRouter); //Temporary route for testing, remove later diff --git a/Server/models/Alert.js b/Server/models/Alert.js deleted file mode 100644 index 758a7eba2..000000000 --- a/Server/models/Alert.js +++ /dev/null @@ -1,38 +0,0 @@ -const mongoose = require('mongoose') - -const AlertSchema = mongoose.Schema( - { - checkId: { - type: mongoose.Schema.Types.ObjectId, - 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, - }, - message: { - type: String, - }, - notifiedStatus: { - type: Boolean, - }, - acknowledgeStatus: { - type: Boolean, - } - }, - { - timestamps: true, - } -); - -module.exports = mongoose.model('Alert', AlertSchema); diff --git a/Server/routes/alertRoute.js b/Server/routes/alertRoute.js deleted file mode 100644 index 434c0495a..000000000 --- a/Server/routes/alertRoute.js +++ /dev/null @@ -1,44 +0,0 @@ -const router = require("express").Router(); -const alertController = require("../controllers/alertController"); -const { verifyOwnership } = require("../middleware/verifyOwnership"); -const Alert = require("../models/Alert"); -const Monitor = require("../models/Monitor"); - -// Create alert -router.post( - "/:monitorId", - verifyOwnership(Monitor, "monitorId"), - alertController.createAlert -); -// Get all alerts for a user -router.get( - "/user/:userId", - verifyOwnership(Monitor, "monitorId"), - alertController.getAlertsByUserId -); -// Get all alerts for a monitor -router.get( - "/monitor/:monitorId", - verifyOwnership(Monitor, "monitorId"), - alertController.getAlertsByMonitorId -); -// Get a single alert -router.get( - "/:alertId", - verifyOwnership(Monitor, "monitorId"), - alertController.getAlertById -); -// Edit -router.put( - "/:alertId", - verifyOwnership(Monitor, "monitorId"), - alertController.editAlert -); -//Delete -router.delete( - "/:alertId", - verifyOwnership(Monitor, "monitorId"), - alertController.deleteAlert -); - -module.exports = router; From d849374225828db219b2171b2e0409f381a8b5a9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:49:28 +0800 Subject: [PATCH 19/23] remove unused routes from docs --- Server/openapi.json | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Server/openapi.json b/Server/openapi.json index dd9a3ae8b..2c5097649 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -50,25 +50,9 @@ "name": "checks", "description": "Checks" }, - { - "name": "alerts", - "description": "Alerts" - }, - { - "name": "pagespeed", - "description": "Page Speed" - }, { "name": "maintenance-window", "description": "Maintenance window" - }, - { - "name": "healthy", - "description": "Health check" - }, - { - "name": "mail", - "description": "Mail service" } ], "paths": { From f2407ac5fa7ea04ee729f63966009ba3e5494e97 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 11:52:39 +0800 Subject: [PATCH 20/23] Remove unused pagespeed modules --- .../controllers/pageSpeedCheckController.js | 129 ------------------ Server/index.js | 2 - Server/routes/pageSpeedCheckRoute.js | 45 ------ 3 files changed, 176 deletions(-) delete mode 100644 Server/controllers/pageSpeedCheckController.js delete mode 100644 Server/routes/pageSpeedCheckRoute.js diff --git a/Server/controllers/pageSpeedCheckController.js b/Server/controllers/pageSpeedCheckController.js deleted file mode 100644 index b07fac4d7..000000000 --- a/Server/controllers/pageSpeedCheckController.js +++ /dev/null @@ -1,129 +0,0 @@ -const PageSpeedService = require("../service/pageSpeedService"); -const { successMessages } = require("../utils/messages"); -const pageSpeedService = new PageSpeedService(); -const SERVICE_NAME = "pagespeedCheckController"; -const { - getPageSpeedCheckParamValidation, - createPageSpeedCheckParamValidation, - createPageSpeedCheckBodyValidation, - deletePageSpeedCheckParamValidation, -} = require("../validation/joi"); - -/** - * Gets all PageSpeedChecks for a monitor - * @async - * @param {Express.Request} req - The request object - * @param {Express.Response} res - The response object - * @param {Function} next - The next middleware function - * @returns {Promise} - */ -const getPageSpeedChecks = async (req, res, next) => { - try { - // Validate monitorId parameter - await getPageSpeedCheckParamValidation.validateAsync(req.params); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - - try { - return res.status(200).json({ msg: "Hit getPageSpeedChecks" }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "getPageSpeedChecks") : null; - next(error); - } -}; - -/** - * Creates a new PageSpeedCheck for a monitor - * @async - * @param {Express.Request} req - The request object - * @param {Express.Response} res - The response object - * @param {Function} next - The next middleware function - * @returns {Promise} - */ -const createPageSpeedCheck = async (req, res, next) => { - try { - await createPageSpeedCheckParamValidation.validateAsync(req.params); - await createPageSpeedCheckBodyValidation.validateAsync(req.body); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - - try { - const { monitorId } = req.params; - const { url } = req.body; - - // Run the PageSpeed check - const pageSpeedResults = await pageSpeedService.runPageSpeedCheck(url); - - // Extract categories scores - const categories = pageSpeedResults.lighthouseResult?.categories; - - if (!categories) { - throw new Error("Categories not found in PageSpeed results"); - } - - const newPageSpeedCheck = await pageSpeedService.createPageSpeedCheck({ - monitorId, - accessibility: (categories.accessibility?.score || 0) * 100, - bestPractices: (categories["best-practices"]?.score || 0) * 100, - seo: (categories.seo?.score || 0) * 100, - performance: (categories.performance?.score || 0) * 100, - }); - - return res.status(201).json({ - msg: successMessages.CREATED, - data: newPageSpeedCheck, - }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "createPageSpeedCheck") : null; - next(error); - } -}; - -/** - * Deletes all PageSpeedChecks for a monitor - * @async - * @param {Express.Request} req - The request object - * @param {Express.Response} res - The response object - * @param {Function} next - The next middleware function - * @returns {Promise} - */ -const deletePageSpeedCheck = async (req, res, next) => { - try { - // Validate monitorId parameter - await deletePageSpeedCheckParamValidation.validateAsync(req.params); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - try { - return res.status(200).json({ msg: "Hit deletePageSpeedCheck" }); - } catch (error) { - error.service === undefined ? (error.service = SERVICE_NAME) : null; - error.method === undefined ? (error.method = "deletePageSpeedCheck") : null; - next(error); - } -}; - -module.exports = { - getPageSpeedChecks, - createPageSpeedCheck, - deletePageSpeedCheck, -}; diff --git a/Server/index.js b/Server/index.js index e665f21d2..25f70a532 100644 --- a/Server/index.js +++ b/Server/index.js @@ -14,7 +14,6 @@ const authRouter = require("./routes/authRoute"); const inviteRouter = require("./routes/inviteRoute"); const monitorRouter = require("./routes/monitorRoute"); const checkRouter = require("./routes/checkRoute"); -const pageSpeedCheckRouter = require("./routes/pageSpeedCheckRoute"); const maintenanceWindowRouter = require("./routes/maintenanceWindowRoute"); const { connectDbAndRunServer } = require("./configs/db"); @@ -84,7 +83,6 @@ const startApp = async () => { app.use("/api/v1/invite", inviteRouter); app.use("/api/v1/monitors", verifyJWT, monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); - app.use("/api/v1/pagespeed", verifyJWT, pageSpeedCheckRouter); app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRouter); //Temporary route for testing, remove later app.use("/api/v1/job", queueRouter); diff --git a/Server/routes/pageSpeedCheckRoute.js b/Server/routes/pageSpeedCheckRoute.js deleted file mode 100644 index 4b1de49bc..000000000 --- a/Server/routes/pageSpeedCheckRoute.js +++ /dev/null @@ -1,45 +0,0 @@ -const router = require("express").Router(); -const { verifyOwnership } = require("../middleware/verifyOwnership"); -const Monitor = require("../models/Monitor"); -const pageSpeedCheckController = require("../controllers/pageSpeedCheckController"); - -/** - * @route POST /:monitorId - * @description Create a new PageSpeedCheck for a monitor - * @access Private - * @param {string} monitorId - The ID of the monitor - * @middleware verifyOwnership - Ensures the user owns the monitor - */ -router.post( - "/:monitorId", - verifyOwnership(Monitor, "monitorId"), - pageSpeedCheckController.createPageSpeedCheck -); - -/** - * @route GET /:monitorId - * @description Get all PageSpeedChecks for a monitor - * @access Private - * @param {string} monitorId - The ID of the monitor - * @middleware verifyOwnership - Ensures the user owns the monitor - */ -router.get( - "/:monitorId", - verifyOwnership(Monitor, "monitorId"), - pageSpeedCheckController.getPageSpeedChecks -); - -/** - * @route DELETE /:monitorId - * @description Delete all PageSpeedChecks for a monitor - * @access Private - * @param {string} monitorId - The ID of the monitor - * @middleware verifyOwnership - Ensures the user owns the monitor - */ -router.delete( - "/:monitorId", - verifyOwnership(Monitor, "monitorId"), - pageSpeedCheckController.deletePageSpeedCheck -); - -module.exports = router; From 35d2d8301ec12ed63fa5e605808ecd3a4cfc761b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 12:11:18 +0800 Subject: [PATCH 21/23] Add maintenance window routes to docs --- Server/openapi.json | 197 ++++++++++++++++++++++++ Server/routes/maintenanceWindowRoute.js | 14 +- 2 files changed, 204 insertions(+), 7 deletions(-) diff --git a/Server/openapi.json b/Server/openapi.json index 2c5097649..a7de094f4 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -53,6 +53,10 @@ { "name": "maintenance-window", "description": "Maintenance window" + }, + { + "name": "queue", + "description": "Queue" } ], "paths": { @@ -1705,6 +1709,172 @@ } ] } + }, + "/maintenance-window/monitor/{monitorId}": { + "get": { + "tags": ["maintenance-window"], + "description": "Get maintenance window for monitor", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": ["maintenance-window"], + "description": "Create maintenance window for monitor", + "parameters": [ + { + "name": "monitorId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMaintenanceWindowBody" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/maintenance-window/user/{userId}": { + "get": { + "tags": ["maintenance-window"], + "description": "Get maintenance window for user", + "parameters": [ + { + "name": "userId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, @@ -1878,6 +2048,33 @@ "type": "integer" } } + }, + "CreateMaintenanceWindowBody": { + "type": "object", + "required": ["userId", "active", "oneTime", "start", "end"], + "properties": { + "userId": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "oneTime": { + "type": "boolean" + }, + "start": { + "type": "string", + "format": "date-time" + }, + "end": { + "type": "string", + "format": "date-time" + }, + "expiry": { + "type": "string", + "format": "date-time" + } + } } } } diff --git a/Server/routes/maintenanceWindowRoute.js b/Server/routes/maintenanceWindowRoute.js index 876e9e668..c357df76b 100644 --- a/Server/routes/maintenanceWindowRoute.js +++ b/Server/routes/maintenanceWindowRoute.js @@ -3,8 +3,14 @@ const maintenanceWindowController = require("../controllers/maintenanceWindowCon const { verifyOwnership } = require("../middleware/verifyOwnership"); const Monitor = require("../models/Monitor"); +router.get( + "/monitor/:monitorId", + verifyOwnership(Monitor, "monitorId"), + maintenanceWindowController.getMaintenanceWindowsByMonitorId +); + router.post( - "/:monitorId", + "/monitor/:monitorId", verifyOwnership(Monitor, "monitorId"), maintenanceWindowController.createMaintenanceWindow ); @@ -14,10 +20,4 @@ router.get( maintenanceWindowController.getMaintenanceWindowsByUserId ); -router.get( - "/monitor/:monitorId", - verifyOwnership(Monitor, "monitorId"), - maintenanceWindowController.getMaintenanceWindowsByMonitorId -); - module.exports = router; From d55119c28d5ad6acc412ae4b6e6ea290c8d7808c Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 12:55:31 +0800 Subject: [PATCH 22/23] Add job queue to docs --- Server/controllers/queueController.js | 2 +- Server/index.js | 3 +- Server/openapi.json | 170 ++++++++++++++++++++++++++ Server/routes/queueRoute.js | 4 +- Server/service/jobQueue.js | 4 +- 5 files changed, 176 insertions(+), 7 deletions(-) diff --git a/Server/controllers/queueController.js b/Server/controllers/queueController.js index 5960552c4..bbb3304ee 100644 --- a/Server/controllers/queueController.js +++ b/Server/controllers/queueController.js @@ -41,7 +41,7 @@ const addJob = async (req, res, next) => { const obliterateQueue = async (req, res, next) => { try { const obliterated = await req.jobQueue.obliterate(); - return res.status(200).send("Obliterated jobs"); + return res.status(200).send("Obliterated queue"); } catch (error) { error.service === undefined ? (error.service = SERVICE_NAME) : null; error.method === undefined ? (error.method = "obliterateQueue") : null; diff --git a/Server/index.js b/Server/index.js index 25f70a532..05c9d3059 100644 --- a/Server/index.js +++ b/Server/index.js @@ -84,8 +84,7 @@ const startApp = async () => { app.use("/api/v1/monitors", verifyJWT, monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRouter); - //Temporary route for testing, remove later - app.use("/api/v1/job", queueRouter); + app.use("/api/v1/queue", verifyJWT, queueRouter); //health check app.use("/api/v1/healthy", (req, res) => { diff --git a/Server/openapi.json b/Server/openapi.json index a7de094f4..6a19bde13 100644 --- a/Server/openapi.json +++ b/Server/openapi.json @@ -1875,6 +1875,176 @@ } ] } + }, + "/queue/jobs": { + "get": { + "tags": ["queue"], + "description": "Get all jobs in queue", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "post": { + "tags": ["queue"], + "description": "Create a new job. Useful for testing scaling workers", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/queue/metrics": { + "get": { + "tags": ["queue"], + "description": "Get queue metrics", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/queue/obliterate": { + "post": { + "tags": ["queue"], + "description": "Obliterate job queue", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, diff --git a/Server/routes/queueRoute.js b/Server/routes/queueRoute.js index cbc68df6d..b14eaa2b0 100644 --- a/Server/routes/queueRoute.js +++ b/Server/routes/queueRoute.js @@ -4,10 +4,10 @@ const queueController = require("../controllers/queueController"); router.get("/metrics", queueController.getMetrics); // Get Jobs -router.get("/", queueController.getJobs); +router.get("/jobs", queueController.getJobs); // Add Job -router.post("/", queueController.addJob); +router.post("/jobs", queueController.addJob); // Obliterate Queue router.post("/obliterate", queueController.obliterateQueue); diff --git a/Server/service/jobQueue.js b/Server/service/jobQueue.js index 5d58dd4a4..5a6d3e8e0 100644 --- a/Server/service/jobQueue.js +++ b/Server/service/jobQueue.js @@ -240,12 +240,12 @@ class JobQueue { */ async addJob(jobName, payload) { try { - console.log("Adding job", payload.url); + console.log("Adding job", payload?.url ?? "No URL"); // Execute job immediately await this.queue.add(jobName, payload); await this.queue.add(jobName, payload, { repeat: { - every: payload.interval, + every: payload?.interval ?? 60000, }, }); const workerStats = await this.getWorkerStats(); From 825777c2a8bfe868f1c243830c6e2cbec2ec3667 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 25 Sep 2024 13:03:03 +0800 Subject: [PATCH 23/23] Update nginx conf for api docs --- Docker/nginx/conf.d/default.conf | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Docker/nginx/conf.d/default.conf b/Docker/nginx/conf.d/default.conf index a04d32c87..a27e8a744 100644 --- a/Docker/nginx/conf.d/default.conf +++ b/Docker/nginx/conf.d/default.conf @@ -23,6 +23,15 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } + + location /api-doc/ { + proxy_pass http://server:5000/api-doc/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } } server { @@ -48,4 +57,13 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } + + location /api-doc/ { + proxy_pass http://server:5000/api-doc/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } }