import { triggerNotificationBodyValidation } from "../validation/joi.js"; import { handleError, handleValidationError } from "./controllerUtils.js"; const SERVICE_NAME = "NotificationController"; const NOTIFICATION_TYPES = { WEBHOOK: 'webhook', TELEGRAM: 'telegram' }; const PLATFORMS = { SLACK: 'slack', DISCORD: 'discord', TELEGRAM: 'telegram' }; class NotificationController { constructor(notificationService, stringService, statusService) { this.notificationService = notificationService; this.stringService = stringService; this.statusService = statusService; this.triggerNotification = this.triggerNotification.bind(this); this.testWebhook = this.testWebhook.bind(this); } async triggerNotification(req, res, next) { try { await triggerNotificationBodyValidation.validateAsync(req.body, { abortEarly: false, stripUnknown: true, }); } catch (error) { next(handleValidationError(error, SERVICE_NAME)); return; } try { const { monitorId, type, platform, config, status = false } = req.body; // Create a simplified networkResponse similar to what would come from monitoring const networkResponse = { monitorId, status }; // Use the statusService to get monitor details and handle status change logic // This returns { monitor, statusChanged, prevStatus } exactly like your job queue uses const statusResult = await this.statusService.updateStatus(networkResponse); if (type === NOTIFICATION_TYPES.WEBHOOK) { const notification = { type, platform, config, }; await this.notificationService.sendWebhookNotification( statusResult, // Contains monitor, statusChanged, and prevStatus notification ); } return res.success({ msg: this.stringService.webhookSendSuccess, }); } catch (error) { next(handleError(error, SERVICE_NAME, "triggerNotification")); } } createTestNetworkResponse() { return { monitor: { _id: "test-monitor-id", name: "Test Monitor", url: "https://example.com" }, status: true, statusChanged: true, prevStatus: false, }; } handleTelegramTest(botToken, chatId) { if (!botToken || !chatId) { return { isValid: false, error: { msg: this.stringService.telegramRequiresBotTokenAndChatId, status: 400 } }; } return { isValid: true, notification: { type: NOTIFICATION_TYPES.WEBHOOK, platform: PLATFORMS.TELEGRAM, config: { botToken, chatId } } }; } handleWebhookTest(webhookUrl, platform) { if (webhookUrl === null) { return { isValid: false, error: { msg: this.stringService.webhookUrlRequired, status: 400 } }; } return { isValid: true, notification: { type: NOTIFICATION_TYPES.WEBHOOK, platform: platform, config: { webhookUrl } } }; } async testWebhook(req, res, next) { try { const { webhookUrl, platform, botToken, chatId } = req.body; if (platform === null) { return res.error({ msg: this.stringService.platformRequired, status: 400 }); } // Platform-specific handling const platformHandlers = { [PLATFORMS.TELEGRAM]: () => this.handleTelegramTest(botToken, chatId), // Default handler for webhook-based platforms (Slack, Discord, etc.) default: () => this.handleWebhookTest(webhookUrl, platform) }; const handler = platformHandlers[platform] || platformHandlers.default; const handlerResult = handler(); if (!handlerResult.isValid) { return res.error(handlerResult.error); } const networkResponse = this.createTestNetworkResponse(); const result = await this.notificationService.sendWebhookNotification( networkResponse, handlerResult.notification ); if (result && result !== false) { return res.success({ msg: this.stringService.webhookSendSuccess, }); } else { return res.error({ msg: this.stringService.testNotificationFailed, status: 400 }); } } catch (error) { next(handleError(error, SERVICE_NAME, "testWebhook")); } } } export default NotificationController;