Slackで見逃された投稿をスヌーズ機能で気づくようにする

はじめに

Slackに問い合わせが来た時に、複数人が対応するような体制だと「今は手が離せないから対応できないけど、誰かやってくれるやろ」ということが起きるかと思います。

たまに全員がこのマインドになった時に見逃されることがあります。

それを見逃さないようにしようという試みです。

仕様を決める

今回は下記のような仕様にしました

  • 特定のチャンネルの発言を全て対象とする
  • 特定の絵文字が指定されるまで通知する
  • スヌーズの間隔は常に10分とする

実装する

パッケージのインストール

SlackAPIを叩くためのpackageをインストールします

www.npmjs.com

SDKの初期化

トークンを使用してSDKを初期化します

const { WebClient } = require('@slack/web-api');

const web = new WebClient(token);

tokenはアプリをbotユーザーとして登録した時のtokenを使います botをチャンネルに追加しておきます f:id:cgig:20210105233524p:plain

特定のチャンネルのメッセージを取得する

今回はスヌーズ機能なので直近のメッセージさえあればいいので limit はデフォルトの 100 のままいきます

const response = await web.conversations.history({
    channel: 'CXXXXXXXX',
});

メッセージ一覧のテストはこちらから可能です api.slack.com

チャンネルIDの取得方法はこちら cgig.hatenablog.com

スヌーズ対象のメッセージを特定する

上記で定義した仕様に合致するメッセージを特定するための関数を作ります

const isRequiredAlert = (message, lastAlertTimestamp) => {
    const { subtype, reactions, ts } = message;

    // チャンネルに参加したときのメッセージは無視する
    if (subtype && subtype.startsWith('channel')) {
        return false;
    }

    // 特定のスタンプで反応があった時はスヌーズ対象から外す
    const stampNames = ['white_check_mark'];
    const reactionCount = (reactions ? reactions : []).filter((reaction) => stampNames.findIndex((name) => name ===reaction.name)).length;
    if (reactionCount > 0) {
        return false;
    }

    // Slackのタイムスタンプは秒なのでミリ秒に統一する
    const intervalMinutes = 10;
    const timestamp = lastAlertTimestamp ? lastAlertTimestamp : parseInt(ts, 10) * 1000;
    const now = Date.now();
    const diff = now - timestamp;

    // 前回の通知時間 or 投稿時間から10分経ってない場合は対象外
    if (diff < intervalMinutes * 60 * 1000) {
        return false;
    }

    return true;    
}

通知する

スヌーズ対象のメッセージが存在した場合はスレッドに返信します

await web.chat.postMessage({
    token: token,
    channel: channelId,
    text: `:alarm_clock:`,    // 目覚まし時計の絵文字でも送っておく
    thread_ts: message.ts,
});

// 何かしらで最後に通知した時間を保存しておく
await saveLastAlertTimestamp(message);

定期実行する

GCPAWSのサーバーレス環境を使用して1分間に1回動作するように設定すれば完了です