pythonでシンプルなinteractive button付きSlackbotを作る

SWを利用してpythonでインタラクティブなボタン付きslackbotの作成にチャレンジしました。
他の人が書いているものだと、だいたいがnode.jsとかでかなり複雑でjavascript苦手な自分としてはなるべく避けてpythonでやりたい！
ということでflask+heroku+slackclientを用いて可能な限りシンプルな構成で作ってみました。
ボタン付きのSlack botは面倒面倒と巷で評判(な気がする)ので、この記事を参考にすれば比較的サクッとできるのかなと思ってます。

コードは[こちら](https://github.com/sh-tatsuno/slackbot_python_server)に公開してあります。

## 前提
- pyenv, pyenv-virtualenvのインストール
- herokuへの登録
- 適当なslackアカウント

これらはあらかじめ準備しておいてください。

## slack上での準備
これがなかなか面倒ですが頑張っていきましょう。

- slack appの作成
[こちら](https://api.slack.com/apps/new)にログインして新しいslack appを作成します。
<img width="1032" alt="スクリーンショット 2017-09-17 23.22.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/180185/9ee652e2-81f5-b361-bee6-d248e6803ae2.png">
App Nameはなんでも良いですが、Workspaceについては自分がbotを使いたいチームを指定しましょう。

続いて、basic informationに移動します。この時、下記のVerification Tokenを保管しておいてください。

<img width="1009" alt="スクリーンショット 2017-09-17 23.14.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/180185/0784b600-870c-d0f1-d9bf-8d8477f6d864.png">

続いて、bot用の設定を行なっていきます。下記のInteractive MessagesとPermissionsを設定していきます。
<img width="1020" alt="スクリーンショット 2017-09-17 23.12.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/180185/6d391f77-4cc2-05e8-8965-8d26dc991730.png">

- Interactive Messagesの設定
buttonを押した時にリダイレクトするURLを指定します。今回はheroku上の'slack/json_html'にリダイレクトします。
<img width="1036" alt="スクリーンショット 2017-09-17 23.12.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/180185/e8f6f5da-4356-c33c-6005-0ce76f111d33.png">

- Permissionsの設定
ページ真ん中辺りのScopeから必要な許可を設定しましょう。とりあえずはSend messages系でしょうか。続いて、ページ上部のTokens for Your WorkspaceからOAuth Tokenを発行しましょう。こちらも同様に保管しておいてください。

<img width="1014" alt="スクリーンショット 2017-09-17 23.38.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/180185/324a5344-58c2-3b83-d3e0-d3ee7628de3c.png">

## プロジェクトの作成

さて、ここからサーバー側を作っていきます。

- python環境の作成

プロジェクトを作成、virtualenv環境を導入します。必要なライブラリもこの時にインストールしてしまいます。

```
$ mkdir slackbot_python_server
$ cd slackbot_python_server
$ pyenv virtualenv 3.6.2 heroku_python_3.6.2
$ pyenv local heroku_python_3.6.2
$ pip install Flask gunicorn slackclient
$ echo .python-version >> .gitignore
$ pip freeze > requirements.txt
```

- Procfileを作成する

```
$ echo web: gunicorn main:app --log-file=- > Procfile
```

- main.pyを作る

まず、slackclientの定義とflask serverの定義をしてしまいます。SLACK_BOT_TOKENとSLACK_VERIFICATION_TOKENは後ほどherokuに環境変数として設定します。

```main.py
from flask import Flask, request, make_response, Response
import os
import json

from slackclient import SlackClient


# Your app's Slack bot user token
SLACK_BOT_TOKEN = os.environ.get("SLACK_BOT_TOKEN")
SLACK_VERIFICATION_TOKEN = os.environ.get("SLACK_VERIFICATION_TOKEN")

# Slack client for Web API requests
slack_client = SlackClient(SLACK_BOT_TOKEN)

# Flask webserver for incoming traffic from Slack
app = Flask(__name__)
```

続いて、ボタンの投稿のためのattachmentsを定義します。この時、action部分でボタンの各要素の設定を行います。call_back_idは適当に好きなidを入れていいみたいです。

```main.py
# your attachment
attachments_json = [
    {
        "fallback": "Upgrade your Slack client to use messages like these.",
        "color": "#258ab5",
        "attachment_type": "default",
        "callback_id": "the_greatest_war",
        "actions": [
            {
                "name": "choco1",
                "text": "きのこ",
                "value": "kinoko",
                "type": "button"
            },
            {
                "name": "choco2",
                "text": "たけのこ",
                "value": "takenoko",
                "type": "button"
            }
        ]
    }
]
```

ルート部分の設定を行います。GETでリクエストが来ると、slack_client.api_callが呼ばれ、generalチャネルにボタン付きの投稿がされます。attachments_jsonに先ほど設定した要素が入ります。

```main.py
#route
#when you access such as curl command, slackbot post interactive message
@app.route("/", methods=["GET"])
def index():
    slack_client.api_call(
        "chat.postMessage",
        channel="#general",
        text="あなたはどっち派？",
        attachments=attachments_json
    )
    return make_response("", 200)
```
最後に、ボタンを押した際のリダイレクト部分を作成します。form_json["actions"][0]["value"]に先ほどのボタンで選択した方のvalueが入っているので、この値を元に分岐して文を返します。

```main.py
#redirect from button
@app.route("/slack/json_html", methods=["POST"])
def json_html():

    # Parse the request payload
    form_json = json.loads(request.form["payload"])

    val = form_json["actions"][0]["value"]
    if val == "kinoko":
        response_text = "よろしい、ならば戦争だ"
    else:
        response_text = "よろしい、ならば盟友だ"
    response = slack_client.api_call(
        "chat.postMessage",
        channel="#general",
        text=response_text,
        attachments=[]
    )

    return make_response("", 200)
```

これでmain.pyが完成です。

- gitのherokuの設定

gitの設定を行います。

```
$ git init 
$ git add .
$ git commit -m "first commit"
```

herokuの作成と設定を行います。herokuのプロジェクト作成に加え、先ほどSlackで取得したTokenの環境変数設定も行います。

```
$ heroku login
$ heroku create <app-name>
$ heroku config:set SLACK_BOT_TOKEN = "<さっき取得したOAuth Token>" SLACK_VERIFICATION_TOKEN = "<さっき取得したVerification Token>"  --app "<app-name>"
```

## デプロイと動作確認

下記コマンドでherokuにプロジェクトをpushします。

```
$ git push heroku master
```

これで、下記のコマンドでherokuにあげたappにリクエストを送って動作確認をします。

```
$ curl https://<heroku apps>.herokuapp.com/
```
この時、generalにボタンが投稿されて動作すれば成功です。
<img width="365" alt="スクリーンショット 2017-09-18 0.29.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/180185/43b1dc22-bd05-53fa-476c-9aebc268d381.png">

## あとがき

はじめ、　pythonのslackbotでやってドツボにはまりました。slackclientはあまり日本語の記事がなかったので、苦労しましたが、調べたら、リストでの選択方式にできたり色々なオプションができるみたいでけっこう便利そうです（たぶんjsと同等のことができそうです）。皆さんも色々試してみてください。

## 参考文献

- [herokuにFlaskアプリをデプロイする](http://qiita.com/msrks/items/c57e0168fb89f160d488)
- [PythonのslackbotライブラリでSlackボットを作る](http://qiita.com/sukesuke/items/1ac92251def87357fdf6)
- [SlackのBotkitでbuttonとinteractive messagesを使ってみた](http://qiita.com/sh0/items/d857cdb54b635f45d1b9)
- [python-slackclient](https://github.com/slackapi/python-slackclient)