消灯当番を決めてくれるSlackのBotを作る①　～とりあえず返事だけしてくれ編～

#ことの起こり
弊社では入社1年目の社員には新人業務ということで、「**電話応対**」と「**昼休みの消灯・点灯**」の仕事があります。

電話応対は読んで字のごとく、外線からのコールに応えるものです。
昼休みの消灯・点灯について、弊社では昼休みである12:00から13:00の間、照明を落とす決まりがあり、そのスイッチャーを入社1年目の社員が担っています。（以下、消灯係）

電話応対は全員で早い者勝ちです。分担などは特にしていません。（離席で取れなかった場合などがあるため）

さて消灯係の分担ですが、独自のルールを採用しています。
それは、「**各週で電話応対の回数が最も少なかった2人に任命する**」というルールです。詳細は以下。

1. 毎週金曜日の正午に、電話応対の回数の集計を締め切り、選出を行う。
2. 電話応対の回数が少なかった人から順に任命。
3. 同率で人数が溢れた場合は抽選。
4. 全員の回数の合計が、1年目社員の総合人数を下回った場合は、電話応対の回数に関わらず全員で抽選。
5. 任命が終了したら集計をリセット。再び翌週の金曜日の正午まで集計を行う。


電話の回数の集計方法ですが、新人のみのSlackに電話を取ったとき用のスタンプがあるので、それで報告します。
<img width="141" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/2872c0f7-d709-9370-c2e0-1a7ca099808c.png">
このスタンプの数を集計するようにしていました。

以前は、特定の1人に集計を任せていました。しかし、そうすると必然的にヒューマンエラーが発生し、集計ミスなどが起こります。
ここで、「**SlackBotで自動化できないか**」という案が浮かび、今回のSlackBotを作成する運びとなりました。

今回は、SlackBotの作り方を初学者向けにまとめながら、消灯当番用SlackBotの顛末を書き綴りたいと思います。

#SlackBotの作り方
Botの作り方は複数あります。Bot Users、Slash Command、Unfurling links・・・など。

いろいろ調べた結果、今回は**Webhook**を使用することにしました。
理由は・・・なんとなく使いやすそうだったから・・・です・・・。

とりあえず何でもいいので、とにかく作ります！
##Webhookを設定
###Webhookって何ですか？
「設定したURLにPOSTリクエストを送るもの」らしいです。
私も詳しいことはわかりません・・・。

Webhookとは？
https://qiita.com/soarflat/items/ed970f6dc59b2ab76169

こちらの記事に詳しい説明が載っていますので、ご参考にどうぞ。（他力本願）

さて、今回Slackで設定するWebhookは2種類あります。
**Outgoing Webhook** と **Incoming Webhook**です。
###Outgoing Webhooks
こちらは簡単に言うと、**Slackで特定のキーワードが投稿されると反応するApp**です。

百聞は一見に如かず、さっそく設定してみましょう。

Slackのチャンネルの「会話の設定」から「アプリを追加する」を選び、Outgoing Webhookを検索します。
ヒットしたものをクリックすると、このような画面に遷移されます。
<img width="742" alt="1-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/888522e5-e9eb-278b-2f5a-ce150aa34d99.png">
「Slackに追加」→「Outgoing Webhook インテグレーションの追加」とクリックすると、新しいWebhookのアカウントのようなものが作られます。
<img width="762" alt="1-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/d7f6b449-0ec3-6d01-e79a-db21147b5781.png">
ページの下の方に行くと、「インテグレーションの設定」という項目があるので、こちらで設定をしていきます。
（「Outgoingペイロードとレスポンス」は今は無視！）
<img width="759" alt="1-4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/6a9e94ab-e77a-4119-2334-12ee089ceed3.png">
####チャンネル
発言を拾うチャンネルを設定します。
ここで新しくチャンネルを設定することもできます。

どうやら、既存のプライベートチャンネルは設定できないみたいですね・・・。
####引き金となる言葉
全部の発言を拾われると困るので、キーワード（トリガー）を設定します。
ここで設定した言葉で始まる行があった場合のみ、Webhookに拾われます。
また、コンマで区切ることで複数のキーワードも設定できるし、`:スタンプ名:`という風にすればスタンプも登録できます。ダブルクォーテーション（"）も必要ありません。ありがたいですね～。
<img width="706" alt="1-5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/43b7ab9a-8d25-5a67-e351-31e0e8d8a938.png">
####URL
POSTリクエストを投げる先のURLを設定します。
今は一旦置いておきます。
####トークン
これはユーザーが設定するのではなく、Outgoing Webhookが自動で生成したものをユーザーが使うことになります。
トークンとは、「これ本当にあのWebhookが投げたの？」ということを確かめるためのパスワードのようなものです。
####その他
それより下の名前やアイコンなどは、お好みで設定しましょう。

設定が終了したら、最下部の「設定を保存する」をクリックします。
設定したチャンネルに以下のようなメッセージが出たら完了です。
<img width="381" alt="1-6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/26ef413e-87ae-a37d-edc0-e6a2cdb33697.png">
消灯当番を決めてくれる、名付けて**消灯くん**です。
###Incoming Webhook
続いてIncoming Webhookです。
こちらは、**リクエストが投げられ時に、自動でSlackに投稿するApp**です。Outgoingの逆、とも言えるものでしょうか。

こちらもさっそく設定していきます。
Outgoingの設定画面に上に検索窓があるので、そちらでIncoming Webhookを検索しましょう。設定画面までの遷移方法はOutgoingと同様ですが、先にチャンネルを設定しないとインテグレーションの設定ができないので注意しましょう。チャンネル設定が完了すると、以下のような投稿がされています。
<img width="422" alt="1-7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/03ce60e1-be2a-cca6-3826-2defe6878cbf.png">
Incoming Webhookの方は、**実はこれ以上の設定をしなくても動きます**。
あとはお好みで名前などを変えるくらいです。

しかし、**SlackBot自体は動きません**。
Outgoingがキーワードを拾っても、リクエストを投げる先がありませんし、Incomingも、リクエストが来なければ投稿できません。

「じゃあOutgoingのURL設定に、IncomingのWebhook URLを貼ればいいのでは？」と思った方は、鋭いです！**できません。**
![setup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/2de27ddd-5ae7-5847-1a00-24a03210a060.png)

あまり詳しい理由は言いませんが・・・Incomingの設定画面の「セットアップの手順」にも書いてある通り、「どういう内容の投稿するか」というプロパティがないと投稿できません。そしてOutgoingではその設定がありません・・・残念ながら・・・。

ではどうするのかというと、**Outgoingからのリクエストを受け取り、Incomingにテキストを指定したリクエストを送るもの**・・・つまり**中継地点**のようなものが必要になります。

ここで今回用意したのは、**Google Apps Script**、通称**GAS**です。
##GASとは？
GASではプログラムのソースコードを作って、Googleのマイドライブに置いておくことができますし、実際に動かすこともできます。
本来ならサーバーを構築して統合開発環境をインストールして・・・というようなことをしなければいけないところを、Google先生によれば**インターネット上でやらせてくれます。**あ、ありがてぇ・・・っ！

さらに、**Google Spread Sheet**と連携をすれば、データを保存しておくこともできます。便利～↑

さっそく作っていきましょう。
####ドライブの新規作成
1. Googleにログインした状態で、「Googleアプリ」の「ドライブ」を開きます。
2. 左上の「新規」ボタンをクリック
3. 「Google スプレッドシート」→「空白のスプレッドシート」をクリック
<img width="406" alt="1-9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/b7157e66-9b93-15b3-3bcb-73205b74652b.png">
4. 「無題のスプレッドシート」が作成されるので、「ツール」→「スクリプト エディタ」をクリック
<img width="504" alt="1-10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/29dd4967-50e9-0e68-0474-a8b582a835ea.png">

<img width="572" alt="1-11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/cfb455ee-ace7-9427-a549-7725885785d2.png">
これでGoogle Spread Sheet と GASの両方が新規作成されました。早いですね～。
####とりあえずBotにする
消灯くんの機能はさておいて、とりあえず返事だけでもできるようにしましょう。
POSTリクエストを受け取るには**doPostメソッド**を定義する必要があります。
なぜかというと、POSTリクエストは「doPost」という名前のメソッドを呼ぶようになっているからです。たぶん。

```js:Post.gs
function doPost(e)
// 何かしらの処理
}
```

引数の「e」は、POSTリクエストで渡されるパラメータがたくさん入っています。
SlackのOutgoing Webhookの場合は、投稿されたチャンネル名、投稿者名、投稿内容、反応したキーワード、投稿時刻・・・などなど。しかし、今回の記事では使わないので置いておきます。

さて、これでは何もしてくれないので、Slackに投稿する処理・・・正確には「Incoming Webhookにリクエストを送る処理」書きましょう。
ちょっと複雑だし自分もよくわかっていないので、コピペしてもいいです。（私もコピペしました）

```js:Post.gs
// リクエストを受け取るメソッド
// 最初に発動する
function doPost(e){
  // 今回はSlackメソッドを呼び出して終わり
  slack();
}

// Slackに投稿するためのメソッド
function slack(){
  // 投稿内容
  var text = "投稿テストです。";
  
  // Incoming Webhookが動くために必要な設定
  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : JSON.stringify(
      {
        // 投稿内容 変数を指定
        "text" : text,
      }
    )
  };
  // Incoming Webhook のURL ・・・(1)
  var url = "https://hooks.slack.com/services/TKJG8LZTN/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX";

  // 指定したURLにリクエストするものらしい
  UrlFetchApp.fetch(url,options);
}
```

(1)のIncoming WebhookのURLは、Incomingのインテグレーションの設定画面にあるものをコピーして貼り付けます。
<img width="706" alt="1-12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/adde39c6-1227-e083-6f8f-3a1ba0d256fd.png">
これでOK！保存したら、ソースコードにはもう触りません。
####アプリケーションの公開
ソースコードを保存しただけでは、SlackBotはまだ動きません。**公開**をする必要があります。

「公開」→「ウェブ アプリケーションとして導入」をクリックします。
<img width="417" alt="1-13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/64c7e432-56cc-d9dd-2f7a-1b42cf5ad9c7.png">
以下のような表示が出るので、
1. プロジェクトバージョン→「New」
2. 次のユーザーとしてアプリケーションを実行→「自分」
3. アプリケーションにアクセスできるユーザー→「全員（匿名ユーザーを含む）」(Anyone, even anonymous)
を選択して、公開します。
<img width="334" alt="1-14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/90976f22-3daa-3a19-4e6e-8d13e08f5760.png">
すると、「承認が必要です。」という表示が出ます。
「許可を確認」をクリックします。
<img width="371" alt="1-15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/3ca067a0-fc97-32e1-55a8-c12ce52cdd9d.png">
そうするとログインを促されます。ログインすると・・・
<img width="459" alt="1-16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/d305bc4c-b76d-624e-2f78-ca4575e521bf.png">
エラーみたいな表示が・・・。しかしこれは、許可をすればいいだけの話なので、許可しましょう。
詳細を開き、「〇〇〇（安全ではないページ）に移動」をクリックします。
<img width="454" alt="1-17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/a0955397-594e-6512-1b9e-89e13a3afce2.png">
許可！
<img width="336" alt="1-18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/8b1433be-6e4c-cb0c-72eb-d49ae84a5287.png">
公開（デプロイ）が完了したようです。良かった・・・。

**まだ終わりではありません！**今度はOutgoing Webhookに、このURLを教えなければいけません。
表示されたURLをコピーし、Outgoing Webhookの設定画面に戻りましょう。
<img width="714" alt="1-19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/dcd0306e-3710-959e-6062-511aded4198d.png">
URLの欄にペーストして、設定を保存しましょう。

**これで完了です！**
さっそく試してみましょう。チャンネルをお間違えなく・・・。
<img width="151" alt="1-20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/899f0e01-a243-59b0-885e-8ae58525e6b1.png">
**やりました・・・。**
#まとめ
今回作成したSlackBotの仕組みを簡単におさらいします。
![消灯くんシーケンス.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431212/954d8158-a735-5e78-0588-be9b2f15fb9b.jpeg)
こんな感じです。大体合ってると思います・・・。

今回はスプレッドシートは使いませんでしたが、次回の記事で大いに活躍することでしょう。

次回はGASで消灯くんの核となる機能の実装をします。

次：[消灯当番を決めてくれるSlackのBotを作る②　～スプレッドシートと回数を受け渡しする編～](https://qiita.com/Hiroyasu_Sato/items/08a445f27ec77d052a02)