【Slack】インタラクティブメッセージについて

この記事の内容は[この](https://api.slack.com/messaging/interactivity)公式ページを参考に作成しました。

SlackのインタラクティブメッセージはSlackアプリを強力なワークフローパートナーになりうる物です。

# メッセージ内アプリの対話性
[Block Kit](https://api.slack.com/messaging/composing/layouts#adding-blocks)を利用してリッチなメッセージレイアウトを作成する事ができます。
また、Block Kitには、インタラクティブ機能を有効にするコンポーネントも含まれています。
これらの対話型コンポーネントを利用して、単純な情報通知アプリから、ユーザー向けの強力なパートナーアプリを作成できます。

## Block Kitに含まれるインタラクティブ機能
- ボタン
- リスト選択
- 複数選択リスト
- オーバーフローメニュー
- 日付ピッカー
- プレーンテキスト入力フィールド
- ラジオボタン

# インタラクティブメッセージの使用方法

## Lambdaの作成
Lambdaのページに行き、適当な名称を付けてLambdaを作成する。


## API GateWayの仮設置
APIの作成を開き、「REST API」を選択する。
APIの管理画面が表示されれば、`アクション`のメニューから`リソースの作成`をクリックし、「interactive-test」を作成する。
作成された、「/interactive-test」を選択し、`アクション`のメニューからメソッドの追加を選択し、`POST`を追加する。

その後、Lambda関数を呼び出すように設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/71ff356a-0d5f-0295-d5a6-2c17d6302ce9.png)

設定が完了すれば、再度、`アクション`メニューから、APIのデプロイを選択する。

初回のデプロイ時は、`新しいステージ`を作成する必要が有る為、必要な情報を記載する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/5a054418-4db7-ba3b-749c-45062e9e3dde.png)

入力が完了すれば、下記のような表示がされて、APIのURLが表示されるので、メモってください。

## Slack アプリの準備
Slackアプリの準備を行います。
[こちら](https://api.slack.com/apps)のページから、アプリの作成をおこないます。
`Create New App`を選択します。

`App Name`にアプリの名前を適当に入力してください。
`Development Slack Workspace`にインストールしたいワークスペースを選択してください。

### Interactive Componentsの設定
アプリの管理画面の「Basic Information」が表示されたら、`Add features and functionality`を選択します。
その中の、`Interactive Components`を選択します。

`Interactivity `をONにし、API GateWayのURLを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/9524cedd-cab5-110c-4b84-9b05d2fc52ff.png)

### Botsの設定
左のタブの`Basic Information`を選択し、トップページに戻ります。
`Add features and functionality`を選択します。
その中の、`Bots`を選択します。
「How Your App Displays」内の`Edit`を選択し、表示名とデフォルト名を入力します。

### Scopeの設定
左のタブの`Basic Information`を選択し、トップページに戻ります。
`Permissions`を選択し、Scopesを設定します。
`Add an OAuth Scope`を選択し、Scopesの「Bot Token Scopes」に`chat:write`を登録する。

### アプリのインストール
Scopesを追加したら、`Install App to Workspace`をクリックして、アプリのインストールを行う

## Actionを含むメッセージの送信

Pythonで下記のようにソースを作成し、メッセージをSlackに送信する。

```py:送信用ソース.py
with open('send_message.json') as f:
    jsn = json.load(f)
# メッセージ送信処理
url = "https://slack.com/api/chat.postMessage"
headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer {0}".format("xoxb-XXXXXXXXXXXXX-XXXXXXXXXXXX-xxxxxxxxxxxxxxxxxxxxxxxx")
}
data = {
    "channel": "123456789",
    "blocks": json.dumps(jsn),
}
print(json.dumps(data))
ret = requests.post(url, json=data, headers=headers)
ret_json = ret.json()
print(json.dumps(ret_json))

```

```json:send_message.json
 [
	{
		"type": "section",
		"text": {
			"type": "mrkdwn",
			"text": "Danny Torrence left the following review for your property:"
		}
	},
	{
		"type": "section",
		"block_id": "section567",
		"text": {
			"type": "mrkdwn",
			"text": "<https://example.com|Overlook Hotel> \n :star: \n Doors had too many axe holes, guest in room 237 was far too rowdy, whole place felt stuck in the 1920s."
		},
		"accessory": {
			"type": "image",
			"image_url": "https://is5-ssl.mzstatic.com/image/thumb/Purple3/v4/d3/72/5c/d3725c8f-c642-5d69-1904-aa36e4297885/source/256x256bb.jpg",
			"alt_text": "Haunted hotel image"
		}
	},
	{
		"type": "section",
		"block_id": "section789",
		"fields": [
			{
				"type": "mrkdwn",
				"text": "*Average Rating*\n1.0"
			}
		]
	},
	{
		"type": "actions",
		"elements": [
			{
                "type": "button",
                "text": {
                    "type": "plain_text",
                    "text": "いいね :+1:",
                    "emoji": true
                },
                "value": "click_me_124"
            }
            ,
            {
                "type": "button",
                "text": {
                    "type": "plain_text",
                    "text": "だめね :-1:",
                    "emoji": true
                },
                "value": "click_me_124"
            }
		]
	}
]
```

## ボタンを押してみる
投稿されたメッセージをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/daa441f3-be79-b1b0-a785-7cab76b063c4.png)

メッセージをクリックすると、Interactiveの設定をしたURLへイベントが飛んでくるので、LambdaでPrint等で確認する事ができます。

# ボディーメッセージの整形方法

Slackに届くeventのBodyは、URLクエリの状態なので、パースする必要がある。

```py:パース.py
import json
import requests
import urllib.parse

def lambda_handler(event, context):
    # TODO implement
    print(json.dumps(event))
    # bodyの内容を解析して、文字列にする
    body = urllib.parse.unquote(event['body'])
    # 先頭に不要な文字列が有るので削除する
    body = body.lstrip('payload=\n')
    # 文字列をjsonに変換する
    body = json.loads(body)
    print(json.dumps(body))
```

```json:解析後の内容
{
	"type": "block_actions",
	"team": {
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
	},
	"user": {
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
	},
	"api_app_id": "XXXXXXXXX"
	"token": "XxxxXXXxxXXXXXXXXXXxXX",
	"container": {
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
	},
	"trigger_id": "929063715702.837835544534.xxxxxxxxxxxxXXXXXXXXXXXXXXXXXXXX",
	"channel": {
		"id": "CSxxxxxxx",
		"name": "インタラクティブメッセージデバッグ"
	},
	"message": {
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
	},
	"response_url": "https://hooks.slack.com/actions/TQMQKG0FQ/916681524913/GDPAnIwA7goLs9iSSaGPD83u",
	"actions": [
　　　　　　　　　　・
　　　　　　　　　　・
　　　　　　　　　　・
	]
}
```
# メッセージの内容を変更する方法
メッセージの内容を変更する方法は２種類有ります。

- レスポンス内に格納されている`response_url`にPOSTする事でメッセージの内容を変更する
 30分以内に5回までの制約がある

- API「chat.update」を利用して変更する
  tokenが有る場合は、message_tsを指定してメッセージを変更する方が良さそう