【Slack】指定したチャンネルでキーワードを含んだ投稿があったときに、別のチャンネルに通知を投げたい


最近ではSlackは業務ツールだけにとどまらず、コミュニティなどでも広く使われるようになってきました。

そこでコミュニティの運営側に質問などがあったときに、すぐに反応できないのは機会損失かなと思います。

Slackの機能で、あるキーワードを含んだ文章を投稿すると、予め決めておいた文章を返すようなbotは設定で簡単に作成できますが、「あるキーワードを含んた投稿があったときに、コミュニティ運営側に通知を投げたい!」という要望の場合は、解決できません。
また、Slackアプリの1つであるOutgoing webhookはキーワードが文章の先頭にないとイベントが発火しないため、これも今回の要件には合いません。

なので、この機能を簡単に作ってみました。

構成


例にもれずSlackApiとGASの組み合わせで実装します。
ただ、今回はOutgoing Webhookは使わないので、SlackApiをカスタマイズして投稿を拾い、GASでチャンネルとキーワードを確認、確認後に任意のチャンネルにIncoming Webhookで通知を落とします。

SlackApiの設定

https://api.slack.com/apps から設定を行います。

SlackApiの設定周りはこちらを参考にさせていただきました。
詳しくは上記を御覧ください。

SlackApi管理画面のEvent SubscriptionsにてGASのAPIのURLの登録と、APIを叩くイベントの設定を行います。

Request URLのところにGASのAPIのURLを打ち込みますが、登録時にSlack側からChallengeというパラメータがpostされ、それを返さないと有効なURLとして承認されないので、GASには以下のようなコードを登録しておきます。

function doPost(e){
  var params = JSON.parse(e.postData.getDataAsString());
  return ContentService.createTextOutput(params.challenge);
}

登録を完了させたら、同ページのSubscribe to events on behalf of usersの項目にて、message.channelsのイベントを追加します。

これが完了したら、任意のワークスペースに、このSlackApiをインストールします。

GASの設定

Slackからくるpostパラメータは以下のような感じです。

{
    "token":"xxxxxxxxxxxxxxxxxxxxxxxx",
    "team_id":"xxxxxxxxxxx",
    "api_app_id":"xxxxxxxxxxx",
    "event":{
        "type":"message",
        "subtype":"bot_enable",
        "text":"投稿したテキスト",
        "user":"xxxxxxxxxxx",
        "bot_id":"xxxxxxxxxxx",
        "bot_link":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "ts":"xxxxxxxxxx.xxxxxx",
        "channel":"xxxxxxxxxxx",
        "event_ts":"xxxxxxxxxx.xxxxxx",
        "channel_type":"channel"
    },
    "type":"event_callback",
    "event_id":"xxxxxxxxxxxx",
    "event_time":xxxxxxxxxx,
    "authorizations":[
        {
            "enterprise_id":null,
            "team_id":"xxxxxxxxxxx",
            "user_id":"xxxxxxxxxxx",
            "is_bot":false,
            "is_enterprise_install":false
        }
    ],
    "is_ext_shared_channel":false,
    "event_context":"1-message-xxxxxxxxxxx-xxxxxxxxxxx"
}

なので、以下に合わせてGASを書きます。

var postUrl = 'Incoming WebhookのURL';
function doPost(e) {
  var params = JSON.parse(e.postData.getDataAsString());
  // キーワードを正規表現で抜き出し
  var stoString = params.event.text.match(/キーワード/i)[0];
  var correctChennelId = 'チャンネルIDを入力'

  if (params.event.channel == correctChennelId && stoString) {
    var jsonData =
      {
        "text" : 'キーワードの入った投稿があったよ!'
      };
    var payload = JSON.stringify(jsonData);

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

    UrlFetchApp.fetch(postUrl, options);
  }
}

上記のコードでAPIを公開します。
チャンネルIDはSlackの任意のチャンネルで右クリック>リンクをコピーすると取得できます。

https://ワークスペース名.slack.com/archives/チャンネルID

GASのAPI公開の仕方はこちらを御覧ください。

Incoming Webhookの設定

GASとIncoming Webhookの連携の記事はメチャクチャあるので、是非そちらを参照してみてください。
(例えばこんな記事

Incoming Webhookから発行されたURLをGASに設定してAPIを公開し直したら完了です。

動作確認・問題点

チャンネルIDを設定したチャンネルで、キーワードを含んだ投稿をして、Incoming Webhookの向き先のチャンネルに通知が落ちたら完成です。

問題点としては、現状GASのAPIがWorkspace配下のチャンネルでの投稿すべてに反応してしまい、GAS側でチャンネルIDから条件分岐をしているので、どうしてもGASの実行回数が増えてしまいます。
せめてチャンネルだけでもSlackApi側で指定できないかなぁと試行錯誤中です。
知見のある方いたら教えて下さいm(_ _)m

20201229追記

わざわざImcoming Webhookのアプリ入れなくても、SlackApiのImcoming Webhookの機能使えばできるやん