この記事はCAMPHOR- Advent Calendar 2015 12日目の投稿です。
ごあいさつ
初投稿になります。見習いエンジニアの@andoshin11です。
普段は旅行会社で働いているのでそちらのリンクも貼っときます(宣伝)
http://meetuskyoto.com
プログラミング初心者なので開発方面のメイン業務には貢献できないのですが、みんながいつも利用するSlackを活用して業務の効率化・潤滑化を図りたいなぁと思う次第です。
CAMPHOR- Advent Calendar 2015 6日目の記事でも@kakennがSlackのTips記事を書いてくれましたが、今回は自分のようなプログラミング初心者でもサクッと実装できる簡易botをGoogle Apps Scriptを利用して実現したいと思います。
Botを活用する意義としては
業務の自動化
そして何よりも
Botは癒し!
日夜の業務で枯れ果てた僕らの心を癒すオアシスのごとく、ときにBotの一声でチーム全体が活気を取り戻すこともあるのです。
Moduleを利用した拡張性等を考えると本来はNodeのHubot Generatorを利用するのが良いのですが、より簡単に、サーバー知識のない初心者でもできるよう今回はGoogle Apps Scriptに焦点をあてたいと思います。
(箇条書きですがNodeを利用したHubot生成方法はこちらのリンクから)
スクショ多めでスクロール大変ですがよろしくです。
Index
- 1. GAS(Google Apps Script)を使う利点
- 2. GASからSlackにメッセージを投稿する
- 3. 投稿に反応してメッセージを返す
- 4. Botを強化する
- 5. SpreadSheet上のデータを扱う
- 6. Google FormsとSlackの連携
- 7. 最後に
1. GAS(Google Apps Script)を使う利点
プログラミング初心者がGASを使用する利点としてはざっくり以下の3つがあげられます
- Googleが常時ホスティング → サーバーを用意する必要がない
- 他Googleサービスとの豊富な連携
- 関数実行トリガーの設定が簡単
とくに2つ目の「他Googleサービスとの連携」という部分はほんとに強力で具体的には
- Spreadsheetをマクロのように活用する
- Google Formに投稿された内容を取得する
- コマンド1つでGmailの操作ができる
- Google Calendarの予定を取得、作成する
といったことが簡単にできます。業務の自動化にぴったりですね。
GASについてより詳しく知りたい方はこちら↓↓
超初心者へGoogleAppsScriptを始めるメリットをこれでもかと説明します
つまりGoogle Apps Scriptは僕のようにサーバーやDBに関する知識のないプログラミング初心者がWebアプリを作るのにぴったりな言語だというわけです
2. GASからSlackにメッセージを投稿する
何はともあれまずはSlack上の特定のチャンネルにメッセージを流してみましょう
2.1 Google Apps Scriptプロジェクトの準備
Google Drive上の任意のフォルダに新規プロジェクトを作成します
2.2 GASにSlackAppライブラリを導入する
こちらで紹介されているライブラリを導入することでSlackへのPostが非常に簡単になります。
個人的にマストです。
Slack BotをGASでいい感じで書くためのライブラリを作った
メニューから「リソース」→「ライブラリ」選択し、Library Keyを入力することで目的のライブラリを導入できます。
SlackAppのLibrary Key → M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO
任意のバージョンを選択し、「保存」をクリックし完了。
2.3 Slack API Tokenの取得
下記ページの「Authentication」からAPI Tokenが取得できます
https://api.slack.com/web
取得したトークンはプロジェクトのプロパティとして保存しておきましょう。
メニューの「ファイル」→「プロジェクトのプロパティ」→「スクリプトのプロパティ」からSLACK_ACCESS_TOKENとして保存します
2.4 メッセージの投稿
ここから実際にコードを書いていきます。GASで使用する言語はJavascriptです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function postSlackMessage() { var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); var slackApp = SlackApp.create(token); //SlackApp インスタンスの取得 var options = { channelId: "#general", //チャンネル名 userName: "bot", //投稿するbotの名前 message: "Hello, World" //投稿するメッセージ }; slackApp.postMessage(options.channelId, options.message, {username: options.userName}); } |
SlackAppインスタンスの作成に必要なAPI Tokenは、1つ前のステップで取得してプロパティに格納したものを呼び出しています。
投稿先のチャンネルやメッセージ、名前、アイコンなどはすべてoptionsで指定できます。
ソースを保存する際に承認を求められるので、Googleアカウントで承認
実行する
投稿できた!
関数に対して実行トリガーを設定することで定期的にメッセージを送信させたりといったことが可能なのですが、トリガーについては後ほど設定方法を解説します
3. 投稿に反応してメッセージを返す
Slackにメッセージを送信できるようになりましたが、これだけでは一方通行の投稿しかできません。次はより実用的なBotになるようユーザーの投稿に対してレスポンスを返せるようにしたいと思います。
ゴールは以下の特徴を備えたBotを作ることです。
- 名前(秘書子)が呼ばれたら反応する ← Trigger Wordsの設定
- 呼ばれたチャンネルに対してメッセージを投稿する
- ユーザーの投稿内容によってメッセージが変わる
- 投稿の認証機能
上記の3つをマスターすればいろいろ応用が効くので、是非この機会に覚えちゃいましょう!
3.1 Outgoing WebHooksの設定
SlackのIntegrationの1つにOutgoing WebHooksというものがあります。
簡単に言うとユーザーの投稿データを指定のURL(アプリケーション)にPOSTできるというものです。
(正確には先頭がTrigger Wordsで始まる投稿に限りますが)
これを利用してGASアプリケーションにSlackからPOSTがあったら適切なメッセージをレスポンスとして返すようなしくみを作りましょう。
SlackのIntegrationsを管理するページからOutgoing WebHooksを設定していきます。
導入がまだの人はIntegrations一覧の下の方からOutgoing WebHooksを見つけてあげてください。
主に設定するのは以下の項目です
Channel : Botへのメッセージを監視するチャンネルを指定します。「Any」を選択することでチーム内の全てのチャンネルが対象となります。
Trigger Word(s) : このワードで始まるメッセージが外部のアプリケーションにPOSTされます。「(Bot名):」みたいな感じがわかりやすいかなと。今回は「秘書子:」をTrigger Wordとして設定しました。
URL(s) : POST先のURL(アプリケーション)を設定します。後ほど取得するGASアプリの公開URLをここに入力します。
Token : POSTされるデータに付随するTokenです。Bot側でちゃんと任意のSlackチームからの投稿か判別するための認証に使用するので、コピーしておいてください。
設定が終わったら早速コードを書いていきます!
3.2 doPost
Google Apps ScriptにはdoPostというイベントハンドラが用意されています。
アプリケーションに対してPOSTリクエストがあった際に自動で実行される関数です。
つまりSlackからOurgoing WebHooksを利用してリクエストがあった際はこちらの関数が実行されるわけですね。
今回はdoPost(e)とすることでユーザーからPOSTされた投稿データを引数として渡してやります。
まずは実際のコードを見てみましょう
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function doPost(e) { var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); var bot_name = "秘書子"; var bot_icon = "http://i.imgur.com/DP2oyoM.jpg"; var app = SlackApp.create(token); var message = "はい、こんにちは" return app.postMessage("#general", message, { username: bot_name, icon_url: bot_icon }); } |
こちらのGASアプリケーションにリクエストがあると「秘書子」から「#general」チャンネルに「はい、こんにちは」というメッセージが投稿されるシンプルなものです。
3.3 アプリを公開する
一般的にいうデプロイ的な作業です。
作成したGASアプリを公開状態にし、そのURLに対してSlackから投稿データがPOSTされるようOutgoing Webhooksを設定してやります。
メニューから「公開」→「ウェブアプリケーションとして導入」を選択
Slackからは認証も特に行わないまま単純なリクエストが飛んでくるので、「アプリケーションにアクセスできるユーザー」の項目を「全員(匿名ユーザーを含む)」と設定しておいてください。
※トークンによる認証は後ほどスクリプト内で実装します
「導入」をクリックするとアプリケーションの公開URLが表示されます。
こちらのURLをOutgoing WebHooks設定画面のURL(s)のところにコピペしましょう。
これでSlackとGASアプリの連携は完了です。
3.4 Let’s テスト!
それではここまでで実装した内容をテストしましょう!
文頭にTrigger Wordsをつけることでメッセージがアプリに渡され、レスポンスが帰ってくるはず。
秘書子かわいいよ秘書子
これで目標の1つ目はクリアしました!
名前(秘書子)が呼ばれたら反応する- 呼ばれたチャンネルに対してメッセージを投稿する
- ユーザーの投稿内容によってメッセージが変わる
- 投稿の認証機能
しかしこのままではどのチャンネルでBotを呼び出しても、「#general」チャンネルにしか投稿が帰ってきません。。。
投稿も毎回同じで少し寂しい・・・
4. Botを強化する
ここからは残る3つの機能についてまとめて解説していきます
4.1 投稿の取得
まず知らなければいけないのがデータフォーマットです。
Outgoing WebHooksでPOSTされる個別の投稿データは以下のようなフォーマットの配列となっています。
例えば投稿があったチャンネルはchannel_idに、投稿文はtextに格納されているのが分かりますね。
こちらのデータを読み出すカタチにコードを書き換えてやりましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function doPost(e) { var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); var bot_name = "秘書子"; var bot_icon = "http://i.imgur.com/DP2oyoM.jpg"; var verify_token = "Llv4n1b8ExPYBihjnjq2V7IB"; //投稿の認証 if (verify_token != e.parameter.token) { throw new Error("invalid token."); } var app = SlackApp.create(token); //Trigger Words部分の削除 var text = e.parameter.text.substr(4); var message = e.parameter.user_name + "さんは「" + text + "」と言っています。"; return app.postMessage(e.parameter.channel_id, message, { username: bot_name, icon_url: bot_icon }); } |
ユーザーの投稿があったチャンネルに対してメッセージを返したいため、e.parameter.channel_idを投稿先として指定しています。
またBotの出力するメッセージも投稿元のユーザーと内容によって変化させたいため、それぞれe.parameter.user_nameとe.parameter.textから読み込んでいます。
4.2 アプリの更新
さて、強化したBotを早速テストしたいのですが手順が少々ややこしいです。
公開済みGASアプリの内容を変更した際は毎回「バージョンの更新」という作業を行わなくてはなりません。
メニューから「ファイル」→「版を管理」を選択。更新内容を記述し、「新しいバージョンを保存」をクリックします。
今回はver. 34として最新のコードが保存されました。番号の並びがおかしいのは当方の環境のせいなので気にしないでください。OKを押しましょう。
さきほどのアプリ公開作業と同じくメニューから「公開」→「ウェブアプリケーションとして導入」を選択します。1つ違う点として、プロジェクトのバージョンのところで新しく保存した最新版を選択することに注意してください!
これで変更を加えた最新版のGASアプリケーションが公開できました!
さっそくテストしてみましょう
5. SpreadSheet上のデータを扱う
4章までで基本的な双方向通信機能を備えたBotの作り方はだいたい理解できたでしょうか。
ここからは応用編として各種Googleサービスとの連携方法を解説していきます。
まずはSpreadSheet上のデータを取得する方法です。
この方法を用いるとSQLとか触らなくてもGASアプリにおける簡易データベースのようにSpreadsheetを利用できるので知っておいて損はないかと思います。
例として、毎朝イベントへの参加希望者の累計人数を通知するアプリを作りましょう。
参考にさせていただいたのはこちら↓↓
スプレッドシートで管理しているKPIをSlackに自動投稿するGoogle Apps Scriptを作ってみた
5.1 イベントの参加者を管理するSpreadSheetを用意する
目的のデータ(累計人数)はE1のセルに格納されています。
このSpreadSheetのURLをコピーしておきましょう。
5.2 コード書く
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function postSlackMessage(content) { var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); var slackApp = SlackApp.create(token); //SlackApp インスタンスの取得 var options = { channelId: "#general", userName: "bot", message: content }; slackApp.postMessage(options.channelId, options.message, {username: options.userName}); } function getAttendance(){ var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1cDglAF5rAJGU-iAPY9VVBuh0__iuwo56hw9Ep42VYA0/edit#gid=0&vpid=A1'); var sheet = ss.getSheets()[0]; var attendance = sheet.getSheetValues(1,5,1,1); postSlackMessage("昨日までの参加希望者数は合計" + attendance + "名です。"); } |
SpreadsheetApp.openByUrl(’SpreadSheetのURL’)
→ SpreadSheetの取得
getSheets()[‘シート番号’]
→ シートを指定。getSheets()[0]
は一番左のシートを、getSheets()[4]
なら左から5番目を取得するといった感じです。
getSheetValues()
→ 公式のリファレンスが分かりやすく解説してくれているのでそちらを参考にどうぞ。
今回はSpreadSheet上のE1に格納されているデータが欲しいので、getSheetValues(1,5,1,1)といった感じに指定しています。
5.3 トリガーを設定する
GASを使用する利点の1つとして関数を実行するトリガーの設定が非常に容易であることが挙げられます。
「リソース」→「現在のプロジェクトのトリガー」から新しいトリガーを設定してみましょう。
関数getAttendance()が毎日午前9~10時の間に実行されるよう設定
できた
これでcronとか使わなくても定時実行されるトリガーが設定できちゃいます。
GAS素晴らしい。
6. Google FormsとSlackの連携
次は同じくGoogleのサービスであるGoogle Formsに新しいエントリが来たらSlackに通知するアプリを作りましょう。
ちょっとしたイベントの参加申請や、アンケート等にGoogle Formsを使う機会って多いですよね?
新しいエントリがあるたびに通知メールが届いたり、いちいちブラウザを開いたりするのも面倒な方のために、フォームへの送信内容を自動でSlackに飛ばす仕組みをご紹介します。
方法としては大きく
1. フォームがsubmitされたらPOSTされた内容を取ってくる
2. 集計先のSpreadSheetに更新が発生したらその内容を取ってくる
といった2パターンに分かれるのですが、今回紹介するのは1つめのパターンです。
6.1 Formを用意する
例としてイベントへの参加者を募集する申請フォームを用意しました。
このフォームに新しいエントリがあると通知が飛ぶようにしたいと思います。
6.2 新しいスクリプトを作成する
メニューの「ツール」→「スクリプトエディタ」より新しいスクリプトを作成します
プロジェクト名はattendant_formとでもしておきましょう
余談ですがこのように特定のFormやSpreadSheetから直接GASプロジェクトを立ち上げると、そのプロジェクトと対象のFormやSpreadSheetが紐付けされた状態になります。
わざわざリンクしたいものをURLで指定したりせずにすむので、良いですね。
6.3 コード書く
まずはお決まりのSlackにメッセージ飛ばす部分を書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function postSlackMessage(content) { var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); var slackApp = SlackApp.create(token); var options = { channelId: "#attendance", userName: "参加申請通知bot", message: content }; slackApp.postMessage(options.channelId, options.message, {username: options.userName}); } function test(){ postSlackMessage("テストです:sushi:"); } |
新規プロジェクトなので、SLACK_ACCESS_TOKENとSlackApp Libraryを設定するのを忘れないでください。
今回は投稿先のチャンネルとして「#attendance」、投稿者名として「参加申請通知bot」をそれぞれ設定しています。
テスト用の関数が実際に動作するか確かめてみましょう
上手くいきました
6.4 投稿内容を取得・処理する
次は実際に投稿された内容を受け取って、通知メッセージに必要なデータを抜き出します。
さきほどのコードに追記していきましょう
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
function postSlackMessage(content) { var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN'); var slackApp = SlackApp.create(token); var options = { channelId: "#attendance", userName: "参加申請通知bot", message: content }; slackApp.postMessage(options.channelId, options.message, {username: options.userName}); } function onFormSubmit(e){ var message = "新しい参加申請が届きました!\n```\n"; var itemResponse = e.response.getItemResponses(); for (var i = 0; i < itemResponse.length; i++){ var formData = itemResponse[i]; var title = formData.getItem().getTitle(); var response = formData.getResponse(); message += "【" + title + "】\n" + response + "\n"; } message += "```\n"; postSlackMessage(message); } |
getItemResponsesはフォームの各項目のタイトルやデータを引っ張れる便利なメソッドです。
その各項目に対してfor文をまわしてそれぞれタイトルとデータを抽出しています。
6.5 トリガーの設定
先ほどは毎朝関数が実行されるように時間主導型のトリガーを設定しました。
今回はフォームが来るたびに動作して欲しいので、イベントの種類を「フォームの送信時」に設定します。
実際にフォームに投稿してみましょう
通知が来た!
実際の利用ではFor文をまわすときにtitleをSwitch文で判別してresponseを個別の変数に格納すると便利かと思います。
詳しくはこちらの記事をご参照ください↓↓
Googleフォームで作った申請フォームからSlackに通知をする方法
7. 最後に
いかがだったでしょうか。
自分も初めてHubot作ったときはNodeをインストールして、coffeescript書いて、Herokuにデプロイして・・・と初心者なりに苦労していたわけですが、Google Apps Scriptによって一気にSlack Bot導入のハードルが下がったかと思います。
Google Apps Scriptを覚えてからというもの、弊社Slack上はゴミのようなbotの群れで溢れる始末です。
最近はDocomoの雑談対話apiを使用した新キャラクター「坂本」が誕生しました。
解説記事はこちら↓↓
Google Apps ScriptでSlackに雑談対話botを導入する
単体でマクロや関数が実行できるSpreadSheetと連携することでGAS botの可能性も無限大です。
みなさんも楽しいbotライフを!!
明日は@kakizoeの記事です
ピンバック: 非エンジニアがカップル専用アプリ「Slack」でGAS製Bot運用してみた - Web制作をもっと楽しく「リパレード」
ピンバック: 研究室にはネコがいる | kitayama lab
ピンバック: 非エンジニアがカップル専用アプリ「Slack」でGAS製Bot運用してみた - Webを楽しもう「リパレード」
ピンバック: 分単位指定で定期的に繰り返し実行するための Google Apps Script
ピンバック: Botで課題解決!小さな改善を積み重ねて生産性の向上を | BIZREACH Designer Blog