GASとSlackワークフロービルダーを連携してGoogleカレンダーの予定をリマインドする

# GASとSlackワークフロービルダーを連携してGoogleカレンダーの予定をリマインドする
## 概要
「Slack上で動的なリマインダーを作れないか？」
と思い調べていたら、GASと連携してリマインダーが簡単に作れそうだったので手順を記載します。

### やること
**GAS**と**Slackワークフロービルダー**を連携し、**Googleカレンダー**の今日・明日の予定を毎朝リマインドするようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112941/d22466b6-55c3-9644-e6cd-865d3710ab2f.png)
※この画像は手動実行したので時間が異なります

大まかな処理の流れは以下の通りです。
1. GASでGoogleカレンダーから予定を取得する
2. Slackワークフロービルダーに予定を送信する
3. Slackワークフロービルダーが受信した予定をチャット上に通知する
### GASとは？
**GAS（Google Apps Script）**はGoogleが提供するスクリプト環境で、WebアプリやWebAPIを簡単に作成できます。
※利用にはGoogleアカウントが必要

GASのプロジェクトの作り方については[こちら](http://makimakimakino.hatenablog.com/entry/2017/03/16/010759)の説明などを確認してください。

## Slackワークフロービルダー
**ワークフロービルダー**とはSlack上の定型作業を自動化する為の機能です。
`remind`コマンドと似ていますが、ワークフロービルダーではGUI上で簡単に設定できます。
※スタンダードプラン以上のユーザのみ利用可能

詳しくは[ワークフロービルダーガイド](https://slack.com/intl/ja-jp/help/articles/360035692513-ワークフロービルダーガイド)を確認してください。


## 手順

### Slackのワークフロービルダーを設定する
以下のように[Webhook](https://qiita.com/soarflat/items/ed970f6dc59b2ab76169)をトリガーとしたワークフローを作成します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112941/03a14fe6-e64e-825e-ab4f-b5efe0fc0794.png)

#### Webhook > GASからPOSTする変数を設定する
以下の変数を設定しています

- `today`
- `tomorrow`

#### メッセージを送信 > リマインドするメッセージの内容を設定する
1. メッセージの送信先を自分に設定する
2. Webhookの変数を含めたメッセージを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112941/bae5d3ed-851d-509e-e85d-f78589eeb217.png)

### GASの実装・設定する
#### GASのスクリプトを作成する
以下の処理を行うスクリプトを作成します。
1. Googleカレンダーから今日と明日の予定を取得する
2. 上記で取得した予定から文章を生成する
3. 生成した文章をJSON形式にする
4. SlackワークフロービルダーにJSONをPOSTする
  ※特定の曜日にだけ通知するように条件指定（トリガーを簡単にする為）

```javascript
/**
* トリガーが実行する関数
*/
function main() {
  let today = new Date();
  let dayOfWeek = today.getDay();
  if (dayOfWeek >= 1 && dayOfWeek <= 5) { // （月）～（金）の場合
    send(generate(today));
    console.log("message has sent.");
  } else {
    console.log("message hasn't sent.");
  }
}
/**
* 今日と明日の予定を持ったオブジェクトを生成する
*/
function generate(today) {
  let tomorrow = new Date();
  tomorrow.setDate(today.getDate() + 1);
  let todayEvents = CalendarApp.getEventsForDay(today);
  let tomorrowEvents = CalendarApp.getEventsForDay(tomorrow);
  let createMessage = e => `- ${format(e.getStartTime())} - ${format(e.getEndTime())} ${e.getTitle()} `; // 「- 開始時間 - 終了時間 予定名」の文字列を生成
  let todayMessages = todayEvents.map(createMessage);
  let tomorrowMessages = tomorrowEvents.map(createMessage);
  let joinMessages = messages => messages.length === 0? 'なし': messages.join("\n"); // 予定がない場合は「なし」、ある場合は改行で連結する
  return {
    today: joinMessages(todayMessages),
    tommorow: joinMessages(tomorrowMessages)
  } 
}
/**
* Dateを時分（HH:mm形式）の文字列に変換する
*/
function format(date) {
  let hours = ('0' + date.getHours()).slice(-2);
  let minutes = ('0' + date.getMinutes()).slice(-2);
  return `${hours}:${minutes}`
}

/**
* HTTP POSTを送信する
*/
function send(obj) {
  let params = {
    'method' : 'post',
    'contentType': 'application/json',
    'payload' : JSON.stringify(obj)
  };
  
  UrlFetchApp.fetch('https://hooks.slack.com/workflows/{ワークフロー固有の文字列}', params); 
}
```

#### プロジェクトのトリガーを設定する
毎朝9~10時にリマインドするようにトリガーを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112941/982f11d9-4fa0-923c-fd58-7f15c83e2893.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112941/b26c7d09-26ef-62f4-6a65-49c17d620589.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112941/9d417729-f521-69f5-806b-b7191504e5cb.png)

以上の設定により、指定した時間にSlack上にリマインド通知がされるようになります。
## あとがき
単純なリマインダーならワークフロービルダー単体で作成可能ですが、
動的なリマインダーはプログラムで実装したくなるのでWebhookを使って外部サーバと連携できるのは便利だと思いました。