EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
notificationHelper.js
Go to the documentation of this file.
1const pool = require('../services/db');
2
3/**
4 * Create a notification and optionally send to Slack
5 * @param {object} options - Notification options
6 * @param {number|null} options.userId - User ID to notify (null for system-wide)
7 * @param {number|null} options.customerId - Customer ID related to notification
8 * @param {string} options.title - Notification title
9 * @param {string} options.message - Notification message
10 * @param {string} options.type - Notification type (e.g., 'ticket', 'alert', 'agent', 'system')
11 * @param {number|null} options.tenantId - Tenant ID for multi-tenancy
12 * @returns {Promise<object>} Created notification object
13 */
14async function createNotification({ userId = null, customerId = null, title, message, type, tenantId = null }) {
15 try {
16 // Insert notification into database
17 const result = await pool.query(
18 `INSERT INTO notifications (user_id, customer_id, title, message, type, tenant_id)
19 VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
20 [userId, customerId, title, message, type, tenantId]
21 );
22
23 const notification = result.rows[0];
24
25 // Try to send to Slack if integration is configured
26 try {
27 const slackRes = await pool.query(
28 `SELECT config FROM integrations
29 WHERE tenant_id = $1 AND integration_type = 'slack' AND is_active = true LIMIT 1`,
30 [tenantId]
31 );
32
33 if (slackRes.rows.length) {
34 const slackCfg = slackRes.rows[0].config;
35 const webhookUrl = slackCfg.webhookUrl;
36 const channel = slackCfg.channel || '';
37
38 if (webhookUrl) {
39 const payload = {
40 text: `*${title}*\n${message}`,
41 channel: channel || undefined
42 };
43
44 await fetch(webhookUrl, {
45 method: 'POST',
46 headers: { 'Content-Type': 'application/json' },
47 body: JSON.stringify(payload)
48 });
49 }
50 }
51 } catch (slackError) {
52 console.error('Slack notification error:', slackError);
53 // Don't fail the notification creation if Slack fails
54 }
55
56 return notification;
57 } catch (err) {
58 console.error('Error creating notification:', err);
59 throw err;
60 }
61}
62
63/**
64 * Create a notification for a new ticket
65 * @param {object} ticket - Ticket object
66 * @param {number} ticket.ticket_id - Ticket ID
67 * @param {string} ticket.title - Ticket title
68 * @param {string} ticket.description - Ticket description
69 * @param {string} ticket.priority - Ticket priority
70 * @param {number} ticket.assigned_to - User ID of assigned user
71 * @param {number} ticket.customer_id - Customer ID
72 * @param {number} ticket.tenant_id - Tenant ID
73 */
74async function notifyTicketCreated(ticket) {
75 const { ticket_id, title, description, priority, assigned_to, customer_id, tenant_id } = ticket;
76
77 // Notify assigned user if specified
78 if (assigned_to) {
79 await createNotification({
80 userId: assigned_to,
81 customerId: customer_id,
82 title: `New ticket assigned: ${title}`,
83 message: `You have been assigned ${priority} priority ticket #${ticket_id}: ${description.substring(0, 100)}${description.length > 100 ? '...' : ''}`,
84 type: 'ticket',
85 tenantId: tenant_id
86 });
87 }
88
89 // Notify admins if no one is assigned (system notification for tenant)
90 if (!assigned_to) {
91 await createNotification({
92 userId: null, // System notification
93 customerId: customer_id,
94 title: `Unassigned ticket created: ${title}`,
95 message: `A new ${priority} priority ticket #${ticket_id} needs assignment: ${description.substring(0, 100)}${description.length > 100 ? '...' : ''}`,
96 type: 'ticket',
97 tenantId: tenant_id
98 });
99 }
100}
101
102/**
103 * Create a notification for agent status changes
104 * @param {object} agent - Agent object
105 * @param {number} agent.agent_id - Agent ID
106 * @param {string} agent.hostname - Agent hostname
107 * @param {string} agent.status - Agent status (online/offline)
108 * @param {number} agent.customer_id - Customer ID
109 * @param {number} agent.tenant_id - Tenant ID
110 */
111async function notifyAgentStatusChange(agent) {
112 const { agent_id, hostname, status, customer_id, tenant_id } = agent;
113
114 if (status === 'offline') {
115 await createNotification({
116 userId: null, // System notification for tenant
117 customerId: customer_id,
118 title: `Agent Offline: ${hostname}`,
119 message: `Agent ${hostname} (ID: ${agent_id}) has gone offline and may require attention.`,
120 type: 'agent',
121 tenantId: tenant_id
122 });
123 }
124}
125
126/**
127 * Create a notification for monitoring alerts
128 * @param {object} alert - Alert object
129 * @param {number} alert.agent_id - Agent ID
130 * @param {string} alert.hostname - Agent hostname
131 * @param {string} alert.alertType - Type of alert (cpu, memory, disk, service)
132 * @param {string} alert.message - Alert message
133 * @param {number} alert.value - Current value
134 * @param {number} alert.threshold - Threshold value
135 * @param {number} alert.customer_id - Customer ID
136 * @param {number} alert.tenant_id - Tenant ID
137 */
138async function notifyMonitoringAlert(alert) {
139 const { agent_id, hostname, alertType, message, value, threshold, customer_id, tenant_id } = alert;
140
141 let title = `Alert: ${hostname}`;
142 switch (alertType) {
143 case 'cpu':
144 title = `CPU Alert: ${hostname}`;
145 break;
146 case 'memory':
147 title = `Memory Alert: ${hostname}`;
148 break;
149 case 'disk':
150 title = `Disk Space Alert: ${hostname}`;
151 break;
152 case 'service':
153 title = `Service Alert: ${hostname}`;
154 break;
155 }
156
157 await createNotification({
158 userId: null, // System notification for tenant
159 customerId: customer_id,
160 title: title,
161 message: message || `${alertType.toUpperCase()} on ${hostname} (Agent ${agent_id}): ${value}% exceeds threshold of ${threshold}%`,
162 type: 'alert',
163 tenantId: tenant_id
164 });
165}
166
167module.exports = {
168 createNotification,
169 notifyTicketCreated,
170 notifyAgentStatusChange,
171 notifyMonitoringAlert
172};