【Slack bot】「問いかけによって、スプレッドシートから値を取得してきて応答するbot」をSlack APIで実装する

#前回の内容

　前回は、「Googleスプレッドシートの出社表から自分の出社日を探し、その前日に「明日は出社日！」とSlackにリマインダーを送信してくれるスクリプト」を作りました。
[出社日の前日にSlackへリマインダーを送信するスクリプト](https://qiita.com/fkdmkhr/items/981a8128ee163b28d32b)

#今回やりたいこと

　今回は、Slackに出社日を問いかけると、該当日付をGoogleスプレッドシートから取得して教えてくれるSlack botを作ります。
　具体的には以下のようにしたいです。
　・「次の出社日」と投稿→未到来の直近の出社日を返す
　・「出社日一覧」と投稿→未到来のすべての出社日を返す
　また、Slack botの作成について、Outgoing Webhookは非推奨ということなので、今回はSlack APIを使用します。

#スプレッドシートの作成
前回使用したスプレッドシートにF列（曜日）を追加しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/a2093353-6f8a-b160-0f7f-e502601f5c9d.png)

#Slack APIの設定①

1.[Slack APIの設定ページ](https://api.slack.com/apps)にアクセス
2.「Create New App」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/b9fcb13a-d286-b397-ccbc-d526144518ea.png)
3.「App Name」と「Workspace」を入力し、「Create App」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/feaf1cb3-7e92-a85f-bc73-8db9e0fb8a13.png)
4.「Bots」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/2a47c503-f2e0-ede0-c2ea-91ed5c5b2d92.png)
5.左側のメニューから「OAuth & Permissions」を選択し、「Bot Token Scopes」に以下を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/478b98d8-48c5-c95a-1e09-8df8ffc93fe8.png)
6.「Install App to Workspace」をクリックし、権限のリクエストを許可する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/333f4c1b-3980-403f-a355-5bf00244aef6.png)
・Bot User OAuth Access Tokenが発行されたらいったんOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/b416a09c-a7ec-ba04-1132-3dcb6f4a7cae.png)


#実装①
参考にした記事
[Outgoing Webhook の代わりとして Slack App の Event Subscriptions を使う](https://etauthenonprogrammercoder.tumblr.com/post/185572851353/gasslack-appoutgoing-webhook-%E3%81%AE%E4%BB%A3%E3%82%8F%E3%82%8A%E3%81%A8%E3%81%97%E3%81%A6-event)

1.GASの記述

```
function doPost(e) {
  var json  = JSON.parse(e.postData.getDataAsString());

  if (json.type === 'url_verification') {
    return ContentService.createTextOutput(json.challenge);
  }
}
```

2.スクリプトのプロパティの設定
・「ファイル」→「プロジェクトのプロパティ」→「スクリプトのプロパティ」を選択
・プロパティ名に「SLACK_ACCESS_TOKEN」、値には前述のSlack APIの設定で取得できる「Bot User OAuth Access Token」を入力し、保存をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/51de2ffb-8be3-62d7-2e7f-47a45b308b44.png)

3.ライブラリの設定

参考にした記事
[Slack BotをGASでいい感じで書くためのライブラリを作った](https://qiita.com/soundTricker/items/43267609a870fc9c7453)

・「リソース」→「ライブラリ」を選択
・ライブラリキーに「M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO」を指定し、追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/c782d83a-a930-6216-83b7-297541fe9e1f.png)

4.アプリケーションを公開
・「公開」→「Webアプリケーションとして導入」を選択
・以下の設定で「Deploy」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/52979dcd-5120-df47-30a3-08b248cd9709.png)
・URLが発行される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/fcf1b420-9e96-d901-5e8f-6039536f10f0.png)

#Slack APIの設定②

1.左側のメニューから「Event Subscriptions」を選択し、「Enable Events」をOnに変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/5386a9c4-d37e-5385-917c-f4dee31adf7a.png)
2.Request URLに「4.アプリケーションの公開」で取得したURLをペースト（Verifiedが表示されればOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/b49111e5-a179-1388-917b-4fe7d284078a.png)
3.「Subscribe to bot ebents」と「Subscribe to events on behalf of users」を以下のように設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/dc1eebc1-2529-b9f4-c74e-89d40067c9d0.png)
4.変更を保存し、Slack AppをReinstallする（Reinstall後に以下のように表示されればOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/cd36d472-a30e-33ce-60a5-6f4a48886225.png)

#実装②
1.GASを修正

```
function doPost(e){
  
  var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN');  
  var slackApp = SlackApp.create(token); //SlackApp インスタンスの取得
  
  //スプレッドシートを取得
  var obj = SpreadsheetApp.openById("");//スプレッドシートのキー
  var sheet = obj.getSheetByName("");// シート名
  var lastRow = sheet.getLastRow();
  
  var json = JSON.parse(e.postData.getDataAsString());
  var text = json.event.text;
  var workDay = null;
  
  if (text === "次の出社日") {
    workDay  = searchSingleWorkDay(sheet, lastRow);
    var options = {
      channelId: "", //チャンネルID
      userName: "出社日検索bot", //投稿するbotの名前
      message: "次の出社日は " + workDay + " です！", //投稿するメッセージ
      icon_emoji: ":spiral_calendar_pad:", //投稿するbotのアイコン
    };
  } else if (text === "出社日一覧") {
    workDay = searchAllWorkDay(sheet, lastRow);
    var options = {
      channelId: "",
      userName: "出社日検索bot",
      message: "未到来の出社日一覧です！\n" + workDay,
      icon_emoji: ":spiral_calendar_pad:",
    };
  }

  //キャッシュを設定
  var channel = json.event.channel;
  var ts = json.event.ts;
  var cache = CacheService.getScriptCache();
  var cacheKey = channel + ":" + ts;
  var cached = cache.get(cacheKey);
  if (cached != null){
    console.log("test");
    return;
  }
  cache.put(cacheKey, true, 600);
  
  //Slackに送信
  slackApp.postMessage(options.channelId, options.message, {username: options.userName, icon_emoji: options.icon_emoji});
}

//次の出社日を探索
function searchSingleWorkDay(sheet, lastRow){

  for(var i=3; i<=lastRow; i++){
    for(var j=2; j<=4; j++){
      if(sheet.getRange(i, j).getValue() === "探索したい文字列" && !sheet.getRange(i, 5).getValue()){
        var workDay = sheet.getRange(i, 1).getValue() + "(" + sheet.getRange(i, 6).getValue() + ")";
        return workDay;
      }
    }
  }
}

//未到来の出社日一覧を探索
function searchAllWorkDay(sheet, lastRow){

  var workDay = "";
  
  for(var i=3; i<=lastRow; i++){
    for(var j=2; j<=4; j++){
      if(sheet.getRange(i, j).getValue() === "探索したい文字列" && !sheet.getRange(i, 5).getValue()){
        workDay = workDay + sheet.getRange(i, 1).getValue() + "(" + sheet.getRange(i, 6).getValue() + ")" + "\n";
      }
    }
  }
  return workDay;
}
```

2.GASを修正したら再びWebアプリケーションを公開する
（2回目以降は「Deploy」ではなく「更新」に表示が変わる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/c7529a19-fc10-9c77-9bc4-5d7b6de2a606.png)

#Slackにアプリを追加

Slackを開き、GASで指定したチャンネルに「チャンネル詳細」→「その他」→「アプリを追加する」でアプリを追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/2b080776-7122-933f-5d42-0fb077bd4cbd.png)

#実行

・「次の出社日」と投稿→未到来の直近の出社日を返す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/8c753936-b0a2-e8f1-db90-1ca5f4f98708.png)
・「出社日一覧」と投稿→未到来のすべての出社日を返す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674043/ff53dc61-759f-073f-615d-eaa289d17c9b.png)
できた！