【GASで作るslack bot】スプレッドシートと連携してシフト管理botを作る（予定の入力と確認通知）

# はじめに
　歴も長いことからインターン先でチームのまとめ役を担うことになり、これまで手作業で行っていたシフト管理を自動化したいとの思いからシフト管理botを作ることにしました。
　本記事で紹介するのは一般的な「月一で次月の勤務希望日を提出する」シフト管理ではなく、「明日の勤務の予定時間を登録する」ものとなっています。ちょっと特殊な仕様かもしれませんが、見ていただいた方の一助となれば幸いです。

# botアプリの構成
###構成概念図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/26bbf8af-f145-31b1-53f8-29b9db1b525a.png)

|構成要素|用途|
|:-----------|:------------|
| Slack       |構成員による勤務予定時間の投稿、botによる投稿確認の通知        |
| Spreadsheet     |勤務予定時間の保存      |
| Google Apps Script (GAS)    |botの動作の記述（JavaScript）      |
| Incoming Webhook     |botからの通知      |
| Outgoing Webhook     |Slackに投稿された特定のワード（トリガーワード）をトリガーとし、GASに記述したコードを実行する      |

# アプリケーションの作成
<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/5e55bc81-79e6-c720-bc1f-d32bfca1a022.png">

[Slack api のページ](https://api.slack.com/apps)からアプリケーションの作成を行います。```Create New App``` を押すと図のような画面に移るので、
「App Name」にはbotにつける名前を設定し、「Development Slack Workspace」ではbotを導入したいWorkspaceを選択します。以上2点が設定されたら```Create App```を押します。遷移先の画面で先ほどつけた名前のアプリケーションが追加されていることを確認してください。


# Google Apps Script (GAS)
　Google Drive 内で右クリックから```その他```→```Google Apps Script```を選択します。すると新たなプロジェクトが生成され、アプリの挙動を記述するためのエディタが開きます。
　説明の都合上、ひとまずこのままウェブアプリケーションとして公開します（中身の記述は後半に記述します）。```公開```→```ウェブアプリケーションとして導入```をクリックし、プロジェクトに名前をつけると、「Deploy as web app」というウィンドウが開きます。ここでは以下の2項目を設定します。

<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/80e795b7-b9d2-6442-cea3-4ea79c0b2b93.png">

「version」→　デプロイするアプリのバージョンを指定。```New```を選択。
「Who has access to the app」→　```Anyone, even anonymous``` に設定。

そして```Deploy```を押すと、WebアプリケーションのURLが表示される（Outgoing Webhookの設定でこのURLを用います）。

# Incoming Webhook の設定
[Slack api のページ](https://api.slack.com/apps)で先ほど作成したアプリをクリックし、att_management_botに関する基本画面に移ります。Featuresの「Incoming Webhooks」をクリックし、遷移先のページでIncoming Webhooksをアクティベートします（画面右上の```off```をクリックし```on```にする）。
　するとページ下方に「Webhook URLs for Your Workspace」が現れます。（Incoming Webhookは作動する状態になりましたが）botがどのチャンネルに投稿すれば良いかが設定されていないので、その設定を行います。```Add New Webhook to Workspace```を押し、連携したいチャンネルを選択し```許可する```を押します。
　「Webhook URLs for Your Workspace」の部分が更新されていることを確認してください。「Webhook URL」が生成され、curlコマンドによって動作を確認することができます。

### 確認してみる
```terminal

curl -X POST -H 'Content-type: application/json' --data '{"text":"Hello, World!"}' <incoming webhookの設定で得られるURL>
```

<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/9f36518e-f104-b820-8399-a152558612ee.png">
terminalを開き、「Sample curl request to post to a channel:」以下の部分をコピーアンドペーストして実行してみます。すると先ほど指定したチャンネル（#test_kintai）にatt_management_botから「Hello, World!」という投稿が行われることが確認できます。


# Outgoing Webhook の設定
ブラウザで「https://<ワークスペース名（小文字）>.slack.com/app」にアクセスします。検索欄に「Outgoing Webhook」と打ち込み、検索します。「Outgoing Webhook」のページに遷移したら、```Slackに追加```を押し、遷移先の画面で```Outgoing Webhook のインテグレーションの追加```を押します。

<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/c621ffe7-cec9-d14e-4ba0-5f7d4163d6f9.png">

　すると、Outgoing Webhook の設定のページに移ります。ここでは以下の３項目を設定します。

「チャンネル」　　　　→　連携したいチャンネル（#test_kintai）
「引き金となる言葉」　→　botを作動させる合言葉（att_entry）
「URL」　　　　　　　→　botの挙動を記述したGASのURL（WebアプリケーションのURL）

本説明では図のように設定しています。```設定の保存```を押して設定を完了します。

### 確認してみる
　ここで、#test_kintai チャンネルにトリガーワードである「att_entry」を投稿して、GASに記述した挙動が正しく行われるかを確認します。先ほどのGASには特にコードは記述していなかったので、現状何も起きません。GASに以下のようなコードを記述し、反応を見てみます。なお、< > の部分はincoming webhookの設定の際に得られたURLに変更してください。

```javascript

postSlack("test");

function postSlack(text){
  var url = "<incoming webhook を設定した時のURL（botから投稿先のSlackのチャンネル）>";
  var options = {
    "method" : "POST",
    "headers": {"Content-type": "application/json"},
    "payload" : '{"text":"' + text + '"}'
  };
  UrlFetchApp.fetch(url, options);
}
```

test_kintai チャンネルにトリガーワードである「att_entry」を投稿してみましょう。att_management_bot から「test」というテキストが帰ってくれば成功です。これで、Slack → GAS → Slack の連携が取れるようになりました。

<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/d533330d-2962-72b5-6d59-7f26cba503cd.png">


# GASとスプレッドシートの連携
### スプレッドシートの作成
 Googleドライブ内で新たにスプレッドシートを作成します。今回は構成員が、①勤務するか否か（entry (yes or no)）、②勤務を開始する時間（time）、を登録したいので、図のようなワークシートを作成しておきます。
<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/20002ad7-c735-8626-ae48-0fcc61a2e6d4.png">

|構成要素|用途|
|:-----------|:------------|
| input date       |投稿日時        |
| name     |投稿した構成員の名前     |
| command    |トリガーワード      |
| entry (yes or no)     |勤務するか否か      |
| time     |勤務開始予定時間|

### GASの記述
今回は以下のようなコードを作成しました。

```javascript
function doPost(e) {
/*   //test（Slackからjson形式で以下のようにデータが送られてくる（一部分）。GAS上で実行テストを行う際にはこの部分のコメントアウトを外して実行してください。）
  e = {
    parameter : {
      user_name : "hoge_hoge",
      text : "att_entry yes 23:45",
    }
  }
*/
  var data = e.parameter.text // textを取得
  var username = e.parameter.user_name // user_nameを取得
  data = username + ' ' + data // dataの結合（[user_name] [yes or no] [time]）
  data = data.split(' ') // dataをスペース区切りで分割
  recordData(data);
}

// botからSlackへの投稿
function postSlack(text){
  var url = "<incoming webhook を設定した時のURL（botから投稿先のSlackのチャンネル）>";
  var options = {
    "method" : "POST",
    "headers": {"Content-type": "application/json"},
    "payload" : '{"text":"' + text + '"}'
  };
  UrlFetchApp.fetch(url, options);
}

// Spreadsheetへの入力
function recordData (data) {
  var spreadsheet = SpreadsheetApp.openById('<スプレッドシートのID>');
  var recordsheet = spreadsheet.getSheetByName('シート1');  
  var lastrow = recordsheet.getLastRow();
  var recordrow = lastrow + 1;
  var date = new Date();
  var formatdate = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');
  
  // セルを指定してdataを入力
  recordsheet.getRange("A" + recordrow).setValue(formatdate);
  recordsheet.getRange("B" + recordrow).setValue(data[0]);
  recordsheet.getRange("C" + recordrow).setValue(data[1]);
  recordsheet.getRange("D" + recordrow).setValue(data[2]);
  recordsheet.getRange("E" + recordrow).setValue(data[3]);
  
  // 入力完了をSlackへ通知
  postSlack(data[0] + "さんの勤務予定を入力しました\n" + "勤務予定時間：" + data[3]);
}
```

2箇所の<incoming webhook を設定した時のURL（botから投稿先のSlackのチャンネル）>と<スプレッドシートのID>をそれぞれ書き換えてください。なお<スプレッドシートのID>は、スプレッドシートのURLの
```https://docs.google.com/spreadsheets/d/[この部分]/edit#gid=0
```
[この部分]を渡します。
　GASにコードを入力したら保存し、ウェブアプリケーションとして公開します（公開の際にはversionを```New```に設定）。

### 確認してみる
　Slackのtest_kintaiチャンネルに半角スペース区切りで「[トリガーワード] [勤務の有無（yes or no）] [勤務開始時間]」を投稿してみましょう。
<img width="600" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431877/1786fe48-30cd-2a69-db41-676079be5316.png">
すると上図のようにbotから勤務入力の確認の投稿が送信されてきます。また、スプレッドシートの方を確認してみると、投稿した予定時間が入力されていることが確認できます。なお、SlackからPOSTされたデータに含まれるuser_nameは、Slackの表示名ではありません。この部分はブラウザからアカウント設定を開き、「ユーザ名」の部分を編集することによって変更することができます（なお、Slackより「1時間に2回以上ユーザー名を変更することはできませんので、名前の選択は慎重に！」との記述あり）。
　以上でSlack、GAS、スプレッドシートの連携を確認することができました！

# 最後に
　今回作成した勤務時間管理のシステムはとてもシンプルなものです。同じ人が何回か登録すると、内容は上書きされずにシートにどんどん追加されていきます。この部分に関しては作成したいシステムの仕様に合わせて、GAS内のコードを追加・編集していただければと思います。

### 参考にさせていただいた記事
[Slackとスプレッドシートを連携して筋トレ管理する](https://techblog.gmo-ap.jp/2019/09/06/)