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

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

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

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

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

# 構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508796/ef5065a1-018f-8cbf-41cb-ad02d3f59d6f.png)
例にもれずSlackApiとGASの組み合わせで実装します。
ただ、今回はOutgoing Webhookは使わないので、SlackApiをカスタマイズして投稿を拾い、GASでチャンネルとキーワードを確認、確認後に任意のチャンネルにIncoming Webhookで通知を落とします。

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

SlackApiの設定周りは[こちら](https://qiita.com/risto24/items/342256f6ed6cb504059a)を参考にさせていただきました。
詳しくは上記を御覧ください。

SlackApi管理画面のEvent SubscriptionsにてGASのAPIのURLの登録と、APIを叩くイベントの設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508796/2af853b9-f931-6e16-4632-a77ddfc4a657.png)

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

```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**のイベントを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508796/1cb0a9e7-bb73-e4e4-adbf-90c4c5f1e900.png)

これが完了したら、任意のワークスペースに、この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を書きます。

```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公開の仕方は[こちら](https://qiita.com/10inoino/items/b010070338e4361635e5)を御覧ください。

# Incoming Webhookの設定
GASとIncoming Webhookの連携の記事はメチャクチャあるので、是非そちらを参照してみてください。
（例えば[こんな記事](https://qiita.com/chihiro/items/c7b11abc78f5d806c3a8)）

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

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

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

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