← back to Animate Museum Posts

src/slackNotify.js

127 lines

import https from 'https';
import dotenv from 'dotenv';

dotenv.config();

const WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;

async function sendSlackMessage(message) {
  if (!WEBHOOK_URL) {
    console.log('[Slack] No webhook configured, skipping notification');
    return false;
  }

  return new Promise((resolve, reject) => {
    try {
      const url = new URL(WEBHOOK_URL);
      const payload = JSON.stringify(message);

      const options = {
        hostname: url.hostname,
        path: url.pathname,
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Content-Length': Buffer.byteLength(payload)
        }
      };

      const req = https.request(options, (res) => {
        if (res.statusCode === 200) {
          resolve(true);
        } else {
          console.log('[Slack] Webhook returned:', res.statusCode);
          resolve(false);
        }
      });

      req.on('error', (error) => {
        console.log('[Slack] Error:', error.message);
        resolve(false);
      });

      req.write(payload);
      req.end();
    } catch (error) {
      console.log('[Slack] Error:', error.message);
      resolve(false);
    }
  });
}

export async function notifySuccess(artwork, tweetId) {
  const message = {
    blocks: [
      {
        type: 'header',
        text: {
          type: 'plain_text',
          text: 'Museum Art Bot Posted!'
        }
      },
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `*${artwork.title}*\nby ${artwork.artist} (${artwork.year})\n\nSource: ${artwork.museum || artwork.sourceMuseum || 'Public Domain'}`
        }
      },
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `<https://twitter.com/goodquestionai/status/${tweetId}|View Tweet>`
        }
      }
    ]
  };

  return sendSlackMessage(message);
}

export async function notifyError(error, context = '') {
  const message = {
    blocks: [
      {
        type: 'header',
        text: {
          type: 'plain_text',
          text: 'Museum Art Bot Error'
        }
      },
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `*Error:* ${error}\n*Context:* ${context || 'Unknown'}\n*Time:* ${new Date().toISOString()}`
        }
      }
    ]
  };

  return sendSlackMessage(message);
}

export async function notifyDailySummary(stats) {
  const message = {
    blocks: [
      {
        type: 'header',
        text: {
          type: 'plain_text',
          text: 'Museum Art Bot - Daily Summary'
        }
      },
      {
        type: 'section',
        text: {
          type: 'mrkdwn',
          text: `*Posts Today:* ${stats.postsToday}\n*Errors:* ${stats.errorsToday}\n*Uptime:* ${stats.uptime}`
        }
      }
    ]
  };

  return sendSlackMessage(message);
}