← back to Daily Reporting
slack-notifier.ts
178 lines
/**
* Slack Notifier for Daily Reports
*
* Sends formatted reports to Slack channels
*/
import fetch from 'node-fetch';
import type { DailyReport } from './report-generator';
import { formatSlackReport, formatSlackBlocks } from './slack-formatter';
export interface SlackConfig {
webhookUrl: string;
channel?: string;
username?: string;
iconEmoji?: string;
mentionChannelOnIssues?: boolean;
}
/**
* Send report to Slack webhook
*/
export async function sendToSlack(
report: DailyReport,
config: SlackConfig
): Promise<boolean> {
try {
const mentionChannel = config.mentionChannelOnIssues && report.executiveSummary.criticalIssues > 0;
// Format the message
const text = formatSlackReport(report, mentionChannel);
// Prepare payload
const payload: any = {
username: config.username || 'DW-Agents Reporter',
icon_emoji: config.iconEmoji || (report.reportType === 'morning' ? ':sunrise:' : ':city_sunset:'),
text: text
};
// Add channel if specified
if (config.channel) {
payload.channel = config.channel;
}
// Send to Slack
const response = await fetch(config.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`Slack API error: ${response.status} ${response.statusText}`);
}
console.log(`✅ Successfully sent ${report.reportType} report to Slack`);
return true;
} catch (error) {
console.error('❌ Failed to send report to Slack:', error);
return false;
}
}
/**
* Send report with rich formatting (blocks)
*/
export async function sendToSlackWithBlocks(
report: DailyReport,
config: SlackConfig
): Promise<boolean> {
try {
const mentionChannel = config.mentionChannelOnIssues && report.executiveSummary.criticalIssues > 0;
// Format blocks
const blocks = formatSlackBlocks(report);
const text = formatSlackReport(report, false); // Fallback text
// Prepare payload
const payload: any = {
username: config.username || 'DW-Agents Reporter',
icon_emoji: config.iconEmoji || (report.reportType === 'morning' ? ':sunrise:' : ':city_sunset:'),
text: text, // Fallback
blocks: blocks
};
// Add channel if specified
if (config.channel) {
payload.channel = config.channel;
}
// Add channel mention if needed
if (mentionChannel) {
payload.text = '<!channel> Critical issues detected!\n\n' + payload.text;
}
// Send to Slack
const response = await fetch(config.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`Slack API error: ${response.status} ${response.statusText}`);
}
console.log(`✅ Successfully sent ${report.reportType} report with blocks to Slack`);
return true;
} catch (error) {
console.error('❌ Failed to send report with blocks to Slack:', error);
// Fallback to simple text
return sendToSlack(report, config);
}
}
/**
* Test Slack connection
*/
export async function testSlackConnection(webhookUrl: string): Promise<boolean> {
try {
const response = await fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
text: '🧪 Test message from DW-Agents Daily Reporting System\n\nIf you see this, the webhook is configured correctly! ✅'
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
console.log('✅ Slack connection test successful');
return true;
} catch (error) {
console.error('❌ Slack connection test failed:', error);
return false;
}
}
/**
* Save report to file (backup)
*/
export async function saveReportToFile(report: DailyReport, directory: string = '/root/DW-Agents/reports'): Promise<string> {
const fs = require('fs').promises;
const path = require('path');
try {
// Ensure directory exists
await fs.mkdir(directory, { recursive: true });
// Generate filename
const date = new Date(report.timestamp);
const dateStr = date.toISOString().split('T')[0];
const timeStr = date.toTimeString().split(' ')[0].replace(/:/g, '-');
const filename = `${report.reportType}-report-${dateStr}-${timeStr}.json`;
const filepath = path.join(directory, filename);
// Save report
await fs.writeFile(filepath, JSON.stringify(report, null, 2));
console.log(`📁 Report saved to ${filepath}`);
return filepath;
} catch (error) {
console.error('❌ Failed to save report to file:', error);
throw error;
}
}