mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-22 01:29:57 -06:00
refactor to monitor service
This commit is contained in:
@@ -4,8 +4,6 @@ import {
|
||||
getMonitorsByTeamIdParamValidation,
|
||||
getMonitorsByTeamIdQueryValidation,
|
||||
createMonitorBodyValidation,
|
||||
createMonitorsBodyValidation,
|
||||
getMonitorURLByQueryValidation,
|
||||
editMonitorBodyValidation,
|
||||
pauseMonitorParamValidation,
|
||||
getMonitorStatsByIdParamValidation,
|
||||
@@ -15,21 +13,18 @@ import {
|
||||
getHardwareDetailsByIdQueryValidation,
|
||||
} from "../validation/joi.js";
|
||||
import sslChecker from "ssl-checker";
|
||||
import logger from "../utils/logger.js";
|
||||
import axios from "axios";
|
||||
import seedDb from "../db/mongo/utils/seedDb.js";
|
||||
import pkg from "papaparse";
|
||||
import { asyncHandler, createServerError } from "../utils/errorUtils.js";
|
||||
import { asyncHandler } from "../utils/errorUtils.js";
|
||||
import { fetchMonitorCertificate } from "./controllerUtils.js";
|
||||
|
||||
const SERVICE_NAME = "monitorController";
|
||||
class MonitorController {
|
||||
constructor(db, settingsService, jobQueue, stringService, emailService) {
|
||||
constructor({ db, settingsService, jobQueue, stringService, emailService, monitorService }) {
|
||||
this.db = db;
|
||||
this.settingsService = settingsService;
|
||||
this.jobQueue = jobQueue;
|
||||
this.stringService = stringService;
|
||||
this.emailService = emailService;
|
||||
this.monitorService = monitorService;
|
||||
}
|
||||
|
||||
async verifyTeamAccess(teamId, monitorId) {
|
||||
@@ -41,18 +36,9 @@ class MonitorController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all monitors
|
||||
* @async
|
||||
* @param {Express.Request} req
|
||||
* @param {Express.Response} res
|
||||
* @param {function} next
|
||||
* @returns {Promise<Express.Response>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
getAllMonitors = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
const monitors = await this.db.getAllMonitors();
|
||||
async (req, res) => {
|
||||
const monitors = await this.monitorService.getAllMonitors();
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetAll,
|
||||
data: monitors,
|
||||
@@ -63,56 +49,47 @@ class MonitorController {
|
||||
);
|
||||
|
||||
getUptimeDetailsById = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
const { monitorId } = req.params;
|
||||
const { dateRange, normalize } = req.query;
|
||||
async (req, res) => {
|
||||
const monitorId = req?.params?.monitorId;
|
||||
const dateRange = req?.query?.dateRange;
|
||||
const normalize = req?.query?.normalize;
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
await this.verifyTeamAccess(teamId, monitorId);
|
||||
|
||||
const data = await this.db.getUptimeDetailsById({
|
||||
const data = await this.monitorService.getUptimeDetailsById({
|
||||
teamId,
|
||||
monitorId,
|
||||
dateRange,
|
||||
normalize,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data,
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getUptimeDetailsById"
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns monitor stats for monitor with matching ID
|
||||
* @async
|
||||
* @param {Express.Request} req
|
||||
* @param {Express.Response} res
|
||||
* @param {function} next
|
||||
* @returns {Promise<Express.Response>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
getMonitorStatsById = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getMonitorStatsByIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorStatsByIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
let { limit, sortOrder, dateRange, numToDisplay, normalize } = req.query;
|
||||
const { monitorId } = req.params;
|
||||
const monitorId = req?.params?.monitorId;
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
await this.verifyTeamAccess(teamId, monitorId);
|
||||
|
||||
const monitorStats = await this.db.getMonitorStatsById({
|
||||
const monitorStats = await this.monitorService.getMonitorStatsById({
|
||||
teamId,
|
||||
monitorId,
|
||||
limit,
|
||||
sortOrder,
|
||||
@@ -120,6 +97,7 @@ class MonitorController {
|
||||
numToDisplay,
|
||||
normalize,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorStatsById,
|
||||
data: monitorStats,
|
||||
@@ -139,7 +117,7 @@ class MonitorController {
|
||||
* @throws {Error} - Throws error if monitor not found or other database errors
|
||||
*/
|
||||
getHardwareDetailsById = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getHardwareDetailsByIdParamValidation.validateAsync(req.params);
|
||||
await getHardwareDetailsByIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
@@ -150,8 +128,12 @@ class MonitorController {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
await this.verifyTeamAccess(teamId, monitorId);
|
||||
const monitor = await this.db.getHardwareDetailsById({ monitorId, dateRange });
|
||||
const monitor = await this.monitorService.getHardwareDetailsById({
|
||||
teamId,
|
||||
monitorId,
|
||||
dateRange,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
data: monitor,
|
||||
@@ -180,34 +162,17 @@ class MonitorController {
|
||||
"getMonitorCertificate"
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieves a monitor by its ID.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.params - The parameters of the request.
|
||||
* @property {string} req.params.monitorId - The ID of the monitor to be retrieved.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status, a message, and the retrieved monitor data.
|
||||
* @throws {Error} If there is an error during the process, especially if the monitor is not found (404) or if there is a validation error (422).
|
||||
*/
|
||||
getMonitorById = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getMonitorByIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorByIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const monitor = await this.db.getMonitorById(req.params.monitorId);
|
||||
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
if (!monitor.teamId.equals(teamId)) {
|
||||
const error = new Error("Unauthorized");
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId: req?.params?.monitorId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByIdSuccess,
|
||||
@@ -218,30 +183,15 @@ class MonitorController {
|
||||
"getMonitorById"
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a new monitor and adds it to the job queue.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.body - The body of the request.
|
||||
* @property {Array} req.body.notifications - The notifications associated with the monitor.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status, a message indicating the creation of the monitor, and the created monitor data.
|
||||
* @throws {Error} If there is an error during the process, especially if there is a validation error (422).
|
||||
*/
|
||||
createMonitor = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await createMonitorBodyValidation.validateAsync(req.body);
|
||||
|
||||
const { _id, teamId } = req.user;
|
||||
const monitor = await this.db.createMonitor({
|
||||
body: req.body,
|
||||
teamId,
|
||||
userId: _id,
|
||||
});
|
||||
const userId = req?.user?._id;
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
const monitor = await this.monitorService.createMonitor({ teamId, userId, body: req.body });
|
||||
|
||||
// Add monitor to job queue
|
||||
this.jobQueue.addJob(monitor._id, monitor);
|
||||
return res.success({
|
||||
msg: this.stringService.monitorCreate,
|
||||
data: monitor,
|
||||
@@ -251,141 +201,45 @@ class MonitorController {
|
||||
"createMonitor"
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates bulk monitors and adds them to the job queue after parsing CSV.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.file - The uploaded CSV file.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status and message.
|
||||
* @throws {Error} If there is an error during the process, especially if there is a validation error (422).
|
||||
*/
|
||||
createBulkMonitors = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
const { parse } = pkg;
|
||||
|
||||
// validate the file
|
||||
async (req, res) => {
|
||||
if (!req.file) {
|
||||
throw new Error("No file uploaded");
|
||||
}
|
||||
|
||||
// Check if the file is a CSV
|
||||
if (!req.file.mimetype.includes("csv")) {
|
||||
throw new Error("File is not a CSV");
|
||||
}
|
||||
|
||||
// Validate if the file is empty
|
||||
if (req.file.size === 0) {
|
||||
throw new Error("File is empty");
|
||||
}
|
||||
|
||||
const { _id, teamId } = req.user;
|
||||
const userId = req?.user?._id;
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
if (!_id || !teamId) {
|
||||
if (!userId || !teamId) {
|
||||
throw new Error("Missing userId or teamId");
|
||||
}
|
||||
|
||||
// Get file buffer from memory and convert to string
|
||||
const fileData = req.file.buffer.toString("utf-8");
|
||||
const fileData = req?.file?.buffer?.toString("utf-8");
|
||||
if (!fileData) {
|
||||
throw new Error("Cannot get file from buffer");
|
||||
}
|
||||
|
||||
// Parse the CSV data
|
||||
parse(fileData, {
|
||||
header: true,
|
||||
skipEmptyLines: true,
|
||||
transform: (value, header) => {
|
||||
if (value === "") return undefined; // Empty fields become undefined
|
||||
const monitors = await this.monitorService.createBulkMonitors({ fileData, userId, teamId });
|
||||
|
||||
// Handle 'port' and 'interval' fields, check if they're valid numbers
|
||||
if (["port", "interval"].includes(header)) {
|
||||
const num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
throw new Error(`${header} should be a valid number, got: ${value}`);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
complete: async ({ data, errors }) => {
|
||||
if (errors.length > 0) {
|
||||
throw createServerError("Error parsing CSV");
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
throw createServerError("CSV file contains no data rows");
|
||||
}
|
||||
|
||||
const enrichedData = data.map((monitor) => ({
|
||||
userId: _id,
|
||||
teamId,
|
||||
...monitor,
|
||||
description: monitor.description || monitor.name || monitor.url,
|
||||
name: monitor.name || monitor.url,
|
||||
type: monitor.type || "http",
|
||||
}));
|
||||
|
||||
await createMonitorsBodyValidation.validateAsync(enrichedData);
|
||||
|
||||
const monitors = await this.db.createBulkMonitors(enrichedData);
|
||||
|
||||
await Promise.all(
|
||||
monitors.map(async (monitor, index) => {
|
||||
this.jobQueue.addJob(monitor._id, monitor);
|
||||
})
|
||||
);
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.bulkMonitorsCreate,
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
return res.success({
|
||||
msg: this.stringService.bulkMonitorsCreate,
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"createBulkMonitors"
|
||||
);
|
||||
/**
|
||||
* Checks if the endpoint can be resolved
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.query - The query parameters of the request.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status, a message, and the resolution result.
|
||||
* @throws {Error} If there is an error during the process, especially if there is a validation error (422).
|
||||
*/
|
||||
checkEndpointResolution = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
await getMonitorURLByQueryValidation.validateAsync(req.query);
|
||||
const { monitorURL } = req.query;
|
||||
const parsedUrl = new URL(monitorURL);
|
||||
const response = await axios.get(parsedUrl, {
|
||||
timeout: 5000,
|
||||
validateStatus: () => true,
|
||||
});
|
||||
return res.success({
|
||||
status: response.status,
|
||||
msg: response.statusText,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"checkEndpointResolution"
|
||||
);
|
||||
|
||||
/**
|
||||
* Deletes a monitor by its ID and also deletes associated checks, alerts, and notifications.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.params - The parameters of the request.
|
||||
* @property {string} req.params.monitorId - The ID of the monitor to be deleted.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status and a message indicating the deletion of the monitor.
|
||||
* @throws {Error} If there is an error during the process, especially if there is a validation error (422) or an error in deleting associated records.
|
||||
*/
|
||||
deleteMonitor = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getMonitorByIdParamValidation.validateAsync(req.params);
|
||||
const monitorId = req.params.monitorId;
|
||||
const teamId = req?.user?.teamId;
|
||||
@@ -393,70 +247,31 @@ class MonitorController {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
await this.verifyTeamAccess(teamId, monitorId);
|
||||
const deletedMonitor = await this.monitorService.deleteMonitor({ teamId, monitorId });
|
||||
|
||||
const monitor = await this.db.deleteMonitor({ monitorId });
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.deleteStatusPagesByMonitorId(monitor._id);
|
||||
return res.success({ msg: this.stringService.monitorDelete });
|
||||
return res.success({ msg: this.stringService.monitorDelete, data: deletedMonitor });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteMonitor"
|
||||
);
|
||||
|
||||
/**
|
||||
* Deletes all monitors associated with a team.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.headers - The headers of the request.
|
||||
* @property {string} req.headers.authorization - The authorization header containing the JWT token.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next
|
||||
* @returns {Object} The response object with a success status and a message indicating the number of deleted monitors.
|
||||
* @throws {Error} If there is an error during the deletion process.
|
||||
*/
|
||||
deleteAllMonitors = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
const teamId = req?.user?.teamId;
|
||||
const { monitors, deletedCount } = await this.db.deleteAllMonitors(teamId);
|
||||
await Promise.all(
|
||||
monitors.map(async (monitor) => {
|
||||
try {
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.deleteChecks(monitor._id);
|
||||
await this.db.deletePageSpeedChecksByMonitorId(monitor._id);
|
||||
await this.db.deleteNotificationsByMonitorId(monitor._id);
|
||||
} catch (error) {
|
||||
logger.warn({
|
||||
message: `Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "deleteAllMonitors",
|
||||
stack: error.stack,
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
const deletedCount = await this.monitorService.deleteAllMonitors({ teamId });
|
||||
|
||||
return res.success({ msg: `Deleted ${deletedCount} monitors` });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"deleteAllMonitors"
|
||||
);
|
||||
|
||||
/**
|
||||
* Edits a monitor by its ID, updates its notifications, and updates its job in the job queue.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.params - The parameters of the request.
|
||||
* @property {string} req.params.monitorId - The ID of the monitor to be edited.
|
||||
* @property {Object} req.body - The body of the request.
|
||||
* @property {Array} req.body.notifications - The notifications to be associated with the monitor.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status, a message indicating the editing of the monitor, and the edited monitor data.
|
||||
* @throws {Error} If there is an error during the process, especially if there is a validation error (422).
|
||||
*/
|
||||
editMonitor = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getMonitorByIdParamValidation.validateAsync(req.params);
|
||||
await editMonitorBodyValidation.validateAsync(req.body);
|
||||
const monitorId = req?.params?.monitorId;
|
||||
@@ -466,11 +281,7 @@ class MonitorController {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
await this.verifyTeamAccess(teamId, monitorId);
|
||||
|
||||
const editedMonitor = await this.db.editMonitor(monitorId, req.body);
|
||||
|
||||
await this.jobQueue.updateJob(editedMonitor);
|
||||
const editedMonitor = await this.monitorService.editMonitor({ teamId, monitorId, body: req.body });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorEdit,
|
||||
@@ -481,19 +292,8 @@ class MonitorController {
|
||||
"editMonitor"
|
||||
);
|
||||
|
||||
/**
|
||||
* Pauses or resumes a monitor based on its current state.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.params - The parameters of the request.
|
||||
* @property {string} req.params.monitorId - The ID of the monitor to be paused or resumed.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status, a message indicating the new state of the monitor, and the updated monitor data.
|
||||
* @throws {Error} If there is an error during the process.
|
||||
*/
|
||||
pauseMonitor = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await pauseMonitorParamValidation.validateAsync(req.params);
|
||||
|
||||
const monitorId = req.params.monitorId;
|
||||
@@ -502,10 +302,7 @@ class MonitorController {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
await this.verifyTeamAccess(teamId, monitorId);
|
||||
|
||||
const monitor = await this.db.pauseMonitor({ monitorId });
|
||||
monitor.isActive === true ? await this.jobQueue.resumeJob(monitor._id, monitor) : await this.jobQueue.pauseJob(monitor);
|
||||
const monitor = await this.monitorService.pauseMonitor({ teamId, monitorId });
|
||||
|
||||
return res.success({
|
||||
msg: monitor.isActive ? this.stringService.monitorResume : this.stringService.monitorPause,
|
||||
@@ -516,60 +313,28 @@ class MonitorController {
|
||||
"pauseMonitor"
|
||||
);
|
||||
|
||||
/**
|
||||
* Adds demo monitors for a team.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.headers - The headers of the request.
|
||||
* @property {string} req.headers.authorization - The authorization header containing the JWT token.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status, a message indicating the addition of demo monitors, and the number of demo monitors added.
|
||||
* @throws {Error} If there is an error during the process.
|
||||
*/
|
||||
addDemoMonitors = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
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)));
|
||||
const demoMonitors = await this.monitorService.addDemoMonitors({ userId: _id, teamId });
|
||||
|
||||
return res.success({
|
||||
msg: this.stringService.monitorDemoAdded,
|
||||
data: demoMonitors.length,
|
||||
data: demoMonitors?.length ?? 0,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"addDemoMonitors"
|
||||
);
|
||||
|
||||
/**
|
||||
* Sends a test email to verify email delivery functionality.
|
||||
* @async
|
||||
* @param {Object} req - The Express request object.
|
||||
* @property {Object} req.body - The body of the request.
|
||||
* @property {string} req.body.to - The email address to send the test email to.
|
||||
* @param {Object} res - The Express response object.
|
||||
* @param {function} next - The next middleware function.
|
||||
* @returns {Object} The response object with a success status and the email delivery message ID.
|
||||
* @throws {Error} If there is an error while sending the test email.
|
||||
*/
|
||||
sendTestEmail = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
const { to } = req.body;
|
||||
if (!to || typeof to !== "string") {
|
||||
throw new Error(this.stringService.errorForValidEmailAddress);
|
||||
}
|
||||
|
||||
const subject = this.stringService.testEmailSubject;
|
||||
const context = { testName: "Monitoring System" };
|
||||
|
||||
const html = await this.emailService.buildEmail("testEmailTemplate", context);
|
||||
const messageId = await this.emailService.sendEmail(to, subject, html);
|
||||
|
||||
if (!messageId) {
|
||||
throw createServerError("Failed to send test email.");
|
||||
}
|
||||
|
||||
const messageId = await this.monitorService.sendTestEmail({ to });
|
||||
return res.success({
|
||||
msg: this.stringService.sendTestEmail,
|
||||
data: { messageId },
|
||||
@@ -585,18 +350,10 @@ class MonitorController {
|
||||
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const teamId = req.user.teamId;
|
||||
const teamId = req?.user?.teamId;
|
||||
|
||||
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId, limit, type, page, rowsPerPage, filter, field, order });
|
||||
|
||||
const monitors = await this.db.getMonitorsByTeamId({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: this.stringService.monitorGetByTeamId,
|
||||
data: monitors,
|
||||
@@ -607,19 +364,19 @@ class MonitorController {
|
||||
);
|
||||
|
||||
getMonitorsAndSummaryByTeamId = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const { explain } = req;
|
||||
const { type } = req.query;
|
||||
const { teamId } = req.user;
|
||||
const explain = req?.query?.explain;
|
||||
const type = req?.query?.type;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
const result = await this.monitorService.getMonitorsAndSummaryByTeamId({ teamId, type, explain });
|
||||
|
||||
const result = await this.db.getMonitorsAndSummaryByTeamId({
|
||||
type,
|
||||
explain,
|
||||
teamId,
|
||||
});
|
||||
return res.success({
|
||||
msg: "OK", // TODO
|
||||
data: result,
|
||||
@@ -630,15 +387,19 @@ class MonitorController {
|
||||
);
|
||||
|
||||
getMonitorsWithChecksByTeamId = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
await getMonitorsByTeamIdParamValidation.validateAsync(req.params);
|
||||
await getMonitorsByTeamIdQueryValidation.validateAsync(req.query);
|
||||
|
||||
const { explain } = req;
|
||||
const explain = req?.query?.explain;
|
||||
let { limit, type, page, rowsPerPage, filter, field, order } = req.query;
|
||||
const { teamId } = req.user;
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
|
||||
const result = await this.db.getMonitorsWithChecksByTeamId({
|
||||
const monitors = await this.monitorService.getMonitorsWithChecksByTeamId({
|
||||
teamId,
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
@@ -646,51 +407,26 @@ class MonitorController {
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
explain,
|
||||
});
|
||||
|
||||
return res.success({
|
||||
msg: "OK",
|
||||
data: result,
|
||||
data: monitors,
|
||||
});
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"getMonitorsWithChecksByTeamId"
|
||||
);
|
||||
|
||||
seedDb = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
const { _id, teamId } = req.user;
|
||||
await seedDb(_id, teamId);
|
||||
res.success({ msg: "Database seeded" });
|
||||
},
|
||||
SERVICE_NAME,
|
||||
"seedDb"
|
||||
);
|
||||
|
||||
exportMonitorsToCSV = asyncHandler(
|
||||
async (req, res, next) => {
|
||||
const { teamId } = req.user;
|
||||
|
||||
const monitors = await this.db.getMonitorsByTeamId({ teamId });
|
||||
if (!monitors || monitors.length === 0) {
|
||||
return res.success({
|
||||
msg: this.stringService.noMonitorsFound,
|
||||
data: null,
|
||||
});
|
||||
async (req, res) => {
|
||||
const teamId = req?.user?.teamId;
|
||||
if (!teamId) {
|
||||
throw new Error("Team ID is required");
|
||||
}
|
||||
const csvData = monitors?.filteredMonitors?.map((monitor) => ({
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
type: monitor.type,
|
||||
url: monitor.url,
|
||||
interval: monitor.interval,
|
||||
port: monitor.port,
|
||||
ignoreTlsErrors: monitor.ignoreTlsErrors,
|
||||
isActive: monitor.isActive,
|
||||
}));
|
||||
|
||||
const csv = pkg.unparse(csvData);
|
||||
const csv = await this.monitorService.exportMonitorsToCSV({ teamId });
|
||||
|
||||
return res.file({
|
||||
data: csv,
|
||||
|
||||
@@ -126,18 +126,22 @@ MonitorSchema.pre("findOneAndDelete", async function (next) {
|
||||
try {
|
||||
const doc = await this.model.findOne(this.getFilter());
|
||||
|
||||
if (doc.type === "pagespeed") {
|
||||
if (!doc) {
|
||||
throw new Error("Monitor not found");
|
||||
}
|
||||
|
||||
if (doc?.type === "pagespeed") {
|
||||
await PageSpeedCheck.deleteMany({ monitorId: doc._id });
|
||||
} else if (doc.type === "hardware") {
|
||||
} else if (doc?.type === "hardware") {
|
||||
await HardwareCheck.deleteMany({ monitorId: doc._id });
|
||||
} else {
|
||||
await Check.deleteMany({ monitorId: doc._id });
|
||||
}
|
||||
|
||||
// Deal with status pages
|
||||
await StatusPage.updateMany({ monitors: doc._id }, { $pull: { monitors: doc._id } });
|
||||
await StatusPage.updateMany({ monitors: doc?._id }, { $pull: { monitors: doc?._id } });
|
||||
|
||||
await MonitorStats.deleteMany({ monitorId: doc._id.toString() });
|
||||
await MonitorStats.deleteMany({ monitorId: doc?._id.toString() });
|
||||
next();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
|
||||
@@ -279,7 +279,6 @@ const calculateGroupStats = (group) => {
|
||||
* @throws {Error}
|
||||
*/
|
||||
const getUptimeDetailsById = async ({ monitorId, dateRange, normalize }) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
try {
|
||||
const dates = getDateRange(dateRange);
|
||||
const formatLookup = {
|
||||
@@ -595,16 +594,16 @@ const createBulkMonitors = async (req) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const deleteMonitor = async ({ monitorId }) => {
|
||||
const deleteMonitor = async ({ teamId, monitorId }) => {
|
||||
const stringService = ServiceRegistry.get(StringService.SERVICE_NAME);
|
||||
try {
|
||||
const monitor = await Monitor.findByIdAndDelete(monitorId);
|
||||
const deletedMonitor = await Monitor.findOneAndDelete({ _id: monitorId, teamId });
|
||||
|
||||
if (!monitor) {
|
||||
if (!deletedMonitor) {
|
||||
throw new Error(stringService.getDbFindMonitorById(monitorId));
|
||||
}
|
||||
|
||||
return monitor;
|
||||
return deletedMonitor;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "deleteMonitor";
|
||||
@@ -654,9 +653,9 @@ const deleteMonitorsByUserId = async (userId) => {
|
||||
* @returns {Promise<Monitor>}
|
||||
* @throws {Error}
|
||||
*/
|
||||
const editMonitor = async (candidateId, candidateMonitor) => {
|
||||
const editMonitor = async ({ monitorId, body }) => {
|
||||
try {
|
||||
const editedMonitor = await Monitor.findByIdAndUpdate(candidateId, candidateMonitor, {
|
||||
const editedMonitor = await Monitor.findByIdAndUpdate(monitorId, body, {
|
||||
new: true,
|
||||
});
|
||||
return editedMonitor;
|
||||
|
||||
@@ -138,6 +138,7 @@ const buildUptimeDetailsPipeline = (monitorId, dates, dateString) => {
|
||||
{
|
||||
$project: {
|
||||
_id: 1,
|
||||
teamId: 1,
|
||||
name: 1,
|
||||
status: 1,
|
||||
interval: 1,
|
||||
|
||||
@@ -2,6 +2,7 @@ import path from "path";
|
||||
import fs from "fs";
|
||||
import swaggerUi from "swagger-ui-express";
|
||||
import jwt from "jsonwebtoken";
|
||||
import papaparse from "papaparse";
|
||||
|
||||
import express from "express";
|
||||
import helmet from "helmet";
|
||||
@@ -63,6 +64,7 @@ import CheckService from "./service/business/checkService.js";
|
||||
import DiagnosticService from "./service/business/diagnosticService.js";
|
||||
import InviteService from "./service/business/inviteService.js";
|
||||
import MaintenanceWindowService from "./service/business/maintenanceWindowService.js";
|
||||
import MonitorService from "./service/business/monitorService.js";
|
||||
|
||||
//Network service and dependencies
|
||||
import NetworkService from "./service/infrastructure/networkService.js";
|
||||
@@ -185,32 +187,6 @@ const startApp = async () => {
|
||||
|
||||
const redisService = new RedisService({ Redis: IORedis, logger });
|
||||
|
||||
// Business services
|
||||
const userService = new UserService({
|
||||
db,
|
||||
emailService,
|
||||
settingsService,
|
||||
logger,
|
||||
stringService,
|
||||
jwt,
|
||||
});
|
||||
const checkService = new CheckService({
|
||||
db,
|
||||
settingsService,
|
||||
stringService,
|
||||
});
|
||||
const diagnosticService = new DiagnosticService();
|
||||
const inviteService = new InviteService({
|
||||
db,
|
||||
settingsService,
|
||||
emailService,
|
||||
stringService,
|
||||
});
|
||||
const maintenanceWindowService = new MaintenanceWindowService({
|
||||
db,
|
||||
settingsService,
|
||||
stringService,
|
||||
});
|
||||
// const jobQueueHelper = new JobQueueHelper({
|
||||
// redisService,
|
||||
// Queue,
|
||||
@@ -256,6 +232,41 @@ const startApp = async () => {
|
||||
helper: superSimpleQueueHelper,
|
||||
});
|
||||
|
||||
// Business services
|
||||
const userService = new UserService({
|
||||
db,
|
||||
emailService,
|
||||
settingsService,
|
||||
logger,
|
||||
stringService,
|
||||
jwt,
|
||||
});
|
||||
const checkService = new CheckService({
|
||||
db,
|
||||
settingsService,
|
||||
stringService,
|
||||
});
|
||||
const diagnosticService = new DiagnosticService();
|
||||
const inviteService = new InviteService({
|
||||
db,
|
||||
settingsService,
|
||||
emailService,
|
||||
stringService,
|
||||
});
|
||||
const maintenanceWindowService = new MaintenanceWindowService({
|
||||
db,
|
||||
settingsService,
|
||||
stringService,
|
||||
});
|
||||
const monitorService = new MonitorService({
|
||||
db,
|
||||
settingsService,
|
||||
jobQueue: superSimpleQueue,
|
||||
stringService,
|
||||
emailService,
|
||||
papaparse,
|
||||
logger,
|
||||
});
|
||||
// Register services
|
||||
// ServiceRegistry.register(JobQueue.SERVICE_NAME, jobQueue);
|
||||
// ServiceRegistry.register(JobQueue.SERVICE_NAME, pulseQueue);
|
||||
@@ -273,6 +284,7 @@ const startApp = async () => {
|
||||
ServiceRegistry.register(CheckService.SERVICE_NAME, checkService);
|
||||
ServiceRegistry.register(InviteService.SERVICE_NAME, inviteService);
|
||||
ServiceRegistry.register(MaintenanceWindowService.SERVICE_NAME, maintenanceWindowService);
|
||||
ServiceRegistry.register(MonitorService.SERVICE_NAME, monitorService);
|
||||
|
||||
await translationService.initialize();
|
||||
|
||||
@@ -296,13 +308,14 @@ const startApp = async () => {
|
||||
userService: ServiceRegistry.get(UserService.SERVICE_NAME),
|
||||
});
|
||||
|
||||
const monitorController = new MonitorController(
|
||||
ServiceRegistry.get(MongoDB.SERVICE_NAME),
|
||||
ServiceRegistry.get(SettingsService.SERVICE_NAME),
|
||||
ServiceRegistry.get(JobQueue.SERVICE_NAME),
|
||||
ServiceRegistry.get(StringService.SERVICE_NAME),
|
||||
ServiceRegistry.get(EmailService.SERVICE_NAME)
|
||||
);
|
||||
const monitorController = new MonitorController({
|
||||
db: ServiceRegistry.get(MongoDB.SERVICE_NAME),
|
||||
settingsService: ServiceRegistry.get(SettingsService.SERVICE_NAME),
|
||||
jobQueue: ServiceRegistry.get(JobQueue.SERVICE_NAME),
|
||||
stringService: ServiceRegistry.get(StringService.SERVICE_NAME),
|
||||
emailService: ServiceRegistry.get(EmailService.SERVICE_NAME),
|
||||
monitorService: ServiceRegistry.get(MonitorService.SERVICE_NAME),
|
||||
});
|
||||
|
||||
const settingsController = new SettingsController({
|
||||
db: ServiceRegistry.get(MongoDB.SERVICE_NAME),
|
||||
|
||||
@@ -2,9 +2,6 @@ import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import multer from "multer";
|
||||
import { fetchMonitorCertificate } from "../controllers/controllerUtils.js";
|
||||
import Monitor from "../db/models/Monitor.js";
|
||||
import { verifyOwnership } from "../middleware/verifyOwnership.js";
|
||||
import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js";
|
||||
const upload = multer({
|
||||
storage: multer.memoryStorage(), // Store file in memory as Buffer
|
||||
});
|
||||
@@ -33,7 +30,6 @@ class MonitorRoutes {
|
||||
this.router.get("/stats/:monitorId", this.monitorController.getMonitorStatsById);
|
||||
|
||||
// Util routes
|
||||
this.router.get("/resolution/url", isAllowed(["admin", "superadmin"]), this.monitorController.checkEndpointResolution);
|
||||
this.router.get("/certificate/:monitorId", (req, res, next) => {
|
||||
this.monitorController.getMonitorCertificate(req, res, next, fetchMonitorCertificate);
|
||||
});
|
||||
@@ -46,7 +42,6 @@ class MonitorRoutes {
|
||||
// Other static routes
|
||||
this.router.post("/demo", isAllowed(["admin", "superadmin"]), this.monitorController.addDemoMonitors);
|
||||
this.router.get("/export", isAllowed(["admin", "superadmin"]), this.monitorController.exportMonitorsToCSV);
|
||||
this.router.post("/seed", isAllowed(["superadmin"]), this.monitorController.seedDb);
|
||||
this.router.post("/bulk", isAllowed(["admin", "superadmin"]), upload.single("csvFile"), this.monitorController.createBulkMonitors);
|
||||
this.router.post("/test-email", isAllowed(["admin", "superadmin"]), this.monitorController.sendTestEmail);
|
||||
|
||||
|
||||
265
server/service/business/monitorService.js
Normal file
265
server/service/business/monitorService.js
Normal file
@@ -0,0 +1,265 @@
|
||||
import { createMonitorsBodyValidation } from "../../validation/joi.js";
|
||||
import { createServerError } from "../../utils/errorUtils.js";
|
||||
import logger from "../../utils/logger.js";
|
||||
|
||||
const SERVICE_NAME = "MonitorService";
|
||||
class MonitorService {
|
||||
SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
constructor({ db, settingsService, jobQueue, stringService, emailService, papaparse }) {
|
||||
this.db = db;
|
||||
this.settingsService = settingsService;
|
||||
this.jobQueue = jobQueue;
|
||||
this.stringService = stringService;
|
||||
this.emailService = emailService;
|
||||
this.papaparse = papaparse;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
verifyTeamAccess = async ({ teamId, monitorId }) => {
|
||||
const monitor = await this.db.getMonitorById(monitorId);
|
||||
if (!monitor?.teamId?.equals(teamId)) {
|
||||
const error = new Error("Unauthorized");
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
getAllMonitors = async () => {
|
||||
const monitors = await this.db.getAllMonitors();
|
||||
return monitors;
|
||||
};
|
||||
|
||||
getUptimeDetailsById = async ({ teamId, monitorId, dateRange, normalize }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const data = await this.db.getUptimeDetailsById({
|
||||
monitorId,
|
||||
dateRange,
|
||||
normalize,
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
getMonitorStatsById = async ({ teamId, monitorId, limit, sortOrder, dateRange, numToDisplay, normalize }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const monitorStats = await this.db.getMonitorStatsById({
|
||||
monitorId,
|
||||
limit,
|
||||
sortOrder,
|
||||
dateRange,
|
||||
numToDisplay,
|
||||
normalize,
|
||||
});
|
||||
|
||||
return monitorStats;
|
||||
};
|
||||
|
||||
getHardwareDetailsById = async ({ teamId, monitorId, dateRange }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const monitor = await this.db.getHardwareDetailsById({ monitorId, dateRange });
|
||||
|
||||
return monitor;
|
||||
};
|
||||
|
||||
getMonitorById = async ({ teamId, monitorId }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const monitor = await this.db.getMonitorById(monitorId);
|
||||
|
||||
return monitor;
|
||||
};
|
||||
|
||||
createMonitor = async ({ teamId, userId, body }) => {
|
||||
const monitor = await this.db.createMonitor({
|
||||
body,
|
||||
teamId,
|
||||
userId,
|
||||
});
|
||||
|
||||
this.jobQueue.addJob(monitor._id, monitor);
|
||||
};
|
||||
|
||||
createBulkMonitors = async ({ fileData, userId, teamId }) => {
|
||||
const { parse } = this.papaparse;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
parse(fileData, {
|
||||
header: true,
|
||||
skipEmptyLines: true,
|
||||
transform: (value, header) => {
|
||||
if (value === "") return undefined; // Empty fields become undefined
|
||||
|
||||
// Handle 'port' and 'interval' fields, check if they're valid numbers
|
||||
if (["port", "interval"].includes(header)) {
|
||||
const num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
throw new Error(`${header} should be a valid number, got: ${value}`);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
complete: async ({ data, errors }) => {
|
||||
try {
|
||||
if (errors.length > 0) {
|
||||
throw createServerError("Error parsing CSV");
|
||||
}
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
throw createServerError("CSV file contains no data rows");
|
||||
}
|
||||
|
||||
const enrichedData = data.map((monitor) => ({
|
||||
userId,
|
||||
teamId,
|
||||
...monitor,
|
||||
description: monitor.description || monitor.name || monitor.url,
|
||||
name: monitor.name || monitor.url,
|
||||
type: monitor.type || "http",
|
||||
}));
|
||||
|
||||
await createMonitorsBodyValidation.validateAsync(enrichedData);
|
||||
|
||||
const monitors = await this.db.createBulkMonitors(enrichedData);
|
||||
|
||||
await Promise.all(
|
||||
monitors.map(async (monitor) => {
|
||||
this.jobQueue.addJob(monitor._id, monitor);
|
||||
})
|
||||
);
|
||||
|
||||
resolve(monitors);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
deleteMonitor = async ({ teamId, monitorId }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const monitor = await this.db.deleteMonitor({ teamId, monitorId });
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.deleteStatusPagesByMonitorId(monitor._id);
|
||||
return monitor;
|
||||
};
|
||||
|
||||
deleteAllMonitors = async ({ teamId }) => {
|
||||
const { monitors, deletedCount } = await this.db.deleteAllMonitors(teamId);
|
||||
await Promise.all(
|
||||
monitors.map(async (monitor) => {
|
||||
try {
|
||||
await this.jobQueue.deleteJob(monitor);
|
||||
await this.db.deleteChecks(monitor._id);
|
||||
await this.db.deletePageSpeedChecksByMonitorId(monitor._id);
|
||||
await this.db.deleteNotificationsByMonitorId(monitor._id);
|
||||
} catch (error) {
|
||||
logger.warn({
|
||||
message: `Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "deleteAllMonitors",
|
||||
stack: error.stack,
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
return deletedCount;
|
||||
};
|
||||
|
||||
editMonitor = async ({ teamId, monitorId, body }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const editedMonitor = await this.db.editMonitor({ monitorId, body });
|
||||
await this.jobQueue.updateJob(editedMonitor);
|
||||
};
|
||||
|
||||
pauseMonitor = async ({ teamId, monitorId }) => {
|
||||
await this.verifyTeamAccess({ teamId, monitorId });
|
||||
const monitor = await this.db.pauseMonitor({ monitorId });
|
||||
monitor.isActive === true ? await this.jobQueue.resumeJob(monitor._id, monitor) : await this.jobQueue.pauseJob(monitor);
|
||||
return monitor;
|
||||
};
|
||||
|
||||
addDemoMonitors = async ({ userId, teamId }) => {
|
||||
const demoMonitors = await this.db.addDemoMonitors(userId, teamId);
|
||||
await Promise.all(demoMonitors.map((monitor) => this.jobQueue.addJob(monitor._id, monitor)));
|
||||
return demoMonitors;
|
||||
};
|
||||
|
||||
sendTestEmail = async ({ to }) => {
|
||||
const subject = this.stringService.testEmailSubject;
|
||||
const context = { testName: "Monitoring System" };
|
||||
|
||||
const html = await this.emailService.buildEmail("testEmailTemplate", context);
|
||||
const messageId = await this.emailService.sendEmail(to, subject, html);
|
||||
|
||||
if (!messageId) {
|
||||
throw createServerError("Failed to send test email.");
|
||||
}
|
||||
|
||||
return messageId;
|
||||
};
|
||||
|
||||
getMonitorsByTeamId = async ({ teamId, limit, type, page, rowsPerPage, filter, field, order }) => {
|
||||
const monitors = await this.db.getMonitorsByTeamId({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
});
|
||||
return monitors;
|
||||
};
|
||||
|
||||
getMonitorsAndSummaryByTeamId = async ({ teamId, type, explain }) => {
|
||||
const result = await this.db.getMonitorsAndSummaryByTeamId({
|
||||
type,
|
||||
explain,
|
||||
teamId,
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
getMonitorsWithChecksByTeamId = async ({ teamId, limit, type, page, rowsPerPage, filter, field, order, explain }) => {
|
||||
const result = await this.db.getMonitorsWithChecksByTeamId({
|
||||
limit,
|
||||
type,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
teamId,
|
||||
explain,
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
exportMonitorsToCSV = async ({ teamId }) => {
|
||||
const monitors = await this.monitorService.getMonitorsByTeamId({ teamId });
|
||||
|
||||
if (!monitors || monitors.length === 0) {
|
||||
throw new Error("No monitors to export");
|
||||
}
|
||||
|
||||
const csvData = monitors?.filteredMonitors?.map((monitor) => ({
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
type: monitor.type,
|
||||
url: monitor.url,
|
||||
interval: monitor.interval,
|
||||
port: monitor.port,
|
||||
ignoreTlsErrors: monitor.ignoreTlsErrors,
|
||||
isActive: monitor.isActive,
|
||||
}));
|
||||
|
||||
const csv = this.papaparse.unparse(csvData);
|
||||
return csv;
|
||||
};
|
||||
}
|
||||
|
||||
export default MonitorService;
|
||||
@@ -65,12 +65,16 @@ export const asyncHandler = (fn, serviceName, methodName) => {
|
||||
return next(appError);
|
||||
}
|
||||
|
||||
if (error.status) {
|
||||
const appError = createError(error.message, error.status, serviceName, methodName, { originalError: error.message, stack: error.stack });
|
||||
return next(appError);
|
||||
}
|
||||
|
||||
// For unknown errors, create a server error
|
||||
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
|
||||
|
||||
return next(appError);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user