diff --git a/server/services/alertService.js b/server/services/alertService.js index e62bdb7..085de9d 100644 --- a/server/services/alertService.js +++ b/server/services/alertService.js @@ -555,6 +555,17 @@ class AlertService { console.log(`✅ SMS sent successfully to ${phoneNumber}: ${twilioMessage.sid}`); + // Store success details for SMS + const smsSuccessDetails = { + messageId: twilioMessage.sid, + status: twilioMessage.status, + direction: twilioMessage.direction, + price: twilioMessage.price, + priceUnit: twilioMessage.priceUnit, + timestamp: new Date().toISOString(), + segments: twilioMessage.numSegments + }; + return await AlertLog.create({ alert_rule_id: rule.id, detection_id: detection.id, @@ -565,11 +576,24 @@ class AlertService { sent_at: new Date(), external_id: twilioMessage.sid, priority: rule.priority, - alert_event_id: alertEventId + alert_event_id: alertEventId, + error_message: `Success: ${JSON.stringify(smsSuccessDetails)}` }); } catch (error) { console.error(`❌ Failed to send SMS to ${phoneNumber}:`, error.message); + // Enhanced SMS error details + const smsErrorDetails = { + errorType: 'SMS_SEND_FAILED', + errorMessage: error.message, + twilioError: error.code || null, + twilioStatus: error.status || null, + phoneNumber: phoneNumber, + messageLength: message.length, + timestamp: new Date().toISOString(), + moreInfo: error.moreInfo || null + }; + return await AlertLog.create({ alert_rule_id: rule.id, detection_id: detection.id, @@ -580,28 +604,66 @@ class AlertService { sent_at: new Date(), external_id: null, priority: rule.priority, - error_message: error.message, + error_message: `SMS Failed: ${JSON.stringify(smsErrorDetails)}`, alert_event_id: alertEventId }); } } async sendEmailAlert(email, message, rule, detection, threatAssessment = null, alertEventId = null) { - // Email implementation would go here - // For now, just log the alert - console.log(`Email alert would be sent to ${email}: ${message}`); + try { + // Email implementation would go here + // For now, just log the alert + console.log(`Email alert would be sent to ${email}: ${message}`); - return await AlertLog.create({ - alert_rule_id: rule.id, - detection_id: detection.id, - alert_type: 'email', - recipient: email, - message: message, - status: 'sent', - sent_at: new Date(), - priority: rule.priority, - alert_event_id: alertEventId - }); + // Simulate email success with detailed info + const emailSuccessDetails = { + recipient: email, + messageLength: message.length, + timestamp: new Date().toISOString(), + simulatedDelivery: true, + ruleId: rule.id, + detectionId: detection.id + }; + + return await AlertLog.create({ + alert_rule_id: rule.id, + detection_id: detection.id, + alert_type: 'email', + recipient: email, + message: message, + status: 'sent', + sent_at: new Date(), + priority: rule.priority, + alert_event_id: alertEventId, + error_message: `Success: ${JSON.stringify(emailSuccessDetails)}` + }); + + } catch (error) { + // Enhanced email error details + const emailErrorDetails = { + errorType: 'EMAIL_SEND_FAILED', + errorMessage: error.message, + recipient: email, + messageLength: message.length, + timestamp: new Date().toISOString(), + smtpError: error.code || null, + responseCode: error.responseCode || null + }; + + return await AlertLog.create({ + alert_rule_id: rule.id, + detection_id: detection.id, + alert_type: 'email', + recipient: email, + message: message, + status: 'failed', + sent_at: new Date(), + priority: rule.priority, + alert_event_id: alertEventId, + error_message: `Email Failed: ${JSON.stringify(emailErrorDetails)}` + }); + } } async sendWebhookAlert(webhookUrl, detection, device, rule, threatAssessment = null, alertEventId = null) { @@ -633,30 +695,89 @@ class AlertService { } }; - const response = await fetch(webhookUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'DroneDetectionSystem/1.0' - }, - body: JSON.stringify(payload) - }); + try { + const startTime = Date.now(); + + const response = await fetch(webhookUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'DroneDetectionSystem/1.0' + }, + body: JSON.stringify(payload), + timeout: 10000 // 10 second timeout + }); - if (!response.ok) { - throw new Error(`Webhook failed with status ${response.status}`); + const responseTime = Date.now() - startTime; + + if (!response.ok) { + // Enhanced error information for failed webhooks + let errorDetails = { + httpStatus: response.status, + httpStatusText: response.statusText, + url: webhookUrl, + responseTime: `${responseTime}ms`, + timestamp: new Date().toISOString(), + requestPayload: JSON.stringify(payload).length + ' bytes' + }; + + // Try to capture response body for additional context + try { + let responseBody = await response.text(); + if (responseBody.length > 500) { + responseBody = responseBody.substring(0, 500) + '...'; + } + errorDetails.responseBody = responseBody; + } catch (bodyError) { + errorDetails.responseBody = `Could not read response: ${bodyError.message}`; + } + + // Capture response headers + try { + errorDetails.responseHeaders = Object.fromEntries(response.headers.entries()); + } catch (headerError) { + errorDetails.responseHeaders = `Could not read headers: ${headerError.message}`; + } + + const detailedErrorMessage = `Webhook HTTP ${response.status}: ${JSON.stringify(errorDetails)}`; + throw new Error(detailedErrorMessage); + } + + // Success case - store success info in error_message field for details + const successInfo = { + httpStatus: response.status, + responseTime: `${responseTime}ms`, + timestamp: new Date().toISOString(), + responseHeaders: Object.fromEntries(response.headers.entries()) + }; + + return await AlertLog.create({ + alert_rule_id: rule.id, + detection_id: detection.id, + alert_type: 'webhook', + recipient: webhookUrl, + message: JSON.stringify(payload), + status: 'sent', + sent_at: new Date(), + priority: rule.priority, + alert_event_id: alertEventId, + external_id: response.headers.get('x-request-id') || response.headers.get('request-id') || null, + error_message: `Success: ${JSON.stringify(successInfo)}` + }); + + } catch (fetchError) { + // Network or timeout errors + const networkErrorDetails = { + errorType: fetchError.name || 'NetworkError', + errorMessage: fetchError.message, + url: webhookUrl, + timestamp: new Date().toISOString(), + cause: fetchError.cause?.toString() || null + }; + + const detailedErrorMessage = `Webhook network error: ${JSON.stringify(networkErrorDetails)}`; + throw new Error(detailedErrorMessage); } - - return await AlertLog.create({ - alert_rule_id: rule.id, - detection_id: detection.id, - alert_type: 'webhook', - recipient: webhookUrl, - message: JSON.stringify(payload), - status: 'sent', - sent_at: new Date(), - priority: rule.priority, - alert_event_id: alertEventId - }); } generateAlertMessage(detection, device, rule) {