slackのボタンを押した時の情報をlambdaで受け取ろうとしたら、躓いた話

はじめに

以前の記事 でPythonでSlackチャンネル内を操作する方法を紹介しました。
slackではmethodが “chat.postMessage”の時に”attachments”に次のjson形式のコードを入れてあげると次に出てくる画像のようなボタン付きのメッセージを送ることができます。

このボタンを押した時、AWSのlambda関数にAPI Gatewayを通じてeventをPOSTしようとしたら躓いたので、その方法を紹介していきます。

{
    "text": "Choose a game to play",
    "fallback": "You are unable to choose a game",
    "callback_id": "wopr_game",
    "color": "#3AA3E3",
    "attachment_type": "default",
    "actions": [
        {
            "name": "game",
            "text": "Chess",
            "type": "button",
            "value": "chess"
        },
        {
            "name": "game",
            "text": "Falken's Maze",
            "type": "button",
            "value": "maze"
        },
        {
            "name": "game",
            "text": "Thermonuclear War",
            "style": "danger",
            "type": "button",
            "value": "war",
            "confirm": {
                "title": "Are you sure?",
                "text": "Wouldn't you prefer a good game of chess?",
                "ok_text": "Yes",
                "dismiss_text": "No"
            }
        }
    ]
}

作成した物の構造図

localからボタン付きメッセージ送信=>slackのボタンタップ=>AWS API Gatewayへボタンタップ情報をPOST=>API Gatewayが受け取り、lambdaへeventで情報送信

用意するもの と その中身

  • slack app
  • slack appのtoken
  • APIGateway
  • lambda関数

APIGAteway

こちらの記事を参考にして作成してください
Amazon Translateを使ってSlackで翻訳コマンドを作成
しかし、以下の統合リクエストの中のLambdaプロキシ統合の使用にチェックを入れないとcurlでデータは届くが、Slackのボタンをタップしたという情報が届かなくなるので注意!!!(自分はココで躓きました…API Gatewayとlambdaはきちんとつながってるのになんで届かないの…ってな感じに)

slack app と slack appのtoken

slack appの作成も途中までこの記事を参考にして作成してください。
Amazon Translateを使ってSlackで翻訳コマンドを作成
ただし、今回はスラッシュコマンドは使わないのでその前まで
今回設定するのは赤枠で囲ったこの3つ

Incoming Webhookはactivateにし、Add New Webhook to Workspaceをしてください。

Interactive ComponentsはOnにし、Request URLにAPI Gatewayのデプロイで作成したURLを貼り、Save Changesをクリックしてください。

OAuth & PermissionsはInstall App to Workspaceをしてください。
するとTokenが発行されると思います。
後で使うのでとっておいてください(当たり前ですが流出させては絶対に駄目です)。

その後、OAuth & Permissionsの下の方のScopesでSlack appの権限を設定します。
一例を画像で貼っておきます。
Adminはなくて良いです。
権限を追加するとページの上の方に再インストールしますか?的な文が出てくると思うので、その指示に従って再インストールします。

以上でSlack appの設定はOKです。

lambda関数

コメントを見てください。
コメント通りに実行すればpayloadがslackチャンネルに表示されます。
slackclientはlambdaにないため、ローカルで実行ファイルと同じディレクトリにインストールしZipに圧縮してアップロードする必要があります。

from slackclient import SlackClient
import json

slack_token ='Slackのtoken'
client = SlackClient(slack_token)
channel_id="チャンネルID" #https://ワークスペース.slack.com/messages/チャンネルID/ となっています

button_set={
    "text": "Choose a game to play",
    "fallback": "You are unable to choose a game",
    "callback_id": "wopr_game",
    "color": "#3AA3E3",
    "attachment_type": "default",
    "actions": [
        {
            "name": "game",
            "text": "Chess",
            "type": "button",
            "value": "chess"
        },
        {
            "name": "game",
            "text": "Falken's Maze",
            "type": "button",
            "value": "maze"
        },
        {
            "name": "game",
            "text": "Thermonuclear War",
            "style": "danger",
            "type": "button",
            "value": "war",
            "confirm": {
                "title": "Are you sure?",
                "text": "Wouldn't you prefer a good game of chess?",
                "ok_text": "Yes",
                "dismiss_text": "No"
            }
        }
    ]
}
def send_message(client, channel_id, message):
    response = client.api_call(
        "chat.postMessage",
        channel=channel_id,
        text=message,
    )
    return response

def send_message_button(client, channel_id, message,button_set):
    response = client.api_call(
        "chat.postMessage",
        channel=channel_id,
        text=message,
        attachments = [button_set]
    )
    return response


def lambda_handler(event, context):
    res=send_message_button(client, channel_id,"test",button_set) #最初に一回だけ後はコメントアウト

#---以下1回目のみコメントアウト--slackでボタンを押された後のレスポンスを返すコード-----
    test=str(event["body"]) #httpでpostされたpayloadの格納
    test=urllib.parse.unquote(test) #URLデコード
    send_message(client,channel_id,test)

これでボタンを押した時のpayloadを受け取って同じチャンネルにメッセージとして送れるようになりました!!!