258 lines
6.0 KiB
JavaScript
258 lines
6.0 KiB
JavaScript
import { ObjectId } from "mongodb";
|
|||
|
|
|
||
|
|
const SERVICE_NAME = "incidentModule";
|
||
|
|
|
||
|
|
const dateRangeLookup = {
|
||
|
|
recent: new Date(new Date().setDate(new Date().getDate() - 2)),
|
||
|
|
hour: new Date(new Date().setHours(new Date().getHours() - 1)),
|
||
|
|
day: new Date(new Date().setDate(new Date().getDate() - 1)),
|
||
|
|
week: new Date(new Date().setDate(new Date().getDate() - 7)),
|
||
|
|
month: new Date(new Date().setMonth(new Date().getMonth() - 1)),
|
||
|
|
all: undefined,
|
||
|
|
};
|
||
|
|
|
||
|
|
class IncidentModule {
|
||
|
|
constructor({ logger, Incident, Monitor, User }) {
|
||
|
|
this.logger = logger;
|
||
|
|
this.Incident = Incident;
|
||
|
|
this.Monitor = Monitor;
|
||
|
|
this.User = User;
|
||
|
|
}
|
||
|
|
|
||
|
|
createIncident = async (incidentData) => {
|
||
|
|
try {
|
||
|
|
const incident = await this.Incident.create(incidentData);
|
||
|
|
return incident;
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "createIncident";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
createIncidents = async (incidents) => {
|
||
|
|
try {
|
||
|
|
await this.Incident.insertMany(incidents, { ordered: false });
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "createIncidents";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
getActiveIncidentByMonitor = async (monitorId) => {
|
||
|
|
try {
|
||
|
|
return await this.Incident.findOne({ monitorId: new ObjectId(monitorId), status: "active" });
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "getActiveIncidentByMonitor";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
getIncidentById = async (incidentId) => {
|
||
|
|
try {
|
||
|
|
return await this.Incident.findById(incidentId)
|
||
|
|
.populate("monitorId", "name type url")
|
||
|
|
.populate("resolvedBy", "name email");
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "getIncidentById";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
resolveIncident = async (incidentId, { resolutionType = "automatic", resolvedBy = null, comment = null, endTime = new Date() } = {}) => {
|
||
|
|
try {
|
||
|
|
const update = {
|
||
|
|
status: "resolved",
|
||
|
|
endTime,
|
||
|
|
resolutionType,
|
||
|
|
resolvedBy,
|
||
|
|
...(comment !== null && { comment }),
|
||
|
|
};
|
||
|
|
const incident = await this.Incident.findOneAndUpdate(
|
||
|
|
{ _id: new ObjectId(incidentId) },
|
||
|
|
{ $set: update },
|
||
|
|
{ new: true }
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!incident) {
|
||
|
|
throw new Error("Incident not found");
|
||
|
|
}
|
||
|
|
|
||
|
|
return incident;
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "resolveIncident";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
addCheckToIncident = async (incidentId, checkId) => {
|
||
|
|
try {
|
||
|
|
const incident = await this.Incident.findOneAndUpdate(
|
||
|
|
{ _id: new ObjectId(incidentId) },
|
||
|
|
{ $addToSet: { checks: new ObjectId(checkId) } },
|
||
|
|
{ new: true }
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!incident) {
|
||
|
|
throw new Error("Incident not found");
|
||
|
|
}
|
||
|
|
|
||
|
|
return incident;
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "addCheckToIncident";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
getIncidentsByTeam = async ({ teamId, sortOrder, dateRange, filter, page, rowsPerPage, status, monitorId, resolutionType }) => {
|
||
|
|
try {
|
||
|
|
page = parseInt(page);
|
||
|
|
rowsPerPage = parseInt(rowsPerPage);
|
||
|
|
|
||
|
|
const matchStage = {
|
||
|
|
teamId: new ObjectId(teamId),
|
||
|
|
...(status && { status }),
|
||
|
|
...(monitorId && { monitorId: new ObjectId(monitorId) }),
|
||
|
|
...(resolutionType && { resolutionType }),
|
||
|
|
...(dateRangeLookup[dateRange] && {
|
||
|
|
startTime: {
|
||
|
|
$gte: dateRangeLookup[dateRange],
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
if (filter !== undefined) {
|
||
|
|
switch (filter) {
|
||
|
|
case "all":
|
||
|
|
break;
|
||
|
|
case "active":
|
||
|
|
matchStage.status = "active";
|
||
|
|
break;
|
||
|
|
case "resolved":
|
||
|
|
matchStage.status = "resolved";
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
sortOrder = sortOrder === "asc" ? 1 : -1;
|
||
|
|
|
||
|
|
let skip = 0;
|
||
|
|
if (page && rowsPerPage) {
|
||
|
|
skip = page * rowsPerPage;
|
||
|
|
}
|
||
|
|
|
||
|
|
const incidents = await this.Incident.aggregate([
|
||
|
|
{ $match: matchStage },
|
||
|
|
{ $sort: { startTime: sortOrder } },
|
||
|
|
{
|
||
|
|
$facet: {
|
||
|
|
summary: [{ $count: "incidentsCount" }],
|
||
|
|
incidents: [{ $skip: skip }, { $limit: rowsPerPage }],
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
$project: {
|
||
|
|
incidentsCount: {
|
||
|
|
$ifNull: [{ $arrayElemAt: ["$summary.incidentsCount", 0] }, 0],
|
||
|
|
},
|
||
|
|
incidents: {
|
||
|
|
$ifNull: ["$incidents", []],
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
|
||
|
|
return incidents[0];
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "getIncidentsByTeam";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
getIncidentSummary = async ({ teamId, dateRange }) => {
|
||
|
|
try {
|
||
|
|
const matchStage = {
|
||
|
|
teamId: new ObjectId(teamId),
|
||
|
|
...(dateRangeLookup[dateRange] && {
|
||
|
|
startTime: {
|
||
|
|
$gte: dateRangeLookup[dateRange],
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
const summary = await this.Incident.aggregate([
|
||
|
|
{ $match: matchStage },
|
||
|
|
{
|
||
|
|
$group: {
|
||
|
|
_id: "$status",
|
||
|
|
count: { $sum: 1 },
|
||
|
|
manualResolutions: {
|
||
|
|
$sum: {
|
||
|
|
$cond: [{ $eq: ["$resolutionType", "manual"] }, 1, 0],
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
]);
|
||
|
|
|
||
|
|
const result = {
|
||
|
|
total: 0,
|
||
|
|
active: 0,
|
||
|
|
resolved: 0,
|
||
|
|
manual: 0,
|
||
|
|
};
|
||
|
|
|
||
|
|
summary.forEach((item) => {
|
||
|
|
result.total += item.count;
|
||
|
|
if (item._id === "active") {
|
||
|
|
result.active = item.count;
|
||
|
|
}
|
||
|
|
if (item._id === "resolved") {
|
||
|
|
result.resolved = item.count;
|
||
|
|
}
|
||
|
|
result.manual += item.manualResolutions;
|
||
|
|
});
|
||
|
|
|
||
|
|
return result;
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "getIncidentSummary";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
deleteIncidentsByMonitor = async (monitorId) => {
|
||
|
|
try {
|
||
|
|
const result = await this.Incident.deleteMany({ monitorId: new ObjectId(monitorId) });
|
||
|
|
return result.deletedCount;
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "deleteIncidentsByMonitor";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
deleteIncidentsByTeamId = async (teamId) => {
|
||
|
|
try {
|
||
|
|
const teamMonitors = await this.Monitor.find({ teamId }, { _id: 1 });
|
||
|
|
const monitorIds = teamMonitors.map((monitor) => monitor._id);
|
||
|
|
const deleteResult = await this.Incident.deleteMany({ monitorId: { $in: monitorIds } });
|
||
|
|
return deleteResult.deletedCount;
|
||
|
|
} catch (error) {
|
||
|
|
error.service = SERVICE_NAME;
|
||
|
|
error.method = "deleteIncidentsByTeamId";
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export default IncidentModule;
|
||
|
|
|