1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

slackにスタンプが押されたら、Trelloにカードを追加する

Last updated at Posted at 2020-06-02

この記事について

slackのスタンプでTrelloにカード追加を追加します。
lambdaを使ったサーバーレス構成の勉強もかねてやってみました。

全体図

こうなることを目指していきます。
スクリーンショット 2020-06-01 21.23.31.png

サーバー(AWS)側の設定

lambdaの作成

AWSのアプリケーションで、「Lambda」を選択して、「関数の作成」を選びます。
適当な名前をつけて、ぽちぽちで作成できます。
rubyが好きなので、rubyで書きます。
スクリーンショット 2020-06-01 21.45.06.png

lambdaが作成されます。
中身は変えずに、そのままにしておきます。
スクリーンショット 2020-06-01 21.55.46.png
スクリーンショット 2020-06-01 21.55.52.png

API-Gatewayの作成

lambdaは、サーバーレスでロジックを実行することができますが、
このロジックを実行するためのリクエストURLが必要です。そこにAPI-Gatewayが利用できます。

これもぽちぽちのみで完了します。
lambdaのコンソールから、自動で生成できます。
「トリガーを追加」をクリック
「Api Gateway」を選択して、セキュリティは「オープン」を選択して、追加します。
スクリーンショット 2020-06-01 21.59.05.png

疎通の確認

  1. API-Gatawayを開くと、先ほど作成したlambdaと同名のapiが作成されています。
スクリーンショット 2020-06-02 9.30.34.png
  1. 名前をクリックして、URLとルートを確認します。
スクリーンショット 2020-06-02 9.32.14.png スクリーンショット 2020-06-02 9.34.38.png
  1. コンソールでリクエストしてみる

"Hello from Lambda!"と表示されれば成功です。

$curl https://{API ID}.execute-api.ap-northeast-1.amazonaws.com/slack-reaction-trello
"Hello from Lambda!"%

Slack Events APIの設定

Appの作成

slackで何かしらのアクションを拾う場合は、Events APIを使います。
https://api.slack.com/apps にアクセスして、「Create New App」を押します。

以下の2つを入力して「OK」します。
・ App名(適当)
・ workspace

登録できると、こんな画面が表示されますので、「Event Subscriptions」を選択します。
スクリーンショット 2020-06-01 21.35.38.png

challenge認証を成功させる

「Event Subscriptions」の画面で、URLを単純に入力すると、エラー
スクリーンショット 2020-06-02 9.43.08.png

Event APIを作成する際、challenge認証が要求されます。
lambda側で、毎度異なった値が送信されている、"challenge"パラメータをresponseとして返却する必要があります。

requestのbodyは、引数の"event"内に格納されていますので、そちらを返却値にセットするだけです。

lambda_function.rb
def lambda_handler(event:, context:)
    # 送信されたbodyをそのまま返却する
    { statusCode: 200, body: JSON.generate(event["body"]) }
end

slackで、「Retry」すると、成功が表示されます。
スクリーンショット 2020-06-02 10.00.40.png

bot eventsの追加

どんなeventが発生したら、このAppを起動するかを設定してきます。
今回は、スタンプによるeventの発火を狙いたいので、
「Subscribe to bot events」内で、reaction_addを選択して、save changesします。
スクリーンショット 2020-06-02 12.30.29.png

eventが発火されるかの確認

workspaceにAppをインストールします。
スクリーンショット 2020-06-02 12.39.23.png

するとworkspace上で、上記のbotをチャンネルに招待することができるようになります。
このbotが招待されているチャンネルのみで、このeventは発火されるようになります。

早速チャンネルに、botを招待してみます。

/invite @{bot名}
スクリーンショット 2020-06-02 12.47.10.png

スタンプを押してみます。
スクリーンショット 2020-06-02 12.52.36.png

lambdaコンソール > モニタリング > cludwatchLogsのログを確認
で、実行ログを確認できるので見てみます。

スクリーンショット 2020-06-02 12.50.40.png

新たなログが作成されていました。
イベントの発火もこれで完了です。

Trello API用のtokenの準備

アクセスキーの準備

下記の3つを準備します。
こちらの記事を参考にさせていただきました。
https://qiita.com/isseium/items/8eebac5b79ff6ed1a180

  • TrelloAPIの access_token
  • TrelloAPIの secret_key
  • 追加したいリストの list_id

取得できたら、lambdaの環境変数に保存しておきます。
スクリーンショット 2020-06-02 13.11.47.png

試しにカードを作成させてみる

ここまできたら、Trelloにカードが追加できるようになります。
lambdaのロジックを修正して、カードを作成させます。

lambda_function.rb
require 'json'
require 'net/http' #追加

def lambda_handler(event:, context:)
    params = { #追加
         key: ENV['trello_access_key'],
        token: ENV['trello_access_token'],
        idList: ENV['trello_target_list_id'],
        name: 'slackのスタンプによるカード追加'
    }
    uri = URI.parse("https://trello.com/1/cards") #追加
    response = Net::HTTP.post_form(uri, params) #追加
    
    { statusCode: 200, body: JSON.generate(event["body"]) }
end

再度、同じチャンネルでスタンプを押してみます。
Trelloにカードが追加されれば、成功です。

slack APIによるメッセージ・スレッドの取得

あとはイベントからメッセージを取得して、TrelloAPI叩けば完了だー。わーい。
意気揚々と、送信されてきたeventのパラーメータを確認すると、、、

// id系はxxxxでマスクしています。
{
  "token"=>"xxxx",
  "team_id"=>"xxxx",
  "api_app_id"=>"xxxx",
  "event"=>
  {
    "type"=>"reaction_added",
    "user"=>"xxxx",
    "item"=>
    {
      "type"=>"message",
      "channel"=>"xxxx",
      "ts"=>"1591069623.000700"
    },
    "reaction"=>"trello",
    "event_ts"=>"1591071843.001100"
  },
  "type"=>"event_callback",
  "event_id"=>"xxxx",
  "event_time"=>1591071843,
  "authed_users"=>["xxxx"]
}

そう、メッセージの情報は含まれていないのです。。。😭
ついでに先に言ってしまうと、メッセージにスタンプが押された場合と、スレッドにスタンプが押された場合で内容の取得方法が異なっていました。

なのでメッセージの取得をできるようにします。

権限の追加

「OAuth & Permissions」のページ内、「Scopes」にchannels:historyを追加します。
※もし、privateチャンネルで利用したい場合はgroups:historyの追加が必要です。

スクリーンショット 2020-06-02 14.32.54.png

slack access-tokenの取得

OAuth Access Tokenをcopyして、trelloのキーと同じように、lambdaの環境変数に保存します。
スクリーンショット 2020-06-02 14.34.41.png

lambdaでskack apiを利用してメッセージの内容を取得する

結果だけ記載します。
綺麗に書き直してはいないので、ご容赦ください。。。

lambda_function.rb
require 'json'
require 'net/http'

def lambda_handler(event:, context:)
    event_hash = JSON.parse(event['body'])

    # trelloスタンプの場合に実行する
    stamp = event_hash['event']['reaction']
    if stamp == 'trello'
        
        slack_channel_id = event_hash['event']['item']['channel']
        #slackメッセージ取得
        slack_uri = URI.parse('https://slack.com/api/channels.history')
        slack_params = {
            channel: slack_channel_id,
            token: ENV['slack_access_token'],
            oldest: event_hash['event']['item']['ts'],
            latest: event_hash['event']['item']['ts'],
            inclusive: true
        }
        slack_res = Net::HTTP.post_form(slack_uri, slack_params)
        slack_res_hash = JSON.parse(slack_res.body)
        
        # 取得できなかったらスレッドなので再度取得
        unless slack_res_hash['ok']
            slack_uri = URI.parse('https://slack.com/api/conversations.replies')
            slack_params = {
                channel: slack_channel_id,
                token: ENV['slack_access_token'],
                ts: event_hash['event']['item']['ts']
            }
            slack_res = Net::HTTP.post_form(slack_uri, slack_params)
            slack_res_hash = JSON.parse(slack_res.body)
        end
        
        params = {
            key: ENV['trello_access_key'],
            token: ENV['trello_access_token'],
            idList: ENV['trello_target_list_id'],
            name: slack_res_hash['messages'].first['text']
        }
        uri = URI.parse("https://trello.com/1/cards")
        response = Net::HTTP.post_form(uri, params)
    end
    
    { statusCode: 200, body: JSON.generate(event["body"]) }
end

動作確認

以上で、スタンプを押した時に、Trelloにカードを追加できるようになりました!
動作を確認してみましょう。

メッセージと、スレッドに、それぞれtrelloスタンプを押します。

スクリーンショット 2020-06-02 14.44.52.png

すると、
スクリーンショット 2020-06-02 14.45.29.png

無事、Trelloにカードが追加されました。

注意など

lambdaの冪等生性について

上記で、カードを追加できるように放ったのですが運用しているとカードが2つ作成される現状が見られました。
調べてみると、こちらはLambdaの仕様で、Lambdaの実行は最低1回以上実行されることが保証されているだけであって、処理の冪等性については、サーバーロジック側で担保が必要とのことでした。

DynamoDBなどを利用して、タイムスタンプでゴニョゴニョするのが良いらしいです。
アプリケーションにおける不整合性とデータ損失を防ぐために Lambda 関数を冪等にするにはどうすればよいですか?

今回の場合は、別に2つ作成されても消せば良いのでそこまでの対応はしませんでした。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?