mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-19 16:19:45 -06:00
Merge pull request #978 from bluewave-labs/fix/be/prettier-baseline
Format all files on BE with perttier config
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
const PORT = 5000;
|
||||
|
||||
const connectDbAndRunServer = async (app, db) => {
|
||||
try {
|
||||
await db.connect();
|
||||
app.listen(PORT, () => {
|
||||
console.log(`server started on port:${PORT}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Failed to connect to DB");
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
await db.connect();
|
||||
app.listen(PORT, () => {
|
||||
console.log(`server started on port:${PORT}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Failed to connect to DB");
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
export { connectDbAndRunServer };
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {
|
||||
createCheckParamValidation,
|
||||
createCheckBodyValidation,
|
||||
getChecksParamValidation,
|
||||
getChecksQueryValidation,
|
||||
getTeamChecksParamValidation,
|
||||
getTeamChecksQueryValidation,
|
||||
deleteChecksParamValidation,
|
||||
deleteChecksByTeamIdParamValidation,
|
||||
updateChecksTTLBodyValidation,
|
||||
createCheckParamValidation,
|
||||
createCheckBodyValidation,
|
||||
getChecksParamValidation,
|
||||
getChecksQueryValidation,
|
||||
getTeamChecksParamValidation,
|
||||
getTeamChecksQueryValidation,
|
||||
deleteChecksParamValidation,
|
||||
deleteChecksByTeamIdParamValidation,
|
||||
updateChecksTTLBodyValidation,
|
||||
} from "../validation/joi.js";
|
||||
import { successMessages } from "../utils/messages.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
@@ -17,138 +17,138 @@ import { handleValidationError, handleError } from "./controllerUtils.js";
|
||||
const SERVICE_NAME = "checkController";
|
||||
|
||||
const createCheck = async (req, res, next) => {
|
||||
try {
|
||||
await createCheckParamValidation.validateAsync(req.params);
|
||||
await createCheckBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await createCheckParamValidation.validateAsync(req.params);
|
||||
await createCheckBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const checkData = { ...req.body };
|
||||
const check = await req.db.createCheck(checkData);
|
||||
return res
|
||||
.status(200)
|
||||
.json({ success: true, msg: successMessages.CHECK_CREATE, data: check });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "createCheck"));
|
||||
}
|
||||
try {
|
||||
const checkData = { ...req.body };
|
||||
const check = await req.db.createCheck(checkData);
|
||||
return res
|
||||
.status(200)
|
||||
.json({ success: true, msg: successMessages.CHECK_CREATE, data: check });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "createCheck"));
|
||||
}
|
||||
};
|
||||
|
||||
const getChecks = async (req, res, next) => {
|
||||
try {
|
||||
await getChecksParamValidation.validateAsync(req.params);
|
||||
await getChecksQueryValidation.validateAsync(req.query);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await getChecksParamValidation.validateAsync(req.params);
|
||||
await getChecksQueryValidation.validateAsync(req.query);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const checks = await req.db.getChecks(req);
|
||||
const checksCount = await req.db.getChecksCount(req);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: { checksCount, checks },
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getChecks"));
|
||||
}
|
||||
try {
|
||||
const checks = await req.db.getChecks(req);
|
||||
const checksCount = await req.db.getChecksCount(req);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: { checksCount, checks },
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getChecks"));
|
||||
}
|
||||
};
|
||||
|
||||
const getTeamChecks = async (req, res, next) => {
|
||||
try {
|
||||
await getTeamChecksParamValidation.validateAsync(req.params);
|
||||
await getTeamChecksQueryValidation.validateAsync(req.query);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const checkData = await req.db.getTeamChecks(req);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: checkData,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getTeamChecks"));
|
||||
}
|
||||
try {
|
||||
await getTeamChecksParamValidation.validateAsync(req.params);
|
||||
await getTeamChecksQueryValidation.validateAsync(req.query);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const checkData = await req.db.getTeamChecks(req);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: checkData,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getTeamChecks"));
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChecks = async (req, res, next) => {
|
||||
try {
|
||||
await deleteChecksParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await deleteChecksParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const deletedCount = await req.db.deleteChecks(req.params.monitorId);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount },
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "deleteChecks"));
|
||||
}
|
||||
try {
|
||||
const deletedCount = await req.db.deleteChecks(req.params.monitorId);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount },
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "deleteChecks"));
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChecksByTeamId = async (req, res, next) => {
|
||||
try {
|
||||
await deleteChecksByTeamIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await deleteChecksByTeamIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const deletedCount = await req.db.deleteChecksByTeamId(req.params.teamId);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount },
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "deleteChecksByTeamId"));
|
||||
}
|
||||
try {
|
||||
const deletedCount = await req.db.deleteChecksByTeamId(req.params.teamId);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount },
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "deleteChecksByTeamId"));
|
||||
}
|
||||
};
|
||||
|
||||
const updateChecksTTL = async (req, res, next) => {
|
||||
const SECONDS_PER_DAY = 86400;
|
||||
const SECONDS_PER_DAY = 86400;
|
||||
|
||||
try {
|
||||
await updateChecksTTLBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await updateChecksTTLBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get user's teamId
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const ttl = parseInt(req.body.ttl, 10) * SECONDS_PER_DAY;
|
||||
await req.db.updateChecksTTL(teamId, ttl);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_UPDATE_TTL,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "updateTTL"));
|
||||
}
|
||||
try {
|
||||
// Get user's teamId
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const ttl = parseInt(req.body.ttl, 10) * SECONDS_PER_DAY;
|
||||
await req.db.updateChecksTTL(teamId, ttl);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_UPDATE_TTL,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "updateTTL"));
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createCheck,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
createCheck,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
inviteRoleValidation,
|
||||
inviteBodyValidation,
|
||||
inviteVerificationBodyValidation,
|
||||
inviteRoleValidation,
|
||||
inviteBodyValidation,
|
||||
inviteVerificationBodyValidation,
|
||||
} from "../validation/joi.js";
|
||||
import logger from "../utils/logger.js";
|
||||
import dotenv from "dotenv";
|
||||
@@ -27,62 +27,58 @@ const SERVICE_NAME = "inviteController";
|
||||
* @throws {Error} If there is an error during the process, especially if there is a validation error (422).
|
||||
*/
|
||||
const issueInvitation = async (req, res, next) => {
|
||||
try {
|
||||
// Only admins can invite
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { role, firstname, teamId } = jwt.decode(token);
|
||||
req.body.teamId = teamId;
|
||||
try {
|
||||
await inviteRoleValidation.validateAsync({ roles: role });
|
||||
await inviteBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Only admins can invite
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { role, firstname, teamId } = jwt.decode(token);
|
||||
req.body.teamId = teamId;
|
||||
try {
|
||||
await inviteRoleValidation.validateAsync({ roles: role });
|
||||
await inviteBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
const inviteToken = await req.db.requestInviteToken({ ...req.body });
|
||||
const { clientHost } = req.settingsService.getSettings();
|
||||
req.emailService
|
||||
.buildAndSendEmail(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: firstname,
|
||||
link: `${clientHost}/register/${inviteToken.token}`,
|
||||
},
|
||||
req.body.email,
|
||||
"Welcome to Uptime Monitor"
|
||||
)
|
||||
.catch((error) => {
|
||||
logger.error("Error sending invite email", {
|
||||
service: SERVICE_NAME,
|
||||
error: error.message,
|
||||
});
|
||||
});
|
||||
const inviteToken = await req.db.requestInviteToken({ ...req.body });
|
||||
const { clientHost } = req.settingsService.getSettings();
|
||||
req.emailService
|
||||
.buildAndSendEmail(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: firstname,
|
||||
link: `${clientHost}/register/${inviteToken.token}`,
|
||||
},
|
||||
req.body.email,
|
||||
"Welcome to Uptime Monitor"
|
||||
)
|
||||
.catch((error) => {
|
||||
logger.error("Error sending invite email", {
|
||||
service: SERVICE_NAME,
|
||||
error: error.message,
|
||||
});
|
||||
});
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({ success: true, msg: "Invite sent", data: inviteToken });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "inviteController"));
|
||||
}
|
||||
return res.status(200).json({ success: true, msg: "Invite sent", data: inviteToken });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "inviteController"));
|
||||
}
|
||||
};
|
||||
|
||||
const inviteVerifyController = async (req, res, next) => {
|
||||
try {
|
||||
await inviteVerificationBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await inviteVerificationBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const invite = await req.db.getInviteToken(req.body.token);
|
||||
res
|
||||
.status(200)
|
||||
.json({ status: "success", msg: "Invite verified", data: invite });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "inviteVerifyController"));
|
||||
}
|
||||
try {
|
||||
const invite = await req.db.getInviteToken(req.body.token);
|
||||
res.status(200).json({ status: "success", msg: "Invite verified", data: invite });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "inviteVerifyController"));
|
||||
}
|
||||
};
|
||||
|
||||
export { issueInvitation, inviteVerifyController };
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
createMaintenanceWindowBodyValidation,
|
||||
editMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceByIdWindowBodyValidation,
|
||||
getMaintenanceWindowByIdParamValidation,
|
||||
getMaintenanceWindowsByMonitorIdParamValidation,
|
||||
getMaintenanceWindowsByTeamIdQueryValidation,
|
||||
deleteMaintenanceWindowByIdParamValidation,
|
||||
createMaintenanceWindowBodyValidation,
|
||||
editMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceByIdWindowBodyValidation,
|
||||
getMaintenanceWindowByIdParamValidation,
|
||||
getMaintenanceWindowsByMonitorIdParamValidation,
|
||||
getMaintenanceWindowsByTeamIdQueryValidation,
|
||||
deleteMaintenanceWindowByIdParamValidation,
|
||||
} from "../validation/joi.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { getTokenFromHeaders } from "../utils/utils.js";
|
||||
@@ -15,157 +15,153 @@ import { handleValidationError, handleError } from "./controllerUtils.js";
|
||||
const SERVICE_NAME = "maintenanceWindowController";
|
||||
|
||||
const createMaintenanceWindows = async (req, res, next) => {
|
||||
try {
|
||||
await createMaintenanceWindowBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const monitorIds = req.body.monitors;
|
||||
const dbTransactions = monitorIds.map((monitorId) => {
|
||||
return req.db.createMaintenanceWindow({
|
||||
teamId,
|
||||
monitorId,
|
||||
name: req.body.name,
|
||||
active: req.body.active ? req.body.active : true,
|
||||
repeat: req.body.repeat,
|
||||
start: req.body.start,
|
||||
end: req.body.end,
|
||||
});
|
||||
});
|
||||
await Promise.all(dbTransactions);
|
||||
return res.status(201).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "createMaintenanceWindow"));
|
||||
}
|
||||
try {
|
||||
await createMaintenanceWindowBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const monitorIds = req.body.monitors;
|
||||
const dbTransactions = monitorIds.map((monitorId) => {
|
||||
return req.db.createMaintenanceWindow({
|
||||
teamId,
|
||||
monitorId,
|
||||
name: req.body.name,
|
||||
active: req.body.active ? req.body.active : true,
|
||||
repeat: req.body.repeat,
|
||||
start: req.body.start,
|
||||
end: req.body.end,
|
||||
});
|
||||
});
|
||||
await Promise.all(dbTransactions);
|
||||
return res.status(201).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "createMaintenanceWindow"));
|
||||
}
|
||||
};
|
||||
|
||||
const getMaintenanceWindowById = async (req, res, next) => {
|
||||
try {
|
||||
await getMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const maintenanceWindow = await req.db.getMaintenanceWindowById(
|
||||
req.params.id
|
||||
);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID,
|
||||
data: maintenanceWindow,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMaintenanceWindowById"));
|
||||
}
|
||||
try {
|
||||
await getMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const maintenanceWindow = await req.db.getMaintenanceWindowById(req.params.id);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID,
|
||||
data: maintenanceWindow,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMaintenanceWindowById"));
|
||||
}
|
||||
};
|
||||
|
||||
const getMaintenanceWindowsByTeamId = async (req, res, next) => {
|
||||
try {
|
||||
await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const maintenanceWindows = await req.db.getMaintenanceWindowsByTeamId(
|
||||
teamId,
|
||||
req.query
|
||||
);
|
||||
try {
|
||||
const token = getTokenFromHeaders(req.headers);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const { teamId } = jwt.verify(token, jwtSecret);
|
||||
const maintenanceWindows = await req.db.getMaintenanceWindowsByTeamId(
|
||||
teamId,
|
||||
req.query
|
||||
);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM,
|
||||
data: maintenanceWindows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMaintenanceWindowsByUserId"));
|
||||
}
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM,
|
||||
data: maintenanceWindows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMaintenanceWindowsByUserId"));
|
||||
}
|
||||
};
|
||||
|
||||
const getMaintenanceWindowsByMonitorId = async (req, res, next) => {
|
||||
try {
|
||||
await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(
|
||||
req.params
|
||||
);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const maintenanceWindows = await req.db.getMaintenanceWindowsByMonitorId(
|
||||
req.params.monitorId
|
||||
);
|
||||
try {
|
||||
const maintenanceWindows = await req.db.getMaintenanceWindowsByMonitorId(
|
||||
req.params.monitorId
|
||||
);
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER,
|
||||
data: maintenanceWindows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMaintenanceWindowsByMonitorId"));
|
||||
}
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER,
|
||||
data: maintenanceWindows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMaintenanceWindowsByMonitorId"));
|
||||
}
|
||||
};
|
||||
|
||||
const deleteMaintenanceWindow = async (req, res, next) => {
|
||||
try {
|
||||
await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await req.db.deleteMaintenanceWindowById(req.params.id);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_DELETE,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "deleteMaintenanceWindow"));
|
||||
}
|
||||
try {
|
||||
await deleteMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await req.db.deleteMaintenanceWindowById(req.params.id);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_DELETE,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "deleteMaintenanceWindow"));
|
||||
}
|
||||
};
|
||||
|
||||
const editMaintenanceWindow = async (req, res, next) => {
|
||||
try {
|
||||
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const editedMaintenanceWindow = await req.db.editMaintenanceWindowById(
|
||||
req.params.id,
|
||||
req.body
|
||||
);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_EDIT,
|
||||
data: editedMaintenanceWindow,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "editMaintenanceWindow"));
|
||||
}
|
||||
try {
|
||||
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const editedMaintenanceWindow = await req.db.editMaintenanceWindowById(
|
||||
req.params.id,
|
||||
req.body
|
||||
);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_EDIT,
|
||||
data: editedMaintenanceWindow,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "editMaintenanceWindow"));
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createMaintenanceWindows,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindow,
|
||||
editMaintenanceWindow,
|
||||
createMaintenanceWindows,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindow,
|
||||
editMaintenanceWindow,
|
||||
};
|
||||
|
||||
@@ -4,56 +4,54 @@ import { errorMessages, successMessages } from "../utils/messages.js";
|
||||
const SERVICE_NAME = "JobQueueController";
|
||||
|
||||
const getMetrics = async (req, res, next) => {
|
||||
try {
|
||||
const metrics = await req.jobQueue.getMetrics();
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data: metrics,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMetrics"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const metrics = await req.jobQueue.getMetrics();
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data: metrics,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getMetrics"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const getJobs = async (req, res, next) => {
|
||||
try {
|
||||
const jobs = await req.jobQueue.getJobStats();
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data: jobs,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getJobs"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const jobs = await req.jobQueue.getJobStats();
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data: jobs,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getJobs"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const addJob = async (req, res, next) => {
|
||||
try {
|
||||
await req.jobQueue.addJob(Math.random().toString(36).substring(7));
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_ADD_JOB,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "addJob"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await req.jobQueue.addJob(Math.random().toString(36).substring(7));
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_ADD_JOB,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "addJob"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const obliterateQueue = async (req, res, next) => {
|
||||
try {
|
||||
await req.jobQueue.obliterate();
|
||||
return res
|
||||
.status(200)
|
||||
.json({ success: true, msg: successMessages.QUEUE_OBLITERATE });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "obliterateQueue"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await req.jobQueue.obliterate();
|
||||
return res.status(200).json({ success: true, msg: successMessages.QUEUE_OBLITERATE });
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "obliterateQueue"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
export { getMetrics, getJobs, addJob, obliterateQueue };
|
||||
|
||||
@@ -4,39 +4,39 @@ import { handleValidationError, handleError } from "./controllerUtils.js";
|
||||
const SERVICE_NAME = "SettingsController";
|
||||
|
||||
const getAppSettings = async (req, res, next) => {
|
||||
try {
|
||||
const settings = { ...(await req.settingsService.getSettings()) };
|
||||
delete settings.jwtSecret;
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.GET_APP_SETTINGS,
|
||||
data: settings,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getAppSettings"));
|
||||
}
|
||||
try {
|
||||
const settings = { ...(await req.settingsService.getSettings()) };
|
||||
delete settings.jwtSecret;
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.GET_APP_SETTINGS,
|
||||
data: settings,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getAppSettings"));
|
||||
}
|
||||
};
|
||||
|
||||
const updateAppSettings = async (req, res, next) => {
|
||||
try {
|
||||
await updateAppSettingsBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await updateAppSettingsBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await req.db.updateAppSettings(req.body);
|
||||
const updatedSettings = { ...(await req.settingsService.reloadSettings()) };
|
||||
delete updatedSettings.jwtSecret;
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.UPDATE_APP_SETTINGS,
|
||||
data: updatedSettings,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "updateAppSettings"));
|
||||
}
|
||||
try {
|
||||
await req.db.updateAppSettings(req.body);
|
||||
const updatedSettings = { ...(await req.settingsService.reloadSettings()) };
|
||||
delete updatedSettings.jwtSecret;
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.UPDATE_APP_SETTINGS,
|
||||
data: updatedSettings,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "updateAppSettings"));
|
||||
}
|
||||
};
|
||||
|
||||
export { getAppSettings, updateAppSettings };
|
||||
|
||||
@@ -28,111 +28,111 @@ let FAKE_MONITOR_DATA = [];
|
||||
const USERS = [];
|
||||
|
||||
const connect = async () => {
|
||||
try {
|
||||
await console.log("Connected to FakeDB");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
await console.log("Connected to FakeDB");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const insertUser = async (req, res) => {
|
||||
try {
|
||||
const newUser = new UserModel({ ...req.body });
|
||||
const salt = await bcrypt.genSalt(10); //genSalt is asynchronous, need to wait
|
||||
newUser.password = await bcrypt.hash(newUser.password, salt); // hash is also async, need to eitehr await or use hashSync
|
||||
USERS.push(newUser);
|
||||
const userToReturn = { ...newUser._doc };
|
||||
delete userToReturn.password;
|
||||
return userToReturn;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const newUser = new UserModel({ ...req.body });
|
||||
const salt = await bcrypt.genSalt(10); //genSalt is asynchronous, need to wait
|
||||
newUser.password = await bcrypt.hash(newUser.password, salt); // hash is also async, need to eitehr await or use hashSync
|
||||
USERS.push(newUser);
|
||||
const userToReturn = { ...newUser._doc };
|
||||
delete userToReturn.password;
|
||||
return userToReturn;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getUserByEmail = async (req, res) => {
|
||||
const email = req.body.email;
|
||||
try {
|
||||
const idx = USERS.findIndex((user) => {
|
||||
return user.email === email;
|
||||
});
|
||||
if (idx === -1) {
|
||||
return null;
|
||||
}
|
||||
return USERS[idx];
|
||||
} catch (error) {
|
||||
throw new Error(`User with email ${email} not found`);
|
||||
}
|
||||
const email = req.body.email;
|
||||
try {
|
||||
const idx = USERS.findIndex((user) => {
|
||||
return user.email === email;
|
||||
});
|
||||
if (idx === -1) {
|
||||
return null;
|
||||
}
|
||||
return USERS[idx];
|
||||
} catch (error) {
|
||||
throw new Error(`User with email ${email} not found`);
|
||||
}
|
||||
};
|
||||
|
||||
const getAllMonitors = async () => {
|
||||
return FAKE_MONITOR_DATA;
|
||||
return FAKE_MONITOR_DATA;
|
||||
};
|
||||
|
||||
const getMonitorById = async (monitorId) => {
|
||||
const idx = FAKE_MONITOR_DATA.findIndex((monitor) => {
|
||||
return monitor.id === monitorId;
|
||||
});
|
||||
if (idx === -1) {
|
||||
throw new Error(`Monitor with id ${monitorId} not found`);
|
||||
}
|
||||
return FAKE_MONITOR_DATA[idx];
|
||||
const idx = FAKE_MONITOR_DATA.findIndex((monitor) => {
|
||||
return monitor.id === monitorId;
|
||||
});
|
||||
if (idx === -1) {
|
||||
throw new Error(`Monitor with id ${monitorId} not found`);
|
||||
}
|
||||
return FAKE_MONITOR_DATA[idx];
|
||||
};
|
||||
|
||||
const getMonitorsByUserId = async (userId) => {
|
||||
const userMonitors = FAKE_MONITOR_DATA.filter((monitor) => {
|
||||
return monitor.userId === userId;
|
||||
});
|
||||
const userMonitors = FAKE_MONITOR_DATA.filter((monitor) => {
|
||||
return monitor.userId === userId;
|
||||
});
|
||||
|
||||
if (userMonitors.length === 0) {
|
||||
throw new Error(`Monitors for user ${userId} not found`);
|
||||
}
|
||||
return userMonitors;
|
||||
if (userMonitors.length === 0) {
|
||||
throw new Error(`Monitors for user ${userId} not found`);
|
||||
}
|
||||
return userMonitors;
|
||||
};
|
||||
|
||||
const createMonitor = async (req, res) => {
|
||||
const monitor = new Monitor(req.body);
|
||||
monitor.createdAt = Date.now();
|
||||
monitor.updatedAt = Date.now();
|
||||
FAKE_MONITOR_DATA.push(monitor);
|
||||
return monitor;
|
||||
const monitor = new Monitor(req.body);
|
||||
monitor.createdAt = Date.now();
|
||||
monitor.updatedAt = Date.now();
|
||||
FAKE_MONITOR_DATA.push(monitor);
|
||||
return monitor;
|
||||
};
|
||||
|
||||
const deleteMonitor = async (req, res) => {
|
||||
const monitorId = req.params.monitorId;
|
||||
try {
|
||||
const monitor = getMonitorById(monitorId);
|
||||
FAKE_MONITOR_DATA = FAKE_MONITOR_DATA.filter((monitor) => {
|
||||
return monitor.id !== monitorId;
|
||||
});
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
const monitorId = req.params.monitorId;
|
||||
try {
|
||||
const monitor = getMonitorById(monitorId);
|
||||
FAKE_MONITOR_DATA = FAKE_MONITOR_DATA.filter((monitor) => {
|
||||
return monitor.id !== monitorId;
|
||||
});
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const editMonitor = async (req, res) => {
|
||||
const monitorId = req.params.monitorId;
|
||||
const idx = FAKE_MONITOR_DATA.findIndex((monitor) => {
|
||||
return monitor._id.toString() === monitorId;
|
||||
});
|
||||
const oldMonitor = FAKE_MONITOR_DATA[idx];
|
||||
const editedMonitor = new Monitor({ ...req.body });
|
||||
editedMonitor._id = oldMonitor._id;
|
||||
editedMonitor.userId = oldMonitor.userId;
|
||||
editedMonitor.updatedAt = Date.now();
|
||||
editedMonitor.createdAt = oldMonitor.createdAt;
|
||||
FAKE_MONITOR_DATA[idx] = editedMonitor;
|
||||
return FAKE_MONITOR_DATA[idx];
|
||||
const monitorId = req.params.monitorId;
|
||||
const idx = FAKE_MONITOR_DATA.findIndex((monitor) => {
|
||||
return monitor._id.toString() === monitorId;
|
||||
});
|
||||
const oldMonitor = FAKE_MONITOR_DATA[idx];
|
||||
const editedMonitor = new Monitor({ ...req.body });
|
||||
editedMonitor._id = oldMonitor._id;
|
||||
editedMonitor.userId = oldMonitor.userId;
|
||||
editedMonitor.updatedAt = Date.now();
|
||||
editedMonitor.createdAt = oldMonitor.createdAt;
|
||||
FAKE_MONITOR_DATA[idx] = editedMonitor;
|
||||
return FAKE_MONITOR_DATA[idx];
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
connect,
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
getAllMonitors,
|
||||
getMonitorById,
|
||||
getMonitorsByUserId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
editMonitor,
|
||||
connect,
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
getAllMonitors,
|
||||
getMonitorById,
|
||||
getMonitorsByUserId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
editMonitor,
|
||||
};
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const AppSettingsSchema = mongoose.Schema(
|
||||
{
|
||||
apiBaseUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "http://localhost:5000/api/v1",
|
||||
},
|
||||
logLevel: {
|
||||
type: String,
|
||||
default: "debug",
|
||||
enum: ["debug", "none", "error", "warn"],
|
||||
},
|
||||
clientHost: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "http://localhost:5173",
|
||||
},
|
||||
jwtSecret: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "my_secret",
|
||||
},
|
||||
refreshTokenSecret: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "my_refresh_secret",
|
||||
},
|
||||
dbType: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "MongoDB",
|
||||
},
|
||||
dbConnectionString: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "mongodb://localhost:27017/uptime_db",
|
||||
},
|
||||
redisHost: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "127.0.0.1",
|
||||
},
|
||||
redisPort: {
|
||||
type: Number,
|
||||
default: "6379",
|
||||
},
|
||||
jwtTTL: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "2h",
|
||||
},
|
||||
refreshTokenTTL: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "7d",
|
||||
},
|
||||
pagespeedApiKey: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
systemEmailHost: {
|
||||
type: String,
|
||||
default: "smtp.gmail.com",
|
||||
},
|
||||
systemEmailPort: {
|
||||
type: Number,
|
||||
default: 465,
|
||||
},
|
||||
systemEmailAddress: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
systemEmailPassword: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
singleton: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
unique: true,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
apiBaseUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "http://localhost:5000/api/v1",
|
||||
},
|
||||
logLevel: {
|
||||
type: String,
|
||||
default: "debug",
|
||||
enum: ["debug", "none", "error", "warn"],
|
||||
},
|
||||
clientHost: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "http://localhost:5173",
|
||||
},
|
||||
jwtSecret: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "my_secret",
|
||||
},
|
||||
refreshTokenSecret: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "my_refresh_secret",
|
||||
},
|
||||
dbType: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "MongoDB",
|
||||
},
|
||||
dbConnectionString: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "mongodb://localhost:27017/uptime_db",
|
||||
},
|
||||
redisHost: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "127.0.0.1",
|
||||
},
|
||||
redisPort: {
|
||||
type: Number,
|
||||
default: "6379",
|
||||
},
|
||||
jwtTTL: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "2h",
|
||||
},
|
||||
refreshTokenTTL: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "7d",
|
||||
},
|
||||
pagespeedApiKey: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
systemEmailHost: {
|
||||
type: String,
|
||||
default: "smtp.gmail.com",
|
||||
},
|
||||
systemEmailPort: {
|
||||
type: Number,
|
||||
default: 465,
|
||||
},
|
||||
systemEmailAddress: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
systemEmailPassword: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
singleton: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
unique: true,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
export default mongoose.model("AppSettings", AppSettingsSchema);
|
||||
|
||||
@@ -9,67 +9,67 @@ import Notification from "./Notification.js";
|
||||
* about the status and response of a particular check event.
|
||||
*/
|
||||
const CheckSchema = mongoose.Schema(
|
||||
{
|
||||
/**
|
||||
* Reference to the associated Monitor document.
|
||||
*
|
||||
* @type {mongoose.Schema.Types.ObjectId}
|
||||
*/
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
index: true,
|
||||
},
|
||||
/**
|
||||
* Status of the check (true for up, false for down).
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
status: {
|
||||
type: Boolean,
|
||||
index: true,
|
||||
},
|
||||
/**
|
||||
* Response time of the check in milliseconds.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
responseTime: {
|
||||
type: Number,
|
||||
},
|
||||
/**
|
||||
* HTTP status code received during the check.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
statusCode: {
|
||||
type: Number,
|
||||
index: true,
|
||||
},
|
||||
/**
|
||||
* Message or description of the check result.
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
message: {
|
||||
type: String,
|
||||
},
|
||||
/**
|
||||
* Expiry date of the check, auto-calculated to expire after 30 days.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
{
|
||||
/**
|
||||
* Reference to the associated Monitor document.
|
||||
*
|
||||
* @type {mongoose.Schema.Types.ObjectId}
|
||||
*/
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
index: true,
|
||||
},
|
||||
/**
|
||||
* Status of the check (true for up, false for down).
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
status: {
|
||||
type: Boolean,
|
||||
index: true,
|
||||
},
|
||||
/**
|
||||
* Response time of the check in milliseconds.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
responseTime: {
|
||||
type: Number,
|
||||
},
|
||||
/**
|
||||
* HTTP status code received during the check.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
statusCode: {
|
||||
type: Number,
|
||||
index: true,
|
||||
},
|
||||
/**
|
||||
* Message or description of the check result.
|
||||
*
|
||||
* @type {String}
|
||||
*/
|
||||
message: {
|
||||
type: String,
|
||||
},
|
||||
/**
|
||||
* Expiry date of the check, auto-calculated to expire after 30 days.
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 60 * 60 * 24 * 30, // 30 days
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true, // Adds createdAt and updatedAt timestamps
|
||||
}
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 60 * 60 * 24 * 30, // 30 days
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true, // Adds createdAt and updatedAt timestamps
|
||||
}
|
||||
);
|
||||
|
||||
CheckSchema.index({ createdAt: 1 });
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import mongoose from "mongoose";
|
||||
const InviteTokenSchema = mongoose.Schema(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
role: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 3600,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
role: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 3600,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
export default mongoose.model("InviteToken", InviteTokenSchema);
|
||||
|
||||
@@ -27,42 +27,42 @@ import mongoose from "mongoose";
|
||||
*/
|
||||
|
||||
const MaintenanceWindow = mongoose.Schema(
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
repeat: {
|
||||
type: Number,
|
||||
},
|
||||
start: {
|
||||
type: Date,
|
||||
},
|
||||
end: {
|
||||
type: Date,
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
index: { expires: "0s" },
|
||||
},
|
||||
},
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
repeat: {
|
||||
type: Number,
|
||||
},
|
||||
start: {
|
||||
type: Date,
|
||||
},
|
||||
end: {
|
||||
type: Date,
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
index: { expires: "0s" },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
export default mongoose.model("MaintenanceWindow", MaintenanceWindow);
|
||||
|
||||
@@ -2,62 +2,62 @@ import mongoose from "mongoose";
|
||||
import Notification from "./Notification.js";
|
||||
|
||||
const MonitorSchema = mongoose.Schema(
|
||||
{
|
||||
userId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: ["http", "ping", "pagespeed"],
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
interval: {
|
||||
// in milliseconds
|
||||
type: Number,
|
||||
default: 60000,
|
||||
},
|
||||
uptimePercentage: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
notifications: [
|
||||
{
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Notification",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
userId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
teamId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Team",
|
||||
immutable: true,
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: ["http", "ping", "pagespeed"],
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
interval: {
|
||||
// in milliseconds
|
||||
type: Number,
|
||||
default: 60000,
|
||||
},
|
||||
uptimePercentage: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
notifications: [
|
||||
{
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Notification",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
export default mongoose.model("Monitor", MonitorSchema);
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import mongoose from "mongoose";
|
||||
const NotificationSchema = mongoose.Schema(
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: ["email", "sms"],
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
},
|
||||
phone: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
enum: ["email", "sms"],
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
},
|
||||
phone: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
export default mongoose.model("Notification", NotificationSchema);
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import mongoose from "mongoose";
|
||||
const AuditSchema = mongoose.Schema({
|
||||
id: { type: String, required: true },
|
||||
title: { type: String, required: true },
|
||||
description: { type: String, required: true },
|
||||
score: { type: Number, required: true },
|
||||
scoreDisplayMode: { type: String, required: true },
|
||||
displayValue: { type: String, required: true },
|
||||
numericValue: { type: Number, required: true },
|
||||
numericUnit: { type: String, required: true },
|
||||
id: { type: String, required: true },
|
||||
title: { type: String, required: true },
|
||||
description: { type: String, required: true },
|
||||
score: { type: Number, required: true },
|
||||
scoreDisplayMode: { type: String, required: true },
|
||||
displayValue: { type: String, required: true },
|
||||
numericValue: { type: Number, required: true },
|
||||
numericUnit: { type: String, required: true },
|
||||
});
|
||||
|
||||
const AuditsSchema = mongoose.Schema({
|
||||
cls: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
si: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
fcp: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
lcp: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
tbt: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
cls: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
si: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
fcp: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
lcp: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
tbt: {
|
||||
type: AuditSchema,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -44,40 +44,40 @@ const AuditsSchema = mongoose.Schema({
|
||||
*/
|
||||
|
||||
const PageSpeedCheck = mongoose.Schema(
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
accessibility: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
bestPractices: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
seo: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
performance: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
audits: {
|
||||
type: AuditsSchema,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
monitorId: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
immutable: true,
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
accessibility: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
bestPractices: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
seo: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
performance: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
audits: {
|
||||
type: AuditsSchema,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -86,26 +86,26 @@ const PageSpeedCheck = mongoose.Schema(
|
||||
*/
|
||||
|
||||
PageSpeedCheck.pre("save", async function (next) {
|
||||
try {
|
||||
const monitor = await mongoose.model("Monitor").findById(this.monitorId);
|
||||
if (monitor && monitor.status !== this.status) {
|
||||
if (monitor.status === true && this.status === false) {
|
||||
// TODO issue alert
|
||||
console.log("Monitor went down");
|
||||
}
|
||||
try {
|
||||
const monitor = await mongoose.model("Monitor").findById(this.monitorId);
|
||||
if (monitor && monitor.status !== this.status) {
|
||||
if (monitor.status === true && this.status === false) {
|
||||
// TODO issue alert
|
||||
console.log("Monitor went down");
|
||||
}
|
||||
|
||||
if (monitor.status === false && this.status === true) {
|
||||
// TODO issue alert
|
||||
console.log("Monitor went up");
|
||||
}
|
||||
monitor.status = this.status;
|
||||
await monitor.save();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
next();
|
||||
}
|
||||
if (monitor.status === false && this.status === true) {
|
||||
// TODO issue alert
|
||||
console.log("Monitor went up");
|
||||
}
|
||||
monitor.status = this.status;
|
||||
await monitor.save();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
export default mongoose.model("PageSpeedCheck", PageSpeedCheck);
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const RecoveryTokenSchema = mongoose.Schema(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 600,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
expiry: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
expires: 600,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
export default mongoose.model("RecoveryToken", RecoveryTokenSchema);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import mongoose from "mongoose";
|
||||
const TeamSchema = mongoose.Schema(
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
{
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
export default mongoose.model("Team", TeamSchema);
|
||||
|
||||
@@ -7,34 +7,34 @@ import AppSettings from "../models/AppSettings.js";
|
||||
//****************************************
|
||||
|
||||
const connect = async () => {
|
||||
try {
|
||||
const connectionString =
|
||||
process.env.DB_CONNECTION_STRING || "mongodb://localhost:27017/uptime_db";
|
||||
await mongoose.connect(connectionString);
|
||||
// If there are no AppSettings, create one
|
||||
let appSettings = await AppSettings.find();
|
||||
if (appSettings.length === 0) {
|
||||
appSettings = new AppSettings({});
|
||||
await appSettings.save();
|
||||
}
|
||||
try {
|
||||
const connectionString =
|
||||
process.env.DB_CONNECTION_STRING || "mongodb://localhost:27017/uptime_db";
|
||||
await mongoose.connect(connectionString);
|
||||
// If there are no AppSettings, create one
|
||||
let appSettings = await AppSettings.find();
|
||||
if (appSettings.length === 0) {
|
||||
appSettings = new AppSettings({});
|
||||
await appSettings.save();
|
||||
}
|
||||
|
||||
console.log("Connected to MongoDB");
|
||||
} catch (error) {
|
||||
console.error("Failed to connect to MongoDB");
|
||||
throw error;
|
||||
}
|
||||
console.log("Connected to MongoDB");
|
||||
} catch (error) {
|
||||
console.error("Failed to connect to MongoDB");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const checkSuperadmin = async (req, res) => {
|
||||
try {
|
||||
const superAdmin = await UserModel.findOne({ role: "superadmin" });
|
||||
if (superAdmin !== null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const superAdmin = await UserModel.findOne({ role: "superadmin" });
|
||||
if (superAdmin !== null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
//****************************************
|
||||
@@ -42,14 +42,14 @@ const checkSuperadmin = async (req, res) => {
|
||||
//****************************************
|
||||
|
||||
import {
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
} from "./modules/userModule.js";
|
||||
|
||||
//****************************************
|
||||
@@ -57,18 +57,18 @@ import {
|
||||
//****************************************
|
||||
|
||||
import {
|
||||
requestInviteToken,
|
||||
getInviteToken,
|
||||
getInviteTokenAndDelete,
|
||||
requestInviteToken,
|
||||
getInviteToken,
|
||||
getInviteTokenAndDelete,
|
||||
} from "./modules/inviteModule.js";
|
||||
|
||||
//****************************************
|
||||
// Recovery Operations
|
||||
//****************************************
|
||||
import {
|
||||
requestRecoveryToken,
|
||||
validateRecoveryToken,
|
||||
resetPassword,
|
||||
requestRecoveryToken,
|
||||
validateRecoveryToken,
|
||||
resetPassword,
|
||||
} from "./modules/recoveryModule.js";
|
||||
|
||||
//****************************************
|
||||
@@ -76,17 +76,17 @@ import {
|
||||
//****************************************
|
||||
|
||||
import {
|
||||
getAllMonitors,
|
||||
getMonitorStatsById,
|
||||
getMonitorById,
|
||||
getMonitorsAndSummaryByTeamId,
|
||||
getMonitorsByTeamId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
deleteAllMonitors,
|
||||
deleteMonitorsByUserId,
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
getAllMonitors,
|
||||
getMonitorStatsById,
|
||||
getMonitorById,
|
||||
getMonitorsAndSummaryByTeamId,
|
||||
getMonitorsByTeamId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
deleteAllMonitors,
|
||||
deleteMonitorsByUserId,
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
} from "./modules/monitorModule.js";
|
||||
|
||||
//****************************************
|
||||
@@ -94,9 +94,9 @@ import {
|
||||
//****************************************
|
||||
|
||||
import {
|
||||
createPageSpeedCheck,
|
||||
getPageSpeedChecks,
|
||||
deletePageSpeedChecksByMonitorId,
|
||||
createPageSpeedCheck,
|
||||
getPageSpeedChecks,
|
||||
deletePageSpeedChecksByMonitorId,
|
||||
} from "./modules/pageSpeedCheckModule.js";
|
||||
|
||||
//****************************************
|
||||
@@ -104,36 +104,36 @@ import {
|
||||
//****************************************
|
||||
|
||||
import {
|
||||
createCheck,
|
||||
getChecksCount,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
createCheck,
|
||||
getChecksCount,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
} from "./modules/checkModule.js";
|
||||
|
||||
//****************************************
|
||||
// Maintenance Window
|
||||
//****************************************
|
||||
import {
|
||||
createMaintenanceWindow,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindowById,
|
||||
deleteMaintenanceWindowByMonitorId,
|
||||
deleteMaintenanceWindowByUserId,
|
||||
editMaintenanceWindowById,
|
||||
createMaintenanceWindow,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindowById,
|
||||
deleteMaintenanceWindowByMonitorId,
|
||||
deleteMaintenanceWindowByUserId,
|
||||
editMaintenanceWindowById,
|
||||
} from "./modules/maintenanceWindowModule.js";
|
||||
|
||||
//****************************************
|
||||
// Notifications
|
||||
//****************************************
|
||||
import {
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
} from "./modules/notificationModule.js";
|
||||
|
||||
//****************************************
|
||||
@@ -142,54 +142,54 @@ import {
|
||||
import { getAppSettings, updateAppSettings } from "./modules/settingsModule.js";
|
||||
|
||||
export default {
|
||||
connect,
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
requestInviteToken,
|
||||
getInviteToken,
|
||||
getInviteTokenAndDelete,
|
||||
requestRecoveryToken,
|
||||
validateRecoveryToken,
|
||||
resetPassword,
|
||||
checkSuperadmin,
|
||||
getAllMonitors,
|
||||
getMonitorStatsById,
|
||||
getMonitorById,
|
||||
getMonitorsAndSummaryByTeamId,
|
||||
getMonitorsByTeamId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
deleteAllMonitors,
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
createCheck,
|
||||
getChecksCount,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
deleteMonitorsByUserId,
|
||||
createPageSpeedCheck,
|
||||
getPageSpeedChecks,
|
||||
deletePageSpeedChecksByMonitorId,
|
||||
createMaintenanceWindow,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindowById,
|
||||
deleteMaintenanceWindowByMonitorId,
|
||||
deleteMaintenanceWindowByUserId,
|
||||
editMaintenanceWindowById,
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
connect,
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
requestInviteToken,
|
||||
getInviteToken,
|
||||
getInviteTokenAndDelete,
|
||||
requestRecoveryToken,
|
||||
validateRecoveryToken,
|
||||
resetPassword,
|
||||
checkSuperadmin,
|
||||
getAllMonitors,
|
||||
getMonitorStatsById,
|
||||
getMonitorById,
|
||||
getMonitorsAndSummaryByTeamId,
|
||||
getMonitorsByTeamId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
deleteAllMonitors,
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
createCheck,
|
||||
getChecksCount,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
deleteMonitorsByUserId,
|
||||
createPageSpeedCheck,
|
||||
getPageSpeedChecks,
|
||||
deletePageSpeedChecksByMonitorId,
|
||||
createMaintenanceWindow,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindowById,
|
||||
deleteMaintenanceWindowByMonitorId,
|
||||
deleteMaintenanceWindowByUserId,
|
||||
editMaintenanceWindowById,
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
};
|
||||
|
||||
@@ -4,9 +4,9 @@ import User from "../../models/User.js";
|
||||
import logger from "../../../utils/logger.js";
|
||||
const SERVICE_NAME = "checkModule";
|
||||
const dateRangeLookup = {
|
||||
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
||||
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||||
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
||||
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
||||
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||||
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -23,67 +23,67 @@ const dateRangeLookup = {
|
||||
*/
|
||||
|
||||
const createCheck = async (checkData) => {
|
||||
try {
|
||||
const { monitorId, status } = checkData;
|
||||
const n = (await Check.countDocuments({ monitorId })) + 1;
|
||||
const check = await new Check({ ...checkData }).save();
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
try {
|
||||
const { monitorId, status } = checkData;
|
||||
const n = (await Check.countDocuments({ monitorId })) + 1;
|
||||
const check = await new Check({ ...checkData }).save();
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
|
||||
if (!monitor) {
|
||||
logger.error("Monitor not found", {
|
||||
service: SERVICE_NAME,
|
||||
monitorId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!monitor) {
|
||||
logger.error("Monitor not found", {
|
||||
service: SERVICE_NAME,
|
||||
monitorId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Update uptime percentage
|
||||
if (monitor.uptimePercentage === undefined) {
|
||||
monitor.uptimePercentage = status === true ? 1 : 0;
|
||||
} else {
|
||||
monitor.uptimePercentage =
|
||||
(monitor.uptimePercentage * (n - 1) + (status === true ? 1 : 0)) / n;
|
||||
}
|
||||
// Update uptime percentage
|
||||
if (monitor.uptimePercentage === undefined) {
|
||||
monitor.uptimePercentage = status === true ? 1 : 0;
|
||||
} else {
|
||||
monitor.uptimePercentage =
|
||||
(monitor.uptimePercentage * (n - 1) + (status === true ? 1 : 0)) / n;
|
||||
}
|
||||
|
||||
await monitor.save();
|
||||
await monitor.save();
|
||||
|
||||
return check;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createCheck";
|
||||
throw error;
|
||||
}
|
||||
return check;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createCheck";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getChecksCount = async (req) => {
|
||||
const monitorId = req.params.monitorId;
|
||||
const dateRange = req.query.dateRange;
|
||||
const filter = req.query.filter;
|
||||
// Build query
|
||||
const checksQuery = { monitorId: monitorId };
|
||||
// Filter checks by "day", "week", or "month"
|
||||
if (dateRange !== undefined) {
|
||||
checksQuery.createdAt = { $gte: dateRangeLookup[dateRange] };
|
||||
}
|
||||
const monitorId = req.params.monitorId;
|
||||
const dateRange = req.query.dateRange;
|
||||
const filter = req.query.filter;
|
||||
// Build query
|
||||
const checksQuery = { monitorId: monitorId };
|
||||
// Filter checks by "day", "week", or "month"
|
||||
if (dateRange !== undefined) {
|
||||
checksQuery.createdAt = { $gte: dateRangeLookup[dateRange] };
|
||||
}
|
||||
|
||||
if (filter !== undefined) {
|
||||
checksQuery.status = false;
|
||||
switch (filter) {
|
||||
case "all":
|
||||
break;
|
||||
case "down":
|
||||
break;
|
||||
case "resolve":
|
||||
checksQuery.statusCode = 5000;
|
||||
break;
|
||||
default:
|
||||
console.log("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filter !== undefined) {
|
||||
checksQuery.status = false;
|
||||
switch (filter) {
|
||||
case "all":
|
||||
break;
|
||||
case "down":
|
||||
break;
|
||||
case "resolve":
|
||||
checksQuery.statusCode = 5000;
|
||||
break;
|
||||
default:
|
||||
console.log("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const count = await Check.countDocuments(checksQuery);
|
||||
return count;
|
||||
const count = await Check.countDocuments(checksQuery);
|
||||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -95,104 +95,104 @@ const getChecksCount = async (req) => {
|
||||
*/
|
||||
|
||||
const getChecks = async (req) => {
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
let { sortOrder, limit, dateRange, filter, page, rowsPerPage } = req.query;
|
||||
// Default limit to 0 if not provided
|
||||
limit = limit === "undefined" ? 0 : limit;
|
||||
try {
|
||||
const { monitorId } = req.params;
|
||||
let { sortOrder, limit, dateRange, filter, page, rowsPerPage } = req.query;
|
||||
// Default limit to 0 if not provided
|
||||
limit = limit === "undefined" ? 0 : limit;
|
||||
|
||||
// Default sort order is newest -> oldest
|
||||
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||||
// Default sort order is newest -> oldest
|
||||
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||||
|
||||
// Build query
|
||||
const checksQuery = { monitorId: monitorId };
|
||||
// Filter checks by "day", "week", or "month"
|
||||
if (dateRange !== undefined) {
|
||||
checksQuery.createdAt = { $gte: dateRangeLookup[dateRange] };
|
||||
}
|
||||
// Fitler checks by status
|
||||
if (filter !== undefined) {
|
||||
checksQuery.status = false;
|
||||
switch (filter) {
|
||||
case "all":
|
||||
break;
|
||||
case "down":
|
||||
break;
|
||||
case "resolve":
|
||||
checksQuery.statusCode = 5000;
|
||||
break;
|
||||
default:
|
||||
console.log("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Build query
|
||||
const checksQuery = { monitorId: monitorId };
|
||||
// Filter checks by "day", "week", or "month"
|
||||
if (dateRange !== undefined) {
|
||||
checksQuery.createdAt = { $gte: dateRangeLookup[dateRange] };
|
||||
}
|
||||
// Fitler checks by status
|
||||
if (filter !== undefined) {
|
||||
checksQuery.status = false;
|
||||
switch (filter) {
|
||||
case "all":
|
||||
break;
|
||||
case "down":
|
||||
break;
|
||||
case "resolve":
|
||||
checksQuery.statusCode = 5000;
|
||||
break;
|
||||
default:
|
||||
console.log("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to skip and limit here
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
const checks = await Check.find(checksQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort({ createdAt: sortOrder });
|
||||
return checks;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getChecks";
|
||||
throw error;
|
||||
}
|
||||
// Need to skip and limit here
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
const checks = await Check.find(checksQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort({ createdAt: sortOrder });
|
||||
return checks;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getChecks";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getTeamChecks = async (req) => {
|
||||
const { teamId } = req.params;
|
||||
let { sortOrder, limit, dateRange, filter, page, rowsPerPage } = req.query;
|
||||
const { teamId } = req.params;
|
||||
let { sortOrder, limit, dateRange, filter, page, rowsPerPage } = req.query;
|
||||
|
||||
// Get monitorIDs
|
||||
const userMonitors = await Monitor.find({ teamId: teamId }).select("_id");
|
||||
// Get monitorIDs
|
||||
const userMonitors = await Monitor.find({ teamId: teamId }).select("_id");
|
||||
|
||||
//Build check query
|
||||
// Default limit to 0 if not provided
|
||||
limit = limit === undefined ? 0 : limit;
|
||||
// Default sort order is newest -> oldest
|
||||
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||||
//Build check query
|
||||
// Default limit to 0 if not provided
|
||||
limit = limit === undefined ? 0 : limit;
|
||||
// Default sort order is newest -> oldest
|
||||
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||||
|
||||
checksQuery = { monitorId: { $in: userMonitors } };
|
||||
checksQuery = { monitorId: { $in: userMonitors } };
|
||||
|
||||
if (filter !== undefined) {
|
||||
checksQuery.status = false;
|
||||
switch (filter) {
|
||||
case "all":
|
||||
break;
|
||||
case "down":
|
||||
break;
|
||||
case "resolve":
|
||||
checksQuery.statusCode = 5000;
|
||||
break;
|
||||
default:
|
||||
console.log("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filter !== undefined) {
|
||||
checksQuery.status = false;
|
||||
switch (filter) {
|
||||
case "all":
|
||||
break;
|
||||
case "down":
|
||||
break;
|
||||
case "resolve":
|
||||
checksQuery.statusCode = 5000;
|
||||
break;
|
||||
default:
|
||||
console.log("default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dateRange !== undefined) {
|
||||
checksQuery.createdAt = { $gte: dateRangeLookup[dateRange] };
|
||||
}
|
||||
if (dateRange !== undefined) {
|
||||
checksQuery.createdAt = { $gte: dateRangeLookup[dateRange] };
|
||||
}
|
||||
|
||||
// Skip and limit for pagination
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
// Skip and limit for pagination
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
|
||||
const checksCount = await Check.countDocuments(checksQuery);
|
||||
const checksCount = await Check.countDocuments(checksQuery);
|
||||
|
||||
const checks = await Check.find(checksQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort({ createdAt: sortOrder })
|
||||
.select(["monitorId", "status", "responseTime", "statusCode", "message"]);
|
||||
return { checksCount, checks };
|
||||
const checks = await Check.find(checksQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort({ createdAt: sortOrder })
|
||||
.select(["monitorId", "status", "responseTime", "statusCode", "message"]);
|
||||
return { checksCount, checks };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -204,14 +204,14 @@ const getTeamChecks = async (req) => {
|
||||
*/
|
||||
|
||||
const deleteChecks = async (monitorId) => {
|
||||
try {
|
||||
const result = await Check.deleteMany({ monitorId });
|
||||
return result.deletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteChecks";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const result = await Check.deleteMany({ monitorId });
|
||||
return result.deletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteChecks";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -223,63 +223,63 @@ const deleteChecks = async (monitorId) => {
|
||||
*/
|
||||
|
||||
const deleteChecksByTeamId = async (teamId) => {
|
||||
try {
|
||||
const teamMonitors = await Monitor.find({ teamId: teamId });
|
||||
let totalDeletedCount = 0;
|
||||
try {
|
||||
const teamMonitors = await Monitor.find({ teamId: teamId });
|
||||
let totalDeletedCount = 0;
|
||||
|
||||
await Promise.all(
|
||||
teamMonitors.map(async (monitor) => {
|
||||
const result = await Check.deleteMany({ monitorId: monitor._id });
|
||||
totalDeletedCount += result.deletedCount;
|
||||
monitor.status = true;
|
||||
await monitor.save();
|
||||
})
|
||||
);
|
||||
await Promise.all(
|
||||
teamMonitors.map(async (monitor) => {
|
||||
const result = await Check.deleteMany({ monitorId: monitor._id });
|
||||
totalDeletedCount += result.deletedCount;
|
||||
monitor.status = true;
|
||||
await monitor.save();
|
||||
})
|
||||
);
|
||||
|
||||
return totalDeletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteChecksByTeamId";
|
||||
throw error;
|
||||
}
|
||||
return totalDeletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteChecksByTeamId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const updateChecksTTL = async (teamId, ttl) => {
|
||||
try {
|
||||
await Check.collection.dropIndex("expiry_1");
|
||||
} catch (error) {
|
||||
logger.error("Failed to drop index", {
|
||||
service: SERVICE_NAME,
|
||||
method: "updateChecksTTL",
|
||||
});
|
||||
}
|
||||
try {
|
||||
await Check.collection.dropIndex("expiry_1");
|
||||
} catch (error) {
|
||||
logger.error("Failed to drop index", {
|
||||
service: SERVICE_NAME,
|
||||
method: "updateChecksTTL",
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await Check.collection.createIndex(
|
||||
{ expiry: 1 },
|
||||
{ expireAfterSeconds: ttl } // TTL in seconds, adjust as necessary
|
||||
);
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateChecksTTL";
|
||||
throw error;
|
||||
}
|
||||
// Update user
|
||||
try {
|
||||
await User.updateMany({ teamId: teamId }, { checkTTL: ttl });
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateChecksTTL";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await Check.collection.createIndex(
|
||||
{ expiry: 1 },
|
||||
{ expireAfterSeconds: ttl } // TTL in seconds, adjust as necessary
|
||||
);
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateChecksTTL";
|
||||
throw error;
|
||||
}
|
||||
// Update user
|
||||
try {
|
||||
await User.updateMany({ teamId: teamId }, { checkTTL: ttl });
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateChecksTTL";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createCheck,
|
||||
getChecksCount,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
createCheck,
|
||||
getChecksCount,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
};
|
||||
|
||||
@@ -18,17 +18,17 @@ const SERVICE_NAME = "inviteModule";
|
||||
* @throws {Error} If there is an error.
|
||||
*/
|
||||
const requestInviteToken = async (userData) => {
|
||||
try {
|
||||
await InviteToken.deleteMany({ email: userData.email });
|
||||
userData.token = crypto.randomBytes(32).toString("hex");
|
||||
let inviteToken = new InviteToken(userData);
|
||||
await inviteToken.save();
|
||||
return inviteToken;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "requestInviteToken";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await InviteToken.deleteMany({ email: userData.email });
|
||||
userData.token = crypto.randomBytes(32).toString("hex");
|
||||
let inviteToken = new InviteToken(userData);
|
||||
await inviteToken.save();
|
||||
return inviteToken;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "requestInviteToken";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -42,19 +42,19 @@ const requestInviteToken = async (userData) => {
|
||||
* @throws {Error} If the invite token is not found or there is another error.
|
||||
*/
|
||||
const getInviteToken = async (token) => {
|
||||
try {
|
||||
const invite = await InviteToken.findOne({
|
||||
token,
|
||||
});
|
||||
if (invite === null) {
|
||||
throw new Error(errorMessages.AUTH_INVITE_NOT_FOUND);
|
||||
}
|
||||
return invite;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getInviteToken";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const invite = await InviteToken.findOne({
|
||||
token,
|
||||
});
|
||||
if (invite === null) {
|
||||
throw new Error(errorMessages.AUTH_INVITE_NOT_FOUND);
|
||||
}
|
||||
return invite;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getInviteToken";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -68,19 +68,19 @@ const getInviteToken = async (token) => {
|
||||
* @throws {Error} If the invite token is not found or there is another error.
|
||||
*/
|
||||
const getInviteTokenAndDelete = async (token) => {
|
||||
try {
|
||||
const invite = await InviteToken.findOneAndDelete({
|
||||
token,
|
||||
});
|
||||
if (invite === null) {
|
||||
throw new Error(errorMessages.AUTH_INVITE_NOT_FOUND);
|
||||
}
|
||||
return invite;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getInviteToken";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const invite = await InviteToken.findOneAndDelete({
|
||||
token,
|
||||
});
|
||||
if (invite === null) {
|
||||
throw new Error(errorMessages.AUTH_INVITE_NOT_FOUND);
|
||||
}
|
||||
return invite;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getInviteToken";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export { requestInviteToken, getInviteToken, getInviteTokenAndDelete };
|
||||
|
||||
@@ -27,35 +27,35 @@ const SERVICE_NAME = "maintenanceWindowModule";
|
||||
* .catch(error => console.error(error));
|
||||
*/
|
||||
const createMaintenanceWindow = async (maintenanceWindowData) => {
|
||||
try {
|
||||
const maintenanceWindow = new MaintenanceWindow({
|
||||
...maintenanceWindowData,
|
||||
});
|
||||
try {
|
||||
const maintenanceWindow = new MaintenanceWindow({
|
||||
...maintenanceWindowData,
|
||||
});
|
||||
|
||||
// If the maintenance window is a one time window, set the expiry to the end date
|
||||
if (maintenanceWindowData.oneTime) {
|
||||
maintenanceWindow.expiry = maintenanceWindowData.end;
|
||||
}
|
||||
const result = await maintenanceWindow.save();
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createMaintenanceWindow";
|
||||
throw error;
|
||||
}
|
||||
// If the maintenance window is a one time window, set the expiry to the end date
|
||||
if (maintenanceWindowData.oneTime) {
|
||||
maintenanceWindow.expiry = maintenanceWindowData.end;
|
||||
}
|
||||
const result = await maintenanceWindow.save();
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createMaintenanceWindow";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getMaintenanceWindowById = async (maintenanceWindowId) => {
|
||||
try {
|
||||
const maintenanceWindow = await MaintenanceWindow.findById({
|
||||
_id: maintenanceWindowId,
|
||||
});
|
||||
return maintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMaintenanceWindowById";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const maintenanceWindow = await MaintenanceWindow.findById({
|
||||
_id: maintenanceWindowId,
|
||||
});
|
||||
return maintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMaintenanceWindowById";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -72,38 +72,38 @@ const getMaintenanceWindowById = async (maintenanceWindowId) => {
|
||||
* .catch(error => console.error(error));
|
||||
*/
|
||||
const getMaintenanceWindowsByTeamId = async (teamId, query) => {
|
||||
try {
|
||||
let { active, page, rowsPerPage, field, order } = query || {};
|
||||
const maintenanceQuery = { teamId };
|
||||
try {
|
||||
let { active, page, rowsPerPage, field, order } = query || {};
|
||||
const maintenanceQuery = { teamId };
|
||||
|
||||
if (active !== undefined) maintenanceQuery.active = active;
|
||||
if (active !== undefined) maintenanceQuery.active = active;
|
||||
|
||||
const maintenanceWindowCount =
|
||||
await MaintenanceWindow.countDocuments(maintenanceQuery);
|
||||
const maintenanceWindowCount =
|
||||
await MaintenanceWindow.countDocuments(maintenanceQuery);
|
||||
|
||||
// Pagination
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
// Pagination
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
|
||||
// Sorting
|
||||
let sort = {};
|
||||
if (field !== undefined && order !== undefined) {
|
||||
sort[field] = order === "asc" ? 1 : -1;
|
||||
}
|
||||
// Sorting
|
||||
let sort = {};
|
||||
if (field !== undefined && order !== undefined) {
|
||||
sort[field] = order === "asc" ? 1 : -1;
|
||||
}
|
||||
|
||||
const maintenanceWindows = await MaintenanceWindow.find(maintenanceQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort(sort);
|
||||
const maintenanceWindows = await MaintenanceWindow.find(maintenanceQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort(sort);
|
||||
|
||||
return { maintenanceWindows, maintenanceWindowCount };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMaintenanceWindowByUserId";
|
||||
throw error;
|
||||
}
|
||||
return { maintenanceWindows, maintenanceWindowCount };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMaintenanceWindowByUserId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -119,16 +119,16 @@ const getMaintenanceWindowsByTeamId = async (teamId, query) => {
|
||||
* .catch(error => console.error(error));
|
||||
*/
|
||||
const getMaintenanceWindowsByMonitorId = async (monitorId) => {
|
||||
try {
|
||||
const maintenanceWindows = await MaintenanceWindow.find({
|
||||
monitorId: monitorId,
|
||||
});
|
||||
return maintenanceWindows;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMaintenanceWindowsByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const maintenanceWindows = await MaintenanceWindow.find({
|
||||
monitorId: monitorId,
|
||||
});
|
||||
return maintenanceWindows;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMaintenanceWindowsByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -144,15 +144,15 @@ const getMaintenanceWindowsByMonitorId = async (monitorId) => {
|
||||
* .catch(error => console.error(error));
|
||||
*/
|
||||
const deleteMaintenanceWindowById = async (maintenanceWindowId) => {
|
||||
try {
|
||||
const maintenanceWindow =
|
||||
await MaintenanceWindow.findByIdAndDelete(maintenanceWindowId);
|
||||
return maintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMaintenanceWindowById";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const maintenanceWindow =
|
||||
await MaintenanceWindow.findByIdAndDelete(maintenanceWindowId);
|
||||
return maintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMaintenanceWindowById";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -168,14 +168,14 @@ const deleteMaintenanceWindowById = async (maintenanceWindowId) => {
|
||||
* .catch(error => console.error(error));
|
||||
*/
|
||||
const deleteMaintenanceWindowByMonitorId = async (monitorId) => {
|
||||
try {
|
||||
const result = await MaintenanceWindow.deleteMany({ monitorId: monitorId });
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMaintenanceWindowByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const result = await MaintenanceWindow.deleteMany({ monitorId: monitorId });
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMaintenanceWindowByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -191,42 +191,39 @@ const deleteMaintenanceWindowByMonitorId = async (monitorId) => {
|
||||
* .catch(error => console.error(error));
|
||||
*/
|
||||
const deleteMaintenanceWindowByUserId = async (userId) => {
|
||||
try {
|
||||
const result = await MaintenanceWindow.deleteMany({ userId: userId });
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMaintenanceWindowByUserId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const result = await MaintenanceWindow.deleteMany({ userId: userId });
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMaintenanceWindowByUserId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const editMaintenanceWindowById = async (
|
||||
maintenanceWindowId,
|
||||
maintenanceWindowData
|
||||
) => {
|
||||
console.log(maintenanceWindowData);
|
||||
try {
|
||||
const editedMaintenanceWindow = MaintenanceWindow.findByIdAndUpdate(
|
||||
maintenanceWindowId,
|
||||
maintenanceWindowData,
|
||||
{ new: true }
|
||||
);
|
||||
return editedMaintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "editMaintenanceWindowById";
|
||||
throw error;
|
||||
}
|
||||
const editMaintenanceWindowById = async (maintenanceWindowId, maintenanceWindowData) => {
|
||||
console.log(maintenanceWindowData);
|
||||
try {
|
||||
const editedMaintenanceWindow = MaintenanceWindow.findByIdAndUpdate(
|
||||
maintenanceWindowId,
|
||||
maintenanceWindowData,
|
||||
{ new: true }
|
||||
);
|
||||
return editedMaintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "editMaintenanceWindowById";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createMaintenanceWindow,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindowById,
|
||||
deleteMaintenanceWindowByMonitorId,
|
||||
deleteMaintenanceWindowByUserId,
|
||||
editMaintenanceWindowById,
|
||||
createMaintenanceWindow,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindowById,
|
||||
deleteMaintenanceWindowByMonitorId,
|
||||
deleteMaintenanceWindowByUserId,
|
||||
editMaintenanceWindowById,
|
||||
};
|
||||
|
||||
@@ -11,10 +11,7 @@ import { fileURLToPath } from "url";
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const demoMonitorsPath = path.resolve(
|
||||
__dirname,
|
||||
"../../../utils/demoMonitors.json"
|
||||
);
|
||||
const demoMonitorsPath = path.resolve(__dirname, "../../../utils/demoMonitors.json");
|
||||
const demoMonitors = JSON.parse(fs.readFileSync(demoMonitorsPath, "utf8"));
|
||||
|
||||
const SERVICE_NAME = "monitorModule";
|
||||
@@ -28,14 +25,14 @@ const SERVICE_NAME = "monitorModule";
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getAllMonitors = async (req, res) => {
|
||||
try {
|
||||
const monitors = await Monitor.find();
|
||||
return monitors;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getAllMonitors";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const monitors = await Monitor.find();
|
||||
return monitors;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getAllMonitors";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -44,27 +41,27 @@ const getAllMonitors = async (req, res) => {
|
||||
* @returns {number} Uptime duration in ms.
|
||||
*/
|
||||
const calculateUptimeDuration = (checks) => {
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const latestCheck = new Date(checks[0].createdAt);
|
||||
let latestDownCheck = 0;
|
||||
const latestCheck = new Date(checks[0].createdAt);
|
||||
let latestDownCheck = 0;
|
||||
|
||||
for (let i = checks.length; i <= 0; i--) {
|
||||
if (checks[i].status === false) {
|
||||
latestDownCheck = new Date(checks[i].createdAt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = checks.length; i <= 0; i--) {
|
||||
if (checks[i].status === false) {
|
||||
latestDownCheck = new Date(checks[i].createdAt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no down check is found, uptime is from the last check to now
|
||||
if (latestDownCheck === 0) {
|
||||
return Date.now() - new Date(checks[checks.length - 1].createdAt);
|
||||
}
|
||||
// If no down check is found, uptime is from the last check to now
|
||||
if (latestDownCheck === 0) {
|
||||
return Date.now() - new Date(checks[checks.length - 1].createdAt);
|
||||
}
|
||||
|
||||
// Otherwise the uptime is from the last check to the last down check
|
||||
return latestCheck - latestDownCheck;
|
||||
// Otherwise the uptime is from the last check to the last down check
|
||||
return latestCheck - latestDownCheck;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -73,11 +70,11 @@ const calculateUptimeDuration = (checks) => {
|
||||
* @returns {number} Timestamp of the most recent check.
|
||||
*/
|
||||
const getLastChecked = (checks) => {
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0; // Handle case when no checks are available
|
||||
}
|
||||
// Data is sorted newest->oldest, so last check is the most recent
|
||||
return new Date() - new Date(checks[0].createdAt);
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0; // Handle case when no checks are available
|
||||
}
|
||||
// Data is sorted newest->oldest, so last check is the most recent
|
||||
return new Date() - new Date(checks[0].createdAt);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -86,10 +83,10 @@ const getLastChecked = (checks) => {
|
||||
* @returns {number} Timestamp of the most recent check.
|
||||
*/
|
||||
const getLatestResponseTime = (checks) => {
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
return checks[0].responseTime;
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
return checks[0].responseTime;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -98,13 +95,13 @@ const getLatestResponseTime = (checks) => {
|
||||
* @returns {number} Timestamp of the most recent check.
|
||||
*/
|
||||
const getAverageResponseTime = (checks) => {
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
const aggResponseTime = checks.reduce((sum, check) => {
|
||||
return sum + check.responseTime;
|
||||
}, 0);
|
||||
return aggResponseTime / checks.length;
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
const aggResponseTime = checks.reduce((sum, check) => {
|
||||
return sum + check.responseTime;
|
||||
}, 0);
|
||||
return aggResponseTime / checks.length;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -114,13 +111,13 @@ const getAverageResponseTime = (checks) => {
|
||||
*/
|
||||
|
||||
const getUptimePercentage = (checks) => {
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
const upCount = checks.reduce((count, check) => {
|
||||
return check.status === true ? count + 1 : count;
|
||||
}, 0);
|
||||
return (upCount / checks.length) * 100;
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
const upCount = checks.reduce((count, check) => {
|
||||
return check.status === true ? count + 1 : count;
|
||||
}, 0);
|
||||
return (upCount / checks.length) * 100;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -130,12 +127,12 @@ const getUptimePercentage = (checks) => {
|
||||
*/
|
||||
|
||||
const getIncidents = (checks) => {
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0; // Handle case when no checks are available
|
||||
}
|
||||
return checks.reduce((acc, check) => {
|
||||
return check.status === false ? (acc += 1) : acc;
|
||||
}, 0);
|
||||
if (!checks || checks.length === 0) {
|
||||
return 0; // Handle case when no checks are available
|
||||
}
|
||||
return checks.reduce((acc, check) => {
|
||||
return check.status === false ? (acc += 1) : acc;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -147,140 +144,136 @@ const getIncidents = (checks) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getMonitorStatsById = async (req) => {
|
||||
const startDates = {
|
||||
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
||||
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||||
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
||||
};
|
||||
const endDate = new Date();
|
||||
try {
|
||||
// Get monitor
|
||||
const { monitorId } = req.params;
|
||||
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
if (monitor === null || monitor === undefined) {
|
||||
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
|
||||
}
|
||||
// This effectively removes limit, returning all checks
|
||||
if (limit === undefined) limit = 0;
|
||||
// Default sort order is newest -> oldest
|
||||
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||||
const startDates = {
|
||||
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
||||
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||||
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
||||
};
|
||||
const endDate = new Date();
|
||||
try {
|
||||
// Get monitor
|
||||
const { monitorId } = req.params;
|
||||
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
if (monitor === null || monitor === undefined) {
|
||||
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
|
||||
}
|
||||
// This effectively removes limit, returning all checks
|
||||
if (limit === undefined) limit = 0;
|
||||
// Default sort order is newest -> oldest
|
||||
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||||
|
||||
let model =
|
||||
monitor.type === "http" || monitor.type === "ping"
|
||||
? Check
|
||||
: PageSpeedCheck;
|
||||
let model =
|
||||
monitor.type === "http" || monitor.type === "ping" ? Check : PageSpeedCheck;
|
||||
|
||||
const monitorStats = {
|
||||
...monitor.toObject(),
|
||||
};
|
||||
const monitorStats = {
|
||||
...monitor.toObject(),
|
||||
};
|
||||
|
||||
// Build checks query
|
||||
const checksQuery = { monitorId: monitor._id };
|
||||
// Build checks query
|
||||
const checksQuery = { monitorId: monitor._id };
|
||||
|
||||
// Get all checks
|
||||
const checksAll = await model.find(checksQuery).sort({
|
||||
createdAt: sortOrder,
|
||||
});
|
||||
// Get all checks
|
||||
const checksAll = await model.find(checksQuery).sort({
|
||||
createdAt: sortOrder,
|
||||
});
|
||||
|
||||
const checksQueryForDateRange = {
|
||||
...checksQuery,
|
||||
createdAt: {
|
||||
$gte: startDates[dateRange],
|
||||
$lte: endDate,
|
||||
},
|
||||
};
|
||||
const checksQueryForDateRange = {
|
||||
...checksQuery,
|
||||
createdAt: {
|
||||
$gte: startDates[dateRange],
|
||||
$lte: endDate,
|
||||
},
|
||||
};
|
||||
|
||||
const checksForDateRange = await model
|
||||
.find(checksQueryForDateRange)
|
||||
.sort({ createdAt: sortOrder });
|
||||
const checksForDateRange = await model
|
||||
.find(checksQueryForDateRange)
|
||||
.sort({ createdAt: sortOrder });
|
||||
|
||||
if (monitor.type === "http" || monitor.type === "ping") {
|
||||
// HTTP/PING Specific stats
|
||||
monitorStats.periodAvgResponseTime =
|
||||
getAverageResponseTime(checksForDateRange);
|
||||
monitorStats.periodUptime = getUptimePercentage(checksForDateRange);
|
||||
if (monitor.type === "http" || monitor.type === "ping") {
|
||||
// HTTP/PING Specific stats
|
||||
monitorStats.periodAvgResponseTime = getAverageResponseTime(checksForDateRange);
|
||||
monitorStats.periodUptime = getUptimePercentage(checksForDateRange);
|
||||
|
||||
// Aggregate data
|
||||
let groupedChecks;
|
||||
// Group checks by hour if range is day
|
||||
if (dateRange === "day") {
|
||||
groupedChecks = checksForDateRange.reduce((acc, check) => {
|
||||
const time = new Date(check.createdAt);
|
||||
time.setMinutes(0, 0, 0);
|
||||
if (!acc[time]) {
|
||||
acc[time] = { time, checks: [] };
|
||||
}
|
||||
acc[time].checks.push(check);
|
||||
return acc;
|
||||
}, {});
|
||||
} else {
|
||||
groupedChecks = checksForDateRange.reduce((acc, check) => {
|
||||
const time = new Date(check.createdAt).toISOString().split("T")[0]; // Extract the date part
|
||||
if (!acc[time]) {
|
||||
acc[time] = { time, checks: [] };
|
||||
}
|
||||
acc[time].checks.push(check);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
// Aggregate data
|
||||
let groupedChecks;
|
||||
// Group checks by hour if range is day
|
||||
if (dateRange === "day") {
|
||||
groupedChecks = checksForDateRange.reduce((acc, check) => {
|
||||
const time = new Date(check.createdAt);
|
||||
time.setMinutes(0, 0, 0);
|
||||
if (!acc[time]) {
|
||||
acc[time] = { time, checks: [] };
|
||||
}
|
||||
acc[time].checks.push(check);
|
||||
return acc;
|
||||
}, {});
|
||||
} else {
|
||||
groupedChecks = checksForDateRange.reduce((acc, check) => {
|
||||
const time = new Date(check.createdAt).toISOString().split("T")[0]; // Extract the date part
|
||||
if (!acc[time]) {
|
||||
acc[time] = { time, checks: [] };
|
||||
}
|
||||
acc[time].checks.push(check);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Map grouped checks to stats
|
||||
const aggregateData = Object.values(groupedChecks).map((group) => {
|
||||
const totalChecks = group.checks.length;
|
||||
const uptimePercentage = getUptimePercentage(group.checks);
|
||||
const totalIncidents = group.checks.filter(
|
||||
(check) => check.status === false
|
||||
).length;
|
||||
const avgResponseTime =
|
||||
group.checks.reduce((sum, check) => sum + check.responseTime, 0) /
|
||||
totalChecks;
|
||||
// Map grouped checks to stats
|
||||
const aggregateData = Object.values(groupedChecks).map((group) => {
|
||||
const totalChecks = group.checks.length;
|
||||
const uptimePercentage = getUptimePercentage(group.checks);
|
||||
const totalIncidents = group.checks.filter(
|
||||
(check) => check.status === false
|
||||
).length;
|
||||
const avgResponseTime =
|
||||
group.checks.reduce((sum, check) => sum + check.responseTime, 0) / totalChecks;
|
||||
|
||||
return {
|
||||
time: group.time,
|
||||
uptimePercentage,
|
||||
totalChecks,
|
||||
totalIncidents,
|
||||
avgResponseTime,
|
||||
};
|
||||
});
|
||||
monitorStats.aggregateData = aggregateData;
|
||||
}
|
||||
return {
|
||||
time: group.time,
|
||||
uptimePercentage,
|
||||
totalChecks,
|
||||
totalIncidents,
|
||||
avgResponseTime,
|
||||
};
|
||||
});
|
||||
monitorStats.aggregateData = aggregateData;
|
||||
}
|
||||
|
||||
monitorStats.periodIncidents = getIncidents(checksForDateRange);
|
||||
monitorStats.periodTotalChecks = checksForDateRange.length;
|
||||
monitorStats.periodIncidents = getIncidents(checksForDateRange);
|
||||
monitorStats.periodTotalChecks = checksForDateRange.length;
|
||||
|
||||
// If more than numToDisplay checks, pick every nth check
|
||||
// If more than numToDisplay checks, pick every nth check
|
||||
|
||||
let nthChecks = checksForDateRange;
|
||||
let nthChecks = checksForDateRange;
|
||||
|
||||
if (
|
||||
numToDisplay !== undefined &&
|
||||
checksForDateRange &&
|
||||
checksForDateRange.length > numToDisplay
|
||||
) {
|
||||
const n = Math.ceil(checksForDateRange.length / numToDisplay);
|
||||
nthChecks = checksForDateRange.filter((_, index) => index % n === 0);
|
||||
}
|
||||
if (
|
||||
numToDisplay !== undefined &&
|
||||
checksForDateRange &&
|
||||
checksForDateRange.length > numToDisplay
|
||||
) {
|
||||
const n = Math.ceil(checksForDateRange.length / numToDisplay);
|
||||
nthChecks = checksForDateRange.filter((_, index) => index % n === 0);
|
||||
}
|
||||
|
||||
// Normalize checks if requested
|
||||
if (normalize !== undefined) {
|
||||
const normailzedChecks = NormalizeData(nthChecks, 1, 100);
|
||||
monitorStats.checks = normailzedChecks;
|
||||
} else {
|
||||
monitorStats.checks = nthChecks;
|
||||
}
|
||||
// Normalize checks if requested
|
||||
if (normalize !== undefined) {
|
||||
const normailzedChecks = NormalizeData(nthChecks, 1, 100);
|
||||
monitorStats.checks = normailzedChecks;
|
||||
} else {
|
||||
monitorStats.checks = nthChecks;
|
||||
}
|
||||
|
||||
monitorStats.uptimeDuration = calculateUptimeDuration(checksAll);
|
||||
monitorStats.lastChecked = getLastChecked(checksAll);
|
||||
monitorStats.latestResponseTime = getLatestResponseTime(checksAll);
|
||||
monitorStats.uptimeDuration = calculateUptimeDuration(checksAll);
|
||||
monitorStats.lastChecked = getLastChecked(checksAll);
|
||||
monitorStats.latestResponseTime = getLatestResponseTime(checksAll);
|
||||
|
||||
return monitorStats;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorStatsById";
|
||||
throw error;
|
||||
}
|
||||
return monitorStats;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorStatsById";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -292,23 +285,23 @@ const getMonitorStatsById = async (req) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getMonitorById = async (monitorId) => {
|
||||
try {
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
if (monitor === null || monitor === undefined) {
|
||||
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
|
||||
}
|
||||
// Get notifications
|
||||
const notifications = await Notification.find({
|
||||
monitorId: monitorId,
|
||||
});
|
||||
monitor.notifications = notifications;
|
||||
const monitorWithNotifications = await monitor.save();
|
||||
return monitorWithNotifications;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorById";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const monitor = await Monitor.findById(monitorId);
|
||||
if (monitor === null || monitor === undefined) {
|
||||
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
|
||||
}
|
||||
// Get notifications
|
||||
const notifications = await Notification.find({
|
||||
monitorId: monitorId,
|
||||
});
|
||||
monitor.notifications = notifications;
|
||||
const monitorWithNotifications = await monitor.save();
|
||||
return monitorWithNotifications;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorById";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -321,32 +314,32 @@ const getMonitorById = async (monitorId) => {
|
||||
*/
|
||||
|
||||
const getMonitorsAndSummaryByTeamId = async (teamId, type) => {
|
||||
try {
|
||||
const monitors = await Monitor.find({ teamId, type });
|
||||
const monitorCounts = monitors.reduce(
|
||||
(acc, monitor) => {
|
||||
if (monitor.status === true) {
|
||||
acc.up += 1;
|
||||
}
|
||||
try {
|
||||
const monitors = await Monitor.find({ teamId, type });
|
||||
const monitorCounts = monitors.reduce(
|
||||
(acc, monitor) => {
|
||||
if (monitor.status === true) {
|
||||
acc.up += 1;
|
||||
}
|
||||
|
||||
if (monitor.status === false) {
|
||||
acc.down += 1;
|
||||
}
|
||||
if (monitor.status === false) {
|
||||
acc.down += 1;
|
||||
}
|
||||
|
||||
if (monitor.isActive === false) {
|
||||
acc.paused += 1;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ up: 0, down: 0, paused: 0 }
|
||||
);
|
||||
monitorCounts.total = monitors.length;
|
||||
return { monitors, monitorCounts };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorsAndSummaryByTeamId";
|
||||
throw error;
|
||||
}
|
||||
if (monitor.isActive === false) {
|
||||
acc.paused += 1;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ up: 0, down: 0, paused: 0 }
|
||||
);
|
||||
monitorCounts.total = monitors.length;
|
||||
return { monitors, monitorCounts };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorsAndSummaryByTeamId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -358,104 +351,102 @@ const getMonitorsAndSummaryByTeamId = async (teamId, type) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getMonitorsByTeamId = async (req, res) => {
|
||||
try {
|
||||
let {
|
||||
limit,
|
||||
type,
|
||||
status,
|
||||
checkOrder,
|
||||
normalize,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
} = req.query || {};
|
||||
const monitorQuery = { teamId: req.params.teamId };
|
||||
if (type !== undefined) {
|
||||
monitorQuery.type = type;
|
||||
}
|
||||
// Add filter if provided
|
||||
// $options: "i" makes the search case-insensitive
|
||||
if (filter !== undefined) {
|
||||
monitorQuery.$or = [
|
||||
{ name: { $regex: filter, $options: "i" } },
|
||||
{ url: { $regex: filter, $options: "i" } },
|
||||
];
|
||||
}
|
||||
const monitorsCount = await Monitor.countDocuments(monitorQuery);
|
||||
try {
|
||||
let {
|
||||
limit,
|
||||
type,
|
||||
status,
|
||||
checkOrder,
|
||||
normalize,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
} = req.query || {};
|
||||
const monitorQuery = { teamId: req.params.teamId };
|
||||
if (type !== undefined) {
|
||||
monitorQuery.type = type;
|
||||
}
|
||||
// Add filter if provided
|
||||
// $options: "i" makes the search case-insensitive
|
||||
if (filter !== undefined) {
|
||||
monitorQuery.$or = [
|
||||
{ name: { $regex: filter, $options: "i" } },
|
||||
{ url: { $regex: filter, $options: "i" } },
|
||||
];
|
||||
}
|
||||
const monitorsCount = await Monitor.countDocuments(monitorQuery);
|
||||
|
||||
// Pagination
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
// Pagination
|
||||
let skip = 0;
|
||||
if (page && rowsPerPage) {
|
||||
skip = page * rowsPerPage;
|
||||
}
|
||||
|
||||
if (type !== undefined) {
|
||||
const types = Array.isArray(type) ? type : [type];
|
||||
monitorQuery.type = { $in: types };
|
||||
}
|
||||
if (type !== undefined) {
|
||||
const types = Array.isArray(type) ? type : [type];
|
||||
monitorQuery.type = { $in: types };
|
||||
}
|
||||
|
||||
// Default sort order is newest -> oldest
|
||||
if (checkOrder === "asc") {
|
||||
checkOrder = 1;
|
||||
} else if (checkOrder === "desc") {
|
||||
checkOrder = -1;
|
||||
} else checkOrder = -1;
|
||||
// Default sort order is newest -> oldest
|
||||
if (checkOrder === "asc") {
|
||||
checkOrder = 1;
|
||||
} else if (checkOrder === "desc") {
|
||||
checkOrder = -1;
|
||||
} else checkOrder = -1;
|
||||
|
||||
// Sort order for monitors
|
||||
let sort = {};
|
||||
if (field !== undefined && order !== undefined) {
|
||||
sort[field] = order === "asc" ? 1 : -1;
|
||||
}
|
||||
// Sort order for monitors
|
||||
let sort = {};
|
||||
if (field !== undefined && order !== undefined) {
|
||||
sort[field] = order === "asc" ? 1 : -1;
|
||||
}
|
||||
|
||||
const monitors = await Monitor.find(monitorQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort(sort);
|
||||
const monitors = await Monitor.find(monitorQuery)
|
||||
.skip(skip)
|
||||
.limit(rowsPerPage)
|
||||
.sort(sort);
|
||||
|
||||
// Early return if limit is set to -1, indicating we don't want any checks
|
||||
if (limit === "-1") {
|
||||
return { monitors, monitorCount: monitorsCount };
|
||||
}
|
||||
// Early return if limit is set to -1, indicating we don't want any checks
|
||||
if (limit === "-1") {
|
||||
return { monitors, monitorCount: monitorsCount };
|
||||
}
|
||||
|
||||
// This effectively removes limit, returning all checks
|
||||
if (limit === undefined) limit = 0;
|
||||
// This effectively removes limit, returning all checks
|
||||
if (limit === undefined) limit = 0;
|
||||
|
||||
// Map each monitor to include its associated checks
|
||||
const monitorsWithChecks = await Promise.all(
|
||||
monitors.map(async (monitor) => {
|
||||
const checksQuery = { monitorId: monitor._id };
|
||||
if (status !== undefined) {
|
||||
checksQuery.status = status;
|
||||
}
|
||||
// Map each monitor to include its associated checks
|
||||
const monitorsWithChecks = await Promise.all(
|
||||
monitors.map(async (monitor) => {
|
||||
const checksQuery = { monitorId: monitor._id };
|
||||
if (status !== undefined) {
|
||||
checksQuery.status = status;
|
||||
}
|
||||
|
||||
let model =
|
||||
monitor.type === "http" || monitor.type === "ping"
|
||||
? Check
|
||||
: PageSpeedCheck;
|
||||
let model =
|
||||
monitor.type === "http" || monitor.type === "ping" ? Check : PageSpeedCheck;
|
||||
|
||||
// Checks are order newest -> oldest
|
||||
let checks = await model
|
||||
.find(checksQuery)
|
||||
.sort({
|
||||
createdAt: checkOrder,
|
||||
})
|
||||
.limit(limit);
|
||||
// Checks are order newest -> oldest
|
||||
let checks = await model
|
||||
.find(checksQuery)
|
||||
.sort({
|
||||
createdAt: checkOrder,
|
||||
})
|
||||
.limit(limit);
|
||||
|
||||
//Normalize checks if requested
|
||||
if (normalize !== undefined) {
|
||||
checks = NormalizeData(checks, 10, 100);
|
||||
}
|
||||
return { ...monitor.toObject(), checks };
|
||||
})
|
||||
);
|
||||
return { monitors: monitorsWithChecks, monitorCount: monitorsCount };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorsByTeamId";
|
||||
throw error;
|
||||
}
|
||||
//Normalize checks if requested
|
||||
if (normalize !== undefined) {
|
||||
checks = NormalizeData(checks, 10, 100);
|
||||
}
|
||||
return { ...monitor.toObject(), checks };
|
||||
})
|
||||
);
|
||||
return { monitors: monitorsWithChecks, monitorCount: monitorsCount };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getMonitorsByTeamId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -467,17 +458,17 @@ const getMonitorsByTeamId = async (req, res) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const createMonitor = async (req, res) => {
|
||||
try {
|
||||
const monitor = new Monitor({ ...req.body });
|
||||
// Remove notifications fom monitor as they aren't needed here
|
||||
monitor.notifications = undefined;
|
||||
await monitor.save();
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createMonitor";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const monitor = new Monitor({ ...req.body });
|
||||
// Remove notifications fom monitor as they aren't needed here
|
||||
monitor.notifications = undefined;
|
||||
await monitor.save();
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createMonitor";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -489,18 +480,18 @@ const createMonitor = async (req, res) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const deleteMonitor = async (req, res) => {
|
||||
const monitorId = req.params.monitorId;
|
||||
try {
|
||||
const monitor = await Monitor.findByIdAndDelete(monitorId);
|
||||
if (!monitor) {
|
||||
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
|
||||
}
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMonitor";
|
||||
throw error;
|
||||
}
|
||||
const monitorId = req.params.monitorId;
|
||||
try {
|
||||
const monitor = await Monitor.findByIdAndDelete(monitorId);
|
||||
if (!monitor) {
|
||||
throw new Error(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
|
||||
}
|
||||
return monitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMonitor";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -508,16 +499,16 @@ const deleteMonitor = async (req, res) => {
|
||||
*/
|
||||
|
||||
const deleteAllMonitors = async (teamId) => {
|
||||
try {
|
||||
const monitors = await Monitor.find({ teamId });
|
||||
const { deletedCount } = await Monitor.deleteMany({ teamId });
|
||||
try {
|
||||
const monitors = await Monitor.find({ teamId });
|
||||
const { deletedCount } = await Monitor.deleteMany({ teamId });
|
||||
|
||||
return { monitors, deletedCount };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteAllMonitors";
|
||||
throw error;
|
||||
}
|
||||
return { monitors, deletedCount };
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteAllMonitors";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -527,14 +518,14 @@ const deleteAllMonitors = async (teamId) => {
|
||||
* @returns {Promise} A promise that resolves when the operation is complete.
|
||||
*/
|
||||
const deleteMonitorsByUserId = async (userId) => {
|
||||
try {
|
||||
const result = await Monitor.deleteMany({ userId: userId });
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMonitorsByUserId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const result = await Monitor.deleteMany({ userId: userId });
|
||||
return result;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMonitorsByUserId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -546,54 +537,52 @@ const deleteMonitorsByUserId = async (userId) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const editMonitor = async (candidateId, candidateMonitor) => {
|
||||
candidateMonitor.notifications = undefined;
|
||||
candidateMonitor.notifications = undefined;
|
||||
|
||||
try {
|
||||
const editedMonitor = await Monitor.findByIdAndUpdate(
|
||||
candidateId,
|
||||
candidateMonitor,
|
||||
{ new: true }
|
||||
);
|
||||
return editedMonitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "editMonitor";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const editedMonitor = await Monitor.findByIdAndUpdate(candidateId, candidateMonitor, {
|
||||
new: true,
|
||||
});
|
||||
return editedMonitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "editMonitor";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const addDemoMonitors = async (userId, teamId) => {
|
||||
try {
|
||||
const demoMonitorsToInsert = demoMonitors.map((monitor) => {
|
||||
return {
|
||||
userId,
|
||||
teamId,
|
||||
name: monitor.name,
|
||||
description: monitor.name,
|
||||
type: "http",
|
||||
url: monitor.url,
|
||||
interval: 60000,
|
||||
};
|
||||
});
|
||||
const insertedMonitors = await Monitor.insertMany(demoMonitorsToInsert);
|
||||
return insertedMonitors;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "addDemoMonitors";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const demoMonitorsToInsert = demoMonitors.map((monitor) => {
|
||||
return {
|
||||
userId,
|
||||
teamId,
|
||||
name: monitor.name,
|
||||
description: monitor.name,
|
||||
type: "http",
|
||||
url: monitor.url,
|
||||
interval: 60000,
|
||||
};
|
||||
});
|
||||
const insertedMonitors = await Monitor.insertMany(demoMonitorsToInsert);
|
||||
return insertedMonitors;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "addDemoMonitors";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
getAllMonitors,
|
||||
getMonitorStatsById,
|
||||
getMonitorById,
|
||||
getMonitorsAndSummaryByTeamId,
|
||||
getMonitorsByTeamId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
deleteAllMonitors,
|
||||
deleteMonitorsByUserId,
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
getAllMonitors,
|
||||
getMonitorStatsById,
|
||||
getMonitorById,
|
||||
getMonitorsAndSummaryByTeamId,
|
||||
getMonitorsByTeamId,
|
||||
createMonitor,
|
||||
deleteMonitor,
|
||||
deleteAllMonitors,
|
||||
deleteMonitorsByUserId,
|
||||
editMonitor,
|
||||
addDemoMonitors,
|
||||
};
|
||||
|
||||
@@ -11,14 +11,14 @@ const SERVICE_NAME = "notificationModule";
|
||||
* @throws Will throw an error if the notification cannot be created.
|
||||
*/
|
||||
const createNotification = async (notificationData) => {
|
||||
try {
|
||||
const notification = await new Notification({ ...notificationData }).save();
|
||||
return notification;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createNotification";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const notification = await new Notification({ ...notificationData }).save();
|
||||
return notification;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createNotification";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -28,29 +28,29 @@ const createNotification = async (notificationData) => {
|
||||
* @throws Will throw an error if the notifications cannot be retrieved.
|
||||
*/
|
||||
const getNotificationsByMonitorId = async (monitorId) => {
|
||||
try {
|
||||
const notifications = await Notification.find({ monitorId });
|
||||
return notifications;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getNotificationsByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const notifications = await Notification.find({ monitorId });
|
||||
return notifications;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getNotificationsByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteNotificationsByMonitorId = async (monitorId) => {
|
||||
try {
|
||||
const result = await Notification.deleteMany({ monitorId });
|
||||
return result.deletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteNotificationsByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const result = await Notification.deleteMany({ monitorId });
|
||||
return result.deletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteNotificationsByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
};
|
||||
|
||||
@@ -13,16 +13,16 @@ const SERVICE_NAME = "pageSpeedCheckModule";
|
||||
* @throws {Error}
|
||||
*/
|
||||
const createPageSpeedCheck = async (pageSpeedCheckData) => {
|
||||
try {
|
||||
const pageSpeedCheck = await new PageSpeedCheck({
|
||||
...pageSpeedCheckData,
|
||||
}).save();
|
||||
return pageSpeedCheck;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createPageSpeedCheck";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const pageSpeedCheck = await new PageSpeedCheck({
|
||||
...pageSpeedCheckData,
|
||||
}).save();
|
||||
return pageSpeedCheck;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createPageSpeedCheck";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -34,14 +34,14 @@ const createPageSpeedCheck = async (pageSpeedCheckData) => {
|
||||
*/
|
||||
|
||||
const getPageSpeedChecks = async (monitorId) => {
|
||||
try {
|
||||
const pageSpeedChecks = await PageSpeedCheck.find({ monitorId });
|
||||
return pageSpeedChecks;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getPageSpeedChecks";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const pageSpeedChecks = await PageSpeedCheck.find({ monitorId });
|
||||
return pageSpeedChecks;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getPageSpeedChecks";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -53,18 +53,14 @@ const getPageSpeedChecks = async (monitorId) => {
|
||||
*/
|
||||
|
||||
const deletePageSpeedChecksByMonitorId = async (monitorId) => {
|
||||
try {
|
||||
const result = await PageSpeedCheck.deleteMany({ monitorId });
|
||||
return result.deletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deletePageSpeedChecksByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const result = await PageSpeedCheck.deleteMany({ monitorId });
|
||||
return result.deletedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deletePageSpeedChecksByMonitorId";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createPageSpeedCheck,
|
||||
getPageSpeedChecks,
|
||||
deletePageSpeedChecksByMonitorId,
|
||||
};
|
||||
export { createPageSpeedCheck, getPageSpeedChecks, deletePageSpeedChecksByMonitorId };
|
||||
|
||||
@@ -14,72 +14,72 @@ const SERVICE_NAME = "recoveryModule";
|
||||
* @throws {Error}
|
||||
*/
|
||||
const requestRecoveryToken = async (req, res) => {
|
||||
try {
|
||||
// Delete any existing tokens
|
||||
await RecoveryToken.deleteMany({ email: req.body.email });
|
||||
let recoveryToken = new RecoveryToken({
|
||||
email: req.body.email,
|
||||
token: crypto.randomBytes(32).toString("hex"),
|
||||
});
|
||||
await recoveryToken.save();
|
||||
return recoveryToken;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "requestRecoveryToken";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
// Delete any existing tokens
|
||||
await RecoveryToken.deleteMany({ email: req.body.email });
|
||||
let recoveryToken = new RecoveryToken({
|
||||
email: req.body.email,
|
||||
token: crypto.randomBytes(32).toString("hex"),
|
||||
});
|
||||
await recoveryToken.save();
|
||||
return recoveryToken;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "requestRecoveryToken";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const validateRecoveryToken = async (req, res) => {
|
||||
try {
|
||||
const candidateToken = req.body.recoveryToken;
|
||||
const recoveryToken = await RecoveryToken.findOne({
|
||||
token: candidateToken,
|
||||
});
|
||||
if (recoveryToken !== null) {
|
||||
return recoveryToken;
|
||||
} else {
|
||||
throw new Error(errorMessages.DB_TOKEN_NOT_FOUND);
|
||||
}
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "validateRecoveryToken";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const candidateToken = req.body.recoveryToken;
|
||||
const recoveryToken = await RecoveryToken.findOne({
|
||||
token: candidateToken,
|
||||
});
|
||||
if (recoveryToken !== null) {
|
||||
return recoveryToken;
|
||||
} else {
|
||||
throw new Error(errorMessages.DB_TOKEN_NOT_FOUND);
|
||||
}
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "validateRecoveryToken";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const resetPassword = async (req, res) => {
|
||||
try {
|
||||
const newPassword = req.body.password;
|
||||
try {
|
||||
const newPassword = req.body.password;
|
||||
|
||||
// Validate token again
|
||||
const recoveryToken = await validateRecoveryToken(req, res);
|
||||
const user = await UserModel.findOne({ email: recoveryToken.email });
|
||||
// Validate token again
|
||||
const recoveryToken = await validateRecoveryToken(req, res);
|
||||
const user = await UserModel.findOne({ email: recoveryToken.email });
|
||||
|
||||
const match = await user.comparePassword(newPassword);
|
||||
if (match === true) {
|
||||
throw new Error(errorMessages.DB_RESET_PASSWORD_BAD_MATCH);
|
||||
}
|
||||
const match = await user.comparePassword(newPassword);
|
||||
if (match === true) {
|
||||
throw new Error(errorMessages.DB_RESET_PASSWORD_BAD_MATCH);
|
||||
}
|
||||
|
||||
if (user !== null) {
|
||||
user.password = newPassword;
|
||||
await user.save();
|
||||
await RecoveryToken.deleteMany({ email: recoveryToken.email });
|
||||
// Fetch the user again without the password
|
||||
const userWithoutPassword = await UserModel.findOne({
|
||||
email: recoveryToken.email,
|
||||
})
|
||||
.select("-password")
|
||||
.select("-profileImage");
|
||||
return userWithoutPassword;
|
||||
} else {
|
||||
throw new Error(errorMessages.DB_USER_NOT_FOUND);
|
||||
}
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "resetPassword";
|
||||
throw error;
|
||||
}
|
||||
if (user !== null) {
|
||||
user.password = newPassword;
|
||||
await user.save();
|
||||
await RecoveryToken.deleteMany({ email: recoveryToken.email });
|
||||
// Fetch the user again without the password
|
||||
const userWithoutPassword = await UserModel.findOne({
|
||||
email: recoveryToken.email,
|
||||
})
|
||||
.select("-password")
|
||||
.select("-profileImage");
|
||||
return userWithoutPassword;
|
||||
} else {
|
||||
throw new Error(errorMessages.DB_USER_NOT_FOUND);
|
||||
}
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "resetPassword";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export { requestRecoveryToken, validateRecoveryToken, resetPassword };
|
||||
|
||||
@@ -2,29 +2,29 @@ import AppSettings from "../../models/AppSettings.js";
|
||||
const SERVICE_NAME = "SettingsModule";
|
||||
|
||||
const getAppSettings = async () => {
|
||||
try {
|
||||
const settings = AppSettings.findOne();
|
||||
return settings;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getSettings";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const settings = AppSettings.findOne();
|
||||
return settings;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getSettings";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const updateAppSettings = async (newSettings) => {
|
||||
try {
|
||||
const settings = await AppSettings.findOneAndUpdate(
|
||||
{},
|
||||
{ $set: newSettings },
|
||||
{ new: true }
|
||||
);
|
||||
return settings;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateAppSettings";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const settings = await AppSettings.findOneAndUpdate(
|
||||
{},
|
||||
{ $set: newSettings },
|
||||
{ new: true }
|
||||
);
|
||||
return settings;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateAppSettings";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export { getAppSettings, updateAppSettings };
|
||||
|
||||
@@ -16,42 +16,42 @@ const SERVICE_NAME = "userModule";
|
||||
* @throws {Error}
|
||||
*/
|
||||
const insertUser = async (userData, imageFile) => {
|
||||
try {
|
||||
if (imageFile) {
|
||||
// 1. Save the full size image
|
||||
userData.profileImage = {
|
||||
data: imageFile.buffer,
|
||||
contentType: imageFile.mimetype,
|
||||
};
|
||||
try {
|
||||
if (imageFile) {
|
||||
// 1. Save the full size image
|
||||
userData.profileImage = {
|
||||
data: imageFile.buffer,
|
||||
contentType: imageFile.mimetype,
|
||||
};
|
||||
|
||||
// 2. Get the avatar sized image
|
||||
const avatar = await GenerateAvatarImage(imageFile);
|
||||
userData.avatarImage = avatar;
|
||||
}
|
||||
// 2. Get the avatar sized image
|
||||
const avatar = await GenerateAvatarImage(imageFile);
|
||||
userData.avatarImage = avatar;
|
||||
}
|
||||
|
||||
// Handle creating team if superadmin
|
||||
if (userData.role.includes("superadmin")) {
|
||||
const team = new TeamModel({
|
||||
email: userData.email,
|
||||
});
|
||||
userData.teamId = team._id;
|
||||
userData.checkTTL = 60 * 60 * 24 * 30;
|
||||
await team.save();
|
||||
}
|
||||
// Handle creating team if superadmin
|
||||
if (userData.role.includes("superadmin")) {
|
||||
const team = new TeamModel({
|
||||
email: userData.email,
|
||||
});
|
||||
userData.teamId = team._id;
|
||||
userData.checkTTL = 60 * 60 * 24 * 30;
|
||||
await team.save();
|
||||
}
|
||||
|
||||
const newUser = new UserModel(userData);
|
||||
await newUser.save();
|
||||
return await UserModel.findOne({ _id: newUser._id })
|
||||
.select("-password")
|
||||
.select("-profileImage"); // .select() doesn't work with create, need to save then find
|
||||
} catch (error) {
|
||||
if (error.code === DUPLICATE_KEY_CODE) {
|
||||
error.message = errorMessages.DB_USER_EXISTS;
|
||||
}
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "insertUser";
|
||||
throw error;
|
||||
}
|
||||
const newUser = new UserModel(userData);
|
||||
await newUser.save();
|
||||
return await UserModel.findOne({ _id: newUser._id })
|
||||
.select("-password")
|
||||
.select("-profileImage"); // .select() doesn't work with create, need to save then find
|
||||
} catch (error) {
|
||||
if (error.code === DUPLICATE_KEY_CODE) {
|
||||
error.message = errorMessages.DB_USER_EXISTS;
|
||||
}
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "insertUser";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -66,22 +66,20 @@ const insertUser = async (userData, imageFile) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getUserByEmail = async (email) => {
|
||||
try {
|
||||
// Need the password to be able to compare, removed .select()
|
||||
// We can strip the hash before returing the user
|
||||
const user = await UserModel.findOne({ email: email }).select(
|
||||
"-profileImage"
|
||||
);
|
||||
if (user) {
|
||||
return user;
|
||||
} else {
|
||||
throw new Error(errorMessages.DB_USER_NOT_FOUND);
|
||||
}
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getUserByEmail";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
// Need the password to be able to compare, removed .select()
|
||||
// We can strip the hash before returing the user
|
||||
const user = await UserModel.findOne({ email: email }).select("-profileImage");
|
||||
if (user) {
|
||||
return user;
|
||||
} else {
|
||||
throw new Error(errorMessages.DB_USER_NOT_FOUND);
|
||||
}
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getUserByEmail";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,45 +92,45 @@ const getUserByEmail = async (email) => {
|
||||
*/
|
||||
|
||||
const updateUser = async (req, res) => {
|
||||
const candidateUserId = req.params.userId;
|
||||
try {
|
||||
const candidateUser = { ...req.body };
|
||||
// ******************************************
|
||||
// Handle profile image
|
||||
// ******************************************
|
||||
const candidateUserId = req.params.userId;
|
||||
try {
|
||||
const candidateUser = { ...req.body };
|
||||
// ******************************************
|
||||
// Handle profile image
|
||||
// ******************************************
|
||||
|
||||
if (ParseBoolean(candidateUser.deleteProfileImage) === true) {
|
||||
candidateUser.profileImage = null;
|
||||
candidateUser.avatarImage = null;
|
||||
} else if (req.file) {
|
||||
// 1. Save the full size image
|
||||
candidateUser.profileImage = {
|
||||
data: req.file.buffer,
|
||||
contentType: req.file.mimetype,
|
||||
};
|
||||
if (ParseBoolean(candidateUser.deleteProfileImage) === true) {
|
||||
candidateUser.profileImage = null;
|
||||
candidateUser.avatarImage = null;
|
||||
} else if (req.file) {
|
||||
// 1. Save the full size image
|
||||
candidateUser.profileImage = {
|
||||
data: req.file.buffer,
|
||||
contentType: req.file.mimetype,
|
||||
};
|
||||
|
||||
// 2. Get the avaatar sized image
|
||||
const avatar = await GenerateAvatarImage(req.file);
|
||||
candidateUser.avatarImage = avatar;
|
||||
}
|
||||
// 2. Get the avaatar sized image
|
||||
const avatar = await GenerateAvatarImage(req.file);
|
||||
candidateUser.avatarImage = avatar;
|
||||
}
|
||||
|
||||
// ******************************************
|
||||
// End handling profile image
|
||||
// ******************************************
|
||||
// ******************************************
|
||||
// End handling profile image
|
||||
// ******************************************
|
||||
|
||||
const updatedUser = await UserModel.findByIdAndUpdate(
|
||||
candidateUserId,
|
||||
candidateUser,
|
||||
{ new: true } // Returns updated user instead of pre-update user
|
||||
)
|
||||
.select("-password")
|
||||
.select("-profileImage");
|
||||
return updatedUser;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateUser";
|
||||
throw error;
|
||||
}
|
||||
const updatedUser = await UserModel.findByIdAndUpdate(
|
||||
candidateUserId,
|
||||
candidateUser,
|
||||
{ new: true } // Returns updated user instead of pre-update user
|
||||
)
|
||||
.select("-password")
|
||||
.select("-profileImage");
|
||||
return updatedUser;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "updateUser";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -144,17 +142,17 @@ const updateUser = async (req, res) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const deleteUser = async (userId) => {
|
||||
try {
|
||||
const deletedUser = await UserModel.findByIdAndDelete(userId);
|
||||
if (!deletedUser) {
|
||||
throw new Error(errorMessages.DB_USER_NOT_FOUND);
|
||||
}
|
||||
return deletedUser;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteUser";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const deletedUser = await UserModel.findByIdAndDelete(userId);
|
||||
if (!deletedUser) {
|
||||
throw new Error(errorMessages.DB_USER_NOT_FOUND);
|
||||
}
|
||||
return deletedUser;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteUser";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -165,56 +163,54 @@ const deleteUser = async (userId) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const deleteTeam = async (teamId) => {
|
||||
try {
|
||||
await TeamModel.findByIdAndDelete(teamId);
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteTeam";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await TeamModel.findByIdAndDelete(teamId);
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteTeam";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteAllOtherUsers = async () => {
|
||||
try {
|
||||
await UserModel.deleteMany({ role: { $ne: "superadmin" } });
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteAllOtherUsers";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await UserModel.deleteMany({ role: { $ne: "superadmin" } });
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteAllOtherUsers";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getAllUsers = async (req, res) => {
|
||||
try {
|
||||
const users = await UserModel.find()
|
||||
.select("-password")
|
||||
.select("-profileImage");
|
||||
return users;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getAllUsers";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const users = await UserModel.find().select("-password").select("-profileImage");
|
||||
return users;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getAllUsers";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const logoutUser = async (userId) => {
|
||||
try {
|
||||
await UserModel.updateOne({ _id: userId }, { $unset: { authToken: null } });
|
||||
return true;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "logoutUser";
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await UserModel.updateOne({ _id: userId }, { $unset: { authToken: null } });
|
||||
return true;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "logoutUser";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
};
|
||||
|
||||
@@ -2,14 +2,14 @@ import logger from "../utils/logger.js";
|
||||
import { errorMessages } from "../utils/messages.js";
|
||||
|
||||
const handleErrors = (error, req, res, next) => {
|
||||
const status = error.status || 500;
|
||||
const message = error.message || errorMessages.FRIENDLY_ERROR;
|
||||
const service = error.service || errorMessages.UNKNOWN_SERVICE;
|
||||
logger.error(error.message, {
|
||||
service: service,
|
||||
method: error.method,
|
||||
});
|
||||
res.status(status).json({ success: false, msg: message });
|
||||
const status = error.status || 500;
|
||||
const message = error.message || errorMessages.FRIENDLY_ERROR;
|
||||
const service = error.service || errorMessages.UNKNOWN_SERVICE;
|
||||
logger.error(error.message, {
|
||||
service: service,
|
||||
method: error.method,
|
||||
});
|
||||
res.status(status).json({ success: false, msg: message });
|
||||
};
|
||||
|
||||
export { handleErrors };
|
||||
|
||||
@@ -4,52 +4,52 @@ const SERVICE_NAME = "allowedRoles";
|
||||
import { errorMessages } from "../utils/messages.js";
|
||||
|
||||
const isAllowed = (allowedRoles) => {
|
||||
return (req, res, next) => {
|
||||
const token = req.headers["authorization"];
|
||||
return (req, res, next) => {
|
||||
const token = req.headers["authorization"];
|
||||
|
||||
// If no token is pressent, return an error
|
||||
if (!token) {
|
||||
const error = new Error(errorMessages.NO_AUTH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// If no token is pressent, return an error
|
||||
if (!token) {
|
||||
const error = new Error(errorMessages.NO_AUTH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the token is improperly formatted, return an error
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(errorMessages.INVALID_AUTH_TOKEN);
|
||||
error.status = 400;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// Parse the token
|
||||
try {
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
var decoded = jwt.verify(parsedToken, jwtSecret);
|
||||
const userRoles = decoded.role;
|
||||
// If the token is improperly formatted, return an error
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(errorMessages.INVALID_AUTH_TOKEN);
|
||||
error.status = 400;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// Parse the token
|
||||
try {
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
var decoded = jwt.verify(parsedToken, jwtSecret);
|
||||
const userRoles = decoded.role;
|
||||
|
||||
// Check if the user has the required role
|
||||
if (userRoles.some((role) => allowedRoles.includes(role))) {
|
||||
next();
|
||||
return;
|
||||
} else {
|
||||
const error = new Error(errorMessages.INSUFFICIENT_PERMISSIONS);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
error.status = 401;
|
||||
error.method = "isAllowed";
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
// Check if the user has the required role
|
||||
if (userRoles.some((role) => allowedRoles.includes(role))) {
|
||||
next();
|
||||
return;
|
||||
} else {
|
||||
const error = new Error(errorMessages.INSUFFICIENT_PERMISSIONS);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
error.status = 401;
|
||||
error.method = "isAllowed";
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { isAllowed };
|
||||
|
||||
@@ -13,82 +13,80 @@ const TOKEN_PREFIX = "Bearer ";
|
||||
* @returns {express.Response}
|
||||
*/
|
||||
const verifyJWT = (req, res, next) => {
|
||||
const token = req.headers["authorization"];
|
||||
// Make sure a token is provided
|
||||
if (!token) {
|
||||
const error = new Error(errorMessages.NO_AUTH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// Make sure it is properly formatted
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(errorMessages.INVALID_AUTH_TOKEN); // Instantiate a new Error object for improperly formatted token
|
||||
error.status = 400;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyJWT";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
const token = req.headers["authorization"];
|
||||
// Make sure a token is provided
|
||||
if (!token) {
|
||||
const error = new Error(errorMessages.NO_AUTH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// Make sure it is properly formatted
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(errorMessages.INVALID_AUTH_TOKEN); // Instantiate a new Error object for improperly formatted token
|
||||
error.status = 400;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyJWT";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// Verify the token's authenticity
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
if (err.name === "TokenExpiredError") {
|
||||
// token has expired
|
||||
handleExpiredJwtToken(req, res, next);
|
||||
}
|
||||
else {
|
||||
// Invalid token (signature or token altered or other issue)
|
||||
const errorMessage = errorMessages.INVALID_AUTH_TOKEN;
|
||||
return res.status(401).json({ success: false, msg: errorMessage });
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Token is valid and not expired, carry on with request, Add the decoded payload to the request
|
||||
req.user = decoded;
|
||||
next();
|
||||
}
|
||||
});
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// Verify the token's authenticity
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
if (err.name === "TokenExpiredError") {
|
||||
// token has expired
|
||||
handleExpiredJwtToken(req, res, next);
|
||||
} else {
|
||||
// Invalid token (signature or token altered or other issue)
|
||||
const errorMessage = errorMessages.INVALID_AUTH_TOKEN;
|
||||
return res.status(401).json({ success: false, msg: errorMessage });
|
||||
}
|
||||
} else {
|
||||
// Token is valid and not expired, carry on with request, Add the decoded payload to the request
|
||||
req.user = decoded;
|
||||
next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function handleExpiredJwtToken(req, res, next) {
|
||||
// check for refreshToken
|
||||
const refreshToken = req.headers["x-refresh-token"];
|
||||
// check for refreshToken
|
||||
const refreshToken = req.headers["x-refresh-token"];
|
||||
|
||||
if (!refreshToken) {
|
||||
// No refresh token provided
|
||||
const error = new Error(errorMessages.NO_REFRESH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "handleExpiredJwtToken";
|
||||
return next(error);
|
||||
}
|
||||
if (!refreshToken) {
|
||||
// No refresh token provided
|
||||
const error = new Error(errorMessages.NO_REFRESH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "handleExpiredJwtToken";
|
||||
return next(error);
|
||||
}
|
||||
|
||||
// Verify refresh token
|
||||
const { refreshTokenSecret } = req.settingsService.getSettings();
|
||||
jwt.verify(refreshToken, refreshTokenSecret, (refreshErr, refreshDecoded) => {
|
||||
if (refreshErr) {
|
||||
// Invalid or expired refresh token, trigger logout
|
||||
const errorMessage =
|
||||
refreshErr.name === "TokenExpiredError"
|
||||
? errorMessages.EXPIRED_REFRESH_TOKEN
|
||||
: errorMessages.INVALID_REFRESH_TOKEN;
|
||||
const error = new Error(errorMessage);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
return next(error);
|
||||
}
|
||||
// Verify refresh token
|
||||
const { refreshTokenSecret } = req.settingsService.getSettings();
|
||||
jwt.verify(refreshToken, refreshTokenSecret, (refreshErr, refreshDecoded) => {
|
||||
if (refreshErr) {
|
||||
// Invalid or expired refresh token, trigger logout
|
||||
const errorMessage =
|
||||
refreshErr.name === "TokenExpiredError"
|
||||
? errorMessages.EXPIRED_REFRESH_TOKEN
|
||||
: errorMessages.INVALID_REFRESH_TOKEN;
|
||||
const error = new Error(errorMessage);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
return next(error);
|
||||
}
|
||||
|
||||
// Refresh token is valid and unexpired, request for new access token
|
||||
res.status(403).json({
|
||||
success: false,
|
||||
msg: errorMessages.REQUEST_NEW_ACCESS_TOKEN,
|
||||
});
|
||||
});
|
||||
// Refresh token is valid and unexpired, request for new access token
|
||||
res.status(403).json({
|
||||
success: false,
|
||||
msg: errorMessages.REQUEST_NEW_ACCESS_TOKEN,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export { verifyJWT };
|
||||
export { verifyJWT };
|
||||
|
||||
@@ -3,47 +3,47 @@ import { errorMessages } from "../utils/messages.js";
|
||||
const SERVICE_NAME = "verifyOwnership";
|
||||
|
||||
const verifyOwnership = (Model, paramName) => {
|
||||
return async (req, res, next) => {
|
||||
const userId = req.user._id;
|
||||
const documentId = req.params[paramName];
|
||||
try {
|
||||
const doc = await Model.findById(documentId);
|
||||
//If the document is not found, return a 404 error
|
||||
if (!doc) {
|
||||
logger.error(errorMessages.VERIFY_OWNER_NOT_FOUND, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
const error = new Error(errorMessages.VERIFY_OWNER_NOT_FOUND);
|
||||
error.status = 404;
|
||||
throw error;
|
||||
}
|
||||
return async (req, res, next) => {
|
||||
const userId = req.user._id;
|
||||
const documentId = req.params[paramName];
|
||||
try {
|
||||
const doc = await Model.findById(documentId);
|
||||
//If the document is not found, return a 404 error
|
||||
if (!doc) {
|
||||
logger.error(errorMessages.VERIFY_OWNER_NOT_FOUND, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
const error = new Error(errorMessages.VERIFY_OWNER_NOT_FOUND);
|
||||
error.status = 404;
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Special case for User model, as it will not have a `userId` field as other docs will
|
||||
if (Model.modelName === "User") {
|
||||
if (userId.toString() !== doc._id.toString()) {
|
||||
const error = new Error(errorMessages.VERIFY_OWNER_UNAUTHORIZED);
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
next();
|
||||
return;
|
||||
}
|
||||
// Special case for User model, as it will not have a `userId` field as other docs will
|
||||
if (Model.modelName === "User") {
|
||||
if (userId.toString() !== doc._id.toString()) {
|
||||
const error = new Error(errorMessages.VERIFY_OWNER_UNAUTHORIZED);
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the userID does not match the document's userID, return a 403 error
|
||||
if (userId.toString() !== doc.userId.toString()) {
|
||||
const error = new Error(errorMessages.VERIFY_OWNER_UNAUTHORIZED);
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
next();
|
||||
return;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyOwnership";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
// If the userID does not match the document's userID, return a 403 error
|
||||
if (userId.toString() !== doc.userId.toString()) {
|
||||
const error = new Error(errorMessages.VERIFY_OWNER_UNAUTHORIZED);
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
next();
|
||||
return;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyOwnership";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { verifyOwnership };
|
||||
|
||||
@@ -12,49 +12,47 @@ const { errorMessages } = require("../utils/messages");
|
||||
* @returns {express.Response}
|
||||
*/
|
||||
const verifySuperAdmin = (req, res, next) => {
|
||||
const token = req.headers["authorization"];
|
||||
// Make sure a token is provided
|
||||
if (!token) {
|
||||
const error = new Error(errorMessages.NO_AUTH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// Make sure it is properly formatted
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(errorMessages.INVALID_AUTH_TOKEN); // Instantiate a new Error object for improperly formatted token
|
||||
error.status = 400;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifySuperAdmin";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
const token = req.headers["authorization"];
|
||||
// Make sure a token is provided
|
||||
if (!token) {
|
||||
const error = new Error(errorMessages.NO_AUTH_TOKEN);
|
||||
error.status = 401;
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
// Make sure it is properly formatted
|
||||
if (!token.startsWith(TOKEN_PREFIX)) {
|
||||
const error = new Error(errorMessages.INVALID_AUTH_TOKEN); // Instantiate a new Error object for improperly formatted token
|
||||
error.status = 400;
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifySuperAdmin";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// verify admin role is present
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
// verify admin role is present
|
||||
const { jwtSecret } = req.settingsService.getSettings();
|
||||
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
logger.error(errorMessages.INVALID_AUTH_TOKEN, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
return res
|
||||
.status(401)
|
||||
.json({ success: false, msg: errorMessages.INVALID_AUTH_TOKEN });
|
||||
}
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
logger.error(errorMessages.INVALID_AUTH_TOKEN, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
return res
|
||||
.status(401)
|
||||
.json({ success: false, msg: errorMessages.INVALID_AUTH_TOKEN });
|
||||
}
|
||||
|
||||
if (decoded.role.includes("superadmin") === false) {
|
||||
logger.error(errorMessages.INVALID_AUTH_TOKEN, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
return res
|
||||
.status(401)
|
||||
.json({ success: false, msg: errorMessages.UNAUTHORIZED });
|
||||
}
|
||||
next();
|
||||
});
|
||||
if (decoded.role.includes("superadmin") === false) {
|
||||
logger.error(errorMessages.INVALID_AUTH_TOKEN, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
return res.status(401).json({ success: false, msg: errorMessages.UNAUTHORIZED });
|
||||
}
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { verifySuperAdmin };
|
||||
|
||||
4537
Server/openapi.json
4537
Server/openapi.json
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
import { Router } from "express";
|
||||
import {
|
||||
createCheck,
|
||||
getChecks,
|
||||
deleteChecks,
|
||||
getTeamChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
createCheck,
|
||||
getChecks,
|
||||
deleteChecks,
|
||||
getTeamChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
} from "../controllers/checkController.js";
|
||||
import { verifyOwnership } from "../middleware/verifyOwnership.js";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
@@ -15,19 +15,11 @@ const router = Router();
|
||||
|
||||
router.get("/:monitorId", getChecks);
|
||||
router.post("/:monitorId", verifyOwnership(Monitor, "monitorId"), createCheck);
|
||||
router.delete(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
deleteChecks
|
||||
);
|
||||
router.delete("/:monitorId", verifyOwnership(Monitor, "monitorId"), deleteChecks);
|
||||
|
||||
router.get("/team/:teamId", getTeamChecks);
|
||||
|
||||
router.delete(
|
||||
"/team/:teamId",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
deleteChecksByTeamId
|
||||
);
|
||||
router.delete("/team/:teamId", isAllowed(["admin", "superadmin"]), deleteChecksByTeamId);
|
||||
|
||||
router.put("/team/ttl", isAllowed(["admin", "superadmin"]), updateChecksTTL);
|
||||
|
||||
|
||||
@@ -2,18 +2,13 @@ import { Router } from "express";
|
||||
import { verifyJWT } from "../middleware/verifyJWT.js";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import {
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
} from "../controllers/inviteController.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
"/",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
verifyJWT,
|
||||
issueInvitation
|
||||
);
|
||||
router.post("/", isAllowed(["admin", "superadmin"]), verifyJWT, issueInvitation);
|
||||
router.post("/verify", issueInvitation);
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Router } from "express";
|
||||
import {
|
||||
createMaintenanceWindows,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindow,
|
||||
editMaintenanceWindow,
|
||||
createMaintenanceWindows,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindow,
|
||||
editMaintenanceWindow,
|
||||
} from "../controllers/maintenanceWindowController.js";
|
||||
import { verifyOwnership } from "../middleware/verifyOwnership.js";
|
||||
import Monitor from "../db/models/Monitor.js";
|
||||
@@ -15,9 +15,9 @@ const router = Router();
|
||||
router.post("/", createMaintenanceWindows);
|
||||
|
||||
router.get(
|
||||
"/monitor/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
getMaintenanceWindowsByMonitorId
|
||||
"/monitor/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
getMaintenanceWindowsByMonitorId
|
||||
);
|
||||
|
||||
router.get("/team/", getMaintenanceWindowsByTeamId);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Router } from "express";
|
||||
import {
|
||||
getMetrics,
|
||||
getJobs,
|
||||
addJob,
|
||||
obliterateQueue,
|
||||
getMetrics,
|
||||
getJobs,
|
||||
addJob,
|
||||
obliterateQueue,
|
||||
} from "../controllers/queueController.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { Router } from "express";
|
||||
import {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
} from "../controllers/settingsController.js";
|
||||
import { getAppSettings, updateAppSettings } from "../controllers/settingsController.js";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -15,128 +15,117 @@ const SERVICE_NAME = "EmailService";
|
||||
* Represents an email service that can load templates, build, and send emails.
|
||||
*/
|
||||
class EmailService {
|
||||
/**
|
||||
* Constructs an instance of the EmailService, initializing template loaders and the email transporter.
|
||||
*/
|
||||
constructor(settingsService) {
|
||||
this.settingsService = settingsService;
|
||||
/**
|
||||
* Loads an email template from the filesystem.
|
||||
*
|
||||
* @param {string} templateName - The name of the template to load.
|
||||
* @returns {Function} A compiled template function that can be used to generate HTML email content.
|
||||
*/
|
||||
this.loadTemplate = (templateName) => {
|
||||
try {
|
||||
const templatePath = path.join(
|
||||
__dirname,
|
||||
`../templates/${templateName}.mjml`
|
||||
);
|
||||
const templateContent = fs.readFileSync(templatePath, "utf8");
|
||||
return compile(templateContent);
|
||||
} catch (error) {
|
||||
logger.error("Error loading Email templates", {
|
||||
error,
|
||||
service: this.SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Constructs an instance of the EmailService, initializing template loaders and the email transporter.
|
||||
*/
|
||||
constructor(settingsService) {
|
||||
this.settingsService = settingsService;
|
||||
/**
|
||||
* Loads an email template from the filesystem.
|
||||
*
|
||||
* @param {string} templateName - The name of the template to load.
|
||||
* @returns {Function} A compiled template function that can be used to generate HTML email content.
|
||||
*/
|
||||
this.loadTemplate = (templateName) => {
|
||||
try {
|
||||
const templatePath = path.join(__dirname, `../templates/${templateName}.mjml`);
|
||||
const templateContent = fs.readFileSync(templatePath, "utf8");
|
||||
return compile(templateContent);
|
||||
} catch (error) {
|
||||
logger.error("Error loading Email templates", {
|
||||
error,
|
||||
service: this.SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A lookup object to access preloaded email templates.
|
||||
* @type {Object.<string, Function>}
|
||||
* TODO Load less used templates in their respective functions
|
||||
*/
|
||||
this.templateLookup = {
|
||||
welcomeEmailTemplate: this.loadTemplate("welcomeEmail"),
|
||||
employeeActivationTemplate: this.loadTemplate("employeeActivation"),
|
||||
noIncidentsThisWeekTemplate: this.loadTemplate("noIncidentsThisWeek"),
|
||||
serverIsDownTemplate: this.loadTemplate("serverIsDown"),
|
||||
serverIsUpTemplate: this.loadTemplate("serverIsUp"),
|
||||
passwordResetTemplate: this.loadTemplate("passwordReset"),
|
||||
};
|
||||
/**
|
||||
* A lookup object to access preloaded email templates.
|
||||
* @type {Object.<string, Function>}
|
||||
* TODO Load less used templates in their respective functions
|
||||
*/
|
||||
this.templateLookup = {
|
||||
welcomeEmailTemplate: this.loadTemplate("welcomeEmail"),
|
||||
employeeActivationTemplate: this.loadTemplate("employeeActivation"),
|
||||
noIncidentsThisWeekTemplate: this.loadTemplate("noIncidentsThisWeek"),
|
||||
serverIsDownTemplate: this.loadTemplate("serverIsDown"),
|
||||
serverIsUpTemplate: this.loadTemplate("serverIsUp"),
|
||||
passwordResetTemplate: this.loadTemplate("passwordReset"),
|
||||
};
|
||||
|
||||
/**
|
||||
* The email transporter used to send emails.
|
||||
* @type {Object}
|
||||
*/
|
||||
/**
|
||||
* The email transporter used to send emails.
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
const {
|
||||
systemEmailHost,
|
||||
systemEmailPort,
|
||||
systemEmailAddress,
|
||||
systemEmailPassword,
|
||||
} = this.settingsService.getSettings();
|
||||
const { systemEmailHost, systemEmailPort, systemEmailAddress, systemEmailPassword } =
|
||||
this.settingsService.getSettings();
|
||||
|
||||
const emailConfig = {
|
||||
host: systemEmailHost,
|
||||
port: systemEmailPort,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: systemEmailAddress,
|
||||
pass: systemEmailPassword,
|
||||
},
|
||||
};
|
||||
const emailConfig = {
|
||||
host: systemEmailHost,
|
||||
port: systemEmailPort,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: systemEmailAddress,
|
||||
pass: systemEmailPassword,
|
||||
},
|
||||
};
|
||||
|
||||
this.transporter = nodemailer.createTransport(emailConfig);
|
||||
}
|
||||
this.transporter = nodemailer.createTransport(emailConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously builds and sends an email using a specified template and context.
|
||||
*
|
||||
* @param {string} template - The name of the template to use for the email body.
|
||||
* @param {Object} context - The data context to render the template with.
|
||||
* @param {string} to - The recipient's email address.
|
||||
* @param {string} subject - The subject of the email.
|
||||
* @returns {Promise<string>} A promise that resolves to the messageId of the sent email.
|
||||
*/
|
||||
buildAndSendEmail = async (template, context, to, subject) => {
|
||||
const buildHtml = async (template, context) => {
|
||||
try {
|
||||
const mjml = this.templateLookup[template](context);
|
||||
const html = await mjml2html(mjml);
|
||||
return html.html;
|
||||
} catch (error) {
|
||||
logger.error("Error building Email HTML", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Asynchronously builds and sends an email using a specified template and context.
|
||||
*
|
||||
* @param {string} template - The name of the template to use for the email body.
|
||||
* @param {Object} context - The data context to render the template with.
|
||||
* @param {string} to - The recipient's email address.
|
||||
* @param {string} subject - The subject of the email.
|
||||
* @returns {Promise<string>} A promise that resolves to the messageId of the sent email.
|
||||
*/
|
||||
buildAndSendEmail = async (template, context, to, subject) => {
|
||||
const buildHtml = async (template, context) => {
|
||||
try {
|
||||
const mjml = this.templateLookup[template](context);
|
||||
const html = await mjml2html(mjml);
|
||||
return html.html;
|
||||
} catch (error) {
|
||||
logger.error("Error building Email HTML", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const sendEmail = async (to, subject, html) => {
|
||||
try {
|
||||
const info = await this.transporter.sendMail({
|
||||
to: to,
|
||||
subject: subject,
|
||||
html: html,
|
||||
});
|
||||
return info;
|
||||
} catch (error) {
|
||||
logger.error("Error sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
const sendEmail = async (to, subject, html) => {
|
||||
try {
|
||||
const info = await this.transporter.sendMail({
|
||||
to: to,
|
||||
subject: subject,
|
||||
html: html,
|
||||
});
|
||||
return info;
|
||||
} catch (error) {
|
||||
logger.error("Error sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const info = await sendEmail(
|
||||
to,
|
||||
subject,
|
||||
await buildHtml(template, context)
|
||||
);
|
||||
return info.messageId;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
if (error.method === undefined) {
|
||||
error.method = "buildAndSendEmail";
|
||||
}
|
||||
logger.error("Error building and sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
try {
|
||||
const info = await sendEmail(to, subject, await buildHtml(template, context));
|
||||
return info.messageId;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
if (error.method === undefined) {
|
||||
error.method = "buildAndSendEmail";
|
||||
}
|
||||
logger.error("Error building and sending Email", {
|
||||
error,
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
export default EmailService;
|
||||
|
||||
@@ -13,145 +13,142 @@ const SERVICE_NAME = "JobQueue";
|
||||
* It scales the number of workers based on the number of jobs/worker
|
||||
*/
|
||||
class JobQueue {
|
||||
/**
|
||||
* Constructs a new JobQueue
|
||||
* @constructor
|
||||
* @param {SettingsService} settingsService - The settings service
|
||||
* @throws {Error}
|
||||
*/
|
||||
constructor(settingsService) {
|
||||
const { redisHost, redisPort } = settingsService.getSettings();
|
||||
const connection = {
|
||||
host: redisHost || "127.0.0.1",
|
||||
port: redisPort || 6379,
|
||||
};
|
||||
this.connection = connection;
|
||||
this.queue = new Queue(QUEUE_NAME, {
|
||||
connection,
|
||||
});
|
||||
this.workers = [];
|
||||
this.db = null;
|
||||
this.networkService = null;
|
||||
this.settingsService = settingsService;
|
||||
}
|
||||
/**
|
||||
* Constructs a new JobQueue
|
||||
* @constructor
|
||||
* @param {SettingsService} settingsService - The settings service
|
||||
* @throws {Error}
|
||||
*/
|
||||
constructor(settingsService) {
|
||||
const { redisHost, redisPort } = settingsService.getSettings();
|
||||
const connection = {
|
||||
host: redisHost || "127.0.0.1",
|
||||
port: redisPort || 6379,
|
||||
};
|
||||
this.connection = connection;
|
||||
this.queue = new Queue(QUEUE_NAME, {
|
||||
connection,
|
||||
});
|
||||
this.workers = [];
|
||||
this.db = null;
|
||||
this.networkService = null;
|
||||
this.settingsService = settingsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory method to create a JobQueue
|
||||
* @static
|
||||
* @async
|
||||
* @returns {Promise<JobQueue>} - Returns a new JobQueue
|
||||
*
|
||||
*/
|
||||
static async createJobQueue(db, networkService, settingsService) {
|
||||
const queue = new JobQueue(settingsService);
|
||||
try {
|
||||
queue.db = db;
|
||||
queue.networkService = networkService;
|
||||
const monitors = await db.getAllMonitors();
|
||||
for (const monitor of monitors) {
|
||||
if (monitor.isActive) {
|
||||
await queue.addJob(monitor.id, monitor);
|
||||
}
|
||||
}
|
||||
const workerStats = await queue.getWorkerStats();
|
||||
await queue.scaleWorkers(workerStats);
|
||||
return queue;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "createJobQueue") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Static factory method to create a JobQueue
|
||||
* @static
|
||||
* @async
|
||||
* @returns {Promise<JobQueue>} - Returns a new JobQueue
|
||||
*
|
||||
*/
|
||||
static async createJobQueue(db, networkService, settingsService) {
|
||||
const queue = new JobQueue(settingsService);
|
||||
try {
|
||||
queue.db = db;
|
||||
queue.networkService = networkService;
|
||||
const monitors = await db.getAllMonitors();
|
||||
for (const monitor of monitors) {
|
||||
if (monitor.isActive) {
|
||||
await queue.addJob(monitor.id, monitor);
|
||||
}
|
||||
}
|
||||
const workerStats = await queue.getWorkerStats();
|
||||
await queue.scaleWorkers(workerStats);
|
||||
return queue;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "createJobQueue") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a worker for the queue
|
||||
* Operations are carried out in the async callback
|
||||
* @returns {Worker} The newly created worker
|
||||
*/
|
||||
createWorker() {
|
||||
const worker = new Worker(
|
||||
QUEUE_NAME,
|
||||
async (job) => {
|
||||
try {
|
||||
// Get all maintenance windows for this monitor
|
||||
const monitorId = job.data._id;
|
||||
const maintenanceWindows =
|
||||
await this.db.getMaintenanceWindowsByMonitorId(monitorId);
|
||||
// Check for active maintenance window:
|
||||
const maintenanceWindowActive = maintenanceWindows.reduce(
|
||||
(acc, window) => {
|
||||
if (window.active) {
|
||||
const start = new Date(window.start);
|
||||
const end = new Date(window.end);
|
||||
const now = new Date();
|
||||
const repeatInterval = window.repeat || 0;
|
||||
/**
|
||||
* Creates a worker for the queue
|
||||
* Operations are carried out in the async callback
|
||||
* @returns {Worker} The newly created worker
|
||||
*/
|
||||
createWorker() {
|
||||
const worker = new Worker(
|
||||
QUEUE_NAME,
|
||||
async (job) => {
|
||||
try {
|
||||
// Get all maintenance windows for this monitor
|
||||
const monitorId = job.data._id;
|
||||
const maintenanceWindows =
|
||||
await this.db.getMaintenanceWindowsByMonitorId(monitorId);
|
||||
// Check for active maintenance window:
|
||||
const maintenanceWindowActive = maintenanceWindows.reduce((acc, window) => {
|
||||
if (window.active) {
|
||||
const start = new Date(window.start);
|
||||
const end = new Date(window.end);
|
||||
const now = new Date();
|
||||
const repeatInterval = window.repeat || 0;
|
||||
|
||||
while ((start < now) & (repeatInterval !== 0)) {
|
||||
start.setTime(start.getTime() + repeatInterval);
|
||||
end.setTime(end.getTime() + repeatInterval);
|
||||
}
|
||||
while ((start < now) & (repeatInterval !== 0)) {
|
||||
start.setTime(start.getTime() + repeatInterval);
|
||||
end.setTime(end.getTime() + repeatInterval);
|
||||
}
|
||||
|
||||
if (start < now && end > now) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
false
|
||||
);
|
||||
if (start < now && end > now) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, false);
|
||||
|
||||
if (!maintenanceWindowActive) {
|
||||
const res = await this.networkService.getStatus(job);
|
||||
} else {
|
||||
logger.info(`Monitor ${monitorId} is in maintenance window`, {
|
||||
service: SERVICE_NAME,
|
||||
monitorId,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error processing job ${job.id}: ${error.message}`, {
|
||||
service: SERVICE_NAME,
|
||||
jobId: job.id,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
connection: this.connection,
|
||||
}
|
||||
);
|
||||
return worker;
|
||||
}
|
||||
if (!maintenanceWindowActive) {
|
||||
const res = await this.networkService.getStatus(job);
|
||||
} else {
|
||||
logger.info(`Monitor ${monitorId} is in maintenance window`, {
|
||||
service: SERVICE_NAME,
|
||||
monitorId,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error processing job ${job.id}: ${error.message}`, {
|
||||
service: SERVICE_NAME,
|
||||
jobId: job.id,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
connection: this.connection,
|
||||
}
|
||||
);
|
||||
return worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} WorkerStats
|
||||
* @property {Array<Job>} jobs - Array of jobs in the Queue
|
||||
* @property {number} - workerLoad - The number of jobs per worker
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @typedef {Object} WorkerStats
|
||||
* @property {Array<Job>} jobs - Array of jobs in the Queue
|
||||
* @property {number} - workerLoad - The number of jobs per worker
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets stats related to the workers
|
||||
* This is used for scaling workers right now
|
||||
* In the future we will likely want to scale based on server performance metrics
|
||||
* CPU Usage & memory usage, if too high, scale down workers.
|
||||
* When to scale up? If jobs are taking too long to complete?
|
||||
* @async
|
||||
* @returns {Promise<WorkerStats>} - Returns the worker stats
|
||||
*/
|
||||
async getWorkerStats() {
|
||||
try {
|
||||
const jobs = await this.queue.getRepeatableJobs();
|
||||
const load = jobs.length / this.workers.length;
|
||||
return { jobs, load };
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getWorkerStats") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets stats related to the workers
|
||||
* This is used for scaling workers right now
|
||||
* In the future we will likely want to scale based on server performance metrics
|
||||
* CPU Usage & memory usage, if too high, scale down workers.
|
||||
* When to scale up? If jobs are taking too long to complete?
|
||||
* @async
|
||||
* @returns {Promise<WorkerStats>} - Returns the worker stats
|
||||
*/
|
||||
async getWorkerStats() {
|
||||
try {
|
||||
const jobs = await this.queue.getRepeatableJobs();
|
||||
const load = jobs.length / this.workers.length;
|
||||
return { jobs, load };
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getWorkerStats") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Scale Workers
|
||||
* This function scales workers based on the load per worker
|
||||
* If the load is higher than the JOBS_PER_WORKER threshold, we add more workers
|
||||
@@ -163,201 +160,200 @@ class JobQueue {
|
||||
* @param {WorkerStats} workerStats - The payload for the job.
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async scaleWorkers(workerStats) {
|
||||
if (this.workers.length === 0) {
|
||||
// There are no workers, need to add one
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const worker = this.createWorker();
|
||||
this.workers.push(worker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
async scaleWorkers(workerStats) {
|
||||
if (this.workers.length === 0) {
|
||||
// There are no workers, need to add one
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const worker = this.createWorker();
|
||||
this.workers.push(worker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (workerStats.load > JOBS_PER_WORKER) {
|
||||
// Find out how many more jobs we have than current workers can handle
|
||||
const excessJobs =
|
||||
workerStats.jobs.length - this.workers.length * JOBS_PER_WORKER;
|
||||
if (workerStats.load > JOBS_PER_WORKER) {
|
||||
// Find out how many more jobs we have than current workers can handle
|
||||
const excessJobs = workerStats.jobs.length - this.workers.length * JOBS_PER_WORKER;
|
||||
|
||||
// Divide by jobs/worker to find out how many workers to add
|
||||
const workersToAdd = Math.ceil(excessJobs / JOBS_PER_WORKER);
|
||||
for (let i = 0; i < workersToAdd; i++) {
|
||||
const worker = this.createWorker();
|
||||
this.workers.push(worker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Divide by jobs/worker to find out how many workers to add
|
||||
const workersToAdd = Math.ceil(excessJobs / JOBS_PER_WORKER);
|
||||
for (let i = 0; i < workersToAdd; i++) {
|
||||
const worker = this.createWorker();
|
||||
this.workers.push(worker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (workerStats.load < JOBS_PER_WORKER) {
|
||||
// Find out how much excess capacity we have
|
||||
const workerCapacity = this.workers.length * JOBS_PER_WORKER;
|
||||
const excessCapacity = workerCapacity - workerStats.jobs.length;
|
||||
// Calculate how many workers to remove
|
||||
const workersToRemove = Math.floor(excessCapacity / JOBS_PER_WORKER);
|
||||
if (this.workers.length > 5) {
|
||||
for (let i = 0; i < workersToRemove; i++) {
|
||||
const worker = this.workers.pop();
|
||||
try {
|
||||
await worker.close();
|
||||
} catch (error) {
|
||||
// Catch the error instead of throwing it
|
||||
logger.error(errorMessages.JOB_QUEUE_WORKER_CLOSE, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (workerStats.load < JOBS_PER_WORKER) {
|
||||
// Find out how much excess capacity we have
|
||||
const workerCapacity = this.workers.length * JOBS_PER_WORKER;
|
||||
const excessCapacity = workerCapacity - workerStats.jobs.length;
|
||||
// Calculate how many workers to remove
|
||||
const workersToRemove = Math.floor(excessCapacity / JOBS_PER_WORKER);
|
||||
if (this.workers.length > 5) {
|
||||
for (let i = 0; i < workersToRemove; i++) {
|
||||
const worker = this.workers.pop();
|
||||
try {
|
||||
await worker.close();
|
||||
} catch (error) {
|
||||
// Catch the error instead of throwing it
|
||||
logger.error(errorMessages.JOB_QUEUE_WORKER_CLOSE, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all jobs in the queue.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<Array<Job>>}
|
||||
* @throws {Error} - Throws error if getting jobs fails
|
||||
*/
|
||||
async getJobs() {
|
||||
try {
|
||||
const jobs = await this.queue.getRepeatableJobs();
|
||||
return jobs;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getJobs") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets all jobs in the queue.
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<Array<Job>>}
|
||||
* @throws {Error} - Throws error if getting jobs fails
|
||||
*/
|
||||
async getJobs() {
|
||||
try {
|
||||
const jobs = await this.queue.getRepeatableJobs();
|
||||
return jobs;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getJobs") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getJobStats() {
|
||||
try {
|
||||
const jobs = await this.queue.getJobs();
|
||||
const ret = await Promise.all(
|
||||
jobs.map(async (job) => {
|
||||
const state = await job.getState();
|
||||
return { url: job.data.url, state };
|
||||
})
|
||||
);
|
||||
return { jobs: ret, workers: this.workers.length };
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getJobStats") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async getJobStats() {
|
||||
try {
|
||||
const jobs = await this.queue.getJobs();
|
||||
const ret = await Promise.all(
|
||||
jobs.map(async (job) => {
|
||||
const state = await job.getState();
|
||||
return { url: job.data.url, state };
|
||||
})
|
||||
);
|
||||
return { jobs: ret, workers: this.workers.length };
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "getJobStats") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a job to the queue and scales workers based on worker stats.
|
||||
*
|
||||
* @async
|
||||
* @param {string} jobName - The name of the job to be added.
|
||||
* @param {Monitor} payload - The payload for the job.
|
||||
* @throws {Error} - Will throw an error if the job cannot be added or workers don't scale
|
||||
*/
|
||||
async addJob(jobName, payload) {
|
||||
try {
|
||||
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 ?? 60000,
|
||||
},
|
||||
});
|
||||
const workerStats = await this.getWorkerStats();
|
||||
await this.scaleWorkers(workerStats);
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "addJob") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Adds a job to the queue and scales workers based on worker stats.
|
||||
*
|
||||
* @async
|
||||
* @param {string} jobName - The name of the job to be added.
|
||||
* @param {Monitor} payload - The payload for the job.
|
||||
* @throws {Error} - Will throw an error if the job cannot be added or workers don't scale
|
||||
*/
|
||||
async addJob(jobName, payload) {
|
||||
try {
|
||||
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 ?? 60000,
|
||||
},
|
||||
});
|
||||
const workerStats = await this.getWorkerStats();
|
||||
await this.scaleWorkers(workerStats);
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "addJob") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a job from the queue.
|
||||
*
|
||||
* @async
|
||||
* @param {Monitor} monitor - The monitor to remove.
|
||||
* @throws {Error}
|
||||
*/
|
||||
async deleteJob(monitor) {
|
||||
try {
|
||||
const deleted = await this.queue.removeRepeatable(monitor._id, {
|
||||
every: monitor.interval,
|
||||
});
|
||||
if (deleted) {
|
||||
logger.info(successMessages.JOB_QUEUE_DELETE_JOB, {
|
||||
service: SERVICE_NAME,
|
||||
jobId: monitor.id,
|
||||
});
|
||||
const workerStats = await this.getWorkerStats();
|
||||
await this.scaleWorkers(workerStats);
|
||||
} else {
|
||||
logger.error(errorMessages.JOB_QUEUE_DELETE_JOB, {
|
||||
service: SERVICE_NAME,
|
||||
jobId: monitor.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "deleteJob") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deletes a job from the queue.
|
||||
*
|
||||
* @async
|
||||
* @param {Monitor} monitor - The monitor to remove.
|
||||
* @throws {Error}
|
||||
*/
|
||||
async deleteJob(monitor) {
|
||||
try {
|
||||
const deleted = await this.queue.removeRepeatable(monitor._id, {
|
||||
every: monitor.interval,
|
||||
});
|
||||
if (deleted) {
|
||||
logger.info(successMessages.JOB_QUEUE_DELETE_JOB, {
|
||||
service: SERVICE_NAME,
|
||||
jobId: monitor.id,
|
||||
});
|
||||
const workerStats = await this.getWorkerStats();
|
||||
await this.scaleWorkers(workerStats);
|
||||
} else {
|
||||
logger.error(errorMessages.JOB_QUEUE_DELETE_JOB, {
|
||||
service: SERVICE_NAME,
|
||||
jobId: monitor.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "deleteJob") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getMetrics() {
|
||||
try {
|
||||
const metrics = {
|
||||
waiting: await this.queue.getWaitingCount(),
|
||||
active: await this.queue.getActiveCount(),
|
||||
completed: await this.queue.getCompletedCount(),
|
||||
failed: await this.queue.getFailedCount(),
|
||||
delayed: await this.queue.getDelayedCount(),
|
||||
repeatableJobs: (await this.queue.getRepeatableJobs()).length,
|
||||
};
|
||||
return metrics;
|
||||
} catch (error) {
|
||||
logger.error("Failed to retrieve job queue metrics", {
|
||||
service: SERVICE_NAME,
|
||||
errorMsg: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
async getMetrics() {
|
||||
try {
|
||||
const metrics = {
|
||||
waiting: await this.queue.getWaitingCount(),
|
||||
active: await this.queue.getActiveCount(),
|
||||
completed: await this.queue.getCompletedCount(),
|
||||
failed: await this.queue.getFailedCount(),
|
||||
delayed: await this.queue.getDelayedCount(),
|
||||
repeatableJobs: (await this.queue.getRepeatableJobs()).length,
|
||||
};
|
||||
return metrics;
|
||||
} catch (error) {
|
||||
logger.error("Failed to retrieve job queue metrics", {
|
||||
service: SERVICE_NAME,
|
||||
errorMsg: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @returns {Promise<boolean>} - Returns true if obliteration is successful
|
||||
*/
|
||||
async obliterate() {
|
||||
try {
|
||||
let metrics = await this.getMetrics();
|
||||
console.log(metrics);
|
||||
await this.queue.pause();
|
||||
const jobs = await this.getJobs();
|
||||
/**
|
||||
* @async
|
||||
* @returns {Promise<boolean>} - Returns true if obliteration is successful
|
||||
*/
|
||||
async obliterate() {
|
||||
try {
|
||||
let metrics = await this.getMetrics();
|
||||
console.log(metrics);
|
||||
await this.queue.pause();
|
||||
const jobs = await this.getJobs();
|
||||
|
||||
for (const job of jobs) {
|
||||
await this.queue.removeRepeatableByKey(job.key);
|
||||
await this.queue.remove(job.id);
|
||||
}
|
||||
await Promise.all(
|
||||
this.workers.map(async (worker) => {
|
||||
await worker.close();
|
||||
})
|
||||
);
|
||||
for (const job of jobs) {
|
||||
await this.queue.removeRepeatableByKey(job.key);
|
||||
await this.queue.remove(job.id);
|
||||
}
|
||||
await Promise.all(
|
||||
this.workers.map(async (worker) => {
|
||||
await worker.close();
|
||||
})
|
||||
);
|
||||
|
||||
await this.queue.obliterate();
|
||||
metrics = await this.getMetrics();
|
||||
console.log(metrics);
|
||||
logger.info(successMessages.JOB_QUEUE_OBLITERATE, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "obliterate") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
await this.queue.obliterate();
|
||||
metrics = await this.getMetrics();
|
||||
console.log(metrics);
|
||||
logger.info(successMessages.JOB_QUEUE_OBLITERATE, {
|
||||
service: SERVICE_NAME,
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "obliterate") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default JobQueue;
|
||||
|
||||
@@ -12,321 +12,314 @@ import { errorMessages, successMessages } from "../utils/messages.js";
|
||||
*/
|
||||
|
||||
class NetworkService {
|
||||
constructor(db, emailService) {
|
||||
this.db = db;
|
||||
this.emailService = emailService;
|
||||
this.TYPE_PING = "ping";
|
||||
this.TYPE_HTTP = "http";
|
||||
this.TYPE_PAGESPEED = "pagespeed";
|
||||
this.SERVICE_NAME = "NetworkService";
|
||||
this.NETWORK_ERROR = 5000;
|
||||
}
|
||||
constructor(db, emailService) {
|
||||
this.db = db;
|
||||
this.emailService = emailService;
|
||||
this.TYPE_PING = "ping";
|
||||
this.TYPE_HTTP = "http";
|
||||
this.TYPE_PAGESPEED = "pagespeed";
|
||||
this.SERVICE_NAME = "NetworkService";
|
||||
this.NETWORK_ERROR = 5000;
|
||||
}
|
||||
|
||||
async handleNotification(monitor, isAlive) {
|
||||
try {
|
||||
let template =
|
||||
isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate";
|
||||
let status = isAlive === true ? "up" : "down";
|
||||
async handleNotification(monitor, isAlive) {
|
||||
try {
|
||||
let template = isAlive === true ? "serverIsUpTemplate" : "serverIsDownTemplate";
|
||||
let status = isAlive === true ? "up" : "down";
|
||||
|
||||
const notifications = await this.db.getNotificationsByMonitorId(
|
||||
monitor._id
|
||||
);
|
||||
for (const notification of notifications) {
|
||||
if (notification.type === "email") {
|
||||
await this.emailService.buildAndSendEmail(
|
||||
template,
|
||||
{ monitorName: monitor.name, monitorUrl: monitor.url },
|
||||
notification.address,
|
||||
`Monitor ${monitor.name} is ${status}`
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error.message, {
|
||||
method: "handleNotification",
|
||||
service: this.SERVICE_NAME,
|
||||
monitorId: monitor._id,
|
||||
});
|
||||
}
|
||||
}
|
||||
const notifications = await this.db.getNotificationsByMonitorId(monitor._id);
|
||||
for (const notification of notifications) {
|
||||
if (notification.type === "email") {
|
||||
await this.emailService.buildAndSendEmail(
|
||||
template,
|
||||
{ monitorName: monitor.name, monitorUrl: monitor.url },
|
||||
notification.address,
|
||||
`Monitor ${monitor.name} is ${status}`
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error.message, {
|
||||
method: "handleNotification",
|
||||
service: this.SERVICE_NAME,
|
||||
monitorId: monitor._id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async handleStatusUpdate(job, isAlive) {
|
||||
let monitor;
|
||||
// Look up the monitor, if it doesn't exist, it's probably been removed, return
|
||||
try {
|
||||
const { _id } = job.data;
|
||||
monitor = await this.db.getMonitorById(_id);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
async handleStatusUpdate(job, isAlive) {
|
||||
let monitor;
|
||||
// Look up the monitor, if it doesn't exist, it's probably been removed, return
|
||||
try {
|
||||
const { _id } = job.data;
|
||||
monitor = await this.db.getMonitorById(_id);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, try to update monitor status
|
||||
try {
|
||||
if (monitor === null || monitor === undefined) {
|
||||
logger.error(`Null Monitor: ${_id}`, {
|
||||
method: "handleStatusUpdate",
|
||||
service: this.SERVICE_NAME,
|
||||
jobId: job.id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (monitor.status === undefined || monitor.status !== isAlive) {
|
||||
const oldStatus = monitor.status;
|
||||
monitor.status = isAlive;
|
||||
await monitor.save();
|
||||
// Otherwise, try to update monitor status
|
||||
try {
|
||||
if (monitor === null || monitor === undefined) {
|
||||
logger.error(`Null Monitor: ${_id}`, {
|
||||
method: "handleStatusUpdate",
|
||||
service: this.SERVICE_NAME,
|
||||
jobId: job.id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (monitor.status === undefined || monitor.status !== isAlive) {
|
||||
const oldStatus = monitor.status;
|
||||
monitor.status = isAlive;
|
||||
await monitor.save();
|
||||
|
||||
if (oldStatus !== undefined && oldStatus !== isAlive) {
|
||||
this.handleNotification(monitor, isAlive);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error.message, {
|
||||
method: "handleStatusUpdate",
|
||||
service: this.SERVICE_NAME,
|
||||
jobId: job.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (oldStatus !== undefined && oldStatus !== isAlive) {
|
||||
this.handleNotification(monitor, isAlive);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error.message, {
|
||||
method: "handleStatusUpdate",
|
||||
service: this.SERVICE_NAME,
|
||||
jobId: job.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the response time of an asynchronous operation.
|
||||
* @param {Function} operation - An asynchronous operation to measure.
|
||||
* @returns {Promise<{responseTime: number, response: any}>} An object containing the response time in milliseconds and the response from the operation.
|
||||
* @throws {Error} The error object from the operation, contains response time.
|
||||
*/
|
||||
async measureResponseTime(operation) {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
const response = await operation();
|
||||
const endTime = Date.now();
|
||||
return { responseTime: endTime - startTime, response };
|
||||
} catch (error) {
|
||||
const endTime = Date.now();
|
||||
error.responseTime = endTime - startTime;
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined
|
||||
? (error.method = "measureResponseTime")
|
||||
: null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Measures the response time of an asynchronous operation.
|
||||
* @param {Function} operation - An asynchronous operation to measure.
|
||||
* @returns {Promise<{responseTime: number, response: any}>} An object containing the response time in milliseconds and the response from the operation.
|
||||
* @throws {Error} The error object from the operation, contains response time.
|
||||
*/
|
||||
async measureResponseTime(operation) {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
const response = await operation();
|
||||
const endTime = Date.now();
|
||||
return { responseTime: endTime - startTime, response };
|
||||
} catch (error) {
|
||||
const endTime = Date.now();
|
||||
error.responseTime = endTime - startTime;
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "measureResponseTime") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the ping operation for a given job, measures its response time, and logs the result.
|
||||
* @param {Object} job - The job object containing data for the ping operation.
|
||||
* @returns {Promise<{boolean}} The result of logging and storing the check
|
||||
*/
|
||||
async handlePing(job) {
|
||||
const operation = async () => {
|
||||
const response = await ping.promise.probe(job.data.url);
|
||||
return response;
|
||||
};
|
||||
/**
|
||||
* Handles the ping operation for a given job, measures its response time, and logs the result.
|
||||
* @param {Object} job - The job object containing data for the ping operation.
|
||||
* @returns {Promise<{boolean}} The result of logging and storing the check
|
||||
*/
|
||||
async handlePing(job) {
|
||||
const operation = async () => {
|
||||
const response = await ping.promise.probe(job.data.url);
|
||||
return response;
|
||||
};
|
||||
|
||||
let isAlive;
|
||||
let isAlive;
|
||||
|
||||
try {
|
||||
const { responseTime, response } =
|
||||
await this.measureResponseTime(operation);
|
||||
isAlive = response.alive;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
responseTime,
|
||||
message: isAlive
|
||||
? successMessages.PING_SUCCESS
|
||||
: errorMessages.PING_CANNOT_RESOLVE,
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
message: errorMessages.PING_CANNOT_RESOLVE,
|
||||
responseTime: error.responseTime,
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} finally {
|
||||
this.handleStatusUpdate(job, isAlive);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const { responseTime, response } = await this.measureResponseTime(operation);
|
||||
isAlive = response.alive;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
responseTime,
|
||||
message: isAlive
|
||||
? successMessages.PING_SUCCESS
|
||||
: errorMessages.PING_CANNOT_RESOLVE,
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
message: errorMessages.PING_CANNOT_RESOLVE,
|
||||
responseTime: error.responseTime,
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} finally {
|
||||
this.handleStatusUpdate(job, isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the http operation for a given job, measures its response time, and logs the result.
|
||||
* @param {Object} job - The job object containing data for the ping operation.
|
||||
* @returns {Promise<{boolean}} The result of logging and storing the check
|
||||
*/
|
||||
async handleHttp(job) {
|
||||
// Define operation for timing
|
||||
const operation = async () => {
|
||||
const response = await axios.get(job.data.url);
|
||||
return response;
|
||||
};
|
||||
/**
|
||||
* Handles the http operation for a given job, measures its response time, and logs the result.
|
||||
* @param {Object} job - The job object containing data for the ping operation.
|
||||
* @returns {Promise<{boolean}} The result of logging and storing the check
|
||||
*/
|
||||
async handleHttp(job) {
|
||||
// Define operation for timing
|
||||
const operation = async () => {
|
||||
const response = await axios.get(job.data.url);
|
||||
return response;
|
||||
};
|
||||
|
||||
let isAlive;
|
||||
let isAlive;
|
||||
|
||||
// attempt connection
|
||||
try {
|
||||
const { responseTime, response } =
|
||||
await this.measureResponseTime(operation);
|
||||
// check if response is in the 200 range, if so, service is up
|
||||
isAlive = response.status >= 200 && response.status < 300;
|
||||
// attempt connection
|
||||
try {
|
||||
const { responseTime, response } = await this.measureResponseTime(operation);
|
||||
// check if response is in the 200 range, if so, service is up
|
||||
isAlive = response.status >= 200 && response.status < 300;
|
||||
|
||||
//Create a check with relevant data
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
responseTime,
|
||||
statusCode: response.status,
|
||||
message: http.STATUS_CODES[response.status],
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} catch (error) {
|
||||
const statusCode = error.response?.status || this.NETWORK_ERROR;
|
||||
let message = http.STATUS_CODES[statusCode] || "Network Error";
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
statusCode,
|
||||
responseTime: error.responseTime,
|
||||
message,
|
||||
};
|
||||
//Create a check with relevant data
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
responseTime,
|
||||
statusCode: response.status,
|
||||
message: http.STATUS_CODES[response.status],
|
||||
};
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} catch (error) {
|
||||
const statusCode = error.response?.status || this.NETWORK_ERROR;
|
||||
let message = http.STATUS_CODES[statusCode] || "Network Error";
|
||||
isAlive = false;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
statusCode,
|
||||
responseTime: error.responseTime,
|
||||
message,
|
||||
};
|
||||
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} finally {
|
||||
this.handleStatusUpdate(job, isAlive);
|
||||
}
|
||||
}
|
||||
return await this.logAndStoreCheck(checkData, this.db.createCheck);
|
||||
} finally {
|
||||
this.handleStatusUpdate(job, isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles PageSpeed job types by fetching and processing PageSpeed insights.
|
||||
*
|
||||
* This method sends a request to the Google PageSpeed Insights API to get performance metrics
|
||||
* for the specified URL, then logs and stores the check results.
|
||||
*
|
||||
* @param {Object} job - The job object containing data related to the PageSpeed check.
|
||||
* @param {string} job.data.url - The URL to be analyzed by the PageSpeed Insights API.
|
||||
* @param {string} job.data._id - The unique identifier for the monitor associated with the check.
|
||||
*
|
||||
* @returns {Promise<void>} A promise that resolves when the check results have been logged and stored.
|
||||
*
|
||||
* @throws {Error} Throws an error if there is an issue with fetching or processing the PageSpeed insights.
|
||||
*/
|
||||
async handlePagespeed(job) {
|
||||
let isAlive;
|
||||
try {
|
||||
const url = job.data.url;
|
||||
const response = await axios.get(
|
||||
`https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${url}&category=seo&category=accessibility&category=best-practices&category=performance`
|
||||
);
|
||||
const pageSpeedResults = response.data;
|
||||
const categories = pageSpeedResults.lighthouseResult?.categories;
|
||||
const audits = pageSpeedResults.lighthouseResult?.audits;
|
||||
const {
|
||||
"cumulative-layout-shift": cls,
|
||||
"speed-index": si,
|
||||
"first-contentful-paint": fcp,
|
||||
"largest-contentful-paint": lcp,
|
||||
"total-blocking-time": tbt,
|
||||
} = audits;
|
||||
/**
|
||||
* Handles PageSpeed job types by fetching and processing PageSpeed insights.
|
||||
*
|
||||
* This method sends a request to the Google PageSpeed Insights API to get performance metrics
|
||||
* for the specified URL, then logs and stores the check results.
|
||||
*
|
||||
* @param {Object} job - The job object containing data related to the PageSpeed check.
|
||||
* @param {string} job.data.url - The URL to be analyzed by the PageSpeed Insights API.
|
||||
* @param {string} job.data._id - The unique identifier for the monitor associated with the check.
|
||||
*
|
||||
* @returns {Promise<void>} A promise that resolves when the check results have been logged and stored.
|
||||
*
|
||||
* @throws {Error} Throws an error if there is an issue with fetching or processing the PageSpeed insights.
|
||||
*/
|
||||
async handlePagespeed(job) {
|
||||
let isAlive;
|
||||
try {
|
||||
const url = job.data.url;
|
||||
const response = await axios.get(
|
||||
`https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${url}&category=seo&category=accessibility&category=best-practices&category=performance`
|
||||
);
|
||||
const pageSpeedResults = response.data;
|
||||
const categories = pageSpeedResults.lighthouseResult?.categories;
|
||||
const audits = pageSpeedResults.lighthouseResult?.audits;
|
||||
const {
|
||||
"cumulative-layout-shift": cls,
|
||||
"speed-index": si,
|
||||
"first-contentful-paint": fcp,
|
||||
"largest-contentful-paint": lcp,
|
||||
"total-blocking-time": tbt,
|
||||
} = audits;
|
||||
|
||||
// Weights
|
||||
// First Contentful Paint 10%
|
||||
// Speed Index 10%
|
||||
// Largest Contentful Paint 25%
|
||||
// Total Blocking Time 30%
|
||||
// Cumulative Layout Shift 25%
|
||||
// Weights
|
||||
// First Contentful Paint 10%
|
||||
// Speed Index 10%
|
||||
// Largest Contentful Paint 25%
|
||||
// Total Blocking Time 30%
|
||||
// Cumulative Layout Shift 25%
|
||||
|
||||
isAlive = true;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
statusCode: response.status,
|
||||
message: http.STATUS_CODES[response.status],
|
||||
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,
|
||||
audits: {
|
||||
cls,
|
||||
si,
|
||||
fcp,
|
||||
lcp,
|
||||
tbt,
|
||||
},
|
||||
};
|
||||
isAlive = true;
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
statusCode: response.status,
|
||||
message: http.STATUS_CODES[response.status],
|
||||
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,
|
||||
audits: {
|
||||
cls,
|
||||
si,
|
||||
fcp,
|
||||
lcp,
|
||||
tbt,
|
||||
},
|
||||
};
|
||||
|
||||
this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const statusCode = error.response?.status || this.NETWORK_ERROR;
|
||||
const message = http.STATUS_CODES[statusCode] || "Network Error";
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
statusCode,
|
||||
message,
|
||||
accessibility: 0,
|
||||
bestPractices: 0,
|
||||
seo: 0,
|
||||
performance: 0,
|
||||
};
|
||||
this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck);
|
||||
} finally {
|
||||
this.handleStatusUpdate(job, isAlive);
|
||||
}
|
||||
}
|
||||
this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck);
|
||||
} catch (error) {
|
||||
isAlive = false;
|
||||
const statusCode = error.response?.status || this.NETWORK_ERROR;
|
||||
const message = http.STATUS_CODES[statusCode] || "Network Error";
|
||||
const checkData = {
|
||||
monitorId: job.data._id,
|
||||
status: isAlive,
|
||||
statusCode,
|
||||
message,
|
||||
accessibility: 0,
|
||||
bestPractices: 0,
|
||||
seo: 0,
|
||||
performance: 0,
|
||||
};
|
||||
this.logAndStoreCheck(checkData, this.db.createPageSpeedCheck);
|
||||
} finally {
|
||||
this.handleStatusUpdate(job, isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the status of a given job based on its type.
|
||||
* For unsupported job types, it logs an error and returns false.
|
||||
*
|
||||
* @param {Object} job - The job object containing data necessary for processing.
|
||||
* @returns {Promise<boolean>} The status of the job if it is supported and processed successfully, otherwise false.
|
||||
*/
|
||||
async getStatus(job) {
|
||||
switch (job.data.type) {
|
||||
case this.TYPE_PING:
|
||||
return await this.handlePing(job);
|
||||
case this.TYPE_HTTP:
|
||||
return await this.handleHttp(job);
|
||||
case this.TYPE_PAGESPEED:
|
||||
return await this.handlePagespeed(job);
|
||||
default:
|
||||
logger.error(`Unsupported type: ${job.data.type}`, {
|
||||
service: this.SERVICE_NAME,
|
||||
method: "getStatus",
|
||||
jobId: job.id,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Retrieves the status of a given job based on its type.
|
||||
* For unsupported job types, it logs an error and returns false.
|
||||
*
|
||||
* @param {Object} job - The job object containing data necessary for processing.
|
||||
* @returns {Promise<boolean>} The status of the job if it is supported and processed successfully, otherwise false.
|
||||
*/
|
||||
async getStatus(job) {
|
||||
switch (job.data.type) {
|
||||
case this.TYPE_PING:
|
||||
return await this.handlePing(job);
|
||||
case this.TYPE_HTTP:
|
||||
return await this.handleHttp(job);
|
||||
case this.TYPE_PAGESPEED:
|
||||
return await this.handlePagespeed(job);
|
||||
default:
|
||||
logger.error(`Unsupported type: ${job.data.type}`, {
|
||||
service: this.SERVICE_NAME,
|
||||
method: "getStatus",
|
||||
jobId: job.id,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs and stores the result of a check for a specific job.
|
||||
*
|
||||
* @param {Object} data - Data to be written
|
||||
* @param {function} writeToDB - DB write method
|
||||
*
|
||||
* @returns {Promise<boolean>} The status of the inserted check if successful, otherwise false.
|
||||
*/
|
||||
/**
|
||||
* Logs and stores the result of a check for a specific job.
|
||||
*
|
||||
* @param {Object} data - Data to be written
|
||||
* @param {function} writeToDB - DB write method
|
||||
*
|
||||
* @returns {Promise<boolean>} The status of the inserted check if successful, otherwise false.
|
||||
*/
|
||||
|
||||
async logAndStoreCheck(data, writeToDB) {
|
||||
try {
|
||||
const insertedCheck = await writeToDB(data);
|
||||
if (insertedCheck !== null && insertedCheck !== undefined) {
|
||||
return insertedCheck.status;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error wrtiting check for ${data.monitorId}`, {
|
||||
service: this.SERVICE_NAME,
|
||||
method: "logAndStoreCheck",
|
||||
monitorId: data.monitorId,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
async logAndStoreCheck(data, writeToDB) {
|
||||
try {
|
||||
const insertedCheck = await writeToDB(data);
|
||||
if (insertedCheck !== null && insertedCheck !== undefined) {
|
||||
return insertedCheck.status;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error wrtiting check for ${data.monitorId}`, {
|
||||
service: this.SERVICE_NAME,
|
||||
method: "logAndStoreCheck",
|
||||
monitorId: data.monitorId,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default NetworkService;
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import AppSettings from "../db/models/AppSettings.js";
|
||||
const SERVICE_NAME = "SettingsService";
|
||||
const envConfig = {
|
||||
logLevel: undefined,
|
||||
apiBaseUrl: undefined,
|
||||
clientHost: process.env.CLIENT_HOST,
|
||||
jwtSecret: process.env.JWT_SECRET,
|
||||
refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET,
|
||||
dbType: process.env.DB_TYPE,
|
||||
dbConnectionString: process.env.DB_CONNECTION_STRING,
|
||||
redisHost: process.env.REDIS_HOST,
|
||||
redisPort: process.env.REDIS_PORT,
|
||||
jwtTTL: process.env.TOKEN_TTL,
|
||||
refreshTokenTTL: process.env.REFRESH_TOKEN_TTL,
|
||||
pagespeedApiKey: process.env.PAGESPEED_API_KEY,
|
||||
systemEmailHost: process.env.SYSTEM_EMAIL_HOST,
|
||||
systemEmailPort: process.env.SYSTEM_EMAIL_PORT,
|
||||
systemEmailAddress: process.env.SYSTEM_EMAIL_ADDRESS,
|
||||
systemEmailPassword: process.env.SYSTEM_EMAIL_PASSWORD,
|
||||
logLevel: undefined,
|
||||
apiBaseUrl: undefined,
|
||||
clientHost: process.env.CLIENT_HOST,
|
||||
jwtSecret: process.env.JWT_SECRET,
|
||||
refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET,
|
||||
dbType: process.env.DB_TYPE,
|
||||
dbConnectionString: process.env.DB_CONNECTION_STRING,
|
||||
redisHost: process.env.REDIS_HOST,
|
||||
redisPort: process.env.REDIS_PORT,
|
||||
jwtTTL: process.env.TOKEN_TTL,
|
||||
refreshTokenTTL: process.env.REFRESH_TOKEN_TTL,
|
||||
pagespeedApiKey: process.env.PAGESPEED_API_KEY,
|
||||
systemEmailHost: process.env.SYSTEM_EMAIL_HOST,
|
||||
systemEmailPort: process.env.SYSTEM_EMAIL_PORT,
|
||||
systemEmailAddress: process.env.SYSTEM_EMAIL_ADDRESS,
|
||||
systemEmailPassword: process.env.SYSTEM_EMAIL_PASSWORD,
|
||||
};
|
||||
/**
|
||||
* SettingsService
|
||||
@@ -26,60 +26,60 @@ const envConfig = {
|
||||
* from the database if they are not set in the environment.
|
||||
*/
|
||||
class SettingsService {
|
||||
/**
|
||||
* Constructs a new SettingsService
|
||||
* @constructor
|
||||
* @throws {Error}
|
||||
*/ constructor() {
|
||||
this.settings = { ...envConfig };
|
||||
}
|
||||
/**
|
||||
* Load settings from the database and merge with environment settings.
|
||||
* If there are any settings that weren't set by environment variables, use user settings from the database.
|
||||
* @returns {Promise<Object>} The merged settings.
|
||||
* @throws Will throw an error if settings are not found in the database or if settings have not been loaded.
|
||||
*/ async loadSettings() {
|
||||
try {
|
||||
const dbSettings = await AppSettings.findOne();
|
||||
if (!this.settings) {
|
||||
throw new Error("Settings not found");
|
||||
}
|
||||
/**
|
||||
* Constructs a new SettingsService
|
||||
* @constructor
|
||||
* @throws {Error}
|
||||
*/ constructor() {
|
||||
this.settings = { ...envConfig };
|
||||
}
|
||||
/**
|
||||
* Load settings from the database and merge with environment settings.
|
||||
* If there are any settings that weren't set by environment variables, use user settings from the database.
|
||||
* @returns {Promise<Object>} The merged settings.
|
||||
* @throws Will throw an error if settings are not found in the database or if settings have not been loaded.
|
||||
*/ async loadSettings() {
|
||||
try {
|
||||
const dbSettings = await AppSettings.findOne();
|
||||
if (!this.settings) {
|
||||
throw new Error("Settings not found");
|
||||
}
|
||||
|
||||
// If there are any settings that weren't set by environment variables, use user settings from DB
|
||||
for (const key in envConfig) {
|
||||
if (envConfig[key] === undefined && dbSettings[key] !== undefined) {
|
||||
this.settings[key] = dbSettings[key];
|
||||
}
|
||||
}
|
||||
// If there are any settings that weren't set by environment variables, use user settings from DB
|
||||
for (const key in envConfig) {
|
||||
if (envConfig[key] === undefined && dbSettings[key] !== undefined) {
|
||||
this.settings[key] = dbSettings[key];
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.settings) {
|
||||
throw new Error("Settings not found");
|
||||
}
|
||||
return this.settings;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "loadSettings") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reload settings by calling loadSettings.
|
||||
* @returns {Promise<Object>} The reloaded settings.
|
||||
*/
|
||||
async reloadSettings() {
|
||||
return this.loadSettings();
|
||||
}
|
||||
/**
|
||||
* Get the current settings.
|
||||
* @returns {Object} The current settings.
|
||||
* @throws Will throw an error if settings have not been loaded.
|
||||
*/
|
||||
getSettings() {
|
||||
if (!this.settings) {
|
||||
throw new Error("Settings have not been loaded");
|
||||
}
|
||||
return this.settings;
|
||||
}
|
||||
if (!this.settings) {
|
||||
throw new Error("Settings not found");
|
||||
}
|
||||
return this.settings;
|
||||
} catch (error) {
|
||||
error.service === undefined ? (error.service = SERVICE_NAME) : null;
|
||||
error.method === undefined ? (error.method = "loadSettings") : null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reload settings by calling loadSettings.
|
||||
* @returns {Promise<Object>} The reloaded settings.
|
||||
*/
|
||||
async reloadSettings() {
|
||||
return this.loadSettings();
|
||||
}
|
||||
/**
|
||||
* Get the current settings.
|
||||
* @returns {Object} The current settings.
|
||||
* @throws Will throw an error if settings have not been loaded.
|
||||
*/
|
||||
getSettings() {
|
||||
if (!this.settings) {
|
||||
throw new Error("Settings have not been loaded");
|
||||
}
|
||||
return this.settings;
|
||||
}
|
||||
}
|
||||
|
||||
export default SettingsService;
|
||||
|
||||
@@ -1,35 +1,52 @@
|
||||
<!-- name, link -->
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text font-weight="300" font-size="16px" color="#616161" line-height="24px"></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text align="left" font-size="10px">Message from BlueWave Uptime Service</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>One of the admins created an account for you on the BlueWave Uptime server.</p>
|
||||
<p>You can go ahead and create your account using this link.</p>
|
||||
<p><a href={{link}}>{{link}}</a></p>
|
||||
<p>Thank you.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider border-width="1px" border-color="#E0E0E0"></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
<mj-head>
|
||||
<mj-font
|
||||
name="Roboto"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,500"
|
||||
></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text
|
||||
font-weight="300"
|
||||
font-size="16px"
|
||||
color="#616161"
|
||||
line-height="24px"
|
||||
></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text
|
||||
align="left"
|
||||
font-size="10px"
|
||||
>Message from BlueWave Uptime Service</mj-text
|
||||
>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
One of the admins created an account for you on the BlueWave Uptime server.
|
||||
</p>
|
||||
<p>You can go ahead and create your account using this link.</p>
|
||||
<p><a href="{{link}}">{{link}}</a></p>
|
||||
<p>Thank you.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider
|
||||
border-width="1px"
|
||||
border-color="#E0E0E0"
|
||||
></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
|
||||
@@ -1,38 +1,66 @@
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text font-weight="300" font-size="16px" color="#616161" line-height="24px"></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text align="left" font-size="10px">Message from BlueWave Uptime Service</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="45%" padding-top="20px">
|
||||
<mj-text align="center" font-weight="500" padding="0px" font-size="18px" color="green">No incidents this week!</mj-text>
|
||||
<mj-divider border-width="2px" border-color="#616161"></mj-divider>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>There were no incidents this week. Good job!</p>
|
||||
<p><b>Current monitors:</b></p>
|
||||
<p><b>Google:</b> 100% availability</p>
|
||||
<p><b>Canada.ca:</b>100% availability</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider border-width="1px" border-color="#E0E0E0"></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
<mj-head>
|
||||
<mj-font
|
||||
name="Roboto"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,500"
|
||||
></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text
|
||||
font-weight="300"
|
||||
font-size="16px"
|
||||
color="#616161"
|
||||
line-height="24px"
|
||||
></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text
|
||||
align="left"
|
||||
font-size="10px"
|
||||
>Message from BlueWave Uptime Service</mj-text
|
||||
>
|
||||
</mj-column>
|
||||
<mj-column
|
||||
width="45%"
|
||||
padding-top="20px"
|
||||
>
|
||||
<mj-text
|
||||
align="center"
|
||||
font-weight="500"
|
||||
padding="0px"
|
||||
font-size="18px"
|
||||
color="green"
|
||||
>No incidents this week!</mj-text
|
||||
>
|
||||
<mj-divider
|
||||
border-width="2px"
|
||||
border-color="#616161"
|
||||
></mj-divider>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>There were no incidents this week. Good job!</p>
|
||||
<p><b>Current monitors:</b></p>
|
||||
<p><b>Google:</b> 100% availability</p>
|
||||
<p><b>Canada.ca:</b>100% availability</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider
|
||||
border-width="1px"
|
||||
border-color="#E0E0E0"
|
||||
></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
|
||||
@@ -1,43 +1,56 @@
|
||||
<!-- name, email, url -->
|
||||
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text font-weight="300" font-size="16px" color="#616161" line-height="24px"></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text align="left" font-size="10px">
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
You are receiving this email because a password reset request
|
||||
has been made for {{email}}. Please use the
|
||||
link below on the site to reset your password.
|
||||
</p>
|
||||
<a href="{{url}}">Reset Password</a>
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
<mj-head>
|
||||
<mj-font
|
||||
name="Roboto"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,500"
|
||||
></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text
|
||||
font-weight="300"
|
||||
font-size="16px"
|
||||
color="#616161"
|
||||
line-height="24px"
|
||||
></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text
|
||||
align="left"
|
||||
font-size="10px"
|
||||
>
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
You are receiving this email because a password reset request has been made
|
||||
for {{email}}. Please use the link below on the site to reset your password.
|
||||
</p>
|
||||
<a href="{{url}}">Reset Password</a>
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
|
||||
<p>Thank you.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider border-width="1px" border-color="#E0E0E0"></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
<p>Thank you.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider
|
||||
border-width="1px"
|
||||
border-color="#E0E0E0"
|
||||
></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
|
||||
@@ -1,57 +1,73 @@
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text font-weight="300" font-size="16px" color="#616161" line-height="24px"></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text align="left" font-size="10px">
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="45%" padding-top="20px">
|
||||
<mj-text align="center" font-weight="500" padding="0px" font-size="18px" color="red">
|
||||
Google.com is down
|
||||
</mj-text>
|
||||
<mj-divider border-width="2px" border-color="#616161"></mj-divider>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
We detected an incident on one of your monitors. Your service is
|
||||
currently down. We'll send a message to you once it is up again.
|
||||
</p>
|
||||
<p>
|
||||
<b>Monitor name:</b> {{monitor}}
|
||||
</p>
|
||||
<p>
|
||||
<b>URL:</b> {{url}}
|
||||
</p>
|
||||
<p>
|
||||
<b>Problem:</b> {{problem}}
|
||||
</p>
|
||||
<p>
|
||||
<b>Start date:</b> {{startDate}}
|
||||
</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider border-width="1px" border-color="#E0E0E0"></mj-divider>
|
||||
<mj-button background-color="#1570EF">
|
||||
View incident details
|
||||
</mj-button>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
<mj-head>
|
||||
<mj-font
|
||||
name="Roboto"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,500"
|
||||
></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text
|
||||
font-weight="300"
|
||||
font-size="16px"
|
||||
color="#616161"
|
||||
line-height="24px"
|
||||
></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text
|
||||
align="left"
|
||||
font-size="10px"
|
||||
>
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column
|
||||
width="45%"
|
||||
padding-top="20px"
|
||||
>
|
||||
<mj-text
|
||||
align="center"
|
||||
font-weight="500"
|
||||
padding="0px"
|
||||
font-size="18px"
|
||||
color="red"
|
||||
>
|
||||
Google.com is down
|
||||
</mj-text>
|
||||
<mj-divider
|
||||
border-width="2px"
|
||||
border-color="#616161"
|
||||
></mj-divider>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
We detected an incident on one of your monitors. Your service is currently
|
||||
down. We'll send a message to you once it is up again.
|
||||
</p>
|
||||
<p><b>Monitor name:</b> {{monitor}}</p>
|
||||
<p><b>URL:</b> {{url}}</p>
|
||||
<p><b>Problem:</b> {{problem}}</p>
|
||||
<p><b>Start date:</b> {{startDate}}</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider
|
||||
border-width="1px"
|
||||
border-color="#E0E0E0"
|
||||
></mj-divider>
|
||||
<mj-button background-color="#1570EF"> View incident details </mj-button>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
|
||||
@@ -1,63 +1,72 @@
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text font-weight="300" font-size="16px" color="#616161" line-height="24px"></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text align="left" font-size="10px">
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="45%" padding-top="20px">
|
||||
<mj-text align="center" font-weight="500" padding="0px" font-size="18px" color="green">
|
||||
{{monitor}} is up
|
||||
</mj-text>
|
||||
<mj-divider border-width="2px" border-color="#616161"></mj-divider>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
Your latest incident is resolved and your monitored service is
|
||||
up again.
|
||||
</p>
|
||||
<p>
|
||||
<b>Monitor name:</b> {{monitor}}
|
||||
</p>
|
||||
<p>
|
||||
<b>URL:</b> {{url}}
|
||||
</p>
|
||||
<p>
|
||||
<b>Problem:</b> {{problem}}
|
||||
</p>
|
||||
<p>
|
||||
<b>Start date:</b> {{startDate}}
|
||||
</p>
|
||||
<p>
|
||||
<b>Resolved date:</b> {{resolvedDate}}
|
||||
</p>
|
||||
<p>
|
||||
<b>Duration:</b>{{duration}}
|
||||
</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider border-width="1px" border-color="#E0E0E0"></mj-divider>
|
||||
<mj-button background-color="#1570EF">
|
||||
View incident details
|
||||
</mj-button>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
<mj-head>
|
||||
<mj-font
|
||||
name="Roboto"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,500"
|
||||
></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text
|
||||
font-weight="300"
|
||||
font-size="16px"
|
||||
color="#616161"
|
||||
line-height="24px"
|
||||
></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text
|
||||
align="left"
|
||||
font-size="10px"
|
||||
>
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column
|
||||
width="45%"
|
||||
padding-top="20px"
|
||||
>
|
||||
<mj-text
|
||||
align="center"
|
||||
font-weight="500"
|
||||
padding="0px"
|
||||
font-size="18px"
|
||||
color="green"
|
||||
>
|
||||
{{monitor}} is up
|
||||
</mj-text>
|
||||
<mj-divider
|
||||
border-width="2px"
|
||||
border-color="#616161"
|
||||
></mj-divider>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>Your latest incident is resolved and your monitored service is up again.</p>
|
||||
<p><b>Monitor name:</b> {{monitor}}</p>
|
||||
<p><b>URL:</b> {{url}}</p>
|
||||
<p><b>Problem:</b> {{problem}}</p>
|
||||
<p><b>Start date:</b> {{startDate}}</p>
|
||||
<p><b>Resolved date:</b> {{resolvedDate}}</p>
|
||||
<p><b>Duration:</b>{{duration}}</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider
|
||||
border-width="1px"
|
||||
border-color="#E0E0E0"
|
||||
></mj-divider>
|
||||
<mj-button background-color="#1570EF"> View incident details </mj-button>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
|
||||
@@ -1,44 +1,57 @@
|
||||
<!-- name -->
|
||||
<mjml>
|
||||
<mj-head>
|
||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text font-weight="300" font-size="16px" color="#616161" line-height="24px"></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text align="left" font-size="10px">
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
Thank you for trying out BlueWave Uptime! We developed it with
|
||||
great care to meet our own needs, and we're excited to share it
|
||||
with you.
|
||||
</p>
|
||||
<p>
|
||||
BlueWave Uptime is an automated way of checking whether a
|
||||
service such as a website or an application is available or not.
|
||||
</p>
|
||||
<p>We hope you find our service as valuable as we do.</p>
|
||||
<p>Thank you.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider border-width="1px" border-color="#E0E0E0"></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
<mj-head>
|
||||
<mj-font
|
||||
name="Roboto"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:300,500"
|
||||
></mj-font>
|
||||
<mj-attributes>
|
||||
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
|
||||
<mj-text
|
||||
font-weight="300"
|
||||
font-size="16px"
|
||||
color="#616161"
|
||||
line-height="24px"
|
||||
></mj-text>
|
||||
<mj-section padding="0px"></mj-section>
|
||||
</mj-attributes>
|
||||
</mj-head>
|
||||
<mj-body>
|
||||
<mj-section padding="20px 0">
|
||||
<mj-column width="100%">
|
||||
<mj-text
|
||||
align="left"
|
||||
font-size="10px"
|
||||
>
|
||||
Message from BlueWave Uptime Service
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section>
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{name}}!</p>
|
||||
<p>
|
||||
Thank you for trying out BlueWave Uptime! We developed it with great care to
|
||||
meet our own needs, and we're excited to share it with you.
|
||||
</p>
|
||||
<p>
|
||||
BlueWave Uptime is an automated way of checking whether a service such as a
|
||||
website or an application is available or not.
|
||||
</p>
|
||||
<p>We hope you find our service as valuable as we do.</p>
|
||||
<p>Thank you.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
<mj-column width="100%">
|
||||
<mj-divider
|
||||
border-width="1px"
|
||||
border-color="#E0E0E0"
|
||||
></mj-divider>
|
||||
<mj-text font-size="12px">
|
||||
<p>This email was sent by BlueWave Uptime.</p>
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
</mj-body>
|
||||
</mjml>
|
||||
|
||||
@@ -1,375 +1,373 @@
|
||||
import {
|
||||
createCheck,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
createCheck,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
} from "../../controllers/checkController.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { errorMessages, successMessages } from "../../utils/messages.js";
|
||||
import sinon from "sinon";
|
||||
describe("Check Controller - createCheck", () => {
|
||||
let req, res, next, handleError;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
body: {},
|
||||
db: {
|
||||
createCheck: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
handleError = sinon.stub();
|
||||
});
|
||||
let req, res, next, handleError;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
body: {},
|
||||
db: {
|
||||
createCheck: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
handleError = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore(); // Restore the original methods after each test
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore(); // Restore the original methods after each test
|
||||
});
|
||||
|
||||
it("should reject with a validation if params are invalid", async () => {
|
||||
await createCheck(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with a validation if params are invalid", async () => {
|
||||
await createCheck(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject with a validation error if body is invalid", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
await createCheck(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with a validation error if body is invalid", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
await createCheck(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.body = {
|
||||
monitorId: "monitorId",
|
||||
status: true,
|
||||
responseTime: 100,
|
||||
statusCode: 200,
|
||||
message: "message",
|
||||
};
|
||||
req.db.createCheck.rejects(new Error("error"));
|
||||
await createCheck(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
});
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.body = {
|
||||
monitorId: "monitorId",
|
||||
status: true,
|
||||
responseTime: 100,
|
||||
statusCode: 200,
|
||||
message: "message",
|
||||
};
|
||||
req.db.createCheck.rejects(new Error("error"));
|
||||
await createCheck(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
});
|
||||
|
||||
it("should return a success message if check is created", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.db.createCheck.resolves({ id: "123" });
|
||||
req.body = {
|
||||
monitorId: "monitorId",
|
||||
status: true,
|
||||
responseTime: 100,
|
||||
statusCode: 200,
|
||||
message: "message",
|
||||
};
|
||||
await createCheck(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_CREATE,
|
||||
data: { id: "123" },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.notCalled).to.be.true;
|
||||
});
|
||||
it("should return a success message if check is created", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.db.createCheck.resolves({ id: "123" });
|
||||
req.body = {
|
||||
monitorId: "monitorId",
|
||||
status: true,
|
||||
responseTime: 100,
|
||||
statusCode: 200,
|
||||
message: "message",
|
||||
};
|
||||
await createCheck(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_CREATE,
|
||||
data: { id: "123" },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.notCalled).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Check Controller - getChecks", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
query: {},
|
||||
db: {
|
||||
getChecks: sinon.stub(),
|
||||
getChecksCount: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
query: {},
|
||||
db: {
|
||||
getChecks: sinon.stub(),
|
||||
getChecksCount: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with a validation error if params are invalid", async () => {
|
||||
await getChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with a validation error if params are invalid", async () => {
|
||||
await getChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should return a success message if checks are found", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.db.getChecks.resolves([{ id: "123" }]);
|
||||
req.db.getChecksCount.resolves(1);
|
||||
await getChecks(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: { checksCount: 1, checks: [{ id: "123" }] },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.notCalled).to.be.true;
|
||||
});
|
||||
it("should return a success message if checks are found", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.db.getChecks.resolves([{ id: "123" }]);
|
||||
req.db.getChecksCount.resolves(1);
|
||||
await getChecks(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: { checksCount: 1, checks: [{ id: "123" }] },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.notCalled).to.be.true;
|
||||
});
|
||||
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.db.getChecks.rejects(new Error("error"));
|
||||
await getChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
});
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = {
|
||||
monitorId: "monitorId",
|
||||
};
|
||||
req.db.getChecks.rejects(new Error("error"));
|
||||
await getChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Check Controller - getTeamChecks", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
query: {},
|
||||
db: {
|
||||
getTeamChecks: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
query: {},
|
||||
db: {
|
||||
getTeamChecks: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with a validation error if params are invalid", async () => {
|
||||
await getTeamChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with a validation error if params are invalid", async () => {
|
||||
await getTeamChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should return 200 and check data on successful validation and data retrieval", async () => {
|
||||
req.params = { teamId: "1" };
|
||||
const checkData = [{ id: 1, name: "Check 1" }];
|
||||
req.db.getTeamChecks.resolves(checkData);
|
||||
it("should return 200 and check data on successful validation and data retrieval", async () => {
|
||||
req.params = { teamId: "1" };
|
||||
const checkData = [{ id: 1, name: "Check 1" }];
|
||||
req.db.getTeamChecks.resolves(checkData);
|
||||
|
||||
await getTeamChecks(req, res, next);
|
||||
expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: checkData,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
await getTeamChecks(req, res, next);
|
||||
expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_GET,
|
||||
data: checkData,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = { teamId: "1" };
|
||||
req.db.getTeamChecks.rejects(new Error("Retrieval Error"));
|
||||
await getTeamChecks(req, res, next);
|
||||
expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true;
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(res.status.notCalled).to.be.true;
|
||||
expect(res.json.notCalled).to.be.true;
|
||||
});
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = { teamId: "1" };
|
||||
req.db.getTeamChecks.rejects(new Error("Retrieval Error"));
|
||||
await getTeamChecks(req, res, next);
|
||||
expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true;
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(res.status.notCalled).to.be.true;
|
||||
expect(res.json.notCalled).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Check Controller - deleteChecks", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
db: {
|
||||
deleteChecks: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
db: {
|
||||
deleteChecks: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if param validation fails", async () => {
|
||||
await deleteChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with an error if param validation fails", async () => {
|
||||
await deleteChecks(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = { monitorId: "1" };
|
||||
req.db.deleteChecks.rejects(new Error("Deletion Error"));
|
||||
await deleteChecks(req, res, next);
|
||||
expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true;
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(res.status.notCalled).to.be.true;
|
||||
expect(res.json.notCalled).to.be.true;
|
||||
});
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = { monitorId: "1" };
|
||||
req.db.deleteChecks.rejects(new Error("Deletion Error"));
|
||||
await deleteChecks(req, res, next);
|
||||
expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true;
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(res.status.notCalled).to.be.true;
|
||||
expect(res.json.notCalled).to.be.true;
|
||||
});
|
||||
|
||||
it("should delete checks successfully", async () => {
|
||||
req.params = { monitorId: "123" };
|
||||
req.db.deleteChecks.resolves(1);
|
||||
await deleteChecks(req, res, next);
|
||||
expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount: 1 },
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
it("should delete checks successfully", async () => {
|
||||
req.params = { monitorId: "123" };
|
||||
req.db.deleteChecks.resolves(1);
|
||||
await deleteChecks(req, res, next);
|
||||
expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount: 1 },
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Check Controller - deleteChecksByTeamId", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
db: {
|
||||
deleteChecksByTeamId: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
db: {
|
||||
deleteChecksByTeamId: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if param validation fails", async () => {
|
||||
await deleteChecksByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with an error if param validation fails", async () => {
|
||||
await deleteChecksByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = { teamId: "1" };
|
||||
req.db.deleteChecksByTeamId.rejects(new Error("Deletion Error"));
|
||||
await deleteChecksByTeamId(req, res, next);
|
||||
expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be
|
||||
.true;
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(res.status.notCalled).to.be.true;
|
||||
expect(res.json.notCalled).to.be.true;
|
||||
});
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.params = { teamId: "1" };
|
||||
req.db.deleteChecksByTeamId.rejects(new Error("Deletion Error"));
|
||||
await deleteChecksByTeamId(req, res, next);
|
||||
expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be.true;
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(res.status.notCalled).to.be.true;
|
||||
expect(res.json.notCalled).to.be.true;
|
||||
});
|
||||
|
||||
it("should delete checks successfully", async () => {
|
||||
req.params = { teamId: "123" };
|
||||
req.db.deleteChecksByTeamId.resolves(1);
|
||||
await deleteChecksByTeamId(req, res, next);
|
||||
expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be
|
||||
.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount: 1 },
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
it("should delete checks successfully", async () => {
|
||||
req.params = { teamId: "123" };
|
||||
req.db.deleteChecksByTeamId.resolves(1);
|
||||
await deleteChecksByTeamId(req, res, next);
|
||||
expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_DELETE,
|
||||
data: { deletedCount: 1 },
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Check Controller - updateCheckTTL", () => {
|
||||
let stub, req, res, next;
|
||||
beforeEach(() => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
let stub, req, res, next;
|
||||
beforeEach(() => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
|
||||
req = {
|
||||
body: {},
|
||||
headers: { authorization: "Bearer token" },
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "my_secret" }),
|
||||
},
|
||||
db: {
|
||||
updateChecksTTL: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
req = {
|
||||
body: {},
|
||||
headers: { authorization: "Bearer token" },
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "my_secret" }),
|
||||
},
|
||||
db: {
|
||||
updateChecksTTL: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
stub.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject if body validation fails", async () => {
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if body validation fails", async () => {
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should throw a JwtError if verification fails", async () => {
|
||||
stub.restore();
|
||||
req.body = {
|
||||
ttl: 1,
|
||||
};
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
|
||||
});
|
||||
it("should throw a JwtError if verification fails", async () => {
|
||||
stub.restore();
|
||||
req.body = {
|
||||
ttl: 1,
|
||||
};
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
|
||||
});
|
||||
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.body = {
|
||||
ttl: 1,
|
||||
};
|
||||
req.db.updateChecksTTL.rejects(new Error("Update Error"));
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
});
|
||||
it("should call next with error if data retrieval fails", async () => {
|
||||
req.body = {
|
||||
ttl: 1,
|
||||
};
|
||||
req.db.updateChecksTTL.rejects(new Error("Update Error"));
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
});
|
||||
|
||||
it("should update TTL successfully", async () => {
|
||||
req.body = {
|
||||
ttl: 1,
|
||||
};
|
||||
req.db.updateChecksTTL.resolves();
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(req.db.updateChecksTTL.calledOnceWith("123", 1 * 86400)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_UPDATE_TTL,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
it("should update TTL successfully", async () => {
|
||||
req.body = {
|
||||
ttl: 1,
|
||||
};
|
||||
req.db.updateChecksTTL.resolves();
|
||||
await updateChecksTTL(req, res, next);
|
||||
expect(req.db.updateChecksTTL.calledOnceWith("123", 1 * 86400)).to.be.true;
|
||||
expect(res.status.calledOnceWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.CHECK_UPDATE_TTL,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,203 +1,203 @@
|
||||
import {
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
} from "../../controllers/inviteController.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import sinon from "sinon";
|
||||
import joi from "joi";
|
||||
describe("inviteController - issueInvitation", () => {
|
||||
let req, res, next, stub;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: { authorization: "Bearer token" },
|
||||
body: {
|
||||
email: "test@test.com",
|
||||
role: ["admin"],
|
||||
teamId: "123",
|
||||
},
|
||||
db: { requestInviteToken: sinon.stub() },
|
||||
settingsService: { getSettings: sinon.stub() },
|
||||
emailService: { buildAndSendEmail: sinon.stub() },
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next, stub;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: { authorization: "Bearer token" },
|
||||
body: {
|
||||
email: "test@test.com",
|
||||
role: ["admin"],
|
||||
teamId: "123",
|
||||
},
|
||||
db: { requestInviteToken: sinon.stub() },
|
||||
settingsService: { getSettings: sinon.stub() },
|
||||
emailService: { buildAndSendEmail: sinon.stub() },
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if role validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["bad_role"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(joi.ValidationError);
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error if role validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["bad_role"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(joi.ValidationError);
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["admin"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
req.body = {};
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["admin"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
req.body = {};
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["admin"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
req.db.requestInviteToken.throws(new Error("DB error"));
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return { role: ["admin"], firstname: "first_name", teamId: "1" };
|
||||
});
|
||||
req.db.requestInviteToken.throws(new Error("DB error"));
|
||||
await issueInvitation(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should send an invite successfully", async () => {
|
||||
const token = "token";
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
it("should send an invite successfully", async () => {
|
||||
const token = "token";
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
req.emailService.buildAndSendEmail.resolves();
|
||||
await issueInvitation(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: "Invite sent",
|
||||
data: inviteToken,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
req.emailService.buildAndSendEmail.resolves();
|
||||
await issueInvitation(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: "Invite sent",
|
||||
data: inviteToken,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should send an email successfully", async () => {
|
||||
const token = "token";
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
it("should send an email successfully", async () => {
|
||||
const token = "token";
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
req.emailService.buildAndSendEmail.resolves();
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
req.emailService.buildAndSendEmail.resolves();
|
||||
|
||||
await issueInvitation(req, res, next);
|
||||
expect(req.emailService.buildAndSendEmail.calledOnce).to.be.true;
|
||||
expect(
|
||||
req.emailService.buildAndSendEmail.calledWith(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: "John",
|
||||
link: "http://localhost/register/inviteToken",
|
||||
},
|
||||
"test@test.com",
|
||||
"Welcome to Uptime Monitor"
|
||||
)
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
await issueInvitation(req, res, next);
|
||||
expect(req.emailService.buildAndSendEmail.calledOnce).to.be.true;
|
||||
expect(
|
||||
req.emailService.buildAndSendEmail.calledWith(
|
||||
"employeeActivationTemplate",
|
||||
{
|
||||
name: "John",
|
||||
link: "http://localhost/register/inviteToken",
|
||||
},
|
||||
"test@test.com",
|
||||
"Welcome to Uptime Monitor"
|
||||
)
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should continue executing if sending an email fails", async () => {
|
||||
const token = "token";
|
||||
req.emailService.buildAndSendEmail.rejects(new Error("Email error"));
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
it("should continue executing if sending an email fails", async () => {
|
||||
const token = "token";
|
||||
req.emailService.buildAndSendEmail.rejects(new Error("Email error"));
|
||||
const decodedToken = {
|
||||
role: "admin",
|
||||
firstname: "John",
|
||||
teamId: "team123",
|
||||
};
|
||||
const inviteToken = { token: "inviteToken" };
|
||||
const clientHost = "http://localhost";
|
||||
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
await issueInvitation(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: "Invite sent",
|
||||
data: inviteToken,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
stub = sinon.stub(jwt, "decode").callsFake(() => {
|
||||
return decodedToken;
|
||||
});
|
||||
req.db.requestInviteToken.resolves(inviteToken);
|
||||
req.settingsService.getSettings.returns({ clientHost });
|
||||
await issueInvitation(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
success: true,
|
||||
msg: "Invite sent",
|
||||
data: inviteToken,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("inviteController - inviteVerifyController", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: { token: "token" },
|
||||
db: {
|
||||
getInviteToken: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: { token: "token" },
|
||||
db: {
|
||||
getInviteToken: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
req.body = {};
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
req.body = {};
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.getInviteToken.throws(new Error("DB error"));
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.getInviteToken.throws(new Error("DB error"));
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
|
||||
it("should return 200 and invite data when validation and invite retrieval are successful", async () => {
|
||||
req.db.getInviteToken.resolves({ invite: "data" });
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
status: "success",
|
||||
msg: "Invite verified",
|
||||
data: { invite: "data" },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.called).to.be.false;
|
||||
});
|
||||
it("should return 200 and invite data when validation and invite retrieval are successful", async () => {
|
||||
req.db.getInviteToken.resolves({ invite: "data" });
|
||||
await inviteVerifyController(req, res, next);
|
||||
expect(res.status.calledWith(200)).to.be.true;
|
||||
expect(
|
||||
res.json.calledWith({
|
||||
status: "success",
|
||||
msg: "Invite verified",
|
||||
data: { invite: "data" },
|
||||
})
|
||||
).to.be.true;
|
||||
expect(next.called).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {
|
||||
createMaintenanceWindows,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindow,
|
||||
editMaintenanceWindow,
|
||||
createMaintenanceWindows,
|
||||
getMaintenanceWindowById,
|
||||
getMaintenanceWindowsByTeamId,
|
||||
getMaintenanceWindowsByMonitorId,
|
||||
deleteMaintenanceWindow,
|
||||
editMaintenanceWindow,
|
||||
} from "../../controllers/maintenanceWindowController.js";
|
||||
|
||||
import jwt from "jsonwebtoken";
|
||||
@@ -12,405 +12,399 @@ import { successMessages } from "../../utils/messages.js";
|
||||
import sinon from "sinon";
|
||||
|
||||
describe("maintenanceWindowController - createMaintenanceWindows", () => {
|
||||
let req, res, next, stub;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {
|
||||
monitors: ["66ff52e7c5911c61698ac724"],
|
||||
name: "window",
|
||||
active: true,
|
||||
start: "2024-10-11T05:27:13.747Z",
|
||||
end: "2024-10-11T05:27:14.747Z",
|
||||
repeat: "123",
|
||||
},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
createMaintenanceWindow: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next, stub;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {
|
||||
monitors: ["66ff52e7c5911c61698ac724"],
|
||||
name: "window",
|
||||
active: true,
|
||||
start: "2024-10-11T05:27:13.747Z",
|
||||
end: "2024-10-11T05:27:14.747Z",
|
||||
repeat: "123",
|
||||
},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
createMaintenanceWindow: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.body = {};
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.body = {};
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if jwt.verify fails", async () => {
|
||||
stub = sinon.stub(jwt, "verify").throws(new jwt.JsonWebTokenError());
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error if jwt.verify fails", async () => {
|
||||
stub = sinon.stub(jwt, "verify").throws(new jwt.JsonWebTokenError());
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.db.createMaintenanceWindow.throws(new Error("DB error"));
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
it("should return success message if all operations are successful", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(201);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
it("should return success message if all operations are successful with active set to undefined", async () => {
|
||||
req.body.active = undefined;
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(201);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.db.createMaintenanceWindow.throws(new Error("DB error"));
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
it("should return success message if all operations are successful", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(201);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
it("should return success message if all operations are successful with active set to undefined", async () => {
|
||||
req.body.active = undefined;
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
await createMaintenanceWindows(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(201);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE,
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("maintenanceWindowController - getMaintenanceWindowById", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {
|
||||
id: "123",
|
||||
},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
getMaintenanceWindowById: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {
|
||||
id: "123",
|
||||
},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
getMaintenanceWindowById: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await getMaintenanceWindowById(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await getMaintenanceWindowById(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject if DB operations fail", async () => {
|
||||
req.db.getMaintenanceWindowById.throws(new Error("DB error"));
|
||||
await getMaintenanceWindowById(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
req.db.getMaintenanceWindowById.returns({ id: "123" });
|
||||
await getMaintenanceWindowById(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID,
|
||||
data: { id: "123" },
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
it("should reject if DB operations fail", async () => {
|
||||
req.db.getMaintenanceWindowById.throws(new Error("DB error"));
|
||||
await getMaintenanceWindowById(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
req.db.getMaintenanceWindowById.returns({ id: "123" });
|
||||
await getMaintenanceWindowById(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID,
|
||||
data: { id: "123" },
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("maintenanceWindowController - getMaintenanceWindowsByTeamId", () => {
|
||||
let req, res, next, stub;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
getMaintenanceWindowsByTeamId: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
it("should reject if query validation fails", async () => {
|
||||
req.query = {
|
||||
invalid: 1,
|
||||
};
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if jwt.verify fails", async () => {
|
||||
stub = sinon.stub(jwt, "verify").throws(new jwt.JsonWebTokenError());
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
|
||||
stub.restore();
|
||||
});
|
||||
let req, res, next, stub;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
getMaintenanceWindowsByTeamId: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
it("should reject if query validation fails", async () => {
|
||||
req.query = {
|
||||
invalid: 1,
|
||||
};
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if jwt.verify fails", async () => {
|
||||
stub = sinon.stub(jwt, "verify").throws(new jwt.JsonWebTokenError());
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.db.getMaintenanceWindowsByTeamId.throws(new Error("DB error"));
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.db.getMaintenanceWindowsByTeamId.throws(new Error("DB error"));
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
stub.restore();
|
||||
});
|
||||
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.db.getMaintenanceWindowsByTeamId.returns([{ id: "123" }]);
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM,
|
||||
data: [{ id: jwt.verify().teamId }],
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
stub = sinon.stub(jwt, "verify").callsFake(() => {
|
||||
return { teamId: "123" };
|
||||
});
|
||||
req.db.getMaintenanceWindowsByTeamId.returns([{ id: "123" }]);
|
||||
await getMaintenanceWindowsByTeamId(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM,
|
||||
data: [{ id: jwt.verify().teamId }],
|
||||
})
|
||||
).to.be.true;
|
||||
stub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("maintenanceWindowController - getMaintenanceWindowsByMonitorId", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {
|
||||
monitorId: "123",
|
||||
},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
getMaintenanceWindowsByMonitorId: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {
|
||||
monitorId: "123",
|
||||
},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
getMaintenanceWindowsByMonitorId: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await getMaintenanceWindowsByMonitorId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await getMaintenanceWindowsByMonitorId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.getMaintenanceWindowsByMonitorId.throws(new Error("DB error"));
|
||||
await getMaintenanceWindowsByMonitorId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.getMaintenanceWindowsByMonitorId.throws(new Error("DB error"));
|
||||
await getMaintenanceWindowsByMonitorId(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
const data = [{ monitorId: "123" }];
|
||||
req.db.getMaintenanceWindowsByMonitorId.returns(data);
|
||||
await getMaintenanceWindowsByMonitorId(req, res, next);
|
||||
expect(
|
||||
req.db.getMaintenanceWindowsByMonitorId.calledOnceWith(
|
||||
req.params.monitorId
|
||||
)
|
||||
);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_MONITOR,
|
||||
data: data,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
const data = [{ monitorId: "123" }];
|
||||
req.db.getMaintenanceWindowsByMonitorId.returns(data);
|
||||
await getMaintenanceWindowsByMonitorId(req, res, next);
|
||||
expect(req.db.getMaintenanceWindowsByMonitorId.calledOnceWith(req.params.monitorId));
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_MONITOR,
|
||||
data: data,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("maintenanceWindowController - deleteMaintenanceWindow", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {
|
||||
id: "123",
|
||||
},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
deleteMaintenanceWindowById: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {},
|
||||
params: {
|
||||
id: "123",
|
||||
},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
deleteMaintenanceWindowById: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await deleteMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await deleteMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.deleteMaintenanceWindowById.throws(new Error("DB error"));
|
||||
await deleteMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.deleteMaintenanceWindowById.throws(new Error("DB error"));
|
||||
await deleteMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
|
||||
it("should return success message if all operations are successful", async () => {
|
||||
await deleteMaintenanceWindow(req, res, next);
|
||||
expect(req.db.deleteMaintenanceWindowById.calledOnceWith(req.params.id));
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_DELETE,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
it("should return success message if all operations are successful", async () => {
|
||||
await deleteMaintenanceWindow(req, res, next);
|
||||
expect(req.db.deleteMaintenanceWindowById.calledOnceWith(req.params.id));
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_DELETE,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("maintenanceWindowController - editMaintenanceWindow", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {
|
||||
active: true,
|
||||
name: "test",
|
||||
},
|
||||
params: {
|
||||
id: "123",
|
||||
},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
editMaintenanceWindowById: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
body: {
|
||||
active: true,
|
||||
name: "test",
|
||||
},
|
||||
params: {
|
||||
id: "123",
|
||||
},
|
||||
query: {},
|
||||
headers: {
|
||||
authorization: "Bearer token",
|
||||
},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
|
||||
},
|
||||
db: {
|
||||
editMaintenanceWindowById: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if param validation fails", async () => {
|
||||
req.params = {};
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject if body validation fails", async () => {
|
||||
req.body = { invalid: 1 };
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject if body validation fails", async () => {
|
||||
req.body = { invalid: 1 };
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.editMaintenanceWindowById.throws(new Error("DB error"));
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
it("should reject with an error if DB operations fail", async () => {
|
||||
req.db.editMaintenanceWindowById.throws(new Error("DB error"));
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("DB error");
|
||||
});
|
||||
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
const data = { id: "123" };
|
||||
req.db.editMaintenanceWindowById.returns(data);
|
||||
it("should return success message with data if all operations are successful", async () => {
|
||||
const data = { id: "123" };
|
||||
req.db.editMaintenanceWindowById.returns(data);
|
||||
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(
|
||||
req.db.editMaintenanceWindowById.calledOnceWith(req.params.id, req.body)
|
||||
);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_EDIT,
|
||||
data: data,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
await editMaintenanceWindow(req, res, next);
|
||||
expect(req.db.editMaintenanceWindowById.calledOnceWith(req.params.id, req.body));
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(
|
||||
res.json.calledOnceWith({
|
||||
success: true,
|
||||
msg: successMessages.MAINTENANCE_WINDOW_EDIT,
|
||||
data: data,
|
||||
})
|
||||
).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,166 +1,166 @@
|
||||
import { afterEach } from "node:test";
|
||||
import {
|
||||
getMetrics,
|
||||
getJobs,
|
||||
addJob,
|
||||
obliterateQueue,
|
||||
getMetrics,
|
||||
getJobs,
|
||||
addJob,
|
||||
obliterateQueue,
|
||||
} from "../../controllers/queueController.js";
|
||||
import { successMessages } from "../../utils/messages.js";
|
||||
import sinon from "sinon";
|
||||
|
||||
describe("Queue Controller - getMetrics", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
getMetrics: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should throw an error if getMetrics throws an error", async () => {
|
||||
req.jobQueue.getMetrics.throws(new Error("getMetrics error"));
|
||||
await getMetrics(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("getMetrics error");
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
getMetrics: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should throw an error if getMetrics throws an error", async () => {
|
||||
req.jobQueue.getMetrics.throws(new Error("getMetrics error"));
|
||||
await getMetrics(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("getMetrics error");
|
||||
});
|
||||
|
||||
it("should return a success message and data if getMetrics is successful", async () => {
|
||||
const data = { data: "metrics" };
|
||||
req.jobQueue.getMetrics.returns(data);
|
||||
await getMetrics(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
it("should return a success message and data if getMetrics is successful", async () => {
|
||||
const data = { data: "metrics" };
|
||||
req.jobQueue.getMetrics.returns(data);
|
||||
await getMetrics(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Queue Controller - getJobs", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
getJobStats: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if getJobs throws an error", async () => {
|
||||
req.jobQueue.getJobStats.throws(new Error("getJobs error"));
|
||||
await getJobs(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("getJobs error");
|
||||
});
|
||||
it("should return a success message and data if getJobs is successful", async () => {
|
||||
const data = { data: "jobs" };
|
||||
req.jobQueue.getJobStats.returns(data);
|
||||
await getJobs(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
getJobStats: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if getJobs throws an error", async () => {
|
||||
req.jobQueue.getJobStats.throws(new Error("getJobs error"));
|
||||
await getJobs(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("getJobs error");
|
||||
});
|
||||
it("should return a success message and data if getJobs is successful", async () => {
|
||||
const data = { data: "jobs" };
|
||||
req.jobQueue.getJobStats.returns(data);
|
||||
await getJobs(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_GET_METRICS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Queue Controller - addJob", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
addJob: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if addJob throws an error", async () => {
|
||||
req.jobQueue.addJob.throws(new Error("addJob error"));
|
||||
await addJob(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("addJob error");
|
||||
});
|
||||
it("should return a success message if addJob is successful", async () => {
|
||||
req.jobQueue.addJob.resolves();
|
||||
await addJob(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_ADD_JOB,
|
||||
});
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
addJob: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if addJob throws an error", async () => {
|
||||
req.jobQueue.addJob.throws(new Error("addJob error"));
|
||||
await addJob(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("addJob error");
|
||||
});
|
||||
it("should return a success message if addJob is successful", async () => {
|
||||
req.jobQueue.addJob.resolves();
|
||||
await addJob(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_ADD_JOB,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Queue Controller - obliterateQueue", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
obliterate: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if obliterateQueue throws an error", async () => {
|
||||
req.jobQueue.obliterate.throws(new Error("obliterateQueue error"));
|
||||
await obliterateQueue(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("obliterateQueue error");
|
||||
});
|
||||
it("should return a success message if obliterateQueue is successful", async () => {
|
||||
req.jobQueue.obliterate.resolves();
|
||||
await obliterateQueue(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_OBLITERATE,
|
||||
});
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
jobQueue: {
|
||||
obliterate: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if obliterateQueue throws an error", async () => {
|
||||
req.jobQueue.obliterate.throws(new Error("obliterateQueue error"));
|
||||
await obliterateQueue(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("obliterateQueue error");
|
||||
});
|
||||
it("should return a success message if obliterateQueue is successful", async () => {
|
||||
req.jobQueue.obliterate.resolves();
|
||||
await obliterateQueue(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.QUEUE_OBLITERATE,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,105 +1,103 @@
|
||||
import { afterEach } from "node:test";
|
||||
import {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
} from "../../controllers/settingsController.js";
|
||||
|
||||
import { successMessages } from "../../utils/messages.js";
|
||||
import sinon from "sinon";
|
||||
|
||||
describe("Settings Controller - getAppSettings", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should throw an error if getSettings throws an error", async () => {
|
||||
req.settingsService.getSettings.throws(new Error("getSettings error"));
|
||||
await getAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("getSettings error");
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {},
|
||||
settingsService: {
|
||||
getSettings: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should throw an error if getSettings throws an error", async () => {
|
||||
req.settingsService.getSettings.throws(new Error("getSettings error"));
|
||||
await getAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("getSettings error");
|
||||
});
|
||||
|
||||
it("should return a success message and data if getSettings is successful", async () => {
|
||||
const data = { data: "settings" };
|
||||
req.settingsService.getSettings.returns(data);
|
||||
await getAppSettings(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.GET_APP_SETTINGS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
it("should return a success message and data if getSettings is successful", async () => {
|
||||
const data = { data: "settings" };
|
||||
req.settingsService.getSettings.returns(data);
|
||||
await getAppSettings(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.GET_APP_SETTINGS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Settings Controller - updateAppSettings", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {
|
||||
updateAppSettings: sinon.stub(),
|
||||
},
|
||||
settingsService: {
|
||||
reloadSettings: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
req.body = { invalid: 1 };
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with an error if updateAppSettings throws an error", async () => {
|
||||
req.db.updateAppSettings.throws(new Error("updateAppSettings error"));
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("updateAppSettings error");
|
||||
});
|
||||
it("should reject with an error if reloadSettings throws an error", async () => {
|
||||
req.settingsService.reloadSettings.throws(
|
||||
new Error("reloadSettings error")
|
||||
);
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("reloadSettings error");
|
||||
});
|
||||
it("should return a success message and data if updateAppSettings is successful", async () => {
|
||||
const data = { data: "settings" };
|
||||
req.settingsService.reloadSettings.returns(data);
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.UPDATE_APP_SETTINGS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
headers: {},
|
||||
params: {},
|
||||
body: {},
|
||||
db: {
|
||||
updateAppSettings: sinon.stub(),
|
||||
},
|
||||
settingsService: {
|
||||
reloadSettings: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
it("should reject with an error if body validation fails", async () => {
|
||||
req.body = { invalid: 1 };
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(422);
|
||||
});
|
||||
it("should reject with an error if updateAppSettings throws an error", async () => {
|
||||
req.db.updateAppSettings.throws(new Error("updateAppSettings error"));
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("updateAppSettings error");
|
||||
});
|
||||
it("should reject with an error if reloadSettings throws an error", async () => {
|
||||
req.settingsService.reloadSettings.throws(new Error("reloadSettings error"));
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("reloadSettings error");
|
||||
});
|
||||
it("should return a success message and data if updateAppSettings is successful", async () => {
|
||||
const data = { data: "settings" };
|
||||
req.settingsService.reloadSettings.returns(data);
|
||||
await updateAppSettings(req, res, next);
|
||||
expect(res.status.firstCall.args[0]).to.equal(200);
|
||||
expect(res.json.firstCall.args[0]).to.deep.equal({
|
||||
success: true,
|
||||
msg: successMessages.UPDATE_APP_SETTINGS,
|
||||
data,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,22 +4,22 @@ import sharp from "sharp";
|
||||
* @param {} file
|
||||
*/
|
||||
const GenerateAvatarImage = async (file) => {
|
||||
try {
|
||||
// Resize to target 64 * 64
|
||||
let resizedImageBuffer = await sharp(file.buffer)
|
||||
.resize({
|
||||
width: 64,
|
||||
height: 64,
|
||||
fit: "cover",
|
||||
})
|
||||
.toBuffer();
|
||||
try {
|
||||
// Resize to target 64 * 64
|
||||
let resizedImageBuffer = await sharp(file.buffer)
|
||||
.resize({
|
||||
width: 64,
|
||||
height: 64,
|
||||
fit: "cover",
|
||||
})
|
||||
.toBuffer();
|
||||
|
||||
//Get b64 string
|
||||
const base64Image = resizedImageBuffer.toString("base64");
|
||||
return base64Image;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
//Get b64 string
|
||||
const base64Image = resizedImageBuffer.toString("base64");
|
||||
return base64Image;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export { GenerateAvatarImage };
|
||||
|
||||
@@ -12,15 +12,12 @@ import winston from "winston";
|
||||
* logger.error("User not found!",{"service":"Auth"})
|
||||
*/
|
||||
const logger = winston.createLogger({
|
||||
level: "info",
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.json()
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
new winston.transports.File({ filename: "app.log" }),
|
||||
],
|
||||
level: "info",
|
||||
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
new winston.transports.File({ filename: "app.log" }),
|
||||
],
|
||||
});
|
||||
|
||||
export default logger;
|
||||
|
||||
@@ -1,124 +1,120 @@
|
||||
const errorMessages = {
|
||||
// General Errors:
|
||||
FRIENDLY_ERROR: "Something went wrong...",
|
||||
UNKNOWN_ERROR: "An unknown error occurred",
|
||||
// General Errors:
|
||||
FRIENDLY_ERROR: "Something went wrong...",
|
||||
UNKNOWN_ERROR: "An unknown error occurred",
|
||||
|
||||
// Auth Controller
|
||||
UNAUTHORIZED: "Unauthorized access",
|
||||
AUTH_ADMIN_EXISTS: "Admin already exists",
|
||||
AUTH_INVITE_NOT_FOUND: "Invite not found",
|
||||
// Auth Controller
|
||||
UNAUTHORIZED: "Unauthorized access",
|
||||
AUTH_ADMIN_EXISTS: "Admin already exists",
|
||||
AUTH_INVITE_NOT_FOUND: "Invite not found",
|
||||
|
||||
//Error handling middleware
|
||||
UNKNOWN_SERVICE: "Unknown service",
|
||||
NO_AUTH_TOKEN: "No auth token provided",
|
||||
INVALID_AUTH_TOKEN: "Invalid auth token",
|
||||
EXPIRED_AUTH_TOKEN: "Token expired",
|
||||
NO_REFRESH_TOKEN: "No refresh token provided",
|
||||
INVALID_REFRESH_TOKEN: "Invalid refresh token",
|
||||
EXPIRED_REFRESH_TOKEN: "Refresh token expired",
|
||||
REQUEST_NEW_ACCESS_TOKEN: "Request new access token",
|
||||
//Error handling middleware
|
||||
UNKNOWN_SERVICE: "Unknown service",
|
||||
NO_AUTH_TOKEN: "No auth token provided",
|
||||
INVALID_AUTH_TOKEN: "Invalid auth token",
|
||||
EXPIRED_AUTH_TOKEN: "Token expired",
|
||||
NO_REFRESH_TOKEN: "No refresh token provided",
|
||||
INVALID_REFRESH_TOKEN: "Invalid refresh token",
|
||||
EXPIRED_REFRESH_TOKEN: "Refresh token expired",
|
||||
REQUEST_NEW_ACCESS_TOKEN: "Request new access token",
|
||||
|
||||
//Payload
|
||||
INVALID_PAYLOAD: "Invalid payload",
|
||||
//Payload
|
||||
INVALID_PAYLOAD: "Invalid payload",
|
||||
|
||||
//Ownership Middleware
|
||||
VERIFY_OWNER_NOT_FOUND: "Document not found",
|
||||
VERIFY_OWNER_UNAUTHORIZED: "Unauthorized access",
|
||||
//Ownership Middleware
|
||||
VERIFY_OWNER_NOT_FOUND: "Document not found",
|
||||
VERIFY_OWNER_UNAUTHORIZED: "Unauthorized access",
|
||||
|
||||
//Permissions Middleware
|
||||
INSUFFICIENT_PERMISSIONS: "Insufficient permissions",
|
||||
//Permissions Middleware
|
||||
INSUFFICIENT_PERMISSIONS: "Insufficient permissions",
|
||||
|
||||
//DB Errors
|
||||
DB_USER_EXISTS: "User already exists",
|
||||
DB_USER_NOT_FOUND: "User not found",
|
||||
DB_TOKEN_NOT_FOUND: "Token not found",
|
||||
DB_RESET_PASSWORD_BAD_MATCH:
|
||||
"New password must be different from old password",
|
||||
DB_FIND_MONITOR_BY_ID: (monitorId) =>
|
||||
`Monitor with id ${monitorId} not found`,
|
||||
DB_DELETE_CHECKS: (monitorId) =>
|
||||
`No checks found for monitor with id ${monitorId}`,
|
||||
//DB Errors
|
||||
DB_USER_EXISTS: "User already exists",
|
||||
DB_USER_NOT_FOUND: "User not found",
|
||||
DB_TOKEN_NOT_FOUND: "Token not found",
|
||||
DB_RESET_PASSWORD_BAD_MATCH: "New password must be different from old password",
|
||||
DB_FIND_MONITOR_BY_ID: (monitorId) => `Monitor with id ${monitorId} not found`,
|
||||
DB_DELETE_CHECKS: (monitorId) => `No checks found for monitor with id ${monitorId}`,
|
||||
|
||||
//Auth errors
|
||||
AUTH_INCORRECT_PASSWORD: "Incorrect password",
|
||||
AUTH_UNAUTHORIZED: "Unauthorized access",
|
||||
//Auth errors
|
||||
AUTH_INCORRECT_PASSWORD: "Incorrect password",
|
||||
AUTH_UNAUTHORIZED: "Unauthorized access",
|
||||
|
||||
// Monitor Errors
|
||||
MONITOR_GET_BY_ID: "Monitor not found",
|
||||
MONITOR_GET_BY_USER_ID: "No monitors found for user",
|
||||
// Monitor Errors
|
||||
MONITOR_GET_BY_ID: "Monitor not found",
|
||||
MONITOR_GET_BY_USER_ID: "No monitors found for user",
|
||||
|
||||
// Job Queue Errors
|
||||
JOB_QUEUE_WORKER_CLOSE: "Error closing worker",
|
||||
JOB_QUEUE_DELETE_JOB: "Job not found in queue",
|
||||
JOB_QUEUE_OBLITERATE: "Error obliterating queue",
|
||||
// Job Queue Errors
|
||||
JOB_QUEUE_WORKER_CLOSE: "Error closing worker",
|
||||
JOB_QUEUE_DELETE_JOB: "Job not found in queue",
|
||||
JOB_QUEUE_OBLITERATE: "Error obliterating queue",
|
||||
|
||||
// PING Operations
|
||||
PING_CANNOT_RESOLVE: "No response",
|
||||
// PING Operations
|
||||
PING_CANNOT_RESOLVE: "No response",
|
||||
};
|
||||
|
||||
const successMessages = {
|
||||
//Alert Controller
|
||||
ALERT_CREATE: "Alert created successfully",
|
||||
ALERT_GET_BY_USER: "Got alerts successfully",
|
||||
ALERT_GET_BY_MONITOR: "Got alerts by Monitor successfully",
|
||||
ALERT_GET_BY_ID: "Got alert by Id successfully",
|
||||
ALERT_EDIT: "Alert edited successfully",
|
||||
ALERT_DELETE: "Alert deleted successfully",
|
||||
//Alert Controller
|
||||
ALERT_CREATE: "Alert created successfully",
|
||||
ALERT_GET_BY_USER: "Got alerts successfully",
|
||||
ALERT_GET_BY_MONITOR: "Got alerts by Monitor successfully",
|
||||
ALERT_GET_BY_ID: "Got alert by Id successfully",
|
||||
ALERT_EDIT: "Alert edited successfully",
|
||||
ALERT_DELETE: "Alert deleted successfully",
|
||||
|
||||
// Auth Controller
|
||||
AUTH_CREATE_USER: "User created successfully",
|
||||
AUTH_LOGIN_USER: "User logged in successfully",
|
||||
AUTH_LOGOUT_USER: "User logged out successfully",
|
||||
AUTH_UPDATE_USER: "User updated successfully",
|
||||
AUTH_CREATE_RECOVERY_TOKEN: "Recovery token created successfully",
|
||||
AUTH_VERIFY_RECOVERY_TOKEN: "Recovery token verified successfully",
|
||||
AUTH_RESET_PASSWORD: "Password reset successfully",
|
||||
AUTH_ADMIN_CHECK: "Admin check completed successfully",
|
||||
AUTH_DELETE_USER: "User deleted successfully",
|
||||
// Auth Controller
|
||||
AUTH_CREATE_USER: "User created successfully",
|
||||
AUTH_LOGIN_USER: "User logged in successfully",
|
||||
AUTH_LOGOUT_USER: "User logged out successfully",
|
||||
AUTH_UPDATE_USER: "User updated successfully",
|
||||
AUTH_CREATE_RECOVERY_TOKEN: "Recovery token created successfully",
|
||||
AUTH_VERIFY_RECOVERY_TOKEN: "Recovery token verified successfully",
|
||||
AUTH_RESET_PASSWORD: "Password reset successfully",
|
||||
AUTH_ADMIN_CHECK: "Admin check completed successfully",
|
||||
AUTH_DELETE_USER: "User deleted successfully",
|
||||
|
||||
// Check Controller
|
||||
CHECK_CREATE: "Check created successfully",
|
||||
CHECK_GET: "Got checks successfully",
|
||||
CHECK_DELETE: "Checks deleted successfully",
|
||||
CHECK_UPDATE_TTL: "Checks TTL updated successfully",
|
||||
// Check Controller
|
||||
CHECK_CREATE: "Check created successfully",
|
||||
CHECK_GET: "Got checks successfully",
|
||||
CHECK_DELETE: "Checks deleted successfully",
|
||||
CHECK_UPDATE_TTL: "Checks TTL updated successfully",
|
||||
|
||||
//Monitor Controller
|
||||
MONITOR_GET_ALL: "Got all monitors successfully",
|
||||
MONITOR_STATS_BY_ID: "Got monitor stats by Id successfully",
|
||||
MONITOR_GET_BY_ID: "Got monitor by Id successfully",
|
||||
MONITOR_GET_BY_USER_ID: (userId) => `Got monitor for ${userId} successfully"`,
|
||||
MONITOR_CREATE: "Monitor created successfully",
|
||||
MONITOR_DELETE: "Monitor deleted successfully",
|
||||
MONITOR_EDIT: "Monitor edited successfully",
|
||||
MONITOR_CERTIFICATE: "Got monitor certificate successfully",
|
||||
MONITOR_DEMO_ADDED: "Successfully added demo monitors",
|
||||
//Monitor Controller
|
||||
MONITOR_GET_ALL: "Got all monitors successfully",
|
||||
MONITOR_STATS_BY_ID: "Got monitor stats by Id successfully",
|
||||
MONITOR_GET_BY_ID: "Got monitor by Id successfully",
|
||||
MONITOR_GET_BY_USER_ID: (userId) => `Got monitor for ${userId} successfully"`,
|
||||
MONITOR_CREATE: "Monitor created successfully",
|
||||
MONITOR_DELETE: "Monitor deleted successfully",
|
||||
MONITOR_EDIT: "Monitor edited successfully",
|
||||
MONITOR_CERTIFICATE: "Got monitor certificate successfully",
|
||||
MONITOR_DEMO_ADDED: "Successfully added demo monitors",
|
||||
|
||||
// Queue Controller
|
||||
QUEUE_GET_METRICS: "Got metrics successfully",
|
||||
QUEUE_GET_METRICS: "Got job stats successfully",
|
||||
QUEUE_ADD_JOB: "Job added successfully",
|
||||
QUEUE_OBLITERATE: "Queue obliterated",
|
||||
// Queue Controller
|
||||
QUEUE_GET_METRICS: "Got metrics successfully",
|
||||
QUEUE_GET_METRICS: "Got job stats successfully",
|
||||
QUEUE_ADD_JOB: "Job added successfully",
|
||||
QUEUE_OBLITERATE: "Queue obliterated",
|
||||
|
||||
//Job Queue
|
||||
JOB_QUEUE_DELETE_JOB: "Job removed successfully",
|
||||
JOB_QUEUE_OBLITERATE: "Queue OBLITERATED!!!",
|
||||
JOB_QUEUE_PAUSE_JOB: "Job paused successfully",
|
||||
JOB_QUEUE_RESUME_JOB: "Job resumed successfully",
|
||||
//Job Queue
|
||||
JOB_QUEUE_DELETE_JOB: "Job removed successfully",
|
||||
JOB_QUEUE_OBLITERATE: "Queue OBLITERATED!!!",
|
||||
JOB_QUEUE_PAUSE_JOB: "Job paused successfully",
|
||||
JOB_QUEUE_RESUME_JOB: "Job resumed successfully",
|
||||
|
||||
//Maintenance Window Controller
|
||||
MAINTENANCE_WINDOW_GET_BY_ID: "Got Maintenance Window by Id successfully",
|
||||
MAINTENANCE_WINDOW_CREATE: "Maintenance Window created successfully",
|
||||
MAINTENANCE_WINDOW_GET_BY_TEAM:
|
||||
"Got Maintenance Windows by Team successfully",
|
||||
MAINTENANCE_WINDOW_DELETE: "Maintenance Window deleted successfully",
|
||||
MAINTENANCE_WINDOW_EDIT: "Maintenance Window edited successfully",
|
||||
//Maintenance Window Controller
|
||||
MAINTENANCE_WINDOW_GET_BY_ID: "Got Maintenance Window by Id successfully",
|
||||
MAINTENANCE_WINDOW_CREATE: "Maintenance Window created successfully",
|
||||
MAINTENANCE_WINDOW_GET_BY_TEAM: "Got Maintenance Windows by Team successfully",
|
||||
MAINTENANCE_WINDOW_DELETE: "Maintenance Window deleted successfully",
|
||||
MAINTENANCE_WINDOW_EDIT: "Maintenance Window edited successfully",
|
||||
|
||||
//Ping Operations
|
||||
PING_SUCCESS: "Success",
|
||||
//Ping Operations
|
||||
PING_SUCCESS: "Success",
|
||||
|
||||
// App Settings
|
||||
GET_APP_SETTINGS: "Got app settings successfully",
|
||||
UPDATE_APP_SETTINGS: "Updated app settings successfully",
|
||||
// App Settings
|
||||
GET_APP_SETTINGS: "Got app settings successfully",
|
||||
UPDATE_APP_SETTINGS: "Updated app settings successfully",
|
||||
};
|
||||
|
||||
export { errorMessages, successMessages };
|
||||
|
||||
@@ -5,13 +5,13 @@ import joi from "joi";
|
||||
//****************************************
|
||||
|
||||
const roleValidatior = (role) => (value, helpers) => {
|
||||
const hasRole = role.some((role) => value.includes(role));
|
||||
if (!hasRole) {
|
||||
throw new joi.ValidationError(
|
||||
`You do not have the required authorization. Required roles: ${role.join(", ")}`
|
||||
);
|
||||
}
|
||||
return value;
|
||||
const hasRole = role.some((role) => value.includes(role));
|
||||
if (!hasRole) {
|
||||
throw new joi.ValidationError(
|
||||
`You do not have the required authorization. Required roles: ${role.join(", ")}`
|
||||
);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
//****************************************
|
||||
@@ -19,129 +19,129 @@ const roleValidatior = (role) => (value, helpers) => {
|
||||
//****************************************
|
||||
|
||||
const loginValidation = joi.object({
|
||||
email: joi
|
||||
.string()
|
||||
.email()
|
||||
.required()
|
||||
.custom((value, helpers) => {
|
||||
const lowercasedValue = value.toLowerCase();
|
||||
if (value !== lowercasedValue) {
|
||||
return helpers.message("Email must be in lowercase");
|
||||
}
|
||||
return lowercasedValue;
|
||||
}),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.required()
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
email: joi
|
||||
.string()
|
||||
.email()
|
||||
.required()
|
||||
.custom((value, helpers) => {
|
||||
const lowercasedValue = value.toLowerCase();
|
||||
if (value !== lowercasedValue) {
|
||||
return helpers.message("Email must be in lowercase");
|
||||
}
|
||||
return lowercasedValue;
|
||||
}),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.required()
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
});
|
||||
|
||||
const registrationBodyValidation = joi.object({
|
||||
firstName: joi
|
||||
.string()
|
||||
.required()
|
||||
.pattern(/^[A-Za-z]+$/),
|
||||
lastName: joi
|
||||
.string()
|
||||
.required()
|
||||
.pattern(/^[A-Za-z]+$/),
|
||||
email: joi
|
||||
.string()
|
||||
.email()
|
||||
.required()
|
||||
.custom((value, helpers) => {
|
||||
const lowercasedValue = value.toLowerCase();
|
||||
if (value !== lowercasedValue) {
|
||||
return helpers.message("Email must be in lowercase");
|
||||
}
|
||||
return lowercasedValue;
|
||||
}),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.required()
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
profileImage: joi.any(),
|
||||
role: joi
|
||||
.array()
|
||||
.items(joi.string().valid("superadmin", "admin", "user", "demo"))
|
||||
.min(1)
|
||||
.required(),
|
||||
teamId: joi.string().allow("").required(),
|
||||
inviteToken: joi.string().allow("").required(),
|
||||
firstName: joi
|
||||
.string()
|
||||
.required()
|
||||
.pattern(/^[A-Za-z]+$/),
|
||||
lastName: joi
|
||||
.string()
|
||||
.required()
|
||||
.pattern(/^[A-Za-z]+$/),
|
||||
email: joi
|
||||
.string()
|
||||
.email()
|
||||
.required()
|
||||
.custom((value, helpers) => {
|
||||
const lowercasedValue = value.toLowerCase();
|
||||
if (value !== lowercasedValue) {
|
||||
return helpers.message("Email must be in lowercase");
|
||||
}
|
||||
return lowercasedValue;
|
||||
}),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.required()
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
profileImage: joi.any(),
|
||||
role: joi
|
||||
.array()
|
||||
.items(joi.string().valid("superadmin", "admin", "user", "demo"))
|
||||
.min(1)
|
||||
.required(),
|
||||
teamId: joi.string().allow("").required(),
|
||||
inviteToken: joi.string().allow("").required(),
|
||||
});
|
||||
|
||||
const editUserParamValidation = joi.object({
|
||||
userId: joi.string().required(),
|
||||
userId: joi.string().required(),
|
||||
});
|
||||
|
||||
const editUserBodyValidation = joi.object({
|
||||
firstName: joi.string().pattern(/^[A-Za-z]+$/),
|
||||
lastName: joi.string().pattern(/^[A-Za-z]+$/),
|
||||
profileImage: joi.any(),
|
||||
newPassword: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
deleteProfileImage: joi.boolean(),
|
||||
role: joi.array(),
|
||||
firstName: joi.string().pattern(/^[A-Za-z]+$/),
|
||||
lastName: joi.string().pattern(/^[A-Za-z]+$/),
|
||||
profileImage: joi.any(),
|
||||
newPassword: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
deleteProfileImage: joi.boolean(),
|
||||
role: joi.array(),
|
||||
});
|
||||
|
||||
const recoveryValidation = joi.object({
|
||||
email: joi
|
||||
.string()
|
||||
.email({ tlds: { allow: false } })
|
||||
.required(),
|
||||
email: joi
|
||||
.string()
|
||||
.email({ tlds: { allow: false } })
|
||||
.required(),
|
||||
});
|
||||
|
||||
const recoveryTokenValidation = joi.object({
|
||||
recoveryToken: joi.string().required(),
|
||||
recoveryToken: joi.string().required(),
|
||||
});
|
||||
|
||||
const newPasswordValidation = joi.object({
|
||||
recoveryToken: joi.string().required(),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.required()
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
confirm: joi.string(),
|
||||
recoveryToken: joi.string().required(),
|
||||
password: joi
|
||||
.string()
|
||||
.min(8)
|
||||
.required()
|
||||
.pattern(
|
||||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()])[A-Za-z0-9!@#$%^&*()]+$/
|
||||
),
|
||||
confirm: joi.string(),
|
||||
});
|
||||
|
||||
const deleteUserParamValidation = joi.object({
|
||||
email: joi.string().email().required(),
|
||||
email: joi.string().email().required(),
|
||||
});
|
||||
|
||||
const inviteRoleValidation = joi.object({
|
||||
roles: joi.custom(roleValidatior(["admin", "superadmin"])).required(),
|
||||
roles: joi.custom(roleValidatior(["admin", "superadmin"])).required(),
|
||||
});
|
||||
|
||||
const inviteBodyValidation = joi.object({
|
||||
email: joi.string().trim().email().required().messages({
|
||||
"string.empty": "Email is required",
|
||||
"string.email": "Must be a valid email address",
|
||||
}),
|
||||
role: joi.array().required(),
|
||||
teamId: joi.string().required(),
|
||||
email: joi.string().trim().email().required().messages({
|
||||
"string.empty": "Email is required",
|
||||
"string.email": "Must be a valid email address",
|
||||
}),
|
||||
role: joi.array().required(),
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
|
||||
const inviteVerificationBodyValidation = joi.object({
|
||||
token: joi.string().required(),
|
||||
token: joi.string().required(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
@@ -149,91 +149,91 @@ const inviteVerificationBodyValidation = joi.object({
|
||||
//****************************************
|
||||
|
||||
const getMonitorByIdParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getMonitorByIdQueryValidation = joi.object({
|
||||
status: joi.boolean(),
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
numToDisplay: joi.number(),
|
||||
normalize: joi.boolean(),
|
||||
status: joi.boolean(),
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
numToDisplay: joi.number(),
|
||||
normalize: joi.boolean(),
|
||||
});
|
||||
|
||||
const getMonitorsAndSummaryByTeamIdParamValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getMonitorsAndSummaryByTeamIdQueryValidation = joi.object({
|
||||
type: joi
|
||||
.alternatives()
|
||||
.try(
|
||||
joi.string().valid("http", "ping", "pagespeed"),
|
||||
joi.array().items(joi.string().valid("http", "ping", "pagespeed"))
|
||||
),
|
||||
type: joi
|
||||
.alternatives()
|
||||
.try(
|
||||
joi.string().valid("http", "ping", "pagespeed"),
|
||||
joi.array().items(joi.string().valid("http", "ping", "pagespeed"))
|
||||
),
|
||||
});
|
||||
|
||||
const getMonitorsByTeamIdValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getMonitorsByTeamIdQueryValidation = joi.object({
|
||||
status: joi.boolean(),
|
||||
checkOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
normalize: joi.boolean(),
|
||||
type: joi
|
||||
.alternatives()
|
||||
.try(
|
||||
joi.string().valid("http", "ping", "pagespeed"),
|
||||
joi.array().items(joi.string().valid("http", "ping", "pagespeed"))
|
||||
),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
filter: joi.string(),
|
||||
field: joi.string(),
|
||||
order: joi.string().valid("asc", "desc"),
|
||||
status: joi.boolean(),
|
||||
checkOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
normalize: joi.boolean(),
|
||||
type: joi
|
||||
.alternatives()
|
||||
.try(
|
||||
joi.string().valid("http", "ping", "pagespeed"),
|
||||
joi.array().items(joi.string().valid("http", "ping", "pagespeed"))
|
||||
),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
filter: joi.string(),
|
||||
field: joi.string(),
|
||||
order: joi.string().valid("asc", "desc"),
|
||||
});
|
||||
|
||||
const getMonitorStatsByIdParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
const getMonitorStatsByIdQueryValidation = joi.object({
|
||||
status: joi.string(),
|
||||
limit: joi.number(),
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
numToDisplay: joi.number(),
|
||||
normalize: joi.boolean(),
|
||||
status: joi.string(),
|
||||
limit: joi.number(),
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
numToDisplay: joi.number(),
|
||||
normalize: joi.boolean(),
|
||||
});
|
||||
|
||||
const getCertificateParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const createMonitorBodyValidation = joi.object({
|
||||
_id: joi.string(),
|
||||
userId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
name: joi.string().required(),
|
||||
description: joi.string().required(),
|
||||
type: joi.string().required(),
|
||||
url: joi.string().required(),
|
||||
isActive: joi.boolean(),
|
||||
interval: joi.number(),
|
||||
notifications: joi.array().items(joi.object()),
|
||||
_id: joi.string(),
|
||||
userId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
name: joi.string().required(),
|
||||
description: joi.string().required(),
|
||||
type: joi.string().required(),
|
||||
url: joi.string().required(),
|
||||
isActive: joi.boolean(),
|
||||
interval: joi.number(),
|
||||
notifications: joi.array().items(joi.object()),
|
||||
});
|
||||
|
||||
const editMonitorBodyValidation = joi.object({
|
||||
name: joi.string(),
|
||||
description: joi.string(),
|
||||
interval: joi.number(),
|
||||
notifications: joi.array().items(joi.object()),
|
||||
name: joi.string(),
|
||||
description: joi.string(),
|
||||
interval: joi.number(),
|
||||
notifications: joi.array().items(joi.object()),
|
||||
});
|
||||
|
||||
const pauseMonitorParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
@@ -241,44 +241,44 @@ const pauseMonitorParamValidation = joi.object({
|
||||
//****************************************
|
||||
|
||||
const createAlertParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
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(),
|
||||
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(),
|
||||
userId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getAlertsByMonitorIdParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getAlertByIdParamValidation = joi.object({
|
||||
alertId: joi.string().required(),
|
||||
alertId: joi.string().required(),
|
||||
});
|
||||
|
||||
const editAlertParamValidation = joi.object({
|
||||
alertId: joi.string().required(),
|
||||
alertId: joi.string().required(),
|
||||
});
|
||||
|
||||
const editAlertBodyValidation = joi.object({
|
||||
status: joi.boolean(),
|
||||
message: joi.string(),
|
||||
notifiedStatus: joi.boolean(),
|
||||
acknowledgeStatus: joi.boolean(),
|
||||
status: joi.boolean(),
|
||||
message: joi.string(),
|
||||
notifiedStatus: joi.boolean(),
|
||||
acknowledgeStatus: joi.boolean(),
|
||||
});
|
||||
|
||||
const deleteAlertParamValidation = joi.object({
|
||||
alertId: joi.string().required(),
|
||||
alertId: joi.string().required(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
@@ -286,53 +286,53 @@ const deleteAlertParamValidation = joi.object({
|
||||
//****************************************
|
||||
|
||||
const createCheckParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const createCheckBodyValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
status: joi.boolean().required(),
|
||||
responseTime: joi.number().required(),
|
||||
statusCode: joi.number().required(),
|
||||
message: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
status: joi.boolean().required(),
|
||||
responseTime: joi.number().required(),
|
||||
statusCode: joi.number().required(),
|
||||
message: joi.string().required(),
|
||||
});
|
||||
|
||||
const getChecksParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getChecksQueryValidation = joi.object({
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
filter: joi.string().valid("all", "down", "resolve"),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
filter: joi.string().valid("all", "down", "resolve"),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
});
|
||||
|
||||
const getTeamChecksParamValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
|
||||
const getTeamChecksQueryValidation = joi.object({
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
filter: joi.string().valid("all", "down", "resolve"),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
sortOrder: joi.string().valid("asc", "desc"),
|
||||
limit: joi.number(),
|
||||
dateRange: joi.string().valid("day", "week", "month"),
|
||||
filter: joi.string().valid("all", "down", "resolve"),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
});
|
||||
|
||||
const deleteChecksParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const deleteChecksByTeamIdParamValidation = joi.object({
|
||||
teamId: joi.string().required(),
|
||||
teamId: joi.string().required(),
|
||||
});
|
||||
|
||||
const updateChecksTTLBodyValidation = joi.object({
|
||||
ttl: joi.number().required(),
|
||||
ttl: joi.number().required(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
@@ -340,21 +340,21 @@ const updateChecksTTLBodyValidation = joi.object({
|
||||
//****************************************
|
||||
|
||||
const getPageSpeedCheckParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
//Validation schema for the monitorId parameter
|
||||
const createPageSpeedCheckParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
//Validation schema for the monitorId body
|
||||
const createPageSpeedCheckBodyValidation = joi.object({
|
||||
url: joi.string().required(),
|
||||
url: joi.string().required(),
|
||||
});
|
||||
|
||||
const deletePageSpeedCheckParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
@@ -362,120 +362,120 @@ const deletePageSpeedCheckParamValidation = joi.object({
|
||||
//****************************************
|
||||
|
||||
const createMaintenanceWindowBodyValidation = joi.object({
|
||||
monitors: joi.array().items(joi.string()).required(),
|
||||
name: joi.string().required(),
|
||||
active: joi.boolean(),
|
||||
start: joi.date().required(),
|
||||
end: joi.date().required(),
|
||||
repeat: joi.number().required(),
|
||||
expiry: joi.date(),
|
||||
monitors: joi.array().items(joi.string()).required(),
|
||||
name: joi.string().required(),
|
||||
active: joi.boolean(),
|
||||
start: joi.date().required(),
|
||||
end: joi.date().required(),
|
||||
repeat: joi.number().required(),
|
||||
expiry: joi.date(),
|
||||
});
|
||||
|
||||
const getMaintenanceWindowByIdParamValidation = joi.object({
|
||||
id: joi.string().required(),
|
||||
id: joi.string().required(),
|
||||
});
|
||||
|
||||
const getMaintenanceWindowsByTeamIdQueryValidation = joi.object({
|
||||
active: joi.boolean(),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
field: joi.string(),
|
||||
order: joi.string().valid("asc", "desc"),
|
||||
active: joi.boolean(),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
field: joi.string(),
|
||||
order: joi.string().valid("asc", "desc"),
|
||||
});
|
||||
|
||||
const getMaintenanceWindowsByMonitorIdParamValidation = joi.object({
|
||||
monitorId: joi.string().required(),
|
||||
monitorId: joi.string().required(),
|
||||
});
|
||||
|
||||
const deleteMaintenanceWindowByIdParamValidation = joi.object({
|
||||
id: joi.string().required(),
|
||||
id: joi.string().required(),
|
||||
});
|
||||
|
||||
const editMaintenanceWindowByIdParamValidation = joi.object({
|
||||
id: joi.string().required(),
|
||||
id: joi.string().required(),
|
||||
});
|
||||
|
||||
const editMaintenanceByIdWindowBodyValidation = joi.object({
|
||||
active: joi.boolean(),
|
||||
name: joi.string(),
|
||||
repeat: joi.number(),
|
||||
start: joi.date(),
|
||||
end: joi.date(),
|
||||
expiry: joi.date(),
|
||||
monitors: joi.array(),
|
||||
active: joi.boolean(),
|
||||
name: joi.string(),
|
||||
repeat: joi.number(),
|
||||
start: joi.date(),
|
||||
end: joi.date(),
|
||||
expiry: joi.date(),
|
||||
monitors: joi.array(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
// SettingsValidation
|
||||
//****************************************
|
||||
const updateAppSettingsBodyValidation = joi.object({
|
||||
apiBaseUrl: joi.string().allow(""),
|
||||
logLevel: joi.string().valid("debug", "none", "error", "warn").allow(""),
|
||||
clientHost: joi.string().allow(""),
|
||||
dbType: joi.string().allow(""),
|
||||
dbConnectionString: joi.string().allow(""),
|
||||
redisHost: joi.string().allow(""),
|
||||
redisPort: joi.number().allow(null, ""),
|
||||
jwtTTL: joi.string().allow(""),
|
||||
pagespeedApiKey: joi.string().allow(""),
|
||||
systemEmailHost: joi.string().allow(""),
|
||||
systemEmailPort: joi.number().allow(""),
|
||||
systemEmailAddress: joi.string().allow(""),
|
||||
systemEmailPassword: joi.string().allow(""),
|
||||
apiBaseUrl: joi.string().allow(""),
|
||||
logLevel: joi.string().valid("debug", "none", "error", "warn").allow(""),
|
||||
clientHost: joi.string().allow(""),
|
||||
dbType: joi.string().allow(""),
|
||||
dbConnectionString: joi.string().allow(""),
|
||||
redisHost: joi.string().allow(""),
|
||||
redisPort: joi.number().allow(null, ""),
|
||||
jwtTTL: joi.string().allow(""),
|
||||
pagespeedApiKey: joi.string().allow(""),
|
||||
systemEmailHost: joi.string().allow(""),
|
||||
systemEmailPort: joi.number().allow(""),
|
||||
systemEmailAddress: joi.string().allow(""),
|
||||
systemEmailPassword: joi.string().allow(""),
|
||||
});
|
||||
|
||||
export {
|
||||
roleValidatior,
|
||||
loginValidation,
|
||||
registrationBodyValidation,
|
||||
recoveryValidation,
|
||||
recoveryTokenValidation,
|
||||
newPasswordValidation,
|
||||
inviteRoleValidation,
|
||||
inviteBodyValidation,
|
||||
inviteVerificationBodyValidation,
|
||||
createMonitorBodyValidation,
|
||||
getMonitorByIdParamValidation,
|
||||
getMonitorByIdQueryValidation,
|
||||
getMonitorsAndSummaryByTeamIdParamValidation,
|
||||
getMonitorsAndSummaryByTeamIdQueryValidation,
|
||||
getMonitorsByTeamIdValidation,
|
||||
getMonitorsByTeamIdQueryValidation,
|
||||
getMonitorStatsByIdParamValidation,
|
||||
getMonitorStatsByIdQueryValidation,
|
||||
getCertificateParamValidation,
|
||||
editMonitorBodyValidation,
|
||||
pauseMonitorParamValidation,
|
||||
editUserParamValidation,
|
||||
editUserBodyValidation,
|
||||
createAlertParamValidation,
|
||||
createAlertBodyValidation,
|
||||
getAlertsByUserIdParamValidation,
|
||||
getAlertsByMonitorIdParamValidation,
|
||||
getAlertByIdParamValidation,
|
||||
editAlertParamValidation,
|
||||
editAlertBodyValidation,
|
||||
deleteAlertParamValidation,
|
||||
createCheckParamValidation,
|
||||
createCheckBodyValidation,
|
||||
getChecksParamValidation,
|
||||
getChecksQueryValidation,
|
||||
getTeamChecksParamValidation,
|
||||
getTeamChecksQueryValidation,
|
||||
deleteChecksParamValidation,
|
||||
deleteChecksByTeamIdParamValidation,
|
||||
updateChecksTTLBodyValidation,
|
||||
deleteUserParamValidation,
|
||||
getPageSpeedCheckParamValidation,
|
||||
createPageSpeedCheckParamValidation,
|
||||
deletePageSpeedCheckParamValidation,
|
||||
createPageSpeedCheckBodyValidation,
|
||||
createMaintenanceWindowBodyValidation,
|
||||
getMaintenanceWindowByIdParamValidation,
|
||||
getMaintenanceWindowsByTeamIdQueryValidation,
|
||||
getMaintenanceWindowsByMonitorIdParamValidation,
|
||||
deleteMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceByIdWindowBodyValidation,
|
||||
updateAppSettingsBodyValidation,
|
||||
roleValidatior,
|
||||
loginValidation,
|
||||
registrationBodyValidation,
|
||||
recoveryValidation,
|
||||
recoveryTokenValidation,
|
||||
newPasswordValidation,
|
||||
inviteRoleValidation,
|
||||
inviteBodyValidation,
|
||||
inviteVerificationBodyValidation,
|
||||
createMonitorBodyValidation,
|
||||
getMonitorByIdParamValidation,
|
||||
getMonitorByIdQueryValidation,
|
||||
getMonitorsAndSummaryByTeamIdParamValidation,
|
||||
getMonitorsAndSummaryByTeamIdQueryValidation,
|
||||
getMonitorsByTeamIdValidation,
|
||||
getMonitorsByTeamIdQueryValidation,
|
||||
getMonitorStatsByIdParamValidation,
|
||||
getMonitorStatsByIdQueryValidation,
|
||||
getCertificateParamValidation,
|
||||
editMonitorBodyValidation,
|
||||
pauseMonitorParamValidation,
|
||||
editUserParamValidation,
|
||||
editUserBodyValidation,
|
||||
createAlertParamValidation,
|
||||
createAlertBodyValidation,
|
||||
getAlertsByUserIdParamValidation,
|
||||
getAlertsByMonitorIdParamValidation,
|
||||
getAlertByIdParamValidation,
|
||||
editAlertParamValidation,
|
||||
editAlertBodyValidation,
|
||||
deleteAlertParamValidation,
|
||||
createCheckParamValidation,
|
||||
createCheckBodyValidation,
|
||||
getChecksParamValidation,
|
||||
getChecksQueryValidation,
|
||||
getTeamChecksParamValidation,
|
||||
getTeamChecksQueryValidation,
|
||||
deleteChecksParamValidation,
|
||||
deleteChecksByTeamIdParamValidation,
|
||||
updateChecksTTLBodyValidation,
|
||||
deleteUserParamValidation,
|
||||
getPageSpeedCheckParamValidation,
|
||||
createPageSpeedCheckParamValidation,
|
||||
deletePageSpeedCheckParamValidation,
|
||||
createPageSpeedCheckBodyValidation,
|
||||
createMaintenanceWindowBodyValidation,
|
||||
getMaintenanceWindowByIdParamValidation,
|
||||
getMaintenanceWindowsByTeamIdQueryValidation,
|
||||
getMaintenanceWindowsByMonitorIdParamValidation,
|
||||
deleteMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceByIdWindowBodyValidation,
|
||||
updateAppSettingsBodyValidation,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user