はじめに

この記事ではSlackのキーワード通知botの作成方法を書かせていただきます。

Slackにはマイキーワード設定という機能もあるのですが、この通知はバッジでしか通知してくれません(2024年10月時点では)。

休日や定時後にもアラートが鳴った時メンションで通知が欲しいなという要望からこのアプリを作成してみました。

アプリケーションの構成として・・・

  • スプレッドシート
    • キーワード検出したいチャンネルやメンションしたいユーザー、キーワードを設定できる(複数選択可能)
  • Slack API
    • channels:historyというbotのmessage.channelsというeventを使用して、作成するSlack APIがインテグレーションされているチャンネルの全てのメッセージを拾いGASへ送信する
  • GAS
    • Slack APIから送信されるメッセージ情報とスプシの設定情報をもとにキーワードが含まれているか判別するウェブアプリを作成し、Incoming Webhookに結果をpostする
  • Incoming Webhook
    • 送信したいチャンネルにGASのpostを送信する

という形になっています。

興味関心ありましたらぜひ真似して作ってみてください。

Slack APIの作成

以下URLから作成します

https://api.slack.com/

「Your  apps」クリック

「Create New Apps」をクリック

「From scratch」を選択

アプリ名とアプリを追加したいワークスペース名を追加

アプリの詳細画面に移ったらサイドメニューから「OAuth & Permissions」を選択

Scopes→Bot Token Scopes→Add an oauth scopeからchannels:historyを追加

OAuth TokensからInstall (ワークスペース名)をクリック、ワークスペースにアクセスする権限をリクエストしています→許可するをクリック

サイドメニューから「Event Subscriptions」を選択し、Onにする

Subscribe to bot events→Add user bot eventからmessage.channelsを選択する

後ほど

Incoming Webhookの設定

以下URLからIncoming Webhookと検索して作成

https://slack.com/apps

Incoming Webhook→Slackに追加を選択(ワークスペースを確認)

チャンネルへの投稿→チャンネルを選択から通知をしたいチャンネルを選択してIncoming Webhookインテグレーションの追加をクリック

インテグレーションの設定→Webhook URLからURLをコピーしておく(その他アイコンや名前をカスタマイズしてもOK)

 

GASの作成

Google スプレッドシートから新しいスプレッドシートを作成

https://docs.google.com/spreadsheets/create?hl=ja

ABC列の1行目にチャンネルID、キーワード、送信したいIDと入力

チャンネルIDはキーワードを検出したいチャンネルのIDを入力

Slackからチャンネル情報の最後の方にIDがあります

キーワードには検出したいキーワードを入れてください

送信したいIDはメンションを送りたい人のIDを入力(例:<@UA6B7C3D8E0F>)

Slackのプロフィール→・・・→メンバーIDをコピーし、<@メンバーID>のように加工してください

登録データは何行あっても大丈夫です

データ登録が完了したらメニューから拡張機能→apps scriptをクリック

ファイル→コード.gsであることを確認したら既存のコードを削除し、以下コードをコピペしてください

コード(長いので折りたたんでいます、クリックしてください)

function doPost(e) {
  var contents = JSON.parse(e.postData.contents);

  // Slackのchallenge確認
  if (contents.challenge) {
    return ContentService.createTextOutput(contents.challenge);
  }

    // 既に通知済みのメッセージは無視
  if (contents.event.text.includes('キーワード発見')) {
    return;
  }

  // Slackの3秒タイムアウトリトライ対策
  var cache = CacheService.getScriptCache();
  if (cache.get(contents.event.event_ts) == 'done') {
    // キャッシュヒットした場合は何も処理せずにレスポンスを返す
    return ContentService.createTextOutput(JSON.stringify({status: "ok"})).setMimeType(ContentService.MimeType.JSON);
  } else {
    // キャッシュにevent_tsを保存、60秒 (1分) 保持
    cache.put(contents.event.event_ts, 'done', 60);
  }

  // Googleスプレッドシートから値を取得
  var spreadsheetUrl = ''; // スプレッドシートのURL
  var sheetName = 'シート1'; // シート名(必要に応じて変更)
  var sheet = SpreadsheetApp.openByUrl(spreadsheetUrl).getSheetByName(sheetName);

  // シート全体のデータを取得 (A列: チャンネルID, B列: キーワード, C列: メンション)
  var dataRange = sheet.getRange(2, 1, sheet.getLastRow() - 1, 3).getValues(); // 2行目から最終行まで取得
  var postUrl = ''; // SlackのWebhook URL

  // 送信するメッセージをまとめる変数を定義
  var messages = [];

  // 各行をループしてチェック
  for (var i = 0; i < dataRange.length; i++) {
    var chennelId = dataRange[i][0]; // A列のチャンネルID
    var keyword = dataRange[i][1];   // B列のキーワード
    var mentionUser = dataRange[i][2]; // C列のメンションユーザー

    // Slackの投稿内容を確認
    var keywordInText = contents.event.text.match(new RegExp(keyword, 'i')); // キーワードを正規表現に変換してマッチ

    // 投稿されたチャンネルとキーワードが一致したら、メッセージをまとめる
    if (contents.event.channel == chennelId && keywordInText) {
      // メッセージを配列に追加
      messages.push(mentionUser + '\nキーワード発見: ' + keyword); // メンションユーザーとキーワードを追加
    }
  }

  // メッセージが存在する場合、Slackに1回だけPOSTする
  if (messages.length > 0) {
    // 配列の内容を改行で結合して1つのメッセージにする
    var finalMessage = messages.join('\n\n'); // メッセージ同士を改行で区切る

    // Slackへメッセージを送信
    var jsonData = {
      "text": finalMessage,  // まとめたメッセージを送信
      "link_names": 1
    };
    var payload = JSON.stringify(jsonData);

    var options = {
      "method": "post",
      "contentType": "application/json",
      "payload": payload
    };

    UrlFetchApp.fetch(postUrl, options);
  } else {
    // メッセージが存在しない場合、何もせずに終了
    return;
  }
}

25行目のspreadsheetUrlにはスプシのURLを、31行目のpostUrlにはIncoming Webhook のURLをコピペして、保存ボタンをクリック

右上のデプロイ(青いボタン)から新しいデプロイをクリック

種類の選択の横の歯車ボタンからウェブアプリをクリックし、必要な情報を入力してデプロイをクリック

アクセスできるユーザーは全員にしておきます

アクセス承認が必要な場合は許可してください

デプロイが更新されたらURLをコピー

Slack APIのページに戻りEvent Subscriptions→Request URLにGASのURLを入力

VerifiedとなったらOKですが、ダメだった場合は各所問題がないか見直ししてください

Save Changesを忘れずにクリック(Subscribe to bot eventsにmessage.channelsが入っていることを確認してください)

最後にキーワード検出したいチャンネルで作成したアプリ(Slack API)を追加

チャンネル情報→インテグレーションから追加できます

テストしてみる

Slack APIを入れたチャンネルでキーワードを含んだメッセージをすると

Incoming Webhookに登録したチャンネルに通知が飛ぶことを確認できました