Slackで任意のユーザのGoogleカレンダーの予定を確認するスラッシュコマンドを作る

[ハンズラボ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/handslab) 9日目の記事です。

Googleカレンダー使ってますか？
G Suiteを使っている会社に勤めている方なら使っていますよね。
チームメンバーの予定を確認する時にはPCのブラウザでGoogleカレンダーを開けば一覧で見られて良いですが、電話対応時などで今すぐ予定を確認したい時などには、ブラウザでGoogleカレンダーを開き、該当の人を検索し、予定を見る……というのがなかなか億劫で時間がかかったりします。
弊社で電話をよく取ってくださる方が、ブラウザで十数人のカレンダーを開いた画面を食い入るように見ながら電話対応をしていて、これはなかなか非効率的ではないか……？と思い、簡単に予定を確認できるツールを作ることにしました。

業務中はSlackを常時開きっぱなしにしている人が多く、また非エンジニアが簡単に使えるツールになるよう、SlackのスラッシュコマンドでGoogleカレンダーの予定を確認できるようにしました。
今回は、Googleカレンダーを簡単に呼び出せるよう、GoogleAppsScript（GAS）を用いて作成します。

## 完成品
Slackの任意のチャンネル（DMを含む）で `/getschedule @hoge yyyymmdd` と入力すると、任意のSlackユーザーのGoogleカレンダーの予定を呼び出すことができるスラッシュコマンドを作成します。
<img width="425" alt="スクリーンショット 2018-10-21 23.47.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/f47f645f-7189-8795-af6d-208abc006552.png">

ここでは、Slackユーザーが登録しているメールアドレスがGmailアドレスであり、かつそのアカウントでGoogleカレンダーに予定を登録していることを前提に作成します。

## 手順ざっくり
1. GASのプロジェクト作成
2. Slackのスラッシュコマンドの作成
3. コーディング
4. 動作確認




## 1. GASのプロジェクト作成
### 1-1. スラッシュコマンドに必要なURLを取得
[Google Apps Scriptのホーム画面](https://script.google.com/home)を開き、左上の「新規スクリプト」ボタンをクリックします。
<img width="338" alt="GAS_home.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/58b595d9-8581-3de2-cf34-529699d4cb4c.png">
無題のプロジェクトが作成されます。
とりあえずコードは書かず、初期状態のままSlackのスラッシュコマンドの設定に必要なURLを取得していきます。
上部メニューの「公開」 > 「ウェブアプリケーションとして導入…」をクリックします。
<img width="280" alt="GAS_manu.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/2575366b-0c21-312a-2bab-9f11d8edfd69.png">

| 設定内容 | 設定値 | 備考 |
| --- | --- | --- |
| プロジェクトバージョン | 新規作成 | その下の入力欄はバージョンの説明 |
| 次のユーザーとしてアプリケーションを実行 | 自分 |  |
| アプリケーションにアクセスできるユーザー | 全員（匿名ユーザーを含む） |  |
- Slackのスラッシュコマンドでこのアプリケーションを実行する際には匿名のユーザーとなるため、匿名のユーザーでアクセスできるようにし、カレンダーの閲覧権限を得るために自分のユーザーで実行するようにします。 ※ スクショではアクセスの設定間違えました……。

<img width="239" alt="GAS_installAsWebApp.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/0fdc7cd3-f551-06ac-aead-28fe44bdc2f9.png">

下の「導入」ボタンをクリックすると、ウェブアプリケーションのURLが表示されます。
このURLを使用してスラッシュコマンドを作成します。
<img width="228" alt="GAS_installAsWebApp_done.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/40bb88e4-649a-4c1b-ad02-88fca3d581f6.png">

## 2. Slackのスラッシュコマンドの作成
### 2-1. Slack Appを作成
スラッシュコマンドを作成するのに必要なSlack Appを作成します。
[SlackAPIのYour Appsのページ](https://api.slack.com/apps)を開き、右上の「Create New App」をクリックします。
<img width="750" alt="YourApps.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/3a4f714b-ed26-7905-cc34-1f5027b7db1d.png">
App NameとSlack Workspaceを設定します。App Nameはスラッシュコマンドの名前とは紐づきません。
<img width="269" alt="CreateSlackApp_written.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/aeebc69c-f117-a612-90e3-ab390572d139.png">


Slackアプリを作成すると、「Basic Information」画面になります。
「Add feature and functionality」をクリックすると、そのアプリの機能を追加することができます。
今回はスラッシュコマンドを作成するため、「Slack Commands」をクリックします。
<img width="750" alt="BasicInformation_first.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/0aafbcb7-03ea-737b-e371-a135ec3e7e08.png">
「Slash Commands」画面で「Create New Command」ボタンをクリックし、
新しくコマンドを作成します。

### 2-2. スラッシュコマンドを作成
<img width="1683" alt="CreateSlashCommand.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/a87d016a-4783-85f0-2cd4-233f01388e01.png">

| 設定内容 | 設定値 |
| --- | --- |
| Command| コマンド名 |
| Request URL | 新規作成 |
| Short Description | スラッシュコマンドの説明 |
| Usage Hint | （オプション）引数の説明など、使い方のヒント |
| Escape channels, users, and links sent to your app | チェックしない |

以上の設定が完了したら右下の「Save」をクリックしてスラッシュコマンドの作成は完了です。

### 2-3. Slack AppをWorkspaceに追加
スラッシュコマンドを作成しただけでは、Slack内で使用することはできません。
スラッシュコマンドが紐づいたSlack AppをSlack内に導入します。
「Basic Information」画面にて、「Install your app to your workspace」をクリックし、出てきた「Install App to Workspace」ボタンをクリックします。

<img width="750" alt="BasicInformation_second.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/ae67fb6c-60d1-2afb-b8db-a8b26f0ec440.png">

<img width="586" alt="BasicInformation_add.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/0ac83b67-d116-bd6c-8877-99089c0f83b4.png">

「Authorize」をクリック

<img width="1681" alt="BasicInformation_third.png" src="https://qiita-image-store.s3.amazonaws.com/0/149055/998d3581-b71c-b99a-19ee-68330ad2198b.png">

ここまでできると、Slack上で作成したスラッシュコマンドが出てくるようになります。
が、実行してもエラーが返ってくるだけです。
![installedApp.png](https://qiita-image-store.s3.amazonaws.com/0/149055/736878ce-91c3-d2e7-a995-40ab1cd4db1b.png)

### 2-4. トークンを取得する
Slack Appの「Basic Information」画面内の「Add feature and functionality」、「Permissions」の順にクリックして「OAuth & Permissions」のページを開きます。
このページの「OAuth Access Token」を保存しておきます。
これはGASからSlackを使うのに必要なので、あとで使用します。

## 3. コーディング
### 3-1. とりあえず動くものを作る
実際にスラッシュコマンドから想定のレスポンスが返ってくるように、GASにコードを書いていきましょう。
まず手始めに、スラッシュコマンドに渡した引数をオウム返しさせるようにコードを書いていきます。

```js 
function doPost(e) {
  var text = e.parameter.text; // 入力された文字列を抜き出す
  var responseText = text;
  var response = { text: responseText }; // レスポンス用の文字列を生成
  var json = JSON.stringify(response) // 文字列をJSONに変換

  var output = ContentService.createTextOutput(json); // Webアプリケーションとして出力するテキストを作成
  output.setMimeType(ContentService.MimeType.JSON); // outputのメディアタイプをJSONに設定

  return output;
}
```
これだけ書けば、あとは `responseText` に入れる値をゴリゴリ作っていくだけです。


### 3-2. Slackのユーザーのメールアドレスを取得する
次に、SlackのAPIを使ってユーザーのメールアドレスを取得して返す関数を書いていきます。
が、その前にライブラリにSlackAppを追加しましょう。
GASのメニュー リソース > ライブラリ を選択し、Library Keyに `M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO` を入力してSlackAppを追加しましょう。
また、Slackを使用するためにトークンが必要となります。コードに直書きしてもいいですが、ここはプロパティに書き込みましょう。
GASのメニュー ファイル > プロジェクトのプロパティ を選択し、「スクリプトのプロパティ」タブをクリックします。
「行を追加」をクリックし、プロパティに「token」、値に先ほど保存した「OAuth Access Token」を入力し保存します。

```js
const prop = PropertiesService.getScriptProperties().getProperties();
Logger.log(prop.token)
```
上のようにプロパティに保存した値を取得できます。
これでSlackが使えるようになったので、SlackAPIを使用してユーザー一覧を取得し、その中から任意のユーザーのメールアドレスを取得していきます。

```js
function getEmail(name) {
  const prop = PropertiesService.getScriptProperties().getProperties();
  const slackApp = SlackApp.create(prop.token);
  const list = slackApp.usersList();
  const members = list["members"];

  for(i=0; i<members.length; i++) {
    if (members[i]["name"] == name) {
      Logger.log(members[i].name);
      return members[i].profile.email
    } else {
      continue;
    }
  }
}
```

### 3-3. Googleカレンダーから予定を取得する
メールアドレスが取得できたので、Googleカレンダーから予定を取得します。
GASは標準でGoogleカレンダーを操作できます。
`calendar.getEventsForDay(date)` で1日分の予定のCalendarEventのArrayを取得できます。
`.getStartTime()` や `.getEndTime()` で予定の開始時間と終了時間を取得できますが、終日イベントは開始・終了共に `00:00` になるようです。

```js
var calendarId = getEmail(userName);
var calendar = CalendarApp.getCalendarById(calendarId);
var date = new Date();   
var events = calendar.getEventsForDay(date);
// Slack用のテキストを整形
var responseText = name + "さんの今日の予定\n```";
if (events.length == 0) {
  responseText += "なし";
} else {
  for (var i=0; i<events.length;i++) {
    var title = events[i].getTitle();
    var startTime = HHmm(events[i].getStartTime());
    var endTime = HHmm(events[i].getEndTime());
    if (startTime == "00:00" && endTime == "00:00") {
      responseText += "\n終日: " + title;
    } else {
      responseText += "\n" + startTime + "〜" + endTime + ": " + title;
    }
  }
}
```

### 3-4. 完成品
予定を参照する日付などを端折って紹介してきたので、完成品のコードはこちらをご覧ください。
https://github.com/kurapy-n/GetSchedule


# 参考
- Slack - Slash Commands
    - https://api.slack.com/slash-commands
- Google Apps Script - Simple Triggers
    - https://developers.google.com/apps-script/guides/triggers/
- Google Apps Script - Class PropertiesService
    - https://developers.google.com/apps-script/reference/properties/properties-service
- Google Apps Script - Class CalendarApp
    - https://developers.google.com/apps-script/reference/calendar/calendar-app
- Slash CommandsとGASでSlackのオリジナルコマンドをつくる
    - https://qiita.com/chikuwa111/items/7a1a349b82318a5861cc
- Slack - api.test method
    - https://api.slack.com/methods/api.test/test