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


ことの起こり

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

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

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

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

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

電話の回数の集計方法ですが、新人のみのSlackに電話を取ったとき用のスタンプがあるので、それで報告します。

このスタンプの数を集計するようにしていました。

以前は、特定の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 WebhookIncoming Webhookです。

Outgoing Webhooks

こちらは簡単に言うと、Slackで特定のキーワードが投稿されると反応するAppです。

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

Slackのチャンネルの「会話の設定」から「アプリを追加する」を選び、Outgoing Webhookを検索します。
ヒットしたものをクリックすると、このような画面に遷移されます。

「Slackに追加」→「Outgoing Webhook インテグレーションの追加」とクリックすると、新しいWebhookのアカウントのようなものが作られます。

ページの下の方に行くと、「インテグレーションの設定」という項目があるので、こちらで設定をしていきます。
(「Outgoingペイロードとレスポンス」は今は無視!)

チャンネル

発言を拾うチャンネルを設定します。
ここで新しくチャンネルを設定することもできます。

どうやら、既存のプライベートチャンネルは設定できないみたいですね・・・。

引き金となる言葉

全部の発言を拾われると困るので、キーワード(トリガー)を設定します。
ここで設定した言葉で始まる行があった場合のみ、Webhookに拾われます。
また、コンマで区切ることで複数のキーワードも設定できるし、:スタンプ名:という風にすればスタンプも登録できます。ダブルクォーテーション(")も必要ありません。ありがたいですね~。

URL

POSTリクエストを投げる先のURLを設定します。
今は一旦置いておきます。

トークン

これはユーザーが設定するのではなく、Outgoing Webhookが自動で生成したものをユーザーが使うことになります。
トークンとは、「これ本当にあのWebhookが投げたの?」ということを確かめるためのパスワードのようなものです。

その他

それより下の名前やアイコンなどは、お好みで設定しましょう。

設定が終了したら、最下部の「設定を保存する」をクリックします。
設定したチャンネルに以下のようなメッセージが出たら完了です。

消灯当番を決めてくれる、名付けて消灯くんです。

Incoming Webhook

続いてIncoming Webhookです。
こちらは、リクエストが投げられ時に、自動でSlackに投稿するAppです。Outgoingの逆、とも言えるものでしょうか。

こちらもさっそく設定していきます。
Outgoingの設定画面に上に検索窓があるので、そちらでIncoming Webhookを検索しましょう。設定画面までの遷移方法はOutgoingと同様ですが、先にチャンネルを設定しないとインテグレーションの設定ができないので注意しましょう。チャンネル設定が完了すると、以下のような投稿がされています。

Incoming Webhookの方は、実はこれ以上の設定をしなくても動きます
あとはお好みで名前などを変えるくらいです。

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

「じゃあOutgoingのURL設定に、IncomingのWebhook URLを貼ればいいのでは?」と思った方は、鋭いです!できません。

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

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

ここで今回用意したのは、Google Apps Script、通称GASです。

GASとは?

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

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

さっそく作っていきましょう。

ドライブの新規作成

  1. Googleにログインした状態で、「Googleアプリ」の「ドライブ」を開きます。
  2. 左上の「新規」ボタンをクリック
  3. 「Google スプレッドシート」→「空白のスプレッドシート」をクリック
  4. 「無題のスプレッドシート」が作成されるので、「ツール」→「スクリプト エディタ」をクリック


これでGoogle Spread Sheet と GASの両方が新規作成されました。早いですね~。

とりあえずBotにする

消灯くんの機能はさておいて、とりあえず返事だけでもできるようにしましょう。
POSTリクエストを受け取るにはdoPostメソッドを定義する必要があります。
なぜかというと、POSTリクエストは「doPost」という名前のメソッドを呼ぶようになっているからです。たぶん。

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

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

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

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のインテグレーションの設定画面にあるものをコピーして貼り付けます。

これでOK!保存したら、ソースコードにはもう触りません。

アプリケーションの公開

ソースコードを保存しただけでは、SlackBotはまだ動きません。公開をする必要があります。

「公開」→「ウェブ アプリケーションとして導入」をクリックします。

以下のような表示が出るので、
1. プロジェクトバージョン→「New」
2. 次のユーザーとしてアプリケーションを実行→「自分」
3. アプリケーションにアクセスできるユーザー→「全員(匿名ユーザーを含む)」(Anyone, even anonymous)
を選択して、公開します。

すると、「承認が必要です。」という表示が出ます。
「許可を確認」をクリックします。

そうするとログインを促されます。ログインすると・・・

エラーみたいな表示が・・・。しかしこれは、許可をすればいいだけの話なので、許可しましょう。
詳細を開き、「〇〇〇(安全ではないページ)に移動」をクリックします。

許可!

公開(デプロイ)が完了したようです。良かった・・・。

まだ終わりではありません!今度はOutgoing Webhookに、このURLを教えなければいけません。
表示されたURLをコピーし、Outgoing Webhookの設定画面に戻りましょう。

URLの欄にペーストして、設定を保存しましょう。

これで完了です!
さっそく試してみましょう。チャンネルをお間違えなく・・・。

やりました・・・。

まとめ

今回作成したSlackBotの仕組みを簡単におさらいします。

こんな感じです。大体合ってると思います・・・。

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

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

次:消灯当番を決めてくれるSlackのBotを作る② ~スプレッドシートと回数を受け渡しする編~