Files
Checkmate/server/src/services/infrastructure/NotificationService.ts
T
2025-11-19 23:55:29 +00:00

193 lines
5.4 KiB
TypeScript

import UserService from "../business/UserService.js";
import {
IMonitor,
Monitor,
NotificationChannel,
INotificationChannel,
IIncident,
} from "@/db/models/index.js";
import {
EmailService,
SlackService,
DiscordService,
WebhookService,
} from "./NotificationServices/index.js";
import ApiError from "@/utils/ApiError.js";
import { getChildLogger } from "@/logger/Logger.js";
import type { IEmailTransport } from "./NotificationServices/Email.js";
const SERVICE_NAME = "NotificationService";
const logger = getChildLogger(SERVICE_NAME);
export interface ITestResult {
channelName: string;
channelUrl: string;
channelType: string;
sent: boolean;
}
export interface INotificationService {
handleNotifications: (
monitor: IMonitor,
incident: IIncident
) => Promise<void>;
testNotificationChannels: (
monitorId: string,
teamId: string
) => Promise<ITestResult[]>;
testNotificationChannel: (
notificationChannel: INotificationChannel
) => Promise<Boolean>;
testTransport: (transport: IEmailTransport) => Promise<boolean>;
}
class NotificationService implements INotificationService {
public SERVICE_NAME: string;
private emailService: EmailService;
private slackService: SlackService;
private discordService: DiscordService;
private webhookService: WebhookService;
private userService: UserService;
constructor(userService: UserService) {
this.SERVICE_NAME = SERVICE_NAME;
this.userService = userService;
this.emailService = new EmailService(userService);
this.slackService = new SlackService();
this.discordService = new DiscordService();
this.webhookService = new WebhookService();
}
handleNotifications = async (monitor: IMonitor, incident: IIncident) => {
const notificationIds = monitor.notificationChannels || [];
if (notificationIds.length === 0) {
return;
}
const notificationChannels = await NotificationChannel.find({
_id: { $in: notificationIds },
});
for (const channel of notificationChannels) {
// Implement sending logic based on channel.type and channel.config
let service;
switch (channel.type) {
case "email":
await this.emailService.sendMessage(
this.emailService.buildAlert(monitor, incident),
channel
);
break;
case "slack":
await this.slackService.sendMessage(
this.slackService.buildAlert(monitor, incident),
channel
);
break;
case "discord":
await this.discordService.sendMessage(
this.discordService.buildAlert(monitor, incident),
channel
);
break;
case "webhook":
await this.webhookService.sendMessage(
this.webhookService.buildAlert(monitor, incident),
channel
);
break;
default:
logger.warn(`Unknown notification channel type: ${channel.type}`);
}
}
return;
};
private testNotification = async (
channel: INotificationChannel,
results: any[]
) => {
switch (channel.type) {
case "email":
const sentEmail = await this.emailService.testMessage(channel);
results.push({
channelName: channel.name,
channelType: channel.type,
channelUrl: channel.config?.emailAddress || "N/A",
sent: sentEmail,
});
break;
case "slack":
const sentSlack = await this.slackService.testMessage(channel);
results.push({
channelName: channel.name,
channelType: channel.type,
channelUrl: channel.config?.url || "N/A",
sent: sentSlack,
});
break;
case "discord":
const sentDiscord = await this.discordService.testMessage(channel);
results.push({
channelName: channel.name,
channelType: channel.type,
channelUrl: channel.config?.url || "N/A",
sent: sentDiscord,
});
break;
case "webhook":
const sentWebhook = await this.webhookService.testMessage(channel);
results.push({
channelName: channel.name,
channelType: channel.type,
channelUrl: channel.config?.url || "N/A",
sent: sentWebhook,
});
break;
default:
logger.warn(`Unknown notification channel type: ${channel.type}`);
}
return results;
};
testNotificationChannels = async (monitorId: string, teamId: string) => {
const monitor = await Monitor.findOne({
_id: monitorId,
teamId: teamId,
});
if (!monitor) {
throw new ApiError("Monitor not found", 404);
}
const notificationIds = monitor.notificationChannels || [];
const notificationChannels = await NotificationChannel.find({
_id: { $in: notificationIds },
}).lean();
const results: any[] = [];
for (const channel of notificationChannels) {
await this.testNotification(channel, results);
}
return results;
};
testNotificationChannel = async (
notificationChannel: INotificationChannel
) => {
const result: any[] = [];
await this.testNotification(notificationChannel, result);
if (result.length > 0) {
return true;
}
return false;
};
testEmailTransport = async (transport: IEmailTransport) => {
return this.emailService.testTransport(transport);
};
}
export default NotificationService;