Slack で感謝を伝えるボットを作ろう

寒い日々が続きますが、皆さんはいかがお過ごしでしょうか？私は最近、湯たんぽを足元に置いて身体を温めるようにしています。ぜひ試してみてください。数ヶ月前にカナダから日本に移住してきました Slack で Developer Relations を担当している Jason と申します。

早いもので、今年ももうすぐ終わります。この一年を振り返ってみて、お世話になった人に感謝を伝えてみるのはいかがでしょうか？このチュートリアルでは、それを Slack 上で簡単にできるようにするアプリの作り方をご紹介します。このチュートリアルは、以前 Slack の公式サイトに [英語で書いたもの](https://api.slack.com/tutorials/intro-to-modals-block-kit) をベースにして日本語に翻訳したものです。もしモーダルや Block Kit に興味があれば、ぜひご覧ください！

# 使用する技術
- [**Glitch**](https://glitch.com/) 
    - コードを編集するだけでなく、サーバーを起動したり、友人・同僚に共有することもできます。
- [**Bolt for Python**](https://slack.dev/bolt-python/ja-jp/concepts)
    -  Slack 公式のアプリ開発フレームワークです。 Slack API を活用して開発するとき、Bolt for Python を使えば素早くアプリを作ることができます。

# アプリの完成イメージ

このチュートリアルを読み終わったら、以下のようなアプリを作ることができるようになります。
![final_product.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/4f1a0685-8cb4-6736-9077-870a45c4a285.gif)

# 実装の流れ

## Slack アプリの作成
まずはじめに、開発に使用する Slack ワークスペースにブラウザでログインしてください。その後、この[リンク](https://api.slack.com/apps?new_app=1&ref=bolt_start_hub)から、 Slack アプリを作成しましょう。表示されるモーダルで 「 From Scratch 」 (ゼロから作る、という意味です) を選択し、アプリの名前を 「ありがとうボット」に指定し、ログイン済の Slack ワークスペースも選んでください。

![create_app.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/b6659e6a-c126-94fd-cffc-584abd5bd197.gif)

## Slack アプリに権限を付与
Slack アプリの管理画面から **OAuth & Permissions** に遷移し、**Scopes** までスクロールしてください。 Slack アプリからチャンネルや DM にメッセージを送信するための権限である `chat:write` を追加して、`Add an OAuth Scope` ボタンを押しましょう。英語になりますが、もし `chat:write` についてもっと知りたい場合、 [API ドキュメント](https://api.slack.com/scopes/chat:write) を参照してください。

![choose_scopes.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/001256f4-2502-2c84-cf2a-f8d6f5b72c27.gif)

## ボットユーザーの名前を設定
次に、ボットの名前を設定するには、Slack アプリの管理画面から **App Home** に移動し、**App Display Name** の隣にある `Edit` ボタンを押してください。そうすると、以下のようなモーダルに遷移するので、`App Display Name` と `Default username` を入力しましょう。

| 項目 | コメント |
|:---:|:--------|
| `App Display Name (Bot Name)` | ワークスペース内で表示されるボットユーザーの名前です。今回は「ありがとうボット」をつけましょう。|
| `Default username` | ボットユーザーのワークスペースでのユニークな名前です（システム的な管理だけで使用されます）。使用できるのは半角英数字のみなので、ここでは arigato_bot としておきましょう。

![name_selection.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/8f44a233-2ba9-c7cc-ee0c-1285d0d16e5c.gif)

## Glitch で今回の雛形をコピー
今回のチュートリアルではこちらの雛形を使います。

https://glitch.com/edit/#!/intro-to-modals-jp

以下のリンクをクリックすると、その雛形を使ったあなたのサンドボックスが自動的に作成されます。 Glitch のアカウントでログインしなくても使えますが、後で見直したりしたいなら Glitch のアカウントを作ってログインしてからの方をお勧めします。 Glitch ではあまり細かいことは心配せず、気軽に色々試してみてください。もしアプリの設定やコードを壊してしまってどうにも直せなくなってしまったとしても、また最初から新しいサンドボックスを作成できます。

https://glitch.com/edit/#!/remix/intro-to-modals-jp

## ソースコードの説明

このアプリのソースコードは `server.py` だけを見ればよいです。以下のコードはスラッシュコマンドへの応答をするリスナー関数の実装です。このように Bolt を使うと直感的に何をやっているか理解しやすい実装になります。

```python
# `/thankyou` というスラッシュコマンドを使うと以下のリスナーが実行されます
@app.command("/thankyou")
def handle_command(body, ack, client, logger):
    logger.info(body)

    # スラッシュコマンドのリクエストを受け付けたことを Slack に伝えます
    ack()

    # ユーザに対してモーダルを開くメソッドです
    res = client.views_open(
        trigger_id=body["trigger_id"],
        view={
            "type": "modal",
            "callback_id": "gratitude-modal",
            "title": {"type": "plain_text", "text": "感謝を伝えよう 💖", "emoji": True},
            "submit": {"type": "plain_text", "text": "送信"},
            "close": {"type": "plain_text", "text": "キャンセル"},
            "blocks": [
                {
                    "type": "input",
                    "block_id": "users-select-block",
                    "element": {
                        "type": "multi_users_select",
                        "placeholder": {
                            "type": "plain_text",
                            "text": "一人または複数人を選択できます",
                        },
                        "action_id": "users-action-id",
                    },
                    "label": {"type": "plain_text", "text": "感謝したい人"},
                },
                {
                    "type": "input",
                    "block_id": "message-block-id",
                    "element": {
                        "type": "plain_text_input",
                        "multiline": True,
                        "action_id": "message-action-id",
                        "placeholder": {
                            "type": "plain_text",
                            "text": "このメッセージはチャンネルに投稿されるので、他の人にもわかる内容を書いてください",
                        },
                    },
                    "label": {"type": "plain_text", "text": "メッセージ"},
                },
                {
                    "type": "context",
                    "elements": [
                        {
                            "type": "plain_text",
                            "text": "「送信」を押したら、#thankyou というチャンネルに投稿されます。",
                        }
                    ],
                },
            ],
        },
    )
    logger.info(res)
```

Slack 上のモーダルは Block Kit という JSON 形式のデータによって定義されています。上記のコードでは `view` というの変数の値はその一例です。このアプリの UI をデザインするために [Block Kit Builder](https://app.slack.com/block-kit-builder/T5J4Q04QG#%7B%22type%22:%22modal%22,%22callback_id%22:%22gratitude-modal%22,%22title%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E6%84%9F%E8%AC%9D%E3%82%92%E4%BC%9D%E3%81%88%E3%82%88%E3%81%86%20%F0%9F%92%96%22,%22emoji%22:false%7D,%22submit%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E9%80%81%E4%BF%A1%22%7D,%22close%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%82%AD%E3%83%A3%E3%83%B3%E3%82%BB%E3%83%AB%22%7D,%22blocks%22:%5B%7B%22type%22:%22input%22,%22block_id%22:%22users-select-block%22,%22element%22:%7B%22type%22:%22multi_users_select%22,%22placeholder%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E4%B8%80%E4%BA%BA%E3%81%BE%E3%81%9F%E3%81%AF%E8%A4%87%E6%95%B0%E4%BA%BA%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%22%7D,%22action_id%22:%22users-action-id%22%7D,%22label%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E6%84%9F%E8%AC%9D%E3%81%97%E3%81%9F%E3%81%84%E4%BA%BA%22%7D%7D,%7B%22type%22:%22input%22,%22block_id%22:%22message-block-id%22,%22element%22:%7B%22type%22:%22plain_text_input%22,%22multiline%22:true,%22action_id%22:%22message-action-id%22,%22placeholder%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%81%93%E3%81%AE%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AF%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E6%8A%95%E7%A8%BF%E3%81%95%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%A7%E3%80%81%E4%BB%96%E3%81%AE%E4%BA%BA%E3%81%AB%E3%82%82%E3%82%8F%E3%81%8B%E3%82%8B%E5%86%85%E5%AE%B9%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%22%7D%7D,%22label%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%22%7D%7D,%7B%22type%22:%22context%22,%22elements%22:%5B%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%80%8C%E9%80%81%E4%BF%A1%E3%80%8D%E3%82%92%E6%8A%BC%E3%81%97%E3%81%9F%E3%82%89%E3%80%81#thankyou%20%E3%81%A8%E3%81%84%E3%81%86%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E6%8A%95%E7%A8%BF%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82%22%7D%5D%7D%5D%7D) というプレビューツールを使うと便利です。Block Kit Builder とは、ブラウザだけで Block Kit を使った Slack の UI のプロトタイピングとプレビューをできるツールです。

https://app.slack.com/block-kit-builder/T5J4Q04QG#%7B%22type%22:%22modal%22,%22callback_id%22:%22gratitude-modal%22,%22title%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E6%84%9F%E8%AC%9D%E3%82%92%E4%BC%9D%E3%81%88%E3%82%88%E3%81%86%20%F0%9F%92%96%22,%22emoji%22:false%7D,%22submit%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E9%80%81%E4%BF%A1%22%7D,%22close%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%82%AD%E3%83%A3%E3%83%B3%E3%82%BB%E3%83%AB%22%7D,%22blocks%22:%5B%7B%22type%22:%22input%22,%22block_id%22:%22users-select-block%22,%22element%22:%7B%22type%22:%22multi_users_select%22,%22placeholder%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E4%B8%80%E4%BA%BA%E3%81%BE%E3%81%9F%E3%81%AF%E8%A4%87%E6%95%B0%E4%BA%BA%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%22%7D,%22action_id%22:%22users-action-id%22%7D,%22label%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E6%84%9F%E8%AC%9D%E3%81%97%E3%81%9F%E3%81%84%E4%BA%BA%22%7D%7D,%7B%22type%22:%22input%22,%22block_id%22:%22message-block-id%22,%22element%22:%7B%22type%22:%22plain_text_input%22,%22multiline%22:true,%22action_id%22:%22message-action-id%22,%22placeholder%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%81%93%E3%81%AE%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AF%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E6%8A%95%E7%A8%BF%E3%81%95%E3%82%8C%E3%82%8B%E3%81%AE%E3%81%A7%E3%80%81%E4%BB%96%E3%81%AE%E4%BA%BA%E3%81%AB%E3%82%82%E3%82%8F%E3%81%8B%E3%82%8B%E5%86%85%E5%AE%B9%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%22%7D%7D,%22label%22:%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%22%7D%7D,%7B%22type%22:%22context%22,%22elements%22:%5B%7B%22type%22:%22plain_text%22,%22text%22:%22%E3%80%8C%E9%80%81%E4%BF%A1%E3%80%8D%E3%82%92%E6%8A%BC%E3%81%97%E3%81%9F%E3%82%89%E3%80%81#thankyou%20%E3%81%A8%E3%81%84%E3%81%86%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E6%8A%95%E7%A8%BF%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82%22%7D%5D%7D%5D%7D

## Glitch サーバを Slack と連携
Glitch 画面から `Share` ボタンをクリックし、 **Live Site** の URL をコピーして保存しておきましょう。Glitch はこの URL でアプリを起動してホスティングしてくれます。次に、 Slack アプリの管理画面に移動し、左ペインから **Interactivity & Shortcuts** を選択してください。 Bolt for Python フレームワークでは、ユーザからのインタラクション（ボタンを押す、モーダルを開くなど）は一つの URL エンドポイントを経由します。その URL は先ほどコピーした URL の末尾に `/slack/events` を加えたものになります（例：`https://nyan-nyan-cat.glitch.me/slack/events`）。これを **Request URL** に設定してください。これでユーザからのモーダルでのデータが Glitch のアプリサーバーに送信されるようになります。

![base_link.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/28d8fa06-7fed-e48e-6081-f797a71dac86.gif)

## スラッシュコマンドの作成
Slack アプリの管理画面にて、左ペインに「 **Slash Commands** 」をクリックし、`Create New Command` （新しいスラッシュコマンドを作成）ボタンを押しましょう。スラッシュコマンドを以下のように設定してください。

| 項目 | コメント |
|:--------:|:--------|
| `Command` | スラッシュコマンドの名前でです。今回は `/thankyou` を使いましょう。|
| `Request URL` | エンドユーザがスラッシュコマンドを使うと Slack がここの URL にリクエストを送信します。今回は上記の URL と同じです。（ 例：`https://nyan-nyan-cat.glitch.me/slack/events` ）|
| `Short Description` | このスラッシュコマンドの概要。実行すると何ができるのかを書いておきましょう。|
| `Usage Hint` | スラッシュコマンドを使うときに表示されるヒント。また、スラッシュコマンドが引数に対応している場合は、その説明も入れておくとよいでしょう。（任意）|

![slash_command.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/993d6aa9-5776-6f1c-ccd8-9cc2e592bb7d.png)

## Slack ワークスペースへのインストール
それでは、いよいよこのアプリを Slack ワークスペース内で使えるようにしましょう。左ペインから **Install App** をクリックし、遷移した画面に `Install to Workspace` ボタンを押してください。これで `/thankyou` というスラッシュコマンドがワークスペース内で使えるようになりました。

インストールが終わったら、Slack アプリの管理画面から取得できる二つの値を Glitch アプリサーバーに設定する必要があります。

まず、一つ目はボットトークンです。インストールした後に、リダイレクトされた画面に **Bot User OAuth Token**（ボットトークン）が表示されていると思います。これを使えば Slack 内で様々な操作が行えます。このチュートリアルでは、チャンネルにメッセージを投稿したり、ユーザーに対してモーダルを開いたりするために使います。

ボットトークンの値を Slack アプリの管理画面側で取得したら Glitch の画面を開いてください。そして、ハートの鍵型の `.env` ファイルを選択し、あらかじめ用意されている `SLACK_BOT_TOKEN` という環境変数に先ほどのボットトークンを設定してください。

二つ目は Signing Secret です。これは Slack からのリクエストかどうかを検証するために必要です。Slack アプリの管理画面の **Basic Information** から **Signing secret** の値をコピーし、Glitch サーバーの `SLACK_SIGNING_SECRET` という環境変数（こちらもあらかじめ用意されているはずです）に設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/9d693b16-e7ba-2132-b511-1d7988dfca12.png)

## チャンネルの作成
次に、このアプリが通知する先のチャンネルを作成します。 `#thankyou` という名前（他の名前でも大丈夫です）をつけましょう。そして、ボットユーザーをそのチャンネルに招待しておきましょう。チャンネルの設定画面からも招待できますが、`/invite @ありがとうボット` というスラッシュコマンドを使うと便利です。

## チャンネルに通知
最後に、ユーザがモーダルで書いた感謝の言葉を `#thankyou` チャンネルに投稿する関数を見ましょう。

```python
# ユーザがモーダルからデータ送信したときのリスナーです
@app.view("gratitude-modal")
def view_submission(ack, body, client, logger):
    ack()
    logger.info(body)

    # チャンネル ID を指定することもできます
    thank_you_channel = "#thankyou"
    values = body["view"]["state"]["values"]
    users = values["users-select-block"]["users-action-id"]["selected_users"]
    gratitude_message = values["message-block-id"]["message-action-id"]["value"]

    # Slack API 上、他のユーザを直接通知するには、このようにユーザ ID を不等号に入れ、アットマークをつけると綺麗に表示されます <@user_id> 。
    at_users = " ".join([f"<@{name}>" for name in users])

    # チャンネルにメッセージを送信します
    client.chat_postMessage(channel=thank_you_channel, text=f"{at_users} {gratitude_message}")
```

# 完成 :tada: 

これで完成です！早速 Slack 内で `/thankyou` スラッシュコマンドを実行してみましょう。以下のような動作になっていれば、うまく設定できていると思います。

![final_product.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550365/4f1a0685-8cb4-6736-9077-870a45c4a285.gif)

# 次のステップ

このチュートリアルで作ったアプリはご覧の通り、比較的シンプルなものでした。ぜひこれをベースにもっと使いやすく進化させてみてください。

このようなアプリを使って、お世話になった人にもっと感謝の言葉を気軽に伝えられるようになったらいいなと思います。

もし何か質問があれば、ぜひコメントしてください！

それでは、また！