Slack BotをGASでいい感じで書くためのライブラリを作った


全国のGoogle Apps Scriptファンの皆様こんにちは
Apps Scriptガチ勢の大橋です。

今年でGoogle Apps Scriptアドベントカレンダーも3年目になりました。
年々人は減っている気がしますが、BigQueryとの連携など他のアドベントカレンダーに名前が出ることが増えてきて、嬉しい限りです。

さて、ちょいSlack BotをGASで作る機会があったのでSlack API周りをGASで扱うためのLibraryを作りました。
今回はこのLibraryとそれを使って作った会議予約Botのサンプルコードについて書いていきたいと思います。

なお知らない方も多いので書いておくと、GASの`Library`機能は丁寧に作ると補完が非常に効くようになり、開発効率が10倍以上変わります。

![26_12_08_10_55.png](https://qiita-image-store.s3.amazonaws.com/0/2965/d5740501-439b-7117-b822-2e12e17e9d62.png "26_12_08_10_55.png")

Libraryについて詳しくは以下の記事を見て下さい。

* 2012年Google Apps Scriptアドベントカレンダー
  * [GASのライブラリを使って楽したい① とりあえず使ってみる_(:3」∠)_](http://qiita.com/soundTricker/items/7bbd86425ae8d0641d50)
  * [GASのライブラリを使って楽したい② 外部のJSライブラリを使ってみる(:3」[＿]﻿](http://qiita.com/soundTricker/items/5a7e050a2a20f3e3938a)
  * [GASのライブラリを使って楽したい③ 自分でライブラリを作ってみる(:3っ)っ -=三[布団]﻿](http://qiita.com/soundTricker/items/5f542faf5f2a06bc3091)

# ライブラリ SlackApp

## 基本情報

* **コード**
  * https://github.com/soundTricker/SlackApp
* **Library Key**
  * `M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO`
* **API Document** 
  * https://script.google.com/macros/library/versions/d/M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO
* **License**
  * MIT
 

## 使い方

前提として https://script.google.com からGoogle Apps Scriptプロジェクトを作成して下さい。
当然GASガチ勢の皆様はブラウザのアドレスバーに`sc`ぐらいまで打てば上記URLが補完され、
GASエディターが起動できる状態になっていると思います。

### Libraryを導入

プロジェクトにLibraryを導入します。
「[GASのライブラリを使って楽したい① とりあえず使ってみる_(:3」∠)_](http://qiita.com/soundTricker/items/7bbd86425ae8d0641d50)」を参考に、下記キーのライブラリを導入して下さい。

```
M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO
```

### Slack API Tokenの取得

APIへアクセスするためのtokenを取得します。
tokenは https://api.slack.com/web の「Authentication」から取得できるはずです。

![Slack_API___Slack.png](https://qiita-image-store.s3.amazonaws.com/0/2965/cf6c6414-dc4e-810e-8f74-7f3b1435f39f.png "Slack_API___Slack.png")

取得したらGASプロジェクトのScript Propertiesあたりに保存しておきます。

```javascript:save.gs
function saveToken() {
  PropertiesService.getScriptProperties().setProperty("token", "取得したトークン");
}
```

なお、Slack APIにはOAuth2による認証方式が有り、Library自体もそれに対応しているのですが、めんど... 複雑なためドキュメント化していません。
ほとんど過去に作ったTypeTalkのLibraryと同じ作りなので、そちらを参考にしていただくとやれると思います。

### 投稿してみる

Tokenを使って投稿しています。

```javascript:postMessage.gs
function postMessage() {
  var prop = PropertiesService.getScriptProperties().getProperties();
  
  //slackApp インスタンスの取得
  var slackApp = SlackApp.create(prop.token);
  
  //適当にchannel idを取得
  var channelId = slackApp.channelsList().channels[0].id;

　//投稿
  slackApp.postMessage(channelId, "ハロー世界", {
    username : "MyFirstBot"
  });
}
```

このLibraryの各メソッド名はSlackAppのAPI名と同じです。
例えばチャネル情報を取得する「[channels.info](https://api.slack.com/methods/channels.info)」APIであれば「`slackApp.channelsInfo(channelId)`」が対応します。


### Botとして動かしてみる

Slackへの投稿に対して反応するBotを作成する場合は、Slackの「Outgoing Webhook」とGASの`doGet`を利用します。

#### GASにdoGetを作る

「[2013年度版 5分で始めるWebアプリケーション(Google Apps Script)](http://qiita.com/soundTricker/items/a4878d7e3100082576e4)」を参考にGASプロジェクトにて`doGet`関数をつくり、HTTP GETアクセスできるようにします。

この時入り口のURL(https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxx/exec)をメモっておいて下さい。


なおSlackからは何も認証を行っていない、単純なGetリクエストが来るため、「ウェブアプリケーションとして導入」する際に「アプリケーションにアクセスできるユーザー」を「全員(匿名ユーザーを含む)」にしておいて下さい。
Google Appsのアカウントを利用している場合Apps側の設定によってはこのオプションが選べないのでご注意下さい。
=諦めて下さい。

![無題のプロジェクト.png](https://qiita-image-store.s3.amazonaws.com/0/2965/762295d9-1193-93e9-9078-9b6d3eaa3a41.png "無題のプロジェクト.png")


```javascript:doGet.gs
function doGet(e) {

  return null;
}
```

#### SlackにてOutgoing Webhookの設定を行う。

Slackの[outgoing-webhookの設定画面](https://my.slack.com/services/new/outgoing-webhook)にアクセスします。

画面が表示されたら「Add Outgoing WebHooks Integration」をクリックします。
![outgoing.png](https://qiita-image-store.s3.amazonaws.com/0/2965/3ca46dfb-4143-2916-3d0a-981d9b35c9f3.png "outgoing.png")

次の画面が表示されたら下の方の「Integration Settings」に行き設定を行っていきます。

「Channel」はOutgoing WebHooksが動くChannelですね。
「Any」にしておくとどこでも動きます。Channelを絞りたい場合は何かしらのChannelを選択しておきます。

「Trigger Word(s)」は「Outgoing WebHooks」が動くためのTriggerとなる単語です。
例えば「MyFirstBot:」とかしておくと「MyFirstBot:」が先頭にあるときだけ動きます。

「URL(s)」に先ほどメモったURLを貼り付けておきます。

また必須ではないですが「Token」をメモって置くと良いです。TokenはSlackがGetリクエストを送ってくる際に渡してくれる検証用トークンです。
GASのdoGet内でSlackからのアクセスかどうか突合して置くと良いと思います。

![outgoing-webhooksetting.png](https://qiita-image-store.s3.amazonaws.com/0/2965/4e168760-fab3-dc64-3f2a-a785106b6105.png "outgoing-webhooksetting.png")


#### GAS側でdoGet内のコードを書く

以下の感じでコードを書きます。

```
function doGet(e) {

  //Get properties.
  var prop =  PropertiesService.getScriptProperties().getProperties();
  if (!e) {

    //for Test. Slackからは以下のパラメータで飛んできます。
    e = {
      parameter : {
        token : prop.verifyToken,
        team_id : "T0001",
        channel_id : "C12345678910",
        channel_name : "test",
        timestamp : "1355517523.000005",
        user_id : "U2147483697",
        user_name : "Steve",
        text : "MyFirstBot: Hi",
        trigger_word : "MyFirstBot:"
      }
    };
  }

  if (prop.verifyToken != e.parameter.token) {
    throw new Error("invalid token.");
  }

  //Create an instance.
  var slackApp = SlackApp.create(prop.slackToken); 
 
  //My first Message!
  slackApp.chatPostMessage(e.parameter.channel_id, "Hi " + e.parameter.user_name, {
    username : "My First Bot",
    icon_emoji : ":+1:" 
  });

  return null;
}
```

なおコードの更新後、GASプロジェクトのバージョンを上げ、ウェブアプリケーションのバージョンを上げるのを忘れないで下さい。
何言っているかわからない人は多分「コード更新したんだけど動かない」ってなるはずです。
その時上の呪文を唱えて下さい。

#### Slackから送ってみる

実際に選択したSlackのchannelから上記Trigger Wordを付けてメッセージを送ってみましょう。
Botが返信してくれるはずです。

# まとめ

いかがでしたでしょうか？
GASとSlackが混ざることによりかなりのことが自動化できます。
個人的に作っているものだと「会議予約Bot」というのがあって、
「会議予約: 2014/12/01 17:00-18:00 定例会議 人:"大橋、...." 場所:"A会議室"」
みたいな投稿をすると以下のことをしてくれます。

* Google Calendarへのイベントの作成(参加者全員を呼び出し)
* Goodle Docsの議事録フォーマットをコピーし人、場所、日時を設定
* 会議日前日当日(朝、開始10分前)に事前作成した議事録のURLをSlackに貼り付け

これだけでかなりの自動化と、「会議室予約ミスの削減」「議事録の作り忘れ、テンプレートの場所がわからないから作らない問題の解決」「議事録どこだっけの無駄な時間の削除」ができます。
素敵ですね！

あとはBigQueryのQueryを投げると検索してそのまま返してくれるBotと、
グラフ化して返してくれるBotもいたりします。

BotとGASは色々相性が良いです。
またHubotなどのようにサーバを準備する必要が無いため、
必要になったその日にBotを運用開始できます。

ぜひ素敵なChatOpsライフを！