mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-04 08:40:07 -06:00
format
This commit is contained in:
@@ -91,16 +91,14 @@ class AuthController {
|
||||
const html = await this.emailService.buildEmail("welcomeEmailTemplate", {
|
||||
name: newUser.firstName,
|
||||
});
|
||||
this.emailService
|
||||
.sendEmail(newUser.email, "Welcome to Uptime Monitor", html)
|
||||
.catch((error) => {
|
||||
this.logger.warn({
|
||||
message: error.message,
|
||||
service: SERVICE_NAME,
|
||||
method: "registerUser",
|
||||
stack: error.stack,
|
||||
});
|
||||
this.emailService.sendEmail(newUser.email, "Welcome to Uptime Monitor", html).catch((error) => {
|
||||
this.logger.warn({
|
||||
message: error.message,
|
||||
service: SERVICE_NAME,
|
||||
method: "registerUser",
|
||||
stack: error.stack,
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.warn({
|
||||
message: error.message,
|
||||
@@ -274,11 +272,7 @@ class AuthController {
|
||||
email,
|
||||
url,
|
||||
});
|
||||
const msgId = await this.emailService.sendEmail(
|
||||
email,
|
||||
"Checkmate Password Reset",
|
||||
html
|
||||
);
|
||||
const msgId = await this.emailService.sendEmail(email, "Checkmate Password Reset", html);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.authCreateRecoveryToken,
|
||||
|
||||
@@ -46,8 +46,7 @@ class CheckController {
|
||||
await getChecksQueryValidation.validateAsync(req.query);
|
||||
|
||||
const { monitorId } = req.params;
|
||||
let { type, sortOrder, dateRange, filter, ack, page, rowsPerPage, status } =
|
||||
req.query;
|
||||
let { type, sortOrder, dateRange, filter, ack, page, rowsPerPage, status } = req.query;
|
||||
const result = await this.db.getChecksByMonitor({
|
||||
monitorId,
|
||||
type,
|
||||
|
||||
@@ -12,8 +12,7 @@ obs.observe({ entryTypes: ["measure"] });
|
||||
class DiagnosticController {
|
||||
constructor(db) {
|
||||
this.db = db;
|
||||
this.getMonitorsByTeamIdExecutionStats =
|
||||
this.getMonitorsByTeamIdExecutionStats.bind(this);
|
||||
this.getMonitorsByTeamIdExecutionStats = this.getMonitorsByTeamIdExecutionStats.bind(this);
|
||||
this.getDbStats = this.getDbStats.bind(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
inviteRoleValidation,
|
||||
inviteBodyValidation,
|
||||
inviteVerificationBodyValidation,
|
||||
} from "../validation/joi.js";
|
||||
import { inviteRoleValidation, inviteBodyValidation, inviteVerificationBodyValidation } from "../validation/joi.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { getTokenFromHeaders } from "../utils/utils.js";
|
||||
import { asyncHandler, createServerError } from "../utils/errorUtils.js";
|
||||
@@ -65,15 +61,9 @@ class InviteController {
|
||||
name: firstname,
|
||||
link: `${clientHost}/register/${inviteToken.token}`,
|
||||
});
|
||||
const result = await this.emailService.sendEmail(
|
||||
req.body.email,
|
||||
"Welcome to Uptime Monitor",
|
||||
html
|
||||
);
|
||||
const result = await this.emailService.sendEmail(req.body.email, "Welcome to Uptime Monitor", html);
|
||||
if (!result) {
|
||||
throw createServerError(
|
||||
"Failed to send invite e-mail... Please verify your settings."
|
||||
);
|
||||
throw createServerError("Failed to send invite e-mail... Please verify your settings.");
|
||||
}
|
||||
|
||||
return res.success({
|
||||
|
||||
@@ -63,10 +63,7 @@ class MaintenanceWindowController {
|
||||
await getMaintenanceWindowsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const { teamId } = req.user;
|
||||
const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(
|
||||
teamId,
|
||||
req.query
|
||||
);
|
||||
const maintenanceWindows = await this.db.getMaintenanceWindowsByTeamId(teamId, req.query);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowGetByTeam,
|
||||
@@ -81,9 +78,7 @@ class MaintenanceWindowController {
|
||||
async (req, res, next) => {
|
||||
await getMaintenanceWindowsByMonitorIdParamValidation.validateAsync(req.params);
|
||||
|
||||
const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId(
|
||||
req.params.monitorId
|
||||
);
|
||||
const maintenanceWindows = await this.db.getMaintenanceWindowsByMonitorId(req.params.monitorId);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowGetByUser,
|
||||
@@ -110,10 +105,7 @@ class MaintenanceWindowController {
|
||||
async (req, res, next) => {
|
||||
await editMaintenanceWindowByIdParamValidation.validateAsync(req.params);
|
||||
await editMaintenanceByIdWindowBodyValidation.validateAsync(req.body);
|
||||
const editedMaintenanceWindow = await this.db.editMaintenanceWindowById(
|
||||
req.params.id,
|
||||
req.body
|
||||
);
|
||||
const editedMaintenanceWindow = await this.db.editMaintenanceWindowById(req.params.id, req.body);
|
||||
return res.success({
|
||||
msg: this.stringService.maintenanceWindowEdit,
|
||||
data: editedMaintenanceWindow,
|
||||
|
||||
@@ -463,14 +463,10 @@ class MonitorController {
|
||||
|
||||
const monitorId = req.params.monitorId;
|
||||
const monitor = await this.db.pauseMonitor({ monitorId });
|
||||
monitor.isActive === true
|
||||
? await this.jobQueue.resumeJob(monitor._id, monitor)
|
||||
: await this.jobQueue.pauseJob(monitor);
|
||||
monitor.isActive === true ? await this.jobQueue.resumeJob(monitor._id, monitor) : await this.jobQueue.pauseJob(monitor);
|
||||
|
||||
return res.success({
|
||||
msg: monitor.isActive
|
||||
? this.stringService.monitorResume
|
||||
: this.stringService.monitorPause,
|
||||
msg: monitor.isActive ? this.stringService.monitorResume : this.stringService.monitorPause,
|
||||
data: monitor,
|
||||
});
|
||||
},
|
||||
@@ -493,9 +489,7 @@ class MonitorController {
|
||||
async (req, res, next) => {
|
||||
const { _id, teamId } = req.user;
|
||||
const demoMonitors = await this.db.addDemoMonitors(_id, teamId);
|
||||
await Promise.all(
|
||||
demoMonitors.map((monitor) => this.jobQueue.addJob(monitor._id, monitor))
|
||||
);
|
||||
await Promise.all(demoMonitors.map((monitor) => this.jobQueue.addJob(monitor._id, monitor)));
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorDemoAdded,
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
createStatusPageBodyValidation,
|
||||
getStatusPageParamValidation,
|
||||
getStatusPageQueryValidation,
|
||||
imageValidation,
|
||||
} from "../validation/joi.js";
|
||||
import { createStatusPageBodyValidation, getStatusPageParamValidation, getStatusPageQueryValidation, imageValidation } from "../validation/joi.js";
|
||||
import { asyncHandler } from "../utils/errorUtils.js";
|
||||
|
||||
const SERVICE_NAME = "statusPageController";
|
||||
|
||||
@@ -156,10 +156,7 @@ MonitorSchema.pre("deleteMany", async function (next) {
|
||||
} else {
|
||||
await Check.deleteMany({ monitorId: monitor._id });
|
||||
}
|
||||
await StatusPage.updateMany(
|
||||
{ monitors: monitor._id },
|
||||
{ $pull: { monitors: monitor._id } }
|
||||
);
|
||||
await StatusPage.updateMany({ monitors: monitor._id }, { $pull: { monitors: monitor._id } });
|
||||
await MonitorStats.deleteMany({ monitorId: monitor._id.toString() });
|
||||
}
|
||||
next();
|
||||
|
||||
@@ -89,8 +89,7 @@ class MongoDB {
|
||||
|
||||
connect = async () => {
|
||||
try {
|
||||
const connectionString =
|
||||
this.appSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db";
|
||||
const connectionString = this.appSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db";
|
||||
await mongoose.connect(connectionString);
|
||||
// If there are no AppSettings, create one
|
||||
await AppSettings.findOneAndUpdate(
|
||||
|
||||
@@ -58,26 +58,13 @@ const createChecks = async (checks) => {
|
||||
* @returns {Promise<Array<Check>>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getChecksByMonitor = async ({
|
||||
monitorId,
|
||||
type,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
filter,
|
||||
ack,
|
||||
page,
|
||||
rowsPerPage,
|
||||
status,
|
||||
}) => {
|
||||
const getChecksByMonitor = async ({ monitorId, type, sortOrder, dateRange, filter, ack, page, rowsPerPage, status }) => {
|
||||
try {
|
||||
status = status === "true" ? true : status === "false" ? false : undefined;
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
|
||||
const ackStage =
|
||||
ack === "true"
|
||||
? { ack: true }
|
||||
: { $or: [{ ack: false }, { ack: { $exists: false } }] };
|
||||
const ackStage = ack === "true" ? { ack: true } : { $or: [{ ack: false }, { ack: { $exists: false } }] };
|
||||
|
||||
// Match
|
||||
const matchStage = {
|
||||
@@ -158,23 +145,12 @@ const getChecksByMonitor = async ({
|
||||
}
|
||||
};
|
||||
|
||||
const getChecksByTeam = async ({
|
||||
sortOrder,
|
||||
dateRange,
|
||||
filter,
|
||||
ack,
|
||||
page,
|
||||
rowsPerPage,
|
||||
teamId,
|
||||
}) => {
|
||||
const getChecksByTeam = async ({ sortOrder, dateRange, filter, ack, page, rowsPerPage, teamId }) => {
|
||||
try {
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
|
||||
const ackStage =
|
||||
ack === "true"
|
||||
? { ack: true }
|
||||
: { $or: [{ ack: false }, { ack: { $exists: false } }] };
|
||||
const ackStage = ack === "true" ? { ack: true } : { $or: [{ ack: false }, { ack: { $exists: false } }] };
|
||||
|
||||
const matchStage = {
|
||||
teamId: new ObjectId(teamId),
|
||||
@@ -264,11 +240,7 @@ const getChecksByTeam = async ({
|
||||
*/
|
||||
const ackCheck = async (checkId, teamId, ack) => {
|
||||
try {
|
||||
const updatedCheck = await Check.findOneAndUpdate(
|
||||
{ _id: checkId, teamId: teamId },
|
||||
{ $set: { ack, ackAt: new Date() } },
|
||||
{ new: true }
|
||||
);
|
||||
const updatedCheck = await Check.findOneAndUpdate({ _id: checkId, teamId: teamId }, { $set: { ack, ackAt: new Date() } }, { new: true });
|
||||
|
||||
if (!updatedCheck) {
|
||||
throw new Error("Check not found");
|
||||
@@ -293,10 +265,7 @@ const ackCheck = async (checkId, teamId, ack) => {
|
||||
*/
|
||||
const ackAllChecks = async (monitorId, teamId, ack, path) => {
|
||||
try {
|
||||
const updatedChecks = await Check.updateMany(
|
||||
path === "monitor" ? { monitorId } : { teamId },
|
||||
{ $set: { ack, ackAt: new Date() } }
|
||||
);
|
||||
const updatedChecks = await Check.updateMany(path === "monitor" ? { monitorId } : { teamId }, { $set: { ack, ackAt: new Date() } });
|
||||
return updatedChecks.modifiedCount;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
@@ -317,9 +286,7 @@ const getChecksSummaryByTeamId = async ({ teamId }) => {
|
||||
const matchStage = {
|
||||
teamId: new ObjectId(teamId),
|
||||
};
|
||||
const checks = await Check.aggregate(
|
||||
buildChecksSummaryByTeamIdPipeline({ matchStage })
|
||||
);
|
||||
const checks = await Check.aggregate(buildChecksSummaryByTeamIdPipeline({ matchStage }));
|
||||
return checks[0].summary;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
|
||||
@@ -10,20 +10,12 @@ const buildChecksSummaryByTeamIdPipeline = ({ matchStage }) => {
|
||||
totalChecks: { $sum: { $cond: [{ $eq: ["$status", false] }, 1, 0] } },
|
||||
resolvedChecks: {
|
||||
$sum: {
|
||||
$cond: [
|
||||
{ $and: [{ $eq: ["$ack", true] }, { $eq: ["$status", false] }] },
|
||||
1,
|
||||
0,
|
||||
],
|
||||
$cond: [{ $and: [{ $eq: ["$ack", true] }, { $eq: ["$status", false] }] }, 1, 0],
|
||||
},
|
||||
},
|
||||
downChecks: {
|
||||
$sum: {
|
||||
$cond: [
|
||||
{ $and: [{ $eq: ["$ack", false] }, { $eq: ["$status", false] }] },
|
||||
1,
|
||||
0,
|
||||
],
|
||||
$cond: [{ $and: [{ $eq: ["$ack", false] }, { $eq: ["$status", false] }] }, 1, 0],
|
||||
},
|
||||
},
|
||||
cannotResolveChecks: {
|
||||
|
||||
@@ -2,11 +2,7 @@ import Monitor from "../../models/Monitor.js";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
const SERVICE_NAME = "diagnosticModule";
|
||||
import {
|
||||
buildMonitorSummaryByTeamIdPipeline,
|
||||
buildMonitorsByTeamIdPipeline,
|
||||
buildFilteredMonitorsByTeamIdPipeline,
|
||||
} from "./monitorModuleQueries.js";
|
||||
import { buildMonitorSummaryByTeamIdPipeline, buildMonitorsByTeamIdPipeline, buildFilteredMonitorsByTeamIdPipeline } from "./monitorModuleQueries.js";
|
||||
|
||||
const getMonitorsByTeamIdExecutionStats = async (req) => {
|
||||
try {
|
||||
@@ -24,13 +20,9 @@ const getMonitorsByTeamIdExecutionStats = async (req) => {
|
||||
matchStage.type = Array.isArray(type) ? { $in: type } : type;
|
||||
}
|
||||
|
||||
const summary = await Monitor.aggregate(
|
||||
buildMonitorSummaryByTeamIdPipeline({ matchStage })
|
||||
).explain("executionStats");
|
||||
const summary = await Monitor.aggregate(buildMonitorSummaryByTeamIdPipeline({ matchStage })).explain("executionStats");
|
||||
|
||||
const monitors = await Monitor.aggregate(
|
||||
buildMonitorsByTeamIdPipeline({ matchStage, field, order })
|
||||
).explain("executionStats");
|
||||
const monitors = await Monitor.aggregate(buildMonitorsByTeamIdPipeline({ matchStage, field, order })).explain("executionStats");
|
||||
|
||||
const filteredMonitors = await Monitor.aggregate(
|
||||
buildFilteredMonitorsByTeamIdPipeline({
|
||||
|
||||
@@ -23,14 +23,10 @@ const createHardwareCheck = async (hardwareCheckData) => {
|
||||
if (monitor.uptimePercentage === undefined) {
|
||||
newUptimePercentage = status === true ? 1 : 0;
|
||||
} else {
|
||||
newUptimePercentage =
|
||||
(monitor.uptimePercentage * (n - 1) + (status === true ? 1 : 0)) / n;
|
||||
newUptimePercentage = (monitor.uptimePercentage * (n - 1) + (status === true ? 1 : 0)) / n;
|
||||
}
|
||||
|
||||
await Monitor.findOneAndUpdate(
|
||||
{ _id: monitorId },
|
||||
{ uptimePercentage: newUptimePercentage }
|
||||
);
|
||||
await Monitor.findOneAndUpdate({ _id: monitorId }, { uptimePercentage: newUptimePercentage });
|
||||
|
||||
const hardwareCheck = await new HardwareCheck({
|
||||
...hardwareCheckData,
|
||||
|
||||
@@ -63,8 +63,7 @@ const getMaintenanceWindowsByTeamId = async (teamId, query) => {
|
||||
|
||||
if (active !== undefined) maintenanceQuery.active = active;
|
||||
|
||||
const maintenanceWindowCount =
|
||||
await MaintenanceWindow.countDocuments(maintenanceQuery);
|
||||
const maintenanceWindowCount = await MaintenanceWindow.countDocuments(maintenanceQuery);
|
||||
|
||||
// Pagination
|
||||
let skip = 0;
|
||||
@@ -78,10 +77,7 @@ const getMaintenanceWindowsByTeamId = async (teamId, query) => {
|
||||
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) {
|
||||
@@ -122,8 +118,7 @@ const getMaintenanceWindowsByMonitorId = async (monitorId) => {
|
||||
*/
|
||||
const deleteMaintenanceWindowById = async (maintenanceWindowId) => {
|
||||
try {
|
||||
const maintenanceWindow =
|
||||
await MaintenanceWindow.findByIdAndDelete(maintenanceWindowId);
|
||||
const maintenanceWindow = await MaintenanceWindow.findByIdAndDelete(maintenanceWindowId);
|
||||
return maintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
@@ -174,11 +169,7 @@ const deleteMaintenanceWindowByUserId = async (userId) => {
|
||||
|
||||
const editMaintenanceWindowById = async (maintenanceWindowId, maintenanceWindowData) => {
|
||||
try {
|
||||
const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(
|
||||
maintenanceWindowId,
|
||||
maintenanceWindowData,
|
||||
{ new: true }
|
||||
);
|
||||
const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(maintenanceWindowId, maintenanceWindowData, { new: true });
|
||||
return editedMaintenanceWindow;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
|
||||
@@ -285,10 +285,7 @@ const groupChecksByTime = (checks, dateRange) => {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const time =
|
||||
dateRange === "day"
|
||||
? checkDate.setMinutes(0, 0, 0)
|
||||
: checkDate.toISOString().split("T")[0];
|
||||
const time = dateRange === "day" ? checkDate.setMinutes(0, 0, 0) : checkDate.toISOString().split("T")[0];
|
||||
|
||||
if (!acc[time]) {
|
||||
acc[time] = { time, checks: [] };
|
||||
@@ -306,9 +303,7 @@ const groupChecksByTime = (checks, dateRange) => {
|
||||
const calculateGroupStats = (group) => {
|
||||
const totalChecks = group.checks.length;
|
||||
|
||||
const checksWithResponseTime = group.checks.filter(
|
||||
(check) => typeof check.responseTime === "number" && !Number.isNaN(check.responseTime)
|
||||
);
|
||||
const checksWithResponseTime = group.checks.filter((check) => typeof check.responseTime === "number" && !Number.isNaN(check.responseTime));
|
||||
|
||||
return {
|
||||
time: group.time,
|
||||
@@ -317,8 +312,7 @@ const calculateGroupStats = (group) => {
|
||||
totalIncidents: group.checks.filter((check) => !check.status).length,
|
||||
avgResponseTime:
|
||||
checksWithResponseTime.length > 0
|
||||
? checksWithResponseTime.reduce((sum, check) => sum + check.responseTime, 0) /
|
||||
checksWithResponseTime.length
|
||||
? checksWithResponseTime.reduce((sum, check) => sum + check.responseTime, 0) / checksWithResponseTime.length
|
||||
: 0,
|
||||
};
|
||||
};
|
||||
@@ -344,29 +338,15 @@ const getUptimeDetailsById = async ({ monitorId, dateRange, normalize }) => {
|
||||
|
||||
const dateString = formatLookup[dateRange];
|
||||
|
||||
const results = await Check.aggregate(
|
||||
buildUptimeDetailsPipeline(monitorId, dates, dateString)
|
||||
);
|
||||
const results = await Check.aggregate(buildUptimeDetailsPipeline(monitorId, dates, dateString));
|
||||
|
||||
const monitorData = results[0];
|
||||
|
||||
monitorData.groupedUpChecks = NormalizeDataUptimeDetails(
|
||||
monitorData.groupedUpChecks,
|
||||
10,
|
||||
100
|
||||
);
|
||||
monitorData.groupedUpChecks = NormalizeDataUptimeDetails(monitorData.groupedUpChecks, 10, 100);
|
||||
|
||||
monitorData.groupedDownChecks = NormalizeDataUptimeDetails(
|
||||
monitorData.groupedDownChecks,
|
||||
10,
|
||||
100
|
||||
);
|
||||
monitorData.groupedDownChecks = NormalizeDataUptimeDetails(monitorData.groupedDownChecks, 10, 100);
|
||||
|
||||
const normalizedGroupChecks = NormalizeDataUptimeDetails(
|
||||
monitorData.groupedChecks,
|
||||
10,
|
||||
100
|
||||
);
|
||||
const normalizedGroupChecks = NormalizeDataUptimeDetails(monitorData.groupedChecks, 10, 100);
|
||||
|
||||
monitorData.groupedChecks = normalizedGroupChecks;
|
||||
const monitorStats = await MonitorStats.findOne({ monitorId });
|
||||
@@ -386,14 +366,7 @@ const getUptimeDetailsById = async ({ monitorId, dateRange, normalize }) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getMonitorStatsById = async ({
|
||||
monitorId,
|
||||
limit,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
numToDisplay,
|
||||
normalize,
|
||||
}) => {
|
||||
const getMonitorStatsById = async ({ monitorId, limit, sortOrder, dateRange, numToDisplay, normalize }) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
try {
|
||||
// Get monitor, if we can't find it, abort with error
|
||||
@@ -408,12 +381,7 @@ const getMonitorStatsById = async ({
|
||||
// Get Checks for monitor in date range requested
|
||||
const model = CHECK_MODEL_LOOKUP[monitor.type];
|
||||
const dates = getDateRange(dateRange);
|
||||
const { checksAll, checksForDateRange } = await getMonitorChecks(
|
||||
monitorId,
|
||||
model,
|
||||
dates,
|
||||
sort
|
||||
);
|
||||
const { checksAll, checksForDateRange } = await getMonitorChecks(monitorId, model, dates, sort);
|
||||
|
||||
// Build monitor stats
|
||||
const monitorStats = {
|
||||
@@ -423,20 +391,10 @@ const getMonitorStatsById = async ({
|
||||
latestResponseTime: getLatestResponseTime(checksAll),
|
||||
periodIncidents: getIncidents(checksForDateRange),
|
||||
periodTotalChecks: checksForDateRange.length,
|
||||
checks: processChecksForDisplay(
|
||||
NormalizeData,
|
||||
checksForDateRange,
|
||||
numToDisplay,
|
||||
normalize
|
||||
),
|
||||
checks: processChecksForDisplay(NormalizeData, checksForDateRange, numToDisplay, normalize),
|
||||
};
|
||||
|
||||
if (
|
||||
monitor.type === "http" ||
|
||||
monitor.type === "ping" ||
|
||||
monitor.type === "docker" ||
|
||||
monitor.type === "port"
|
||||
) {
|
||||
if (monitor.type === "http" || monitor.type === "ping" || monitor.type === "docker" || monitor.type === "port") {
|
||||
// HTTP/PING Specific stats
|
||||
monitorStats.periodAvgResponseTime = getAverageResponseTime(checksForDateRange);
|
||||
monitorStats.periodUptime = getUptimePercentage(checksForDateRange);
|
||||
@@ -463,9 +421,7 @@ const getHardwareDetailsById = async ({ monitorId, dateRange }) => {
|
||||
month: "%Y-%m-%dT00:00:00Z",
|
||||
};
|
||||
const dateString = formatLookup[dateRange];
|
||||
const hardwareStats = await HardwareCheck.aggregate(
|
||||
buildHardwareDetailsPipeline(monitor, dates, dateString)
|
||||
);
|
||||
const hardwareStats = await HardwareCheck.aggregate(buildHardwareDetailsPipeline(monitor, dates, dateString));
|
||||
|
||||
const monitorStats = {
|
||||
...monitor.toObject(),
|
||||
@@ -505,16 +461,7 @@ const getMonitorById = async (monitorId) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getMonitorsByTeamId = async ({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
}) => {
|
||||
const getMonitorsByTeamId = async ({ limit, type, page, rowsPerPage, filter, field, order, teamId }) => {
|
||||
limit = parseInt(limit);
|
||||
page = parseInt(page);
|
||||
rowsPerPage = parseInt(rowsPerPage);
|
||||
@@ -528,14 +475,10 @@ const getMonitorsByTeamId = async ({
|
||||
matchStage.type = Array.isArray(type) ? { $in: type } : type;
|
||||
}
|
||||
|
||||
const summaryResult = await Monitor.aggregate(
|
||||
buildMonitorSummaryByTeamIdPipeline({ matchStage })
|
||||
);
|
||||
const summaryResult = await Monitor.aggregate(buildMonitorSummaryByTeamIdPipeline({ matchStage }));
|
||||
const summary = summaryResult[0];
|
||||
|
||||
const monitors = await Monitor.aggregate(
|
||||
buildMonitorsByTeamIdPipeline({ matchStage, field, order })
|
||||
);
|
||||
const monitors = await Monitor.aggregate(buildMonitorsByTeamIdPipeline({ matchStage, field, order }));
|
||||
|
||||
const filteredMonitors = await Monitor.aggregate(
|
||||
buildFilteredMonitorsByTeamIdPipeline({
|
||||
@@ -569,14 +512,10 @@ const getMonitorsAndSummaryByTeamId = async ({ type, explain, teamId }) => {
|
||||
}
|
||||
|
||||
if (explain === true) {
|
||||
return Monitor.aggregate(
|
||||
buildMonitorsAndSummaryByTeamIdPipeline({ matchStage })
|
||||
).explain("executionStats");
|
||||
return Monitor.aggregate(buildMonitorsAndSummaryByTeamIdPipeline({ matchStage })).explain("executionStats");
|
||||
}
|
||||
|
||||
const queryResult = await Monitor.aggregate(
|
||||
buildMonitorsAndSummaryByTeamIdPipeline({ matchStage })
|
||||
);
|
||||
const queryResult = await Monitor.aggregate(buildMonitorsAndSummaryByTeamIdPipeline({ matchStage }));
|
||||
const { monitors, summary } = queryResult?.[0] ?? {};
|
||||
return { monitors, summary };
|
||||
} catch (error) {
|
||||
@@ -586,17 +525,7 @@ const getMonitorsAndSummaryByTeamId = async ({ type, explain, teamId }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getMonitorsWithChecksByTeamId = async ({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
explain,
|
||||
}) => {
|
||||
const getMonitorsWithChecksByTeamId = async ({ limit, type, page, rowsPerPage, filter, field, order, teamId, explain }) => {
|
||||
try {
|
||||
limit = parseInt(limit);
|
||||
page = parseInt(page);
|
||||
@@ -684,9 +613,7 @@ const createMonitor = async ({ body, teamId, userId }) => {
|
||||
*/
|
||||
const createBulkMonitors = async (req) => {
|
||||
try {
|
||||
const monitors = req.map(
|
||||
(item) => new Monitor({ ...item, notifications: undefined })
|
||||
);
|
||||
const monitors = req.map((item) => new Monitor({ ...item, notifications: undefined }));
|
||||
await Monitor.bulkSave(monitors);
|
||||
return monitors;
|
||||
} catch (error) {
|
||||
|
||||
@@ -31,11 +31,7 @@ const buildUptimeDetailsPipeline = (monitorId, dates, dateString) => {
|
||||
$project: {
|
||||
_id: 0,
|
||||
percentage: {
|
||||
$cond: [
|
||||
{ $eq: ["$totalChecks", 0] },
|
||||
0,
|
||||
{ $divide: ["$upChecks", "$totalChecks"] },
|
||||
],
|
||||
$cond: [{ $eq: ["$totalChecks", 0] }, 0, { $divide: ["$upChecks", "$totalChecks"] }],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -235,11 +231,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
{
|
||||
$match: {
|
||||
$expr: {
|
||||
$and: [
|
||||
{ $eq: ["$monitorId", monitor._id] },
|
||||
{ $gte: ["$createdAt", dates.start] },
|
||||
{ $lte: ["$createdAt", dates.end] },
|
||||
],
|
||||
$and: [{ $eq: ["$monitorId", monitor._id] }, { $gte: ["$createdAt", dates.start] }, { $lte: ["$createdAt", dates.end] }],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -326,10 +318,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
input: "$disks",
|
||||
as: "diskArray",
|
||||
in: {
|
||||
$arrayElemAt: [
|
||||
"$$diskArray.read_speed_bytes",
|
||||
"$$diskIndex",
|
||||
],
|
||||
$arrayElemAt: ["$$diskArray.read_speed_bytes", "$$diskIndex"],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -340,10 +329,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
input: "$disks",
|
||||
as: "diskArray",
|
||||
in: {
|
||||
$arrayElemAt: [
|
||||
"$$diskArray.write_speed_bytes",
|
||||
"$$diskIndex",
|
||||
],
|
||||
$arrayElemAt: ["$$diskArray.write_speed_bytes", "$$diskIndex"],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -354,10 +340,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
input: "$disks",
|
||||
as: "diskArray",
|
||||
in: {
|
||||
$arrayElemAt: [
|
||||
"$$diskArray.total_bytes",
|
||||
"$$diskIndex",
|
||||
],
|
||||
$arrayElemAt: ["$$diskArray.total_bytes", "$$diskIndex"],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -379,10 +362,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
input: "$disks",
|
||||
as: "diskArray",
|
||||
in: {
|
||||
$arrayElemAt: [
|
||||
"$$diskArray.usage_percent",
|
||||
"$$diskIndex",
|
||||
],
|
||||
$arrayElemAt: ["$$diskArray.usage_percent", "$$diskIndex"],
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -556,26 +536,14 @@ const buildMonitorsAndSummaryByTeamIdPipeline = ({ matchStage }) => {
|
||||
];
|
||||
};
|
||||
|
||||
const buildMonitorsWithChecksByTeamIdPipeline = ({
|
||||
matchStage,
|
||||
filter,
|
||||
page,
|
||||
rowsPerPage,
|
||||
field,
|
||||
order,
|
||||
limit,
|
||||
type,
|
||||
}) => {
|
||||
const buildMonitorsWithChecksByTeamIdPipeline = ({ matchStage, filter, page, rowsPerPage, field, order, limit, type }) => {
|
||||
const skip = page && rowsPerPage ? page * rowsPerPage : 0;
|
||||
const sort = { [field]: order === "asc" ? 1 : -1 };
|
||||
const limitStage = rowsPerPage ? [{ $limit: rowsPerPage }] : [];
|
||||
|
||||
// Match name
|
||||
if (typeof filter !== "undefined" && field === "name") {
|
||||
matchStage.$or = [
|
||||
{ name: { $regex: filter, $options: "i" } },
|
||||
{ url: { $regex: filter, $options: "i" } },
|
||||
];
|
||||
matchStage.$or = [{ name: { $regex: filter, $options: "i" } }, { url: { $regex: filter, $options: "i" } }];
|
||||
}
|
||||
|
||||
// Match isActive
|
||||
@@ -667,37 +635,20 @@ const buildMonitorsWithChecksByTeamIdPipeline = ({
|
||||
return pipeline;
|
||||
};
|
||||
|
||||
const buildFilteredMonitorsByTeamIdPipeline = ({
|
||||
matchStage,
|
||||
filter,
|
||||
page,
|
||||
rowsPerPage,
|
||||
field,
|
||||
order,
|
||||
limit,
|
||||
type,
|
||||
}) => {
|
||||
const buildFilteredMonitorsByTeamIdPipeline = ({ matchStage, filter, page, rowsPerPage, field, order, limit, type }) => {
|
||||
const skip = page && rowsPerPage ? page * rowsPerPage : 0;
|
||||
const sort = { [field]: order === "asc" ? 1 : -1 };
|
||||
const limitStage = rowsPerPage ? [{ $limit: rowsPerPage }] : [];
|
||||
|
||||
if (typeof filter !== "undefined" && field === "name") {
|
||||
matchStage.$or = [
|
||||
{ name: { $regex: filter, $options: "i" } },
|
||||
{ url: { $regex: filter, $options: "i" } },
|
||||
];
|
||||
matchStage.$or = [{ name: { $regex: filter, $options: "i" } }, { url: { $regex: filter, $options: "i" } }];
|
||||
}
|
||||
|
||||
if (typeof filter !== "undefined" && field === "status") {
|
||||
matchStage.status = filter === "true";
|
||||
}
|
||||
|
||||
const pipeline = [
|
||||
{ $match: matchStage },
|
||||
{ $sort: sort },
|
||||
{ $skip: skip },
|
||||
...limitStage,
|
||||
];
|
||||
const pipeline = [{ $match: matchStage }, { $sort: sort }, { $skip: skip }, ...limitStage];
|
||||
|
||||
// Add checks
|
||||
if (limit) {
|
||||
@@ -792,10 +743,7 @@ const buildGetMonitorsByTeamIdPipeline = (req) => {
|
||||
? [
|
||||
{
|
||||
$match: {
|
||||
$or: [
|
||||
{ name: { $regex: filter, $options: "i" } },
|
||||
{ url: { $regex: filter, $options: "i" } },
|
||||
],
|
||||
$or: [{ name: { $regex: filter, $options: "i" } }, { url: { $regex: filter, $options: "i" } }],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -32,9 +32,7 @@ const createNetworkCheck = async (networkCheckData) => {
|
||||
*/
|
||||
const getNetworkChecksByMonitorId = async (monitorId, limit = 100) => {
|
||||
try {
|
||||
const networkChecks = await NetworkCheck.find({ monitorId })
|
||||
.sort({ createdAt: -1 })
|
||||
.limit(limit);
|
||||
const networkChecks = await NetworkCheck.find({ monitorId }).sort({ createdAt: -1 }).limit(limit);
|
||||
return networkChecks;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
|
||||
@@ -29,9 +29,7 @@ const updateAppSettings = async (newSettings) => {
|
||||
await AppSettings.findOneAndUpdate({}, update, {
|
||||
upsert: true,
|
||||
});
|
||||
const settings = await AppSettings.findOne()
|
||||
.select("-__v -_id -createdAt -updatedAt -singleton")
|
||||
.lean();
|
||||
const settings = await AppSettings.findOne().select("-__v -_id -createdAt -updatedAt -singleton").lean();
|
||||
return settings;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
|
||||
@@ -48,13 +48,9 @@ const updateStatusPage = async (statusPageData, image) => {
|
||||
if (statusPageData.deleteSubmonitors === "true") {
|
||||
statusPageData.subMonitors = [];
|
||||
}
|
||||
const statusPage = await StatusPage.findOneAndUpdate(
|
||||
{ url: statusPageData.url },
|
||||
statusPageData,
|
||||
{
|
||||
new: true,
|
||||
}
|
||||
);
|
||||
const statusPage = await StatusPage.findOneAndUpdate({ url: statusPageData.url }, statusPageData, {
|
||||
new: true,
|
||||
});
|
||||
|
||||
return statusPage;
|
||||
} catch (error) {
|
||||
@@ -98,19 +94,8 @@ const getStatusPage = async (url) => {
|
||||
}
|
||||
|
||||
if (!preliminaryStatusPage.monitors || preliminaryStatusPage.monitors.length === 0) {
|
||||
const {
|
||||
_id,
|
||||
color,
|
||||
companyName,
|
||||
isPublished,
|
||||
logo,
|
||||
originalMonitors,
|
||||
showCharts,
|
||||
showUptimePercentage,
|
||||
timezone,
|
||||
showAdminLoginLink,
|
||||
url,
|
||||
} = preliminaryStatusPage;
|
||||
const { _id, color, companyName, isPublished, logo, originalMonitors, showCharts, showUptimePercentage, timezone, showAdminLoginLink, url } =
|
||||
preliminaryStatusPage;
|
||||
return {
|
||||
statusPage: {
|
||||
_id,
|
||||
|
||||
@@ -16,11 +16,7 @@ const SERVICE_NAME = "userModule";
|
||||
* @returns {Promise<UserModel>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const insertUser = async (
|
||||
userData,
|
||||
imageFile,
|
||||
generateAvatarImage = GenerateAvatarImage
|
||||
) => {
|
||||
const insertUser = async (userData, imageFile, generateAvatarImage = GenerateAvatarImage) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
try {
|
||||
if (imageFile) {
|
||||
@@ -47,9 +43,7 @@ const insertUser = async (
|
||||
|
||||
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
|
||||
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 = stringService.dbUserExists;
|
||||
@@ -98,12 +92,7 @@ const getUserByEmail = async (email) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
|
||||
const updateUser = async (
|
||||
req,
|
||||
res,
|
||||
parseBoolean = ParseBoolean,
|
||||
generateAvatarImage = GenerateAvatarImage
|
||||
) => {
|
||||
const updateUser = async (req, res, parseBoolean = ParseBoolean, generateAvatarImage = GenerateAvatarImage) => {
|
||||
const candidateUserId = req.params.userId;
|
||||
try {
|
||||
const candidateUser = { ...req.body };
|
||||
@@ -220,13 +209,4 @@ const logoutUser = async (userId) => {
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
insertUser,
|
||||
getUserByEmail,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
deleteTeam,
|
||||
deleteAllOtherUsers,
|
||||
getAllUsers,
|
||||
logoutUser,
|
||||
};
|
||||
export { insertUser, getUserByEmail, updateUser, deleteUser, deleteTeam, deleteAllOtherUsers, getAllUsers, logoutUser };
|
||||
|
||||
@@ -99,9 +99,7 @@ const SHUTDOWN_TIMEOUT = 1000;
|
||||
let isShuttingDown = false;
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const openApiSpec = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, "openapi.json"), "utf8")
|
||||
);
|
||||
const openApiSpec = JSON.parse(fs.readFileSync(path.join(__dirname, "openapi.json"), "utf8"));
|
||||
|
||||
const frontendPath = path.join(__dirname, "public");
|
||||
|
||||
@@ -156,25 +154,8 @@ const startApp = async () => {
|
||||
// Set allowed origin
|
||||
const allowedOrigin = appSettings.clientHost;
|
||||
|
||||
const networkService = new NetworkService(
|
||||
axios,
|
||||
ping,
|
||||
logger,
|
||||
http,
|
||||
Docker,
|
||||
net,
|
||||
stringService,
|
||||
settingsService
|
||||
);
|
||||
const emailService = new EmailService(
|
||||
settingsService,
|
||||
fs,
|
||||
path,
|
||||
compile,
|
||||
mjml2html,
|
||||
nodemailer,
|
||||
logger
|
||||
);
|
||||
const networkService = new NetworkService(axios, ping, logger, http, Docker, net, stringService, settingsService);
|
||||
const emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger);
|
||||
const bufferService = new BufferService({ db, logger });
|
||||
const statusService = new StatusService({ db, logger, buffer: bufferService });
|
||||
const notificationUtils = new NotificationUtils({
|
||||
@@ -292,17 +273,11 @@ const startApp = async () => {
|
||||
ServiceRegistry.get(StringService.SERVICE_NAME)
|
||||
);
|
||||
|
||||
const queueController = new QueueController(
|
||||
ServiceRegistry.get(JobQueue.SERVICE_NAME),
|
||||
ServiceRegistry.get(StringService.SERVICE_NAME)
|
||||
);
|
||||
const queueController = new QueueController(ServiceRegistry.get(JobQueue.SERVICE_NAME), ServiceRegistry.get(StringService.SERVICE_NAME));
|
||||
|
||||
const logController = new LogController(logger);
|
||||
|
||||
const statusPageController = new StatusPageController(
|
||||
ServiceRegistry.get(MongoDB.SERVICE_NAME),
|
||||
ServiceRegistry.get(StringService.SERVICE_NAME)
|
||||
);
|
||||
const statusPageController = new StatusPageController(ServiceRegistry.get(MongoDB.SERVICE_NAME), ServiceRegistry.get(StringService.SERVICE_NAME));
|
||||
|
||||
const notificationController = new NotificationController({
|
||||
notificationService: ServiceRegistry.get(NotificationService.SERVICE_NAME),
|
||||
@@ -311,9 +286,7 @@ const startApp = async () => {
|
||||
db: ServiceRegistry.get(MongoDB.SERVICE_NAME),
|
||||
});
|
||||
|
||||
const diagnosticController = new DiagnosticController(
|
||||
ServiceRegistry.get(MongoDB.SERVICE_NAME)
|
||||
);
|
||||
const diagnosticController = new DiagnosticController(ServiceRegistry.get(MongoDB.SERVICE_NAME));
|
||||
|
||||
//Create routes
|
||||
const authRoutes = new AuthRoutes(authController);
|
||||
@@ -321,9 +294,7 @@ const startApp = async () => {
|
||||
const settingsRoutes = new SettingsRoutes(settingsController);
|
||||
const checkRoutes = new CheckRoutes(checkController);
|
||||
const inviteRoutes = new InviteRoutes(inviteController);
|
||||
const maintenanceWindowRoutes = new MaintenanceWindowRoutes(
|
||||
maintenanceWindowController
|
||||
);
|
||||
const maintenanceWindowRoutes = new MaintenanceWindowRoutes(maintenanceWindowController);
|
||||
const queueRoutes = new QueueRoutes(queueController);
|
||||
const logRoutes = new LogRoutes(logController);
|
||||
const statusPageRoutes = new StatusPageRoutes(statusPageController);
|
||||
|
||||
@@ -29,9 +29,7 @@ const isAllowed = (allowedRoles) => {
|
||||
// Parse the token
|
||||
try {
|
||||
const parsedToken = token.slice(TOKEN_PREFIX.length, token.length);
|
||||
const { jwtSecret } = ServiceRegistry.get(
|
||||
SettingsService.SERVICE_NAME
|
||||
).getSettings();
|
||||
const { jwtSecret } = ServiceRegistry.get(SettingsService.SERVICE_NAME).getSettings();
|
||||
var decoded = jwt.verify(parsedToken, jwtSecret);
|
||||
const userRoles = decoded.role;
|
||||
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import logger from "../utils/logger.js";
|
||||
|
||||
const languageMiddleware =
|
||||
(stringService, translationService) => async (req, res, next) => {
|
||||
try {
|
||||
const acceptLanguage = req.headers["accept-language"] || "en";
|
||||
const language = acceptLanguage.split(",")[0].slice(0, 2).toLowerCase();
|
||||
const languageMiddleware = (stringService, translationService) => async (req, res, next) => {
|
||||
try {
|
||||
const acceptLanguage = req.headers["accept-language"] || "en";
|
||||
const language = acceptLanguage.split(",")[0].slice(0, 2).toLowerCase();
|
||||
|
||||
translationService.setLanguage(language);
|
||||
stringService.setLanguage(language);
|
||||
translationService.setLanguage(language);
|
||||
stringService.setLanguage(language);
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
message: error.message,
|
||||
service: "languageMiddleware",
|
||||
});
|
||||
const acceptLanguage = req.headers["accept-language"] || "en";
|
||||
const language = acceptLanguage.split(",")[0].slice(0, 2).toLowerCase();
|
||||
next();
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
message: error.message,
|
||||
service: "languageMiddleware",
|
||||
});
|
||||
const acceptLanguage = req.headers["accept-language"] || "en";
|
||||
const language = acceptLanguage.split(",")[0].slice(0, 2).toLowerCase();
|
||||
|
||||
translationService.setLanguage(language);
|
||||
stringService.setLanguage(language);
|
||||
translationService.setLanguage(language);
|
||||
stringService.setLanguage(language);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
export default languageMiddleware;
|
||||
|
||||
@@ -39,10 +39,7 @@ const verifyJWT = (req, res, next) => {
|
||||
const { jwtSecret } = ServiceRegistry.get(SettingsService.SERVICE_NAME).getSettings();
|
||||
jwt.verify(parsedToken, jwtSecret, (err, decoded) => {
|
||||
if (err) {
|
||||
const errorMessage =
|
||||
err.name === "TokenExpiredError"
|
||||
? stringService.expiredAuthToken
|
||||
: stringService.invalidAuthToken;
|
||||
const errorMessage = err.name === "TokenExpiredError" ? stringService.expiredAuthToken : stringService.invalidAuthToken;
|
||||
err.details = { msg: errorMessage };
|
||||
err.status = 401;
|
||||
err.service = SERVICE_NAME;
|
||||
|
||||
@@ -47,9 +47,7 @@ const verifySuperAdmin = (req, res, next) => {
|
||||
stack: err.stack,
|
||||
details: stringService.invalidAuthToken,
|
||||
});
|
||||
return res
|
||||
.status(401)
|
||||
.json({ success: false, msg: stringService.invalidAuthToken });
|
||||
return res.status(401).json({ success: false, msg: stringService.invalidAuthToken });
|
||||
}
|
||||
|
||||
if (decoded.role.includes("superadmin") === false) {
|
||||
|
||||
@@ -100,14 +100,7 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"firstName",
|
||||
"lastName",
|
||||
"email",
|
||||
"password",
|
||||
"role",
|
||||
"teamId"
|
||||
],
|
||||
"required": ["firstName", "lastName", "email", "password", "role", "teamId"],
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"type": "string"
|
||||
|
||||
@@ -15,12 +15,7 @@ class AnnouncementRoutes {
|
||||
* @desc Create a new announcement
|
||||
* @access Private (Requires JWT verification)
|
||||
*/
|
||||
this.router.post(
|
||||
"/",
|
||||
verifyJWT,
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.announcementController.createAnnouncement
|
||||
);
|
||||
this.router.post("/", verifyJWT, isAllowed(["admin", "superadmin"]), this.announcementController.createAnnouncement);
|
||||
|
||||
/**
|
||||
* @route GET /
|
||||
|
||||
@@ -15,34 +15,14 @@ class CheckRoutes {
|
||||
initRoutes() {
|
||||
this.router.get("/team/summary", this.checkController.getChecksSummaryByTeamId);
|
||||
this.router.get("/team", this.checkController.getChecksByTeam);
|
||||
this.router.put(
|
||||
"/team/ttl",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.checkController.updateChecksTTL
|
||||
);
|
||||
this.router.delete(
|
||||
"/team",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.checkController.deleteChecksByTeamId
|
||||
);
|
||||
this.router.put("/team/ttl", isAllowed(["admin", "superadmin"]), this.checkController.updateChecksTTL);
|
||||
this.router.delete("/team", isAllowed(["admin", "superadmin"]), this.checkController.deleteChecksByTeamId);
|
||||
|
||||
this.router.put(
|
||||
"/check/:checkId",
|
||||
verifyTeamAccess(Check, "checkId"),
|
||||
this.checkController.ackCheck
|
||||
);
|
||||
this.router.put("/check/:checkId", verifyTeamAccess(Check, "checkId"), this.checkController.ackCheck);
|
||||
|
||||
this.router.get("/:monitorId", this.checkController.getChecksByMonitor);
|
||||
this.router.post(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
this.checkController.createCheck
|
||||
);
|
||||
this.router.delete(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
this.checkController.deleteChecks
|
||||
);
|
||||
this.router.post("/:monitorId", verifyOwnership(Monitor, "monitorId"), this.checkController.createCheck);
|
||||
this.router.delete("/:monitorId", verifyOwnership(Monitor, "monitorId"), this.checkController.deleteChecks);
|
||||
|
||||
this.router.put("/:path/:monitorId?", this.checkController.ackAllChecks);
|
||||
}
|
||||
|
||||
@@ -9,10 +9,7 @@ class DiagnosticRoutes {
|
||||
initRoutes() {
|
||||
this.router.post("/db/stats", this.diagnosticController.getDbStats);
|
||||
this.router.get("/system", this.diagnosticController.getSystemStats);
|
||||
this.router.get(
|
||||
"/db/get-monitors-by-team-id/:teamId",
|
||||
this.diagnosticController.getMonitorsByTeamIdExecutionStats
|
||||
);
|
||||
this.router.get("/db/get-monitors-by-team-id/:teamId", this.diagnosticController.getMonitorsByTeamIdExecutionStats);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -12,12 +12,7 @@ class InviteRoutes {
|
||||
initRoutes() {
|
||||
this.router.post("/send", this.inviteController.sendInviteEmail);
|
||||
this.router.post("/verify", this.inviteController.inviteVerifyController);
|
||||
this.router.post(
|
||||
"/",
|
||||
verifyJWT,
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.inviteController.getInviteToken
|
||||
);
|
||||
this.router.post("/", verifyJWT, isAllowed(["admin", "superadmin"]), this.inviteController.getInviteToken);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -13,23 +13,11 @@ class MaintenanceWindowRoutes {
|
||||
this.router.post("/", this.mwController.createMaintenanceWindows);
|
||||
this.router.get("/team/", this.mwController.getMaintenanceWindowsByTeamId);
|
||||
|
||||
this.router.get(
|
||||
"/monitor/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
this.mwController.getMaintenanceWindowsByMonitorId
|
||||
);
|
||||
this.router.get("/monitor/:monitorId", verifyOwnership(Monitor, "monitorId"), this.mwController.getMaintenanceWindowsByMonitorId);
|
||||
|
||||
this.router.get("/:id", this.mwController.getMaintenanceWindowById);
|
||||
this.router.put(
|
||||
"/:id",
|
||||
verifyTeamAccess(MaintenanceWindow, "id"),
|
||||
this.mwController.editMaintenanceWindow
|
||||
);
|
||||
this.router.delete(
|
||||
"/:id",
|
||||
verifyTeamAccess(MaintenanceWindow, "id"),
|
||||
this.mwController.deleteMaintenanceWindow
|
||||
);
|
||||
this.router.put("/:id", verifyTeamAccess(MaintenanceWindow, "id"), this.mwController.editMaintenanceWindow);
|
||||
this.router.delete("/:id", verifyTeamAccess(MaintenanceWindow, "id"), this.mwController.deleteMaintenanceWindow);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -20,17 +20,9 @@ class NotificationRoutes {
|
||||
|
||||
this.router.get("/team", this.notificationController.getNotificationsByTeamId);
|
||||
|
||||
this.router.delete(
|
||||
"/:id",
|
||||
verifyOwnership(Notification, "id"),
|
||||
this.notificationController.deleteNotification
|
||||
);
|
||||
this.router.delete("/:id", verifyOwnership(Notification, "id"), this.notificationController.deleteNotification);
|
||||
this.router.get("/:id", this.notificationController.getNotificationById);
|
||||
this.router.put(
|
||||
"/:id",
|
||||
verifyTeamAccess(Notification, "id"),
|
||||
this.notificationController.editNotification
|
||||
);
|
||||
this.router.put("/:id", verifyTeamAccess(Notification, "id"), this.notificationController.editNotification);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -7,37 +7,13 @@ class QueueRoutes {
|
||||
this.initRoutes();
|
||||
}
|
||||
initRoutes() {
|
||||
this.router.get(
|
||||
"/jobs",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.queueController.getJobs
|
||||
);
|
||||
this.router.post(
|
||||
"/jobs",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.queueController.addJob
|
||||
);
|
||||
this.router.get("/jobs", isAllowed(["admin", "superadmin"]), this.queueController.getJobs);
|
||||
this.router.post("/jobs", isAllowed(["admin", "superadmin"]), this.queueController.addJob);
|
||||
|
||||
this.router.get(
|
||||
"/metrics",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.queueController.getMetrics
|
||||
);
|
||||
this.router.get(
|
||||
"/health",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.queueController.checkQueueHealth
|
||||
);
|
||||
this.router.get(
|
||||
"/all-metrics",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.queueController.getAllMetrics
|
||||
);
|
||||
this.router.post(
|
||||
"/flush",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.queueController.flushQueue
|
||||
);
|
||||
this.router.get("/metrics", isAllowed(["admin", "superadmin"]), this.queueController.getMetrics);
|
||||
this.router.get("/health", isAllowed(["admin", "superadmin"]), this.queueController.checkQueueHealth);
|
||||
this.router.get("/all-metrics", isAllowed(["admin", "superadmin"]), this.queueController.getAllMetrics);
|
||||
this.router.post("/flush", isAllowed(["admin", "superadmin"]), this.queueController.flushQueue);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -14,18 +14,8 @@ class StatusPageRoutes {
|
||||
this.router.get("/", this.statusPageController.getStatusPage);
|
||||
this.router.get("/team", verifyJWT, this.statusPageController.getStatusPagesByTeamId);
|
||||
|
||||
this.router.post(
|
||||
"/",
|
||||
upload.single("logo"),
|
||||
verifyJWT,
|
||||
this.statusPageController.createStatusPage
|
||||
);
|
||||
this.router.put(
|
||||
"/",
|
||||
upload.single("logo"),
|
||||
verifyJWT,
|
||||
this.statusPageController.updateStatusPage
|
||||
);
|
||||
this.router.post("/", upload.single("logo"), verifyJWT, this.statusPageController.createStatusPage);
|
||||
this.router.put("/", upload.single("logo"), verifyJWT, this.statusPageController.updateStatusPage);
|
||||
|
||||
this.router.get("/:url", this.statusPageController.getStatusPageByUrl);
|
||||
this.router.delete("/:url(*)", verifyJWT, this.statusPageController.deleteStatusPage);
|
||||
|
||||
@@ -150,11 +150,7 @@ class JobQueue {
|
||||
};
|
||||
|
||||
const schedulerId = getSchedulerId(monitor);
|
||||
await queue.upsertJobScheduler(
|
||||
schedulerId,
|
||||
{ every: monitor?.interval ?? 60000 },
|
||||
jobTemplate
|
||||
);
|
||||
await queue.upsertJobScheduler(schedulerId, { every: monitor?.interval ?? 60000 }, jobTemplate);
|
||||
}
|
||||
|
||||
async deleteJob(monitor) {
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
const SERVICE_NAME = "JobQueueHelper";
|
||||
|
||||
class JobQueueHelper {
|
||||
constructor({
|
||||
redisService,
|
||||
Queue,
|
||||
Worker,
|
||||
logger,
|
||||
db,
|
||||
networkService,
|
||||
statusService,
|
||||
notificationService,
|
||||
}) {
|
||||
constructor({ redisService, Queue, Worker, logger, db, networkService, statusService, notificationService }) {
|
||||
this.db = db;
|
||||
this.redisService = redisService;
|
||||
this.Queue = Queue;
|
||||
@@ -265,11 +256,7 @@ class JobQueueHelper {
|
||||
|
||||
// Handle status change
|
||||
await job.updateProgress(60);
|
||||
const {
|
||||
monitor: updatedMonitor,
|
||||
statusChanged,
|
||||
prevStatus,
|
||||
} = await this.statusService.updateStatus(networkResponse);
|
||||
const { monitor: updatedMonitor, statusChanged, prevStatus } = await this.statusService.updateStatus(networkResponse);
|
||||
// Handle notifications
|
||||
await job.updateProgress(80);
|
||||
this.notificationService
|
||||
|
||||
@@ -22,8 +22,7 @@ class PulseQueue {
|
||||
// ****************************************
|
||||
init = async () => {
|
||||
try {
|
||||
const mongoConnectionString =
|
||||
this.appSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db";
|
||||
const mongoConnectionString = this.appSettings.dbConnectionString || "mongodb://localhost:27017/uptime_db";
|
||||
this.pulse = new Pulse({ db: { address: mongoConnectionString } });
|
||||
await this.pulse.start();
|
||||
this.pulse.define("monitor-job", this.pulseQueueHelper.getMonitorJob(), {});
|
||||
@@ -186,9 +185,7 @@ class PulseQueue {
|
||||
failReason: job.attrs.failReason,
|
||||
lastRunAt: job.attrs.lastRunAt,
|
||||
lastFinishedAt: job.attrs.lastFinishedAt,
|
||||
lastRunTook: job.attrs.lockedAt
|
||||
? null
|
||||
: job.attrs.lastFinishedAt - job.attrs.lastRunAt,
|
||||
lastRunTook: job.attrs.lockedAt ? null : job.attrs.lastFinishedAt - job.attrs.lastRunAt,
|
||||
lastFailedAt: job.attrs.failedAt,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -34,11 +34,7 @@ class PulseQueueHelper {
|
||||
throw new Error("No network response");
|
||||
}
|
||||
|
||||
const {
|
||||
monitor: updatedMonitor,
|
||||
statusChanged,
|
||||
prevStatus,
|
||||
} = await this.statusService.updateStatus(networkResponse);
|
||||
const { monitor: updatedMonitor, statusChanged, prevStatus } = await this.statusService.updateStatus(networkResponse);
|
||||
|
||||
this.notificationService
|
||||
.handleNotifications({
|
||||
|
||||
@@ -42,10 +42,7 @@ class EmailService {
|
||||
*/
|
||||
this.loadTemplate = (templateName) => {
|
||||
try {
|
||||
const templatePath = this.path.join(
|
||||
__dirname,
|
||||
`../templates/${templateName}.mjml`
|
||||
);
|
||||
const templatePath = this.path.join(__dirname, `../templates/${templateName}.mjml`);
|
||||
const templateContent = this.fs.readFileSync(templatePath, "utf8");
|
||||
return this.compile(templateContent);
|
||||
} catch (error) {
|
||||
|
||||
@@ -78,9 +78,7 @@ class NetworkService {
|
||||
async requestPing(monitor) {
|
||||
try {
|
||||
const url = monitor.url;
|
||||
const { response, responseTime, error } = await this.timeRequest(() =>
|
||||
this.ping.promise.probe(url)
|
||||
);
|
||||
const { response, responseTime, error } = await this.timeRequest(() => this.ping.promise.probe(url));
|
||||
|
||||
const pingResponse = {
|
||||
monitorId: monitor._id,
|
||||
@@ -133,18 +131,7 @@ class NetworkService {
|
||||
*/
|
||||
async requestHttp(monitor) {
|
||||
try {
|
||||
const {
|
||||
url,
|
||||
secret,
|
||||
_id,
|
||||
name,
|
||||
teamId,
|
||||
type,
|
||||
ignoreTlsErrors,
|
||||
jsonPath,
|
||||
matchMethod,
|
||||
expectedValue,
|
||||
} = monitor;
|
||||
const { url, secret, _id, name, teamId, type, ignoreTlsErrors, jsonPath, matchMethod, expectedValue } = monitor;
|
||||
const config = {};
|
||||
|
||||
secret !== undefined && (config.headers = { Authorization: `Bearer ${secret}` });
|
||||
@@ -155,9 +142,7 @@ class NetworkService {
|
||||
});
|
||||
}
|
||||
|
||||
const { response, responseTime, error } = await this.timeRequest(() =>
|
||||
this.axios.get(url, config)
|
||||
);
|
||||
const { response, responseTime, error } = await this.timeRequest(() => this.axios.get(url, config));
|
||||
|
||||
const httpResponse = {
|
||||
monitorId: _id,
|
||||
@@ -171,8 +156,7 @@ class NetworkService {
|
||||
const code = error.response?.status || this.NETWORK_ERROR;
|
||||
httpResponse.code = code;
|
||||
httpResponse.status = false;
|
||||
httpResponse.message =
|
||||
this.http.STATUS_CODES[code] || this.stringService.httpNetworkError;
|
||||
httpResponse.message = this.http.STATUS_CODES[code] || this.stringService.httpNetworkError;
|
||||
return httpResponse;
|
||||
}
|
||||
|
||||
@@ -227,9 +211,7 @@ class NetworkService {
|
||||
else match = result === expectedValue;
|
||||
|
||||
httpResponse.status = match;
|
||||
httpResponse.message = match
|
||||
? this.stringService.httpMatchSuccess
|
||||
: this.stringService.httpMatchFail;
|
||||
httpResponse.message = match ? this.stringService.httpMatchSuccess : this.stringService.httpMatchFail;
|
||||
return httpResponse;
|
||||
} catch (error) {
|
||||
error.service = this.SERVICE_NAME;
|
||||
@@ -320,9 +302,7 @@ class NetworkService {
|
||||
}
|
||||
const container = docker.getContainer(monitor.url);
|
||||
|
||||
const { response, responseTime, error } = await this.timeRequest(() =>
|
||||
container.inspect()
|
||||
);
|
||||
const { response, responseTime, error } = await this.timeRequest(() => container.inspect());
|
||||
|
||||
const dockerResponse = {
|
||||
monitorId: monitor._id,
|
||||
@@ -333,8 +313,7 @@ class NetworkService {
|
||||
if (error) {
|
||||
dockerResponse.status = false;
|
||||
dockerResponse.code = error.statusCode || this.NETWORK_ERROR;
|
||||
dockerResponse.message =
|
||||
error.reason || "Failed to fetch Docker container information";
|
||||
dockerResponse.message = error.reason || "Failed to fetch Docker container information";
|
||||
return dockerResponse;
|
||||
}
|
||||
dockerResponse.status = response?.State?.Status === "running" ? true : false;
|
||||
|
||||
@@ -3,14 +3,7 @@ const SERVICE_NAME = "NotificationService";
|
||||
class NotificationService {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
constructor({
|
||||
emailService,
|
||||
db,
|
||||
logger,
|
||||
networkService,
|
||||
stringService,
|
||||
notificationUtils,
|
||||
}) {
|
||||
constructor({ emailService, db, logger, networkService, stringService, notificationUtils }) {
|
||||
this.emailService = emailService;
|
||||
this.db = db;
|
||||
this.logger = logger;
|
||||
@@ -69,20 +62,15 @@ class NotificationService {
|
||||
const alerts = await this.notificationUtils.buildHardwareAlerts(networkResponse);
|
||||
if (alerts.length === 0) return false;
|
||||
|
||||
const { subject, html } = await this.notificationUtils.buildHardwareEmail(
|
||||
networkResponse,
|
||||
alerts
|
||||
);
|
||||
const content =
|
||||
await this.notificationUtils.buildHardwareNotificationMessage(alerts);
|
||||
const { subject, html } = await this.notificationUtils.buildHardwareEmail(networkResponse, alerts);
|
||||
const content = await this.notificationUtils.buildHardwareNotificationMessage(alerts);
|
||||
|
||||
const success = await this.notifyAll({ notificationIDs, subject, html, content });
|
||||
return success;
|
||||
}
|
||||
|
||||
// Status monitors
|
||||
const { subject, html } =
|
||||
await this.notificationUtils.buildStatusEmail(networkResponse);
|
||||
const { subject, html } = await this.notificationUtils.buildStatusEmail(networkResponse);
|
||||
const content = await this.notificationUtils.buildWebhookMessage(networkResponse);
|
||||
const success = this.notifyAll({ notificationIDs, subject, html, content });
|
||||
return success;
|
||||
|
||||
@@ -26,10 +26,7 @@ class NotificationUtils {
|
||||
const date = new Date(timestamp);
|
||||
|
||||
// Get timezone abbreviation and format the date
|
||||
const timeZoneAbbr = date
|
||||
.toLocaleTimeString("en-US", { timeZoneName: "short" })
|
||||
.split(" ")
|
||||
.pop();
|
||||
const timeZoneAbbr = date.toLocaleTimeString("en-US", { timeZoneName: "short" }).split(" ").pop();
|
||||
|
||||
// Format the date with readable format
|
||||
return (
|
||||
@@ -50,9 +47,7 @@ class NotificationUtils {
|
||||
};
|
||||
|
||||
// Get formatted time
|
||||
const formattedTime = timestamp
|
||||
? formatTime(timestamp)
|
||||
: formatTime(new Date().getTime());
|
||||
const formattedTime = timestamp ? formatTime(timestamp) : formatTime(new Date().getTime());
|
||||
|
||||
// Create different messages based on status with extra spacing
|
||||
let messageText;
|
||||
@@ -73,29 +68,15 @@ class NotificationUtils {
|
||||
buildHardwareAlerts = async (networkResponse) => {
|
||||
const monitor = networkResponse?.monitor;
|
||||
const thresholds = networkResponse?.monitor?.thresholds;
|
||||
const {
|
||||
usage_cpu: cpuThreshold = -1,
|
||||
usage_memory: memoryThreshold = -1,
|
||||
usage_disk: diskThreshold = -1,
|
||||
} = thresholds;
|
||||
const { usage_cpu: cpuThreshold = -1, usage_memory: memoryThreshold = -1, usage_disk: diskThreshold = -1 } = thresholds;
|
||||
|
||||
const metrics = networkResponse?.payload?.data;
|
||||
const {
|
||||
cpu: { usage_percent: cpuUsage = -1 } = {},
|
||||
memory: { usage_percent: memoryUsage = -1 } = {},
|
||||
disk = [],
|
||||
} = metrics;
|
||||
const { cpu: { usage_percent: cpuUsage = -1 } = {}, memory: { usage_percent: memoryUsage = -1 } = {}, disk = [] } = metrics;
|
||||
|
||||
const alerts = {
|
||||
cpu: cpuThreshold !== -1 && cpuUsage > cpuThreshold ? true : false,
|
||||
memory: memoryThreshold !== -1 && memoryUsage > memoryThreshold ? true : false,
|
||||
disk:
|
||||
disk?.some(
|
||||
(d) =>
|
||||
diskThreshold !== -1 &&
|
||||
typeof d?.usage_percent === "number" &&
|
||||
d?.usage_percent > diskThreshold
|
||||
) ?? false,
|
||||
disk: disk?.some((d) => diskThreshold !== -1 && typeof d?.usage_percent === "number" && d?.usage_percent > diskThreshold) ?? false,
|
||||
};
|
||||
|
||||
const alertsToSend = [];
|
||||
@@ -110,16 +91,13 @@ class NotificationUtils {
|
||||
monitor[`${type}AlertThreshold`] = monitor.alertThreshold;
|
||||
|
||||
const formatAlert = {
|
||||
cpu: () =>
|
||||
`Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`,
|
||||
cpu: () => `Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`,
|
||||
memory: () =>
|
||||
`Your current memory usage (${(memoryUsage * 100).toFixed(0)}%) is above your threshold (${(memoryThreshold * 100).toFixed(0)}%)`,
|
||||
disk: () =>
|
||||
`Your current disk usage: ${disk
|
||||
.map((d, idx) => `(Disk${idx}: ${(d.usage_percent * 100).toFixed(0)}%)`)
|
||||
.join(
|
||||
", "
|
||||
)} is above your threshold (${(diskThreshold * 100).toFixed(0)}%)`,
|
||||
.join(", ")} is above your threshold (${(diskThreshold * 100).toFixed(0)}%)`,
|
||||
};
|
||||
alertsToSend.push(formatAlert[type]());
|
||||
}
|
||||
|
||||
@@ -62,14 +62,10 @@ class SettingsService {
|
||||
// Remove any old settings
|
||||
await this.AppSettings.deleteMany({ version: { $exists: false } });
|
||||
|
||||
let settings = await this.AppSettings.findOne({ singleton: true })
|
||||
.select("-__v -_id -createdAt -updatedAt -singleton")
|
||||
.lean();
|
||||
let settings = await this.AppSettings.findOne({ singleton: true }).select("-__v -_id -createdAt -updatedAt -singleton").lean();
|
||||
if (settings === null) {
|
||||
await this.AppSettings.create({});
|
||||
settings = await this.AppSettings.findOne({ singleton: true })
|
||||
.select("-__v -_id -createdAt -updatedAt -singleton")
|
||||
.lean();
|
||||
settings = await this.AppSettings.findOne({ singleton: true }).select("-__v -_id -createdAt -updatedAt -singleton").lean();
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -48,9 +48,7 @@ class StatusService {
|
||||
if (avgResponseTime === 0) {
|
||||
avgResponseTime = responseTime;
|
||||
} else {
|
||||
avgResponseTime =
|
||||
(avgResponseTime * (stats.totalChecks - 1) + responseTime) /
|
||||
stats.totalChecks;
|
||||
avgResponseTime = (avgResponseTime * (stats.totalChecks - 1) + responseTime) / stats.totalChecks;
|
||||
}
|
||||
}
|
||||
stats.avgResponseTime = avgResponseTime;
|
||||
@@ -138,9 +136,7 @@ class StatusService {
|
||||
// Monitor status changed, save prev status and update monitor
|
||||
this.logger.info({
|
||||
service: this.SERVICE_NAME,
|
||||
message: `${monitor.name} went from ${this.getStatusString(
|
||||
monitor.status
|
||||
)} to ${this.getStatusString(status)}`,
|
||||
message: `${monitor.name} went from ${this.getStatusString(monitor.status)} to ${this.getStatusString(status)}`,
|
||||
prevStatus: monitor.status,
|
||||
newStatus: status,
|
||||
});
|
||||
@@ -279,9 +275,7 @@ class StatusService {
|
||||
message: error.message,
|
||||
service: error.service || this.SERVICE_NAME,
|
||||
method: error.method || "insertCheck",
|
||||
details:
|
||||
error.details ||
|
||||
`Error inserting check for monitor: ${networkResponse?.monitorId}`,
|
||||
details: error.details || `Error inserting check for monitor: ${networkResponse?.monitorId}`,
|
||||
stack: error.stack,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -211,23 +211,16 @@ class StringService {
|
||||
}
|
||||
|
||||
getWebhookUnsupportedPlatform(platform) {
|
||||
return this.translationService
|
||||
.getTranslation("webhookUnsupportedPlatform")
|
||||
.replace("{platform}", platform);
|
||||
return this.translationService.getTranslation("webhookUnsupportedPlatform").replace("{platform}", platform);
|
||||
}
|
||||
|
||||
getWebhookSendError(platform) {
|
||||
return this.translationService
|
||||
.getTranslation("webhookSendError")
|
||||
.replace("{platform}", platform);
|
||||
return this.translationService.getTranslation("webhookSendError").replace("{platform}", platform);
|
||||
}
|
||||
|
||||
getMonitorStatus(name, status, url) {
|
||||
const translationKey = status === true ? "monitorStatusUp" : "monitorStatusDown";
|
||||
return this.translationService
|
||||
.getTranslation(translationKey)
|
||||
.replace("{name}", name)
|
||||
.replace("{url}", url);
|
||||
return this.translationService.getTranslation(translationKey).replace("{name}", name).replace("{url}", url);
|
||||
}
|
||||
|
||||
// Error Messages
|
||||
@@ -378,9 +371,7 @@ class StringService {
|
||||
}
|
||||
|
||||
getDeletedCount(count) {
|
||||
return this.translationService
|
||||
.getTranslation("deletedCount")
|
||||
.replace("{count}", count);
|
||||
return this.translationService.getTranslation("deletedCount").replace("{count}", count);
|
||||
}
|
||||
|
||||
get pingSuccess() {
|
||||
@@ -424,9 +415,7 @@ class StringService {
|
||||
}
|
||||
|
||||
getDbFindMonitorById(monitorId) {
|
||||
return this.translationService
|
||||
.getTranslation("dbFindMonitorById")
|
||||
.replace("${monitorId}", monitorId);
|
||||
return this.translationService.getTranslation("dbFindMonitorById").replace("${monitorId}", monitorId);
|
||||
}
|
||||
|
||||
get dbUserExists() {
|
||||
|
||||
@@ -38,9 +38,7 @@ class TranslationService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const files = fs
|
||||
.readdirSync(this.localesDir)
|
||||
.filter((file) => file.endsWith(".json"));
|
||||
const files = fs.readdirSync(this.localesDir).filter((file) => file.endsWith(".json"));
|
||||
|
||||
if (files.length === 0) {
|
||||
return false;
|
||||
|
||||
@@ -32,20 +32,15 @@
|
||||
<mj-text>
|
||||
<p>Hello {{ name }}!</p>
|
||||
<p>
|
||||
We hope you’re finding Checkmate helpful in monitoring your infrastructure.
|
||||
Your support means a lot to us, and we <b>truly appreciate</b> having you as
|
||||
part of our community.
|
||||
We hope you’re finding Checkmate helpful in monitoring your infrastructure. Your support means a lot to us, and we
|
||||
<b>truly appreciate</b> having you as part of our community.
|
||||
</p>
|
||||
<p>
|
||||
If you’re happy with Checkmate, we’d love to hear about your experience!
|
||||
Leaving a review on G2 helps others discover Checkmate and supports our
|
||||
ongoing improvements.
|
||||
If you’re happy with Checkmate, we’d love to hear about your experience! Leaving a review on G2 helps others discover Checkmate and
|
||||
supports our ongoing improvements.
|
||||
</p>
|
||||
G2 Link: TBD
|
||||
<p>
|
||||
Thank you for taking the time to share your thoughts - we greatly appreciate
|
||||
it!
|
||||
</p>
|
||||
<p>Thank you for taking the time to share your thoughts - we greatly appreciate it!</p>
|
||||
Checkmate Team
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
<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.
|
||||
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>
|
||||
|
||||
@@ -48,10 +48,7 @@
|
||||
<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>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>
|
||||
</mj-text>
|
||||
|
||||
@@ -31,14 +31,8 @@
|
||||
<mj-column width="100%">
|
||||
<mj-text>
|
||||
<p>Hello {{ name }}!</p>
|
||||
<p>
|
||||
Thank you for trying out Checkmate! We developed it with great care to meet
|
||||
our own needs, and we're excited to share it with you.
|
||||
</p>
|
||||
<p>
|
||||
Checkmate is an automated way of checking whether a service such as a website
|
||||
or an application is available or not.
|
||||
</p>
|
||||
<p>Thank you for trying out Checkmate! We developed it with great care to meet our own needs, and we're excited to share it with you.</p>
|
||||
<p>Checkmate 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>
|
||||
|
||||
@@ -28,9 +28,7 @@ describe("Auth Controller - issueToken", function () {
|
||||
stub = sinon.stub(jwt, "sign").throws(error);
|
||||
const payload = { id: "123" };
|
||||
const appSettings = { jwtSecret: "my_secret" };
|
||||
expect(() => issueToken(payload, tokenType.ACCESS_TOKEN, appSettings)).to.throw(
|
||||
error
|
||||
);
|
||||
expect(() => issueToken(payload, tokenType.ACCESS_TOKEN, appSettings)).to.throw(error);
|
||||
});
|
||||
|
||||
it("should return a token if jwt.sign is successful and appSettings.jwtTTL is not defined", function () {
|
||||
@@ -163,9 +161,7 @@ describe("Auth Controller - registerUser", function () {
|
||||
req.db.checkSuperadmin.resolves(false);
|
||||
req.db.updateAppSettings.resolves();
|
||||
req.db.insertUser.resolves({ _id: "123" });
|
||||
req.settingsService.getSettings.rejects(
|
||||
new Error("settingsService.getSettings error")
|
||||
);
|
||||
req.settingsService.getSettings.rejects(new Error("settingsService.getSettings error"));
|
||||
await registerUser(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal("settingsService.getSettings error");
|
||||
@@ -304,9 +300,7 @@ describe("Auth Controller - loginUser", function () {
|
||||
user.comparePassword.resolves(false);
|
||||
await loginUser(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].message).to.equal(
|
||||
errorMessages.AUTH_INCORRECT_PASSWORD
|
||||
);
|
||||
expect(next.firstCall.args[0].message).to.equal(errorMessages.AUTH_INCORRECT_PASSWORD);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -370,9 +364,7 @@ describe("Auth Controller - refreshAuthToken", function () {
|
||||
});
|
||||
|
||||
it("should reject if settingsService.getSettings fails", async function () {
|
||||
req.settingsService.getSettings.rejects(
|
||||
new Error("settingsService.getSettings error")
|
||||
);
|
||||
req.settingsService.getSettings.rejects(new Error("settingsService.getSettings error"));
|
||||
await refreshAuthToken(req, res, next);
|
||||
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
@@ -475,9 +467,7 @@ describe("Auth Controller - editUser", function () {
|
||||
await editUser(req, res, next);
|
||||
expect(next.firstCall.args[0]).to.be.an("error");
|
||||
expect(next.firstCall.args[0].status).to.equal(401);
|
||||
expect(next.firstCall.args[0].message).to.equal(
|
||||
errorMessages.AUTH_INCORRECT_PASSWORD
|
||||
);
|
||||
expect(next.firstCall.args[0].message).to.equal(errorMessages.AUTH_INCORRECT_PASSWORD);
|
||||
});
|
||||
|
||||
it("should edit a user if it receives a proper request", async function () {
|
||||
@@ -863,8 +853,7 @@ describe("Auth Controller - deleteUser", function () {
|
||||
).to.be.true;
|
||||
expect(req.jobQueue.deleteJob.calledOnceWith(monitors[0])).to.be.true;
|
||||
expect(req.db.deleteChecks.calledOnceWith("monitor_id")).to.be.true;
|
||||
expect(req.db.deletePageSpeedChecksByMonitorId.calledOnceWith("monitor_id")).to.be
|
||||
.true;
|
||||
expect(req.db.deletePageSpeedChecksByMonitorId.calledOnceWith("monitor_id")).to.be.true;
|
||||
expect(req.db.deleteNotificationsByMonitorId.calledOnceWith("monitor_id")).to.be.true;
|
||||
expect(req.db.deleteTeam.calledOnceWith("team_id")).to.be.true;
|
||||
expect(req.db.deleteAllOtherUsers.calledOnce).to.be.true;
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
createCheck,
|
||||
getChecks,
|
||||
getTeamChecks,
|
||||
deleteChecks,
|
||||
deleteChecksByTeamId,
|
||||
updateChecksTTL,
|
||||
} from "../../controllers/checkController.js";
|
||||
import { 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";
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import sinon from "sinon";
|
||||
|
||||
import {
|
||||
handleValidationError,
|
||||
handleError,
|
||||
fetchMonitorCertificate,
|
||||
} from "../../controllers/controllerUtils.js";
|
||||
import { handleValidationError, handleError, fetchMonitorCertificate } from "../../controllers/controllerUtils.js";
|
||||
import { expect } from "chai";
|
||||
import sslChecker from "ssl-checker";
|
||||
import { afterEach } from "node:test";
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
issueInvitation,
|
||||
inviteVerifyController,
|
||||
} from "../../controllers/inviteController.js";
|
||||
import { issueInvitation, inviteVerifyController } from "../../controllers/inviteController.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import sinon from "sinon";
|
||||
import joi from "joi";
|
||||
|
||||
@@ -623,9 +623,7 @@ describe("Monitor Controller - deleteMonitor", function () {
|
||||
req.jobQueue.deleteJob.rejects(error);
|
||||
await deleteMonitor(req, res, next);
|
||||
expect(logger.error.calledOnce).to.be.true;
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(
|
||||
`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`
|
||||
);
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
|
||||
});
|
||||
|
||||
it("should log an error if deleteChecks throws an error", async function () {
|
||||
@@ -635,9 +633,7 @@ describe("Monitor Controller - deleteMonitor", function () {
|
||||
req.db.deleteChecks.rejects(error);
|
||||
await deleteMonitor(req, res, next);
|
||||
expect(logger.error.calledOnce).to.be.true;
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(
|
||||
`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`
|
||||
);
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
|
||||
});
|
||||
|
||||
it("should log an error if deletePageSpeedChecksByMonitorId throws an error", async function () {
|
||||
@@ -647,9 +643,7 @@ describe("Monitor Controller - deleteMonitor", function () {
|
||||
req.db.deletePageSpeedChecksByMonitorId.rejects(error);
|
||||
await deleteMonitor(req, res, next);
|
||||
expect(logger.error.calledOnce).to.be.true;
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(
|
||||
`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`
|
||||
);
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
|
||||
});
|
||||
|
||||
it("should log an error if deleteNotificationsByMonitorId throws an error", async function () {
|
||||
@@ -659,9 +653,7 @@ describe("Monitor Controller - deleteMonitor", function () {
|
||||
req.db.deleteNotificationsByMonitorId.rejects(error);
|
||||
await deleteMonitor(req, res, next);
|
||||
expect(logger.error.calledOnce).to.be.true;
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(
|
||||
`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`
|
||||
);
|
||||
expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
|
||||
});
|
||||
|
||||
it("should return success message if all operations succeed", async function () {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { afterEach } from "node:test";
|
||||
import {
|
||||
getMetrics,
|
||||
getJobs,
|
||||
addJob,
|
||||
obliterateQueue,
|
||||
} from "../../controllers/queueController.js";
|
||||
import { getMetrics, getJobs, addJob, obliterateQueue } from "../../controllers/queueController.js";
|
||||
import { successMessages } from "../../utils/messages.js";
|
||||
import sinon from "sinon";
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { afterEach } from "node:test";
|
||||
import {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
} from "../../controllers/settingsController.js";
|
||||
import { getAppSettings, updateAppSettings } from "../../controllers/settingsController.js";
|
||||
|
||||
import { successMessages } from "../../utils/messages.js";
|
||||
import sinon from "sinon";
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import sinon from "sinon";
|
||||
import {
|
||||
createStatusPage,
|
||||
getStatusPageByUrl,
|
||||
} from "../../controllers/statusPageController.js";
|
||||
import { createStatusPage, getStatusPageByUrl } from "../../controllers/statusPageController.js";
|
||||
|
||||
describe("statusPageController", function () {
|
||||
let req, res, next;
|
||||
|
||||
@@ -216,11 +216,7 @@ describe("checkModule", function () {
|
||||
const result = await getChecksCount(req);
|
||||
|
||||
expect(result).to.equal(4);
|
||||
expect(checkCountDocumentStub.firstCall.args[0]).to.have.all.keys(
|
||||
"monitorId",
|
||||
"createdAt",
|
||||
"status"
|
||||
);
|
||||
expect(checkCountDocumentStub.firstCall.args[0]).to.have.all.keys("monitorId", "createdAt", "status");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -52,10 +52,7 @@ const mockMonitor = {
|
||||
};
|
||||
|
||||
describe("HardwareCheckModule", function () {
|
||||
let hardwareCheckSaveStub,
|
||||
hardwareCheckCountDocumentsStub,
|
||||
monitorFindByIdStub,
|
||||
loggerStub;
|
||||
let hardwareCheckSaveStub, hardwareCheckCountDocumentsStub, monitorFindByIdStub, loggerStub;
|
||||
|
||||
beforeEach(function () {
|
||||
loggerStub = sinon.stub(logger, "error");
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import sinon from "sinon";
|
||||
import InviteToken from "../../db/models/InviteToken.js";
|
||||
import {
|
||||
requestInviteToken,
|
||||
getInviteToken,
|
||||
getInviteTokenAndDelete,
|
||||
} from "../../db/mongo/modules/inviteModule.js";
|
||||
import { requestInviteToken, getInviteToken, getInviteTokenAndDelete } from "../../db/mongo/modules/inviteModule.js";
|
||||
import { errorMessages } from "../../utils/messages.js";
|
||||
|
||||
describe("Invite Module", function () {
|
||||
@@ -15,10 +11,7 @@ describe("Invite Module", function () {
|
||||
token: "123",
|
||||
};
|
||||
const mockInviteToken = { _id: 123, time: 123 };
|
||||
let inviteTokenDeleteManyStub,
|
||||
inviteTokenSaveStub,
|
||||
inviteTokenFindOneStub,
|
||||
inviteTokenFindOneAndDeleteStub;
|
||||
let inviteTokenDeleteManyStub, inviteTokenSaveStub, inviteTokenFindOneStub, inviteTokenFindOneAndDeleteStub;
|
||||
|
||||
beforeEach(function () {
|
||||
inviteTokenDeleteManyStub = sinon.stub(InviteToken, "deleteMany");
|
||||
|
||||
@@ -40,15 +40,9 @@ describe("MaintenanceWindow Module", function () {
|
||||
}),
|
||||
}),
|
||||
});
|
||||
maintenanceWindowFindByIdAndDeleteStub = sinon.stub(
|
||||
MaintenanceWindow,
|
||||
"findByIdAndDelete"
|
||||
);
|
||||
maintenanceWindowFindByIdAndDeleteStub = sinon.stub(MaintenanceWindow, "findByIdAndDelete");
|
||||
maintenanceWindowDeleteManyStub = sinon.stub(MaintenanceWindow, "deleteMany");
|
||||
maintenanceWindowFindByIdAndUpdateStub = sinon.stub(
|
||||
MaintenanceWindow,
|
||||
"findByIdAndUpdate"
|
||||
);
|
||||
maintenanceWindowFindByIdAndUpdateStub = sinon.stub(MaintenanceWindow, "findByIdAndUpdate");
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@@ -110,10 +104,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
|
||||
it("should return a list of maintenance windows and count", async function () {
|
||||
maintenanceWindowCountDocumentsStub.resolves(1);
|
||||
const result = await getMaintenanceWindowsByTeamId(
|
||||
mockMaintenanceWindow.teamId,
|
||||
query
|
||||
);
|
||||
const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
|
||||
expect(result).to.deep.equal({
|
||||
maintenanceWindows: mockMaintenanceWindows,
|
||||
maintenanceWindowCount: 1,
|
||||
@@ -123,10 +114,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
it("should return a list of maintenance windows and count with empty query", async function () {
|
||||
query = undefined;
|
||||
maintenanceWindowCountDocumentsStub.resolves(1);
|
||||
const result = await getMaintenanceWindowsByTeamId(
|
||||
mockMaintenanceWindow.teamId,
|
||||
query
|
||||
);
|
||||
const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
|
||||
expect(result).to.deep.equal({
|
||||
maintenanceWindows: mockMaintenanceWindows,
|
||||
maintenanceWindowCount: 1,
|
||||
@@ -137,10 +125,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
query.page = undefined;
|
||||
query.rowsPerPage = undefined;
|
||||
maintenanceWindowCountDocumentsStub.resolves(1);
|
||||
const result = await getMaintenanceWindowsByTeamId(
|
||||
mockMaintenanceWindow.teamId,
|
||||
query
|
||||
);
|
||||
const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
|
||||
expect(result).to.deep.equal({
|
||||
maintenanceWindows: mockMaintenanceWindows,
|
||||
maintenanceWindowCount: 1,
|
||||
@@ -150,10 +135,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
it("should return a list of maintenance windows and count with field and desc order", async function () {
|
||||
query.order = "desc";
|
||||
maintenanceWindowCountDocumentsStub.resolves(1);
|
||||
const result = await getMaintenanceWindowsByTeamId(
|
||||
mockMaintenanceWindow.teamId,
|
||||
query
|
||||
);
|
||||
const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
|
||||
expect(result).to.deep.equal({
|
||||
maintenanceWindows: mockMaintenanceWindows,
|
||||
maintenanceWindowCount: 1,
|
||||
@@ -163,10 +145,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
it("should return a list of maintenance windows and count no field", async function () {
|
||||
query.field = undefined;
|
||||
maintenanceWindowCountDocumentsStub.resolves(1);
|
||||
const result = await getMaintenanceWindowsByTeamId(
|
||||
mockMaintenanceWindow.teamId,
|
||||
query
|
||||
);
|
||||
const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
|
||||
expect(result).to.deep.equal({
|
||||
maintenanceWindows: mockMaintenanceWindows,
|
||||
maintenanceWindowCount: 1,
|
||||
@@ -187,9 +166,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
describe("getMaintenanceWindowsByMonitorId", function () {
|
||||
it("should return a list of maintenance windows", async function () {
|
||||
maintenanceWindowFindStub.resolves(mockMaintenanceWindows);
|
||||
const result = await getMaintenanceWindowsByMonitorId(
|
||||
mockMaintenanceWindow.monitorId
|
||||
);
|
||||
const result = await getMaintenanceWindowsByMonitorId(mockMaintenanceWindow.monitorId);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindows);
|
||||
});
|
||||
|
||||
@@ -225,9 +202,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
describe("deleteMaintenanceWindowByMonitorId", function () {
|
||||
it("should return the number of documents deleted", async function () {
|
||||
maintenanceWindowDeleteManyStub.resolves({ deletedCount: 1 });
|
||||
const result = await deleteMaintenanceWindowByMonitorId(
|
||||
mockMaintenanceWindow.monitorId
|
||||
);
|
||||
const result = await deleteMaintenanceWindowByMonitorId(mockMaintenanceWindow.monitorId);
|
||||
expect(result).to.deep.equal({ deletedCount: 1 });
|
||||
});
|
||||
|
||||
@@ -263,10 +238,7 @@ describe("MaintenanceWindow Module", function () {
|
||||
describe("editMaintenanceWindowById", function () {
|
||||
it("should return the updated maintenance window", async function () {
|
||||
maintenanceWindowFindByIdAndUpdateStub.resolves(mockMaintenanceWindow);
|
||||
const result = await editMaintenanceWindowById(
|
||||
mockMaintenanceWindow.id,
|
||||
mockMaintenanceWindow
|
||||
);
|
||||
const result = await editMaintenanceWindowById(mockMaintenanceWindow.id, mockMaintenanceWindow);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindow);
|
||||
});
|
||||
|
||||
|
||||
@@ -120,12 +120,7 @@ describe("monitorModule", function () {
|
||||
},
|
||||
];
|
||||
|
||||
const mockChecks = [
|
||||
{ status: true },
|
||||
{ status: true },
|
||||
{ status: false },
|
||||
{ status: true },
|
||||
];
|
||||
const mockChecks = [{ status: true }, { status: true }, { status: false }, { status: true }];
|
||||
|
||||
monitorFindStub.resolves(mockMonitors);
|
||||
checkFindStub.resolves(mockChecks);
|
||||
@@ -166,12 +161,7 @@ describe("monitorModule", function () {
|
||||
},
|
||||
];
|
||||
|
||||
const mockChecks = [
|
||||
{ status: true },
|
||||
{ status: true },
|
||||
{ status: false },
|
||||
{ status: true },
|
||||
];
|
||||
const mockChecks = [{ status: true }, { status: true }, { status: false }, { status: true }];
|
||||
|
||||
monitorFindStub.resolves(mockMonitors);
|
||||
pageSpeedCheckFindStub.resolves(mockChecks);
|
||||
@@ -212,12 +202,7 @@ describe("monitorModule", function () {
|
||||
},
|
||||
];
|
||||
|
||||
const mockChecks = [
|
||||
{ status: true },
|
||||
{ status: true },
|
||||
{ status: false },
|
||||
{ status: true },
|
||||
];
|
||||
const mockChecks = [{ status: true }, { status: true }, { status: false }, { status: true }];
|
||||
|
||||
monitorFindStub.resolves(mockMonitors);
|
||||
hardwareCheckFindStub.resolves(mockChecks);
|
||||
@@ -400,10 +385,7 @@ describe("monitorModule", function () {
|
||||
});
|
||||
|
||||
it("should handle missing responseTime in checks", function () {
|
||||
const checks = [
|
||||
{ createdAt: "2024-01-01T11:30:00Z" },
|
||||
{ responseTime: 200, createdAt: "2024-01-01T11:00:00Z" },
|
||||
];
|
||||
const checks = [{ createdAt: "2024-01-01T11:30:00Z" }, { responseTime: 200, createdAt: "2024-01-01T11:00:00Z" }];
|
||||
|
||||
expect(getLatestResponseTime(checks)).to.equal(0);
|
||||
});
|
||||
@@ -441,10 +423,7 @@ describe("monitorModule", function () {
|
||||
});
|
||||
|
||||
it("should return 0 when no checks have responseTime", function () {
|
||||
const checks = [
|
||||
{ createdAt: "2024-01-01T11:30:00Z" },
|
||||
{ createdAt: "2024-01-01T11:00:00Z" },
|
||||
];
|
||||
const checks = [{ createdAt: "2024-01-01T11:30:00Z" }, { createdAt: "2024-01-01T11:00:00Z" }];
|
||||
|
||||
expect(getAverageResponseTime(checks)).to.equal(0);
|
||||
});
|
||||
@@ -470,12 +449,7 @@ describe("monitorModule", function () {
|
||||
});
|
||||
|
||||
it("should calculate correct percentage for mixed status checks", function () {
|
||||
const checks = [
|
||||
{ status: true },
|
||||
{ status: false },
|
||||
{ status: true },
|
||||
{ status: true },
|
||||
];
|
||||
const checks = [{ status: true }, { status: false }, { status: true }, { status: true }];
|
||||
// 3 up out of 4 total = 75%
|
||||
expect(getUptimePercentage(checks)).to.equal(75);
|
||||
});
|
||||
@@ -507,23 +481,12 @@ describe("monitorModule", function () {
|
||||
});
|
||||
|
||||
it("should count correct number of incidents for mixed status checks", function () {
|
||||
const checks = [
|
||||
{ status: true },
|
||||
{ status: false },
|
||||
{ status: true },
|
||||
{ status: false },
|
||||
{ status: true },
|
||||
];
|
||||
const checks = [{ status: true }, { status: false }, { status: true }, { status: false }, { status: true }];
|
||||
expect(getIncidents(checks)).to.equal(2);
|
||||
});
|
||||
|
||||
it("should handle undefined status values", function () {
|
||||
const checks = [
|
||||
{ status: true },
|
||||
{ status: undefined },
|
||||
{ status: false },
|
||||
{ status: false },
|
||||
];
|
||||
const checks = [{ status: true }, { status: undefined }, { status: false }, { status: false }];
|
||||
// Only counts explicit false values
|
||||
expect(getIncidents(checks)).to.equal(2);
|
||||
});
|
||||
@@ -628,12 +591,8 @@ describe("monitorModule", function () {
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(result.checksAll[0].createdAt).to.be.greaterThan(
|
||||
result.checksAll[1].createdAt
|
||||
);
|
||||
expect(result.checksForDateRange[0].createdAt).to.be.greaterThan(
|
||||
result.checksForDateRange[1].createdAt
|
||||
);
|
||||
expect(result.checksAll[0].createdAt).to.be.greaterThan(result.checksAll[1].createdAt);
|
||||
expect(result.checksForDateRange[0].createdAt).to.be.greaterThan(result.checksForDateRange[1].createdAt);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -753,10 +712,7 @@ describe("monitorModule", function () {
|
||||
});
|
||||
|
||||
it("should handle checks in same time group", function () {
|
||||
const checksInSameHour = [
|
||||
{ createdAt: "2024-01-15T10:15:00Z" },
|
||||
{ createdAt: "2024-01-15T10:45:00Z" },
|
||||
];
|
||||
const checksInSameHour = [{ createdAt: "2024-01-15T10:15:00Z" }, { createdAt: "2024-01-15T10:45:00Z" }];
|
||||
|
||||
const result = groupChecksByTime(checksInSameHour, "day");
|
||||
|
||||
@@ -816,11 +772,7 @@ describe("monitorModule", function () {
|
||||
it("should handle missing responseTime values", function () {
|
||||
const mockGroup = {
|
||||
time: "2024-01-15",
|
||||
checks: [
|
||||
{ status: true },
|
||||
{ status: false, responseTime: 200 },
|
||||
{ status: true, responseTime: undefined },
|
||||
],
|
||||
checks: [{ status: true }, { status: false, responseTime: 200 }, { status: true, responseTime: undefined }],
|
||||
};
|
||||
|
||||
const result = calculateGroupStats(mockGroup, uptimePercentageStub);
|
||||
@@ -1413,10 +1365,7 @@ describe("monitorModule", function () {
|
||||
|
||||
expect(Monitor.find.firstCall.args[0]).to.deep.equal({
|
||||
teamId: "team123",
|
||||
$or: [
|
||||
{ name: { $regex: "search", $options: "i" } },
|
||||
{ url: { $regex: "search", $options: "i" } },
|
||||
],
|
||||
$or: [{ name: { $regex: "search", $options: "i" } }, { url: { $regex: "search", $options: "i" } }],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1816,14 +1765,9 @@ describe("monitorModule", function () {
|
||||
|
||||
// Assert
|
||||
expect(result).to.deep.equal(mockUpdatedMonitor);
|
||||
sinon.assert.calledWith(
|
||||
monitorFindByIdAndUpdateStub,
|
||||
candidateId,
|
||||
expectedUpdateData,
|
||||
{
|
||||
new: true,
|
||||
}
|
||||
);
|
||||
sinon.assert.calledWith(monitorFindByIdAndUpdateStub, candidateId, expectedUpdateData, {
|
||||
new: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("should return null when monitor not found", async function () {
|
||||
@@ -1840,12 +1784,7 @@ describe("monitorModule", function () {
|
||||
|
||||
// Assert
|
||||
expect(result).to.be.null;
|
||||
sinon.assert.calledWith(
|
||||
monitorFindByIdAndUpdateStub,
|
||||
candidateId,
|
||||
{ name: "Updated Monitor", notifications: undefined },
|
||||
{ new: true }
|
||||
);
|
||||
sinon.assert.calledWith(monitorFindByIdAndUpdateStub, candidateId, { name: "Updated Monitor", notifications: undefined }, { new: true });
|
||||
});
|
||||
|
||||
it("should remove notifications from update data", async function () {
|
||||
@@ -1870,14 +1809,9 @@ describe("monitorModule", function () {
|
||||
await editMonitor(candidateId, candidateMonitor);
|
||||
|
||||
// Assert
|
||||
sinon.assert.calledWith(
|
||||
monitorFindByIdAndUpdateStub,
|
||||
candidateId,
|
||||
expectedUpdateData,
|
||||
{
|
||||
new: true,
|
||||
}
|
||||
);
|
||||
sinon.assert.calledWith(monitorFindByIdAndUpdateStub, candidateId, expectedUpdateData, {
|
||||
new: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle database errors", async function () {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import sinon from "sinon";
|
||||
import Notification from "../../db/models/Notification.js";
|
||||
import {
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
} from "../../db/mongo/modules/notificationModule.js";
|
||||
import { createNotification, getNotificationsByMonitorId, deleteNotificationsByMonitorId } from "../../db/mongo/modules/notificationModule.js";
|
||||
|
||||
describe("notificationModule", function () {
|
||||
const mockNotification = {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import sinon from "sinon";
|
||||
import PageSpeedCheck from "../../db/models/PageSpeedCheck.js";
|
||||
import {
|
||||
createPageSpeedCheck,
|
||||
deletePageSpeedChecksByMonitorId,
|
||||
} from "../../db/mongo/modules/pageSpeedCheckModule.js";
|
||||
import { createPageSpeedCheck, deletePageSpeedChecksByMonitorId } from "../../db/mongo/modules/pageSpeedCheckModule.js";
|
||||
|
||||
const mockPageSpeedCheck = {
|
||||
monitorId: "monitorId",
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import sinon from "sinon";
|
||||
import RecoveryToken from "../../db/models/RecoveryToken.js";
|
||||
import User from "../../db/models/User.js";
|
||||
import {
|
||||
requestRecoveryToken,
|
||||
validateRecoveryToken,
|
||||
resetPassword,
|
||||
} from "../../db/mongo/modules/recoveryModule.js";
|
||||
import { requestRecoveryToken, validateRecoveryToken, resetPassword } from "../../db/mongo/modules/recoveryModule.js";
|
||||
import { errorMessages } from "../../utils/messages.js";
|
||||
|
||||
const mockRecoveryToken = {
|
||||
@@ -44,12 +40,7 @@ const createQueryChain = (finalResult, comparePasswordResult = false) => ({
|
||||
});
|
||||
|
||||
describe("recoveryModule", function () {
|
||||
let deleteManyStub,
|
||||
saveStub,
|
||||
findOneStub,
|
||||
userCompareStub,
|
||||
userSaveStub,
|
||||
userFindOneStub;
|
||||
let deleteManyStub, saveStub, findOneStub, userCompareStub, userSaveStub, userFindOneStub;
|
||||
let req, res;
|
||||
|
||||
beforeEach(function () {
|
||||
@@ -153,9 +144,7 @@ describe("recoveryModule", function () {
|
||||
it("should throw an error if the passwords match", async function () {
|
||||
findOneStub.resolves(mockRecoveryToken);
|
||||
saveStub.resolves();
|
||||
userFindOneStub = sinon
|
||||
.stub(User, "findOne")
|
||||
.returns(createQueryChain(mockUser, true));
|
||||
userFindOneStub = sinon.stub(User, "findOne").returns(createQueryChain(mockUser, true));
|
||||
try {
|
||||
await resetPassword(req, res);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import sinon from "sinon";
|
||||
import {
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
} from "../../db/mongo/modules/settingsModule.js";
|
||||
import { getAppSettings, updateAppSettings } from "../../db/mongo/modules/settingsModule.js";
|
||||
import AppSettings from "../../db/models/AppSettings.js";
|
||||
|
||||
const mockAppSettings = {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import sinon from "sinon";
|
||||
import {
|
||||
createStatusPage,
|
||||
getStatusPageByUrl,
|
||||
} from "../../db/mongo/modules/statusPageModule.js";
|
||||
import { createStatusPage, getStatusPageByUrl } from "../../db/mongo/modules/statusPageModule.js";
|
||||
import StatusPage from "../../db/models/StatusPage.js";
|
||||
import { errorMessages } from "../../utils/messages.js";
|
||||
|
||||
|
||||
@@ -157,12 +157,7 @@ describe("userModule", function () {
|
||||
select: sinon.stub().resolves(mockUser),
|
||||
}),
|
||||
});
|
||||
const result = await updateUser(
|
||||
req,
|
||||
res,
|
||||
parseBooleanStub,
|
||||
generateAvatarImageStub
|
||||
);
|
||||
const result = await updateUser(req, res, parseBooleanStub, generateAvatarImageStub);
|
||||
expect(result).to.deep.equal(mockUser);
|
||||
});
|
||||
|
||||
@@ -173,12 +168,7 @@ describe("userModule", function () {
|
||||
select: sinon.stub().resolves(mockUser),
|
||||
}),
|
||||
});
|
||||
const result = await updateUser(
|
||||
req,
|
||||
res,
|
||||
parseBooleanStub,
|
||||
generateAvatarImageStub
|
||||
);
|
||||
const result = await updateUser(req, res, parseBooleanStub, generateAvatarImageStub);
|
||||
expect(result).to.deep.equal(mockUser);
|
||||
});
|
||||
|
||||
|
||||
@@ -48,15 +48,7 @@ describe("EmailService - Constructor", function () {
|
||||
});
|
||||
|
||||
it("should initialize template loaders and email transporter", function () {
|
||||
const emailService = new EmailService(
|
||||
settingsServiceMock,
|
||||
fsMock,
|
||||
pathMock,
|
||||
compileMock,
|
||||
mjml2htmlMock,
|
||||
nodemailerMock,
|
||||
loggerMock
|
||||
);
|
||||
const emailService = new EmailService(settingsServiceMock, fsMock, pathMock, compileMock, mjml2htmlMock, nodemailerMock, loggerMock);
|
||||
|
||||
// Verify that the settingsService is assigned correctly
|
||||
expect(emailService.settingsService).to.equal(settingsServiceMock);
|
||||
@@ -83,15 +75,7 @@ describe("EmailService - Constructor", function () {
|
||||
fsMock = {
|
||||
readFileSync: sinon.stub().throws(new Error("File read error")),
|
||||
};
|
||||
const emailService = new EmailService(
|
||||
settingsServiceMock,
|
||||
fsMock,
|
||||
pathMock,
|
||||
compileMock,
|
||||
mjml2htmlMock,
|
||||
nodemailerMock,
|
||||
loggerMock
|
||||
);
|
||||
const emailService = new EmailService(settingsServiceMock, fsMock, pathMock, compileMock, mjml2htmlMock, nodemailerMock, loggerMock);
|
||||
expect(loggerMock.error.called).to.be.true;
|
||||
expect(loggerMock.error.firstCall.args[0].message).to.equal("File read error");
|
||||
});
|
||||
@@ -139,15 +123,7 @@ describe("EmailService - buildAndSendEmail", function () {
|
||||
error: sinon.stub(),
|
||||
};
|
||||
|
||||
emailService = new EmailService(
|
||||
settingsServiceMock,
|
||||
fsMock,
|
||||
pathMock,
|
||||
compileMock,
|
||||
mjml2htmlMock,
|
||||
nodemailerMock,
|
||||
loggerMock
|
||||
);
|
||||
emailService = new EmailService(settingsServiceMock, fsMock, pathMock, compileMock, mjml2htmlMock, nodemailerMock, loggerMock);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@@ -155,12 +131,7 @@ describe("EmailService - buildAndSendEmail", function () {
|
||||
});
|
||||
|
||||
it("should build and send email successfully", async function () {
|
||||
const messageId = await emailService.buildAndSendEmail(
|
||||
"welcomeEmailTemplate",
|
||||
{},
|
||||
"recipient@example.com",
|
||||
"Welcome"
|
||||
);
|
||||
const messageId = await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
|
||||
|
||||
expect(messageId).to.equal("12345");
|
||||
expect(nodemailerMock.createTransport().sendMail.calledOnce).to.be.true;
|
||||
@@ -169,24 +140,14 @@ describe("EmailService - buildAndSendEmail", function () {
|
||||
it("should log error if building HTML fails", async function () {
|
||||
mjml2htmlMock.throws(new Error("MJML error"));
|
||||
|
||||
const messageId = await emailService.buildAndSendEmail(
|
||||
"welcomeEmailTemplate",
|
||||
{},
|
||||
"recipient@example.com",
|
||||
"Welcome"
|
||||
);
|
||||
const messageId = await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
|
||||
expect(loggerMock.error.calledOnce).to.be.true;
|
||||
expect(loggerMock.error.getCall(0).args[0].message).to.equal("MJML error");
|
||||
});
|
||||
|
||||
it("should log error if sending email fails", async function () {
|
||||
nodemailerMock.createTransport().sendMail.rejects(new Error("SMTP error"));
|
||||
await emailService.buildAndSendEmail(
|
||||
"welcomeEmailTemplate",
|
||||
{},
|
||||
"recipient@example.com",
|
||||
"Welcome"
|
||||
);
|
||||
await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
|
||||
expect(loggerMock.error.calledOnce).to.be.true;
|
||||
expect(loggerMock.error.getCall(0).args[0].message).to.equal("SMTP error");
|
||||
});
|
||||
@@ -195,12 +156,7 @@ describe("EmailService - buildAndSendEmail", function () {
|
||||
mjml2htmlMock.throws(new Error("MJML error"));
|
||||
nodemailerMock.createTransport().sendMail.rejects(new Error("SMTP error"));
|
||||
|
||||
const messageId = await emailService.buildAndSendEmail(
|
||||
"welcomeEmailTemplate",
|
||||
{},
|
||||
"recipient@example.com",
|
||||
"Welcome"
|
||||
);
|
||||
const messageId = await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
|
||||
|
||||
expect(messageId).to.be.undefined;
|
||||
expect(loggerMock.error.calledTwice).to.be.true;
|
||||
|
||||
@@ -52,13 +52,7 @@ class WorkerStub {
|
||||
}
|
||||
|
||||
describe("JobQueue", function () {
|
||||
let settingsService,
|
||||
logger,
|
||||
db,
|
||||
networkService,
|
||||
statusService,
|
||||
notificationService,
|
||||
jobQueue;
|
||||
let settingsService, logger, db, networkService, statusService, notificationService, jobQueue;
|
||||
|
||||
beforeEach(async function () {
|
||||
settingsService = { getSettings: sinon.stub() };
|
||||
@@ -71,16 +65,7 @@ describe("JobQueue", function () {
|
||||
getMaintenanceWindowsByMonitorId: sinon.stub().returns([]),
|
||||
};
|
||||
networkService = { getStatus: sinon.stub() };
|
||||
jobQueue = await JobQueue.createJobQueue(
|
||||
db,
|
||||
networkService,
|
||||
statusService,
|
||||
notificationService,
|
||||
settingsService,
|
||||
logger,
|
||||
QueueStub,
|
||||
WorkerStub
|
||||
);
|
||||
jobQueue = await JobQueue.createJobQueue(db, networkService, statusService, notificationService, settingsService, logger, QueueStub, WorkerStub);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@@ -327,9 +312,7 @@ describe("JobQueue", function () {
|
||||
const handler = jobQueue.createJobHandler();
|
||||
await handler({ data: { _id: 1 } });
|
||||
expect(logger.info.calledOnce).to.be.true;
|
||||
expect(logger.info.firstCall.args[0].message).to.equal(
|
||||
"Monitor 1 is in maintenance window"
|
||||
);
|
||||
expect(logger.info.firstCall.args[0].message).to.equal("Monitor 1 is in maintenance window");
|
||||
});
|
||||
|
||||
it("should return if status has not changed", async function () {
|
||||
@@ -362,9 +345,7 @@ describe("JobQueue", function () {
|
||||
WorkerStub
|
||||
);
|
||||
jobQueue.isInMaintenanceWindow = sinon.stub().returns(false);
|
||||
statusService.updateStatus = sinon
|
||||
.stub()
|
||||
.returns({ statusChanged: true, prevStatus: undefined });
|
||||
statusService.updateStatus = sinon.stub().returns({ statusChanged: true, prevStatus: undefined });
|
||||
const handler = jobQueue.createJobHandler();
|
||||
await handler({ data: { _id: 1 } });
|
||||
expect(jobQueue.notificationService.handleNotifications.notCalled).to.be.true;
|
||||
@@ -382,9 +363,7 @@ describe("JobQueue", function () {
|
||||
WorkerStub
|
||||
);
|
||||
jobQueue.isInMaintenanceWindow = sinon.stub().returns(false);
|
||||
statusService.updateStatus = sinon
|
||||
.stub()
|
||||
.returns({ statusChanged: true, prevStatus: false });
|
||||
statusService.updateStatus = sinon.stub().returns({ statusChanged: true, prevStatus: false });
|
||||
const handler = jobQueue.createJobHandler();
|
||||
await handler({ data: { _id: 1 } });
|
||||
expect(jobQueue.notificationService.handleNotifications.calledOnce).to.be.true;
|
||||
|
||||
@@ -26,9 +26,7 @@ describe("Network Service", function () {
|
||||
};
|
||||
ping = {
|
||||
promise: {
|
||||
probe: sinon
|
||||
.stub()
|
||||
.resolves({ response: { alive: true }, responseTime: 100, alive: true }),
|
||||
probe: sinon.stub().resolves({ response: { alive: true }, responseTime: 100, alive: true }),
|
||||
},
|
||||
};
|
||||
logger = { error: sinon.stub() };
|
||||
@@ -73,9 +71,7 @@ describe("Network Service", function () {
|
||||
|
||||
it("should return a response object if ping unsuccessful", async function () {
|
||||
const error = new Error("Test error");
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const pingResult = await networkService.requestPing({
|
||||
data: { url: "http://test.com", _id: "123" },
|
||||
});
|
||||
@@ -113,9 +109,7 @@ describe("Network Service", function () {
|
||||
it("should return a response object if http unsuccessful", async function () {
|
||||
const error = new Error("Test error");
|
||||
error.response = { status: 404 };
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const job = { data: { url: "http://test.com", _id: "123", type: "http" } };
|
||||
const httpResult = await networkService.requestHttp(job);
|
||||
expect(httpResult.monitorId).to.equal("123");
|
||||
@@ -128,9 +122,7 @@ describe("Network Service", function () {
|
||||
it("should return a response object if http unsuccessful with unknown code", async function () {
|
||||
const error = new Error("Test error");
|
||||
error.response = {};
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const job = { data: { url: "http://test.com", _id: "123", type: "http" } };
|
||||
const httpResult = await networkService.requestHttp(job);
|
||||
expect(httpResult.monitorId).to.equal("123");
|
||||
@@ -167,9 +159,7 @@ describe("Network Service", function () {
|
||||
it("should return a response object if pagespeed unsuccessful", async function () {
|
||||
const error = new Error("Test error");
|
||||
error.response = { status: 404 };
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const job = { data: { url: "http://test.com", _id: "123", type: "pagespeed" } };
|
||||
const pagespeedResult = await networkService.requestPagespeed(job);
|
||||
expect(pagespeedResult.monitorId).to.equal("123");
|
||||
@@ -182,9 +172,7 @@ describe("Network Service", function () {
|
||||
it("should return a response object if pagespeed unsuccessful with an unknown code", async function () {
|
||||
const error = new Error("Test error");
|
||||
error.response = {};
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const job = { data: { url: "http://test.com", _id: "123", type: "pagespeed" } };
|
||||
const pagespeedResult = await networkService.requestPagespeed(job);
|
||||
expect(pagespeedResult.monitorId).to.equal("123");
|
||||
@@ -237,9 +225,7 @@ describe("Network Service", function () {
|
||||
it("should return a response object if hardware unsuccessful", async function () {
|
||||
const error = new Error("Test error");
|
||||
error.response = { status: 404 };
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const job = { data: { url: "http://test.com", _id: "123", type: "hardware" } };
|
||||
const httpResult = await networkService.requestHardware(job);
|
||||
expect(httpResult.monitorId).to.equal("123");
|
||||
@@ -252,9 +238,7 @@ describe("Network Service", function () {
|
||||
it("should return a response object if hardware unsuccessful with unknown code", async function () {
|
||||
const error = new Error("Test error");
|
||||
error.response = {};
|
||||
networkService.timeRequest = sinon
|
||||
.stub()
|
||||
.resolves({ response: null, responseTime: 1, error });
|
||||
networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
|
||||
const job = { data: { url: "http://test.com", _id: "123", type: "hardware" } };
|
||||
const httpResult = await networkService.requestHardware(job);
|
||||
expect(httpResult.monitorId).to.equal("123");
|
||||
|
||||
@@ -43,10 +43,7 @@ describe("NotificationService", function () {
|
||||
await notificationService.sendEmail(networkResponse, address);
|
||||
expect(notificationService.emailService.buildAndSendEmail.calledOnce).to.be.true;
|
||||
expect(
|
||||
notificationService.emailService.buildAndSendEmail.calledWith(
|
||||
"serverIsUpTemplate",
|
||||
{ monitor: "Test Monitor", url: "http://test.com" }
|
||||
)
|
||||
notificationService.emailService.buildAndSendEmail.calledWith("serverIsUpTemplate", { monitor: "Test Monitor", url: "http://test.com" })
|
||||
);
|
||||
});
|
||||
|
||||
@@ -132,22 +129,14 @@ describe("NotificationService", function () {
|
||||
|
||||
it("should send an email notification with Hardware Template", async function () {
|
||||
emailService.buildAndSendEmail.resolves(true);
|
||||
const res = await notificationService.sendHardwareEmail(
|
||||
networkResponse,
|
||||
address,
|
||||
alerts
|
||||
);
|
||||
const res = await notificationService.sendHardwareEmail(networkResponse, address, alerts);
|
||||
expect(res).to.be.true;
|
||||
});
|
||||
|
||||
it("should return false if no alerts are provided", async function () {
|
||||
alerts = [];
|
||||
emailService.buildAndSendEmail.resolves(true);
|
||||
const res = await notificationService.sendHardwareEmail(
|
||||
networkResponse,
|
||||
address,
|
||||
alerts
|
||||
);
|
||||
const res = await notificationService.sendHardwareEmail(networkResponse, address, alerts);
|
||||
expect(res).to.be.false;
|
||||
});
|
||||
});
|
||||
@@ -172,9 +161,7 @@ describe("NotificationService", function () {
|
||||
});
|
||||
|
||||
it("should handle status notifications", async function () {
|
||||
db.getNotificationsByMonitorId.resolves([
|
||||
{ type: "email", address: "test@test.com" },
|
||||
]);
|
||||
db.getNotificationsByMonitorId.resolves([{ type: "email", address: "test@test.com" }]);
|
||||
const res = await notificationService.handleStatusNotifications(networkResponse);
|
||||
expect(res).to.be.true;
|
||||
});
|
||||
@@ -247,15 +234,13 @@ describe("NotificationService", function () {
|
||||
describe("it should return false if no thresholds are set", function () {
|
||||
it("should return false if no thresholds are set", async function () {
|
||||
networkResponse.monitor.thresholds = undefined;
|
||||
const res =
|
||||
await notificationService.handleHardwareNotifications(networkResponse);
|
||||
const res = await notificationService.handleHardwareNotifications(networkResponse);
|
||||
expect(res).to.be.false;
|
||||
});
|
||||
|
||||
it("should return false if metrics are null", async function () {
|
||||
networkResponse.payload.data = null;
|
||||
const res =
|
||||
await notificationService.handleHardwareNotifications(networkResponse);
|
||||
const res = await notificationService.handleHardwareNotifications(networkResponse);
|
||||
expect(res).to.be.false;
|
||||
});
|
||||
|
||||
@@ -271,8 +256,7 @@ describe("NotificationService", function () {
|
||||
save: sinon.stub().resolves(),
|
||||
},
|
||||
]);
|
||||
const res =
|
||||
await notificationService.handleHardwareNotifications(networkResponse);
|
||||
const res = await notificationService.handleHardwareNotifications(networkResponse);
|
||||
expect(res).to.be.true;
|
||||
});
|
||||
|
||||
@@ -293,8 +277,7 @@ describe("NotificationService", function () {
|
||||
usage_memory: 0.01,
|
||||
usage_disk: 0.01,
|
||||
};
|
||||
const res =
|
||||
await notificationService.handleHardwareNotifications(networkResponse);
|
||||
const res = await notificationService.handleHardwareNotifications(networkResponse);
|
||||
expect(res).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,9 +13,7 @@ describe("SettingsService", function () {
|
||||
sandbox.stub(process.env, "JWT_SECRET").value("secret");
|
||||
sandbox.stub(process.env, "REFRESH_TOKEN_SECRET").value("refreshSecret");
|
||||
sandbox.stub(process.env, "DB_TYPE").value("postgres");
|
||||
sandbox
|
||||
.stub(process.env, "DB_CONNECTION_STRING")
|
||||
.value("postgres://user:pass@localhost/db");
|
||||
sandbox.stub(process.env, "DB_CONNECTION_STRING").value("postgres://user:pass@localhost/db");
|
||||
sandbox.stub(process.env, "REDIS_HOST").value("localhost");
|
||||
sandbox.stub(process.env, "REDIS_PORT").value("6379");
|
||||
sandbox.stub(process.env, "TOKEN_TTL").value("3600");
|
||||
|
||||
@@ -73,9 +73,7 @@ describe("StatusService", () => {
|
||||
});
|
||||
|
||||
it("should return {statusChanged: true} if status has changed from down to up", async function () {
|
||||
statusService.db.getMonitorById = sinon
|
||||
.stub()
|
||||
.returns({ status: false, save: sinon.stub() });
|
||||
statusService.db.getMonitorById = sinon.stub().returns({ status: false, save: sinon.stub() });
|
||||
const result = await statusService.updateStatus({
|
||||
monitorId: "test",
|
||||
status: true,
|
||||
@@ -87,9 +85,7 @@ describe("StatusService", () => {
|
||||
});
|
||||
|
||||
it("should return {statusChanged: true} if status has changed from up to down", async function () {
|
||||
statusService.db.getMonitorById = sinon
|
||||
.stub()
|
||||
.returns({ status: true, save: sinon.stub() });
|
||||
statusService.db.getMonitorById = sinon.stub().returns({ status: true, save: sinon.stub() });
|
||||
const result = await statusService.updateStatus({
|
||||
monitorId: "test",
|
||||
status: false,
|
||||
|
||||
@@ -51,13 +51,7 @@ describe("NormalizeData", function () {
|
||||
|
||||
describe("calculatePercentile", function () {
|
||||
it("should return the lower value when upper is greater than or equal to the length of the sorted array", function () {
|
||||
const checks = [
|
||||
{ responseTime: 10 },
|
||||
{ responseTime: 20 },
|
||||
{ responseTime: 30 },
|
||||
{ responseTime: 40 },
|
||||
{ responseTime: 50 },
|
||||
];
|
||||
const checks = [{ responseTime: 10 }, { responseTime: 20 }, { responseTime: 30 }, { responseTime: 40 }, { responseTime: 50 }];
|
||||
|
||||
const percentile = 100;
|
||||
const result = calculatePercentile(checks, percentile);
|
||||
|
||||
@@ -12,9 +12,7 @@ describe("imageProcessing - GenerateAvatarImage", function () {
|
||||
// Stub the sharp function
|
||||
const toBufferStub = sinon.stub().resolves(Buffer.from("resized image buffer"));
|
||||
const resizeStub = sinon.stub().returns({ toBuffer: toBufferStub });
|
||||
const sharpStub = sinon
|
||||
.stub(sharp.prototype, "resize")
|
||||
.returns({ toBuffer: toBufferStub });
|
||||
const sharpStub = sinon.stub(sharp.prototype, "resize").returns({ toBuffer: toBufferStub });
|
||||
|
||||
const result = await GenerateAvatarImage(file);
|
||||
|
||||
@@ -38,9 +36,7 @@ describe("imageProcessing - GenerateAvatarImage", function () {
|
||||
// Stub the sharp function to throw an error
|
||||
const toBufferStub = sinon.stub().rejects(new Error("Resizing failed"));
|
||||
const resizeStub = sinon.stub().returns({ toBuffer: toBufferStub });
|
||||
const sharpStub = sinon
|
||||
.stub(sharp.prototype, "resize")
|
||||
.returns({ toBuffer: toBufferStub });
|
||||
const sharpStub = sinon.stub(sharp.prototype, "resize").returns({ toBuffer: toBufferStub });
|
||||
|
||||
try {
|
||||
await GenerateAvatarImage(file);
|
||||
|
||||
@@ -3,25 +3,19 @@ describe("Messages", function () {
|
||||
describe("messages - errorMessages", function () {
|
||||
it("should have a DB_FIND_MONITOR_BY_ID function", function () {
|
||||
const monitorId = "12345";
|
||||
expect(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId)).to.equal(
|
||||
`Monitor with id ${monitorId} not found`
|
||||
);
|
||||
expect(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId)).to.equal(`Monitor with id ${monitorId} not found`);
|
||||
});
|
||||
|
||||
it("should have a DB_DELETE_CHECKS function", function () {
|
||||
const monitorId = "12345";
|
||||
expect(errorMessages.DB_DELETE_CHECKS(monitorId)).to.equal(
|
||||
`No checks found for monitor with id ${monitorId}`
|
||||
);
|
||||
expect(errorMessages.DB_DELETE_CHECKS(monitorId)).to.equal(`No checks found for monitor with id ${monitorId}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("messages - successMessages", function () {
|
||||
it("should have a MONITOR_GET_BY_USER_ID function", function () {
|
||||
const userId = "12345";
|
||||
expect(successMessages.MONITOR_GET_BY_USER_ID(userId)).to.equal(
|
||||
`Got monitor for ${userId} successfully"`
|
||||
);
|
||||
expect(successMessages.MONITOR_GET_BY_USER_ID(userId)).to.equal(`Got monitor for ${userId} successfully"`);
|
||||
});
|
||||
|
||||
// Add more tests for other success messages as needed
|
||||
|
||||
@@ -15,9 +15,7 @@ const calculatePercentileUptimeDetails = (arr, percentile) => {
|
||||
const upper = lower + 1;
|
||||
const weight = index % 1;
|
||||
if (upper >= sorted.length) return sorted[lower].avgResponseTime;
|
||||
return (
|
||||
sorted[lower].avgResponseTime * (1 - weight) + sorted[upper].avgResponseTime * weight
|
||||
);
|
||||
return sorted[lower].avgResponseTime * (1 - weight) + sorted[upper].avgResponseTime * weight;
|
||||
};
|
||||
|
||||
const NormalizeData = (checks, rangeMin, rangeMax) => {
|
||||
@@ -28,15 +26,11 @@ const NormalizeData = (checks, rangeMin, rangeMax) => {
|
||||
const normalizedChecks = checks.map((check) => {
|
||||
const originalResponseTime = check.responseTime;
|
||||
// Normalize the response time between 1 and 100
|
||||
let normalizedResponseTime =
|
||||
rangeMin + ((check.responseTime - min) * (rangeMax - rangeMin)) / (max - min);
|
||||
let normalizedResponseTime = rangeMin + ((check.responseTime - min) * (rangeMax - rangeMin)) / (max - min);
|
||||
|
||||
// Put a floor on the response times so we don't have extreme outliers
|
||||
// Better visuals
|
||||
normalizedResponseTime = Math.max(
|
||||
rangeMin,
|
||||
Math.min(rangeMax, normalizedResponseTime)
|
||||
);
|
||||
normalizedResponseTime = Math.max(rangeMin, Math.min(rangeMax, normalizedResponseTime));
|
||||
return {
|
||||
...check,
|
||||
responseTime: normalizedResponseTime,
|
||||
@@ -60,15 +54,11 @@ const NormalizeDataUptimeDetails = (checks, rangeMin, rangeMax) => {
|
||||
const normalizedChecks = checks.map((check) => {
|
||||
const originalResponseTime = check.avgResponseTime;
|
||||
// Normalize the response time between 1 and 100
|
||||
let normalizedResponseTime =
|
||||
rangeMin + ((check.avgResponseTime - min) * (rangeMax - rangeMin)) / (max - min);
|
||||
let normalizedResponseTime = rangeMin + ((check.avgResponseTime - min) * (rangeMax - rangeMin)) / (max - min);
|
||||
|
||||
// Put a floor on the response times so we don't have extreme outliers
|
||||
// Better visuals
|
||||
normalizedResponseTime = Math.max(
|
||||
rangeMin,
|
||||
Math.min(rangeMax, normalizedResponseTime)
|
||||
);
|
||||
normalizedResponseTime = Math.max(rangeMin, Math.min(rangeMax, normalizedResponseTime));
|
||||
return {
|
||||
...check,
|
||||
avgResponseTime: normalizedResponseTime,
|
||||
@@ -107,10 +97,4 @@ const safelyParseFloat = (value, defaultValue = 0) => {
|
||||
return parsedValue;
|
||||
};
|
||||
|
||||
export {
|
||||
safelyParseFloat,
|
||||
calculatePercentile,
|
||||
NormalizeData,
|
||||
calculatePercentileUptimeDetails,
|
||||
NormalizeDataUptimeDetails,
|
||||
};
|
||||
export { safelyParseFloat, calculatePercentile, NormalizeData, calculatePercentileUptimeDetails, NormalizeDataUptimeDetails };
|
||||
|
||||
@@ -10,67 +10,31 @@ class AppError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export const createError = (
|
||||
message,
|
||||
status = 500,
|
||||
service = null,
|
||||
method = null,
|
||||
details = null
|
||||
) => {
|
||||
export const createError = (message, status = 500, service = null, method = null, details = null) => {
|
||||
return new AppError(message, status, service, method, details);
|
||||
};
|
||||
|
||||
export const createValidationError = (
|
||||
message,
|
||||
details = null,
|
||||
service = null,
|
||||
method = null
|
||||
) => {
|
||||
export const createValidationError = (message, details = null, service = null, method = null) => {
|
||||
return createError(message, 422, service, method, details);
|
||||
};
|
||||
|
||||
export const createAuthError = (
|
||||
message,
|
||||
details = null,
|
||||
service = null,
|
||||
method = null
|
||||
) => {
|
||||
export const createAuthError = (message, details = null, service = null, method = null) => {
|
||||
return createError(message, 401, service, method, details);
|
||||
};
|
||||
|
||||
export const createForbiddenError = (
|
||||
message,
|
||||
details = null,
|
||||
service = null,
|
||||
method = null
|
||||
) => {
|
||||
export const createForbiddenError = (message, details = null, service = null, method = null) => {
|
||||
return createError(message, 403, service, method, details);
|
||||
};
|
||||
|
||||
export const createNotFoundError = (
|
||||
message,
|
||||
details = null,
|
||||
service = null,
|
||||
method = null
|
||||
) => {
|
||||
export const createNotFoundError = (message, details = null, service = null, method = null) => {
|
||||
return createError(message, 404, service, method, details);
|
||||
};
|
||||
|
||||
export const createConflictError = (
|
||||
message,
|
||||
details = null,
|
||||
service = null,
|
||||
method = null
|
||||
) => {
|
||||
export const createConflictError = (message, details = null, service = null, method = null) => {
|
||||
return createError(message, 409, service, method, details);
|
||||
};
|
||||
|
||||
export const createServerError = (
|
||||
message,
|
||||
details = null,
|
||||
service = null,
|
||||
method = null
|
||||
) => {
|
||||
export const createServerError = (message, details = null, service = null, method = null) => {
|
||||
return createError(message, 500, service, method, details);
|
||||
};
|
||||
|
||||
@@ -81,12 +45,7 @@ export const asyncHandler = (fn, serviceName, methodName) => {
|
||||
} catch (error) {
|
||||
// Handle validation errors
|
||||
if (error.isJoi || error.name === "ValidationError") {
|
||||
const validationError = createValidationError(
|
||||
error.message,
|
||||
error.details,
|
||||
serviceName,
|
||||
methodName
|
||||
);
|
||||
const validationError = createValidationError(error.message, error.details, serviceName, methodName);
|
||||
return next(validationError);
|
||||
}
|
||||
|
||||
@@ -107,10 +66,7 @@ export const asyncHandler = (fn, serviceName, methodName) => {
|
||||
}
|
||||
|
||||
// For unknown errors, create a server error
|
||||
const appError = createServerError(
|
||||
error.message || "An unexpected error occurred",
|
||||
{ originalError: error.message, stack: error.stack }
|
||||
);
|
||||
const appError = createServerError(error.message || "An unexpected error occurred", { originalError: error.message, stack: error.stack });
|
||||
appError.service = serviceName;
|
||||
appError.method = methodName;
|
||||
appError.stack = error.stack; // Preserve original stack
|
||||
|
||||
@@ -6,43 +6,41 @@ class Logger {
|
||||
constructor() {
|
||||
this.logCache = [];
|
||||
this.maxCacheSize = 1000;
|
||||
const consoleFormat = format.printf(
|
||||
({ level, message, service, method, details, timestamp, stack }) => {
|
||||
if (message instanceof Object) {
|
||||
message = JSON.stringify(message, null, 2);
|
||||
}
|
||||
|
||||
if (details instanceof Object) {
|
||||
details = JSON.stringify(details, null, 2);
|
||||
}
|
||||
let msg = `${timestamp} ${level}:`;
|
||||
service && (msg += ` [${service}]`);
|
||||
method && (msg += `(${method})`);
|
||||
message && (msg += ` ${message}`);
|
||||
details && (msg += ` (details: ${details})`);
|
||||
|
||||
if (typeof stack !== "undefined") {
|
||||
const stackTrace = stack
|
||||
?.split("\n")
|
||||
.slice(1) // Remove first line (error message)
|
||||
.map((line) => {
|
||||
const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
|
||||
if (match) {
|
||||
return {
|
||||
function: match[1],
|
||||
file: match[2],
|
||||
line: parseInt(match[3]),
|
||||
column: parseInt(match[4]),
|
||||
};
|
||||
}
|
||||
return line.trim();
|
||||
});
|
||||
stack && (msg += ` (stack: ${JSON.stringify(stackTrace, null, 2)})`);
|
||||
}
|
||||
|
||||
return msg;
|
||||
const consoleFormat = format.printf(({ level, message, service, method, details, timestamp, stack }) => {
|
||||
if (message instanceof Object) {
|
||||
message = JSON.stringify(message, null, 2);
|
||||
}
|
||||
);
|
||||
|
||||
if (details instanceof Object) {
|
||||
details = JSON.stringify(details, null, 2);
|
||||
}
|
||||
let msg = `${timestamp} ${level}:`;
|
||||
service && (msg += ` [${service}]`);
|
||||
method && (msg += `(${method})`);
|
||||
message && (msg += ` ${message}`);
|
||||
details && (msg += ` (details: ${details})`);
|
||||
|
||||
if (typeof stack !== "undefined") {
|
||||
const stackTrace = stack
|
||||
?.split("\n")
|
||||
.slice(1) // Remove first line (error message)
|
||||
.map((line) => {
|
||||
const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
|
||||
if (match) {
|
||||
return {
|
||||
function: match[1],
|
||||
file: match[2],
|
||||
line: parseInt(match[3]),
|
||||
column: parseInt(match[4]),
|
||||
};
|
||||
}
|
||||
return line.trim();
|
||||
});
|
||||
stack && (msg += ` (stack: ${JSON.stringify(stackTrace, null, 2)})`);
|
||||
}
|
||||
|
||||
return msg;
|
||||
});
|
||||
|
||||
const logLevel = process.env.LOG_LEVEL || "info";
|
||||
|
||||
@@ -51,12 +49,7 @@ class Logger {
|
||||
format: format.combine(format.timestamp()),
|
||||
transports: [
|
||||
new transports.Console({
|
||||
format: format.combine(
|
||||
format.colorize(),
|
||||
format.prettyPrint(),
|
||||
format.json(),
|
||||
consoleFormat
|
||||
),
|
||||
format: format.combine(format.colorize(), format.prettyPrint(), format.json(), consoleFormat),
|
||||
}),
|
||||
new transports.File({
|
||||
format: format.combine(format.json()),
|
||||
|
||||
@@ -6,12 +6,7 @@
|
||||
const ParseBoolean = (value) => {
|
||||
if (value === true || value === "true") {
|
||||
return true;
|
||||
} else if (
|
||||
value === false ||
|
||||
value === "false" ||
|
||||
value === null ||
|
||||
value === undefined
|
||||
) {
|
||||
} else if (value === false || value === "false" || value === null || value === undefined) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -21,8 +16,7 @@ const getTokenFromHeaders = (headers) => {
|
||||
if (!authorizationHeader) throw new Error("No auth headers");
|
||||
|
||||
const parts = authorizationHeader.split(" ");
|
||||
if (parts.length !== 2 || parts[0] !== "Bearer")
|
||||
throw new Error("Invalid auth headers");
|
||||
if (parts.length !== 2 || parts[0] !== "Bearer") throw new Error("Invalid auth headers");
|
||||
|
||||
return parts[1];
|
||||
};
|
||||
|
||||
@@ -7,9 +7,7 @@ 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(", ")}`
|
||||
);
|
||||
throw new joi.ValidationError(`You do not have the required authorization. Required roles: ${role.join(", ")}`);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
@@ -134,11 +132,7 @@ const getMonitorsByTeamIdQueryValidation = joi.object({
|
||||
.alternatives()
|
||||
.try(
|
||||
joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port"),
|
||||
joi
|
||||
.array()
|
||||
.items(
|
||||
joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port")
|
||||
)
|
||||
joi.array().items(joi.string().valid("http", "ping", "pagespeed", "docker", "hardware", "port"))
|
||||
),
|
||||
page: joi.number(),
|
||||
rowsPerPage: joi.number(),
|
||||
@@ -454,8 +448,7 @@ const createStatusPageBodyValidation = joi.object({
|
||||
.pattern(/^[a-zA-Z0-9_-]+$/) // Only allow alphanumeric, underscore, and hyphen
|
||||
.required()
|
||||
.messages({
|
||||
"string.pattern.base":
|
||||
"URL can only contain letters, numbers, underscores, and hyphens",
|
||||
"string.pattern.base": "URL can only contain letters, numbers, underscores, and hyphens",
|
||||
}),
|
||||
timezone: joi.string().optional(),
|
||||
color: joi.string().optional(),
|
||||
@@ -485,13 +478,9 @@ const imageValidation = joi
|
||||
fieldname: joi.string().required(),
|
||||
originalname: joi.string().required(),
|
||||
encoding: joi.string().required(),
|
||||
mimetype: joi
|
||||
.string()
|
||||
.valid("image/jpeg", "image/png", "image/jpg")
|
||||
.required()
|
||||
.messages({
|
||||
"string.valid": "File must be a valid image (jpeg, jpg, or png)",
|
||||
}),
|
||||
mimetype: joi.string().valid("image/jpeg", "image/png", "image/jpg").required().messages({
|
||||
"string.valid": "File must be a valid image (jpeg, jpg, or png)",
|
||||
}),
|
||||
size: joi.number().max(3145728).required().messages({
|
||||
"number.max": "File size must be less than 3MB",
|
||||
}),
|
||||
@@ -578,15 +567,11 @@ const createNotificationBodyValidation = joi.object({
|
||||
"any.required": "Notification name is required",
|
||||
}),
|
||||
|
||||
type: joi
|
||||
.string()
|
||||
.valid("email", "webhook", "slack", "discord", "pager_duty")
|
||||
.required()
|
||||
.messages({
|
||||
"string.empty": "Notification type is required",
|
||||
"any.required": "Notification type is required",
|
||||
"any.only": "Notification type must be email, webhook, or pager_duty",
|
||||
}),
|
||||
type: joi.string().valid("email", "webhook", "slack", "discord", "pager_duty").required().messages({
|
||||
"string.empty": "Notification type is required",
|
||||
"any.required": "Notification type is required",
|
||||
"any.only": "Notification type must be email, webhook, or pager_duty",
|
||||
}),
|
||||
|
||||
address: joi.when("type", {
|
||||
is: "email",
|
||||
|
||||
Reference in New Issue
Block a user