【Slack/Bolt】Slackアプリで自分のステータスを設定する

#1 作ったもの
![operation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74780/e02c5238-29da-8117-1f56-baf69bbcf13c.gif)


ソースコードは[こちら](https://github.com/syoppylife/slack-set-status-app)


#2 この記事で書くこと
**書くこと**
* Slackアプリのコンソール上の設定箇所と関連しているソースコードの説明
* ハマったところ①（Slash '/' コマンドによるアプリの実行）
* ハマったところ②（アイコンを選択した人が自分のステータスを変更できる条件/方法）
* このアプリの問題点
* 作成に至った背景

**書かないこと**

* slackアプリの作り方
* Block Kit Builderの使い方
* Boltについてや使い方
* Herokuの使い方

書かないことばっかですが、それぞれ以下をみていただければ問題ないと思います。
[Slackアプリの作成] (https://api.slack.com/apps) Create newで作れます

[Block Kit Builderの使い方](https://api.slack.com/block-kit) 左ペインの「Block Kit Builder」をクリックするともっとリッチなUIがテンプレート化された状態でみれます。
ブラウザでSlackのワークスペースにログインしていればチャンネルへの投稿もこのページからできます。ドラッグアンドドロップで作れるのでかなり楽です。

[Boltの使い方](https://slack.dev/bolt-js/ja-jp/tutorial/getting-started) いろんな方の記事を読ませていただきましたが、公式ドキュメントを読むのが１番でした。Slackの使い方に慣れていれば書いてあることを理解するのはそれほど難しくないと思います。

[Herokuの使い方] (https://slack.dev/bolt-js/ja-jp/deployments/heroku) Herokuにログインしてアプリを作成すればコンソールに書かれている内容でじゅうぶん操作できるかと思います。
ただしリンクにしてある通り、Boltのドキュメントに記載されている内容を上から試すのが１番簡単で理解しやすいと思います。

#3 Slackアプリのコンソール上の設定箇所と関連しているソースコードの説明

必要な箇所は全て[README.md](https://github.com/syoppylife/slack-set-status-app)に記載してあるのですが、補足的な内容やキャプチャ付きで記載します。
Slackアプリの作成が始めての方だと以下の流れで作業するのがわかりにくいのではないかと思います。

1.Slackアプリの作成とパーミッション設定を済ませてBasic InformationやOAuth & PermissionsからClient IDやBotTokenの情報などを取得する

Basic Information
![Basic Information](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74780/78ff30b4-264f-4d76-8e7d-a5cf96a8b611.png)

OAuth & Permissions
![OAuth & Permissions](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74780/49a53d07-9651-44a2-7fe4-bde4ca400a95.png)

2.上記のトークンの値を環境変数に設定してアプリをデプロイし、ホスティング先のURLを取得する

```bash
heroku config:set SLACK_SIGNING_SECRET=<your-signing-secret>
heroku config:set SLACK_BOT_TOKEN=xoxb-<your-bot-token>
heroku config:set SLACK_CLIENT_ID=<your-client-id>
heroku config:set SLACK_CLIENT_SECRET=<your-client-secret>
```

3.再びSlackアプリの設定で、リダイレクトURLやリクエストURLを設定する

以下は全て上記の3.のタイミングの作業となります。

---
### *Edit Command*
今回のアプリでは `/nikoniko` と入力することでBlock Kitで作成したUIを表示するようにしていますのでそのイベントハンドリングのためにRequest URLが必要となります。
 
![Edit Command](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74780/d89e55e2-9e9a-6af7-8c10-528e2ae6d598.png)

---

### *Interactivity*
こちらは表示されたUI上でアイコン（今日の調子）を選択するためにアイコンをクリックした時のイベントを拾うために使います

![Interactivity](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74780/ea2e94f6-a7d1-0412-4ea0-4601e43c6095.png)

---

### *Redirect URLs*
クリックしたアイコンに応じてステータスをセットするには[こちら](https://api.slack.com/scopes/users.profile:write)の権限が割り当てられたユーザートークンをアプリ側が知る必要があるので[ここの処理](https://github.com/syoppylife/slack-set-status-app/blob/66d1002752144d566ad61cdf43a0f4617d672ea7/app.js#L146)で許可を得るようにしています。
[リダイレクト先](https://github.com/syoppylife/slack-set-status-app/blob/66d1002752144d566ad61cdf43a0f4617d672ea7/app.js#L12)がslack側の設定と一致している必要があります。

![RedirectURLs](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74780/e402eafe-1655-5e76-4ff2-61f1d57ee6e8.png)


ちなみに僕はいくつかのメッセージに対してアプリが反応するようにしたので、*Event Subscriptions*の設定も必要でした。設定するURLやパスは*Interactivity*と同様のものとなります
※上記に関しては付随するパーミッション設定も必要ですがソースコードからは削除してあるので割愛します。


#4  ハマったところ①（Slash '/' コマンドによるアプリの実行）
単純に自分の理解力が足りなかっただけですが、[ドキュメント](https://slack.dev/bolt-js/ja-jp/concepts#commands)にちゃんと書いてあります
>Slack アプリの管理画面でスラッシュコマンドを設定するとき、そのスラッシュコマンドの Request URL に（https://{ドメイン} に続いて） /slack/events を指定するようにしてください。

SlackアプリのUIはアプリ側にあるけど、制御はNode.JS側にあるのでイベントハンドリングを経由する必要があるのですがなんとなくブラウザ上でJavascriptが動くようなイメージを抱いてしまっていました。

#5  ハマったところ②（アイコンを選択した人が自分のステータスを変更できる条件/方法）
Scopeや権限について調べていた時はどういうわけか、Slackアプリ作成＆ワークスペースインストール時の権限でなんとかなるものだと思い込んでいました・・・。そんなことができたらワークスペースに存在するメンバーの設定がやりたい放題になっちゃいますね・・・

トークンなしで `client.users.profile.set` を呼び出そうとしたり、contextからユーザートークンを取ろうとしてエラーになったりして試行錯誤してましたが、[@dbgso様の記事](https://qiita.com/dbgso/items/a95a3364d9a8c67f3387#web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%8B%E3%82%89%E8%AA%8D%E5%8F%AF%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88)にてブラウザ越しに権限の要求ができることがわかり、実装取り込ませていただきました。ありがとうございました。

#6  このアプリの問題点

#### *トークンが永続化できない*

現状OAuth認証後に取得できるユーザートークンは変数に保持させてあるのでHerokuを再起動すると消えてしまいます。
[node-json-db](https://www.npmjs.com/package/node-json-db)で実装されているコードがあったり、[bolt-json-db](https://github.com/BoltDoggy/bolt-json-db)といったものも見つけて試してみましたが、Herokuはおそらく再起動するとインスタンスも変わるので結局永続化はできませんでした。
DB周りの実装まで手を出している時間がなかったのでこれで良しとします。（そもそも時間効率を優先してBoltやSlackアプリについてあまり調べずに[こちら](https://slack.dev/bolt-js/deployments/heroku)を参考にトライアンドエラーで進めてしまったのがまずかったかもしれません[^1]）

[^1]: でもこれを参考にしてなかったら週末で完成させるのは無理だったかもしれないです。

安易にRDBで管理してしまうと、万が一ユーザートークンが漏れてしまった際に色んなことができてしまうので、ソルトを使ってしっかりハッシュ化するなど安全に管理する必要があるためサクッと作りたかった今回はここまでとなります。

#### *Oauth認証がv2じゃない*

こちらに記載のあるv2付きのURLだとエラーになってしまったので `/v2` を外してあります
https://api.slack.com/authentication/oauth-v2

#7 作成に至った背景

長くなるので[note](https://note.com/ssyyoo/n/n9315df8d6cbc)に書きました。