diff --git a/server/controllers/notificationController.js b/server/controllers/notificationController.js index 108233847..7cb642977 100755 --- a/server/controllers/notificationController.js +++ b/server/controllers/notificationController.js @@ -18,10 +18,11 @@ const PLATFORMS = { }; class NotificationController { - constructor(notificationService, stringService, statusService) { + constructor({ notificationService, stringService, statusService, db }) { this.notificationService = notificationService; this.stringService = stringService; this.statusService = statusService; + this.db = db; this.triggerNotification = this.triggerNotification.bind(this); this.testWebhook = this.testWebhook.bind(this); } diff --git a/server/db/models/Notification.js b/server/db/models/Notification.js index 7ba3bb142..27f2f932a 100755 --- a/server/db/models/Notification.js +++ b/server/db/models/Notification.js @@ -39,6 +39,10 @@ const NotificationSchema = mongoose.Schema( type: configSchema, default: () => ({}), }, + notificationName: { + type: String, + required: true, + }, address: { type: String, }, diff --git a/server/index.js b/server/index.js index 2d48d753f..b520e6171 100755 --- a/server/index.js +++ b/server/index.js @@ -291,11 +291,12 @@ const startApp = async () => { ServiceRegistry.get(StringService.SERVICE_NAME) ); - const notificationController = new NotificationController( - ServiceRegistry.get(NotificationService.SERVICE_NAME), - ServiceRegistry.get(StringService.SERVICE_NAME), - ServiceRegistry.get(StatusService.SERVICE_NAME) - ); + const notificationController = new NotificationController({ + notificationService: ServiceRegistry.get(NotificationService.SERVICE_NAME), + stringService: ServiceRegistry.get(StringService.SERVICE_NAME), + statusService: ServiceRegistry.get(StatusService.SERVICE_NAME), + db: ServiceRegistry.get(MongoDB.SERVICE_NAME), + }); const diagnosticController = new DiagnosticController( ServiceRegistry.get(MongoDB.SERVICE_NAME) diff --git a/server/service/notificationService.js b/server/service/notificationService.js index ed74ff539..878881334 100755 --- a/server/service/notificationService.js +++ b/server/service/notificationService.js @@ -112,8 +112,7 @@ class NotificationService { async sendWebhookNotification(networkResponse, notification) { const { monitor, status, code } = networkResponse; - const { platform } = notification; - const { webhookUrl, botToken, chatId } = notification.config; + const { webhookUrl, platform, botToken, chatId } = notification.config; // Early return if platform is not supported if (!PLATFORM_TYPES.includes(platform)) { @@ -204,6 +203,38 @@ class NotificationService { return true; } + async sendPagerDutyNotification(networkResponse, notification) { + const { monitor, status, code } = networkResponse; + const { routingKey, platform } = notification.config; + + const message = this.formatNotificationMessage( + monitor, + status, + platform, + null, + code, // Pass the code field directly + networkResponse.timestamp + ); + + try { + const response = await this.networkService.requestPagerDuty({ + message, + routingKey, + monitorUrl: monitor.url, + }); + return response.status; + } catch (error) { + this.logger.error({ + message: "Failed to send PagerDuty notification", + details: error.details, + service: error.service || this.SERVICE_NAME, + method: error.method || "sendPagerDutyNotification", + stack: error.stack, + }); + return false; + } + } + async handleStatusNotifications(networkResponse) { try { // If status hasn't changed, we're done @@ -211,17 +242,17 @@ class NotificationService { // if prevStatus is undefined, monitor is resuming, we're done if (networkResponse.prevStatus === undefined) return false; - const notifications = await this.db.getNotificationsByMonitorId( - networkResponse.monitorId - ); + const notificationIDs = networkResponse.monitor?.notifications ?? []; + const notifications = await this.db.getNotificationsByIds(notificationIDs); for (const notification of notifications) { if (notification.type === "email") { await this.sendEmail(networkResponse, notification.address); } else if (notification.type === "webhook") { await this.sendWebhookNotification(networkResponse, notification); + } else if (notification.type === "pager_duty") { + await this.sendPagerDutyNotification(networkResponse, notification); } - // Handle other types of notifications here } return true; } catch (error) { diff --git a/server/validation/joi.js b/server/validation/joi.js index 1e3325fcb..d261b852a 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -567,11 +567,11 @@ const triggerNotificationBodyValidation = joi.object({ }); const createNotificationBodyValidation = joi.object({ - userId: joi.number().required().messages({ + userId: joi.string().required().messages({ "number.empty": "User ID is required", "any.required": "User ID is required", }), - teamId: joi.number().required().messages({ + teamId: joi.string().required().messages({ "string.empty": "Team ID is required", "any.required": "Team ID is required", }),