2
1

More than 1 year has passed since last update.

Slackアプリへのメンションを契機にYes/Noボタンを返信して処理を分岐させる

Posted at

概要

メンションを元に外部APIを叩き、取得した情報を元にDBを更新するSlackアプリを作成しました。
Image from Gyazo

Lambdaの準備

Node.jsでLambdaを作成しています。

const axios = require('axios');

const SLACK_BOT_TOKEN = process.env.SLACK_BOT_TOKEN;

exports.handler = async (event) => {
  console.log(`Event: ${JSON.stringify(event)}`);
  let body = "";
  if (event.isBase64Encoded) {
    // ボタンを押された時のblock_actionsペイロードはbase64でエンコードされているのでそのまま使えない
    const encodePayload = event.body;
    const decodePayload = decodeURIComponent(Buffer.from(encodePayload, "base64").toString("utf-8")).replace('payload=', '');
    body = JSON.parse(decodePayload);
  } else {
    // メンションや疎通確認はエンコードされていないのでそのまま使える
    body = JSON.parse(event.body);
  }

  // Slackアプリからの疎通確認用
  if (body.type === 'url_verification') {
    return {
      statusCode: 200,
      body: body.challenge,
    };
  }

  // Yes No ボタンクリックイベント
  if (body.type === "block_actions") {
    const actionId = body.actions[0].action_id;
    // Yes No ボタンを再度押下されないようにボタンを削除したメッセージに元メッセージを更新する
    const updatedText = decodeURIComponent(body.message.blocks[0].text.text.replace(/\+/g, ' '));
    await updateMessage(body.channel.id, updatedText, body.message.ts);

    // 押されたボタンによって処理の分岐
    let message = "";
    if (actionId === "yes_action") {
      // Yes ボタンが押された場合の処理
      // DB更新処理
      message = "更新が完了しました。";
    } else if (actionId === "no_action") {
      // No ボタンが押された場合の処理
      message = "更新をキャンセルしました。";
    }

    // 更新結果をスレッドに返信
    await sendSlackMessage(body.channel.id, message, body.message.ts);
    return {
      statusCode: 200,
      body: '',
    };
  }

  // メンション時イベント
  if (body.event.type === "app_mention") {
    let message = `<@${body.event.user}>\nデータが見つかりません`;
    let appendBlock = false;
    // Slackから投稿されたidを正規表現を用いて取得
    const matchResult = body.event.text.match(/\d{11}/);

    if (matchResult) {
      const companyId = matchResult[0];
      try {
        // APIから情報を取得処理
        message = `<@${body.event.user}>\n更新対象は ${code}_${companyName} でよろしいですか?\nHubSpot Id : ${companyId}`; 
        appendBlock = true;
      } catch (error) {
        // APIのリクエスト形式に合わなかった場合
        console.log("Failed. companyId : " + companyId);
      }
    }
    // Slackに返信
    await sendSlackMessage(body.event.channel, message, body.event.ts, appendBlock);

    return {
      statusCode: 200,
      body: '',
    };
  }
};


async function sendSlackMessage(channel, text, thread_ts, appendBlock=false) {
  let blocks = [];
  if (appendBlock) {
    // Yes No ボタンの追加
    blocks = [
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: text,
        },
      },
      {
        type: "actions",
        elements: [
          {
            type: "button",
            text: {
              type: "plain_text",
              text: "YES",
            },
            "style": "primary",
            value: "yes",
            action_id: "yes_action",
          },
          {
            type: "button",
            text: {
              type: "plain_text",
              text: "NO",
            },
            value: "no",
            action_id: "no_action",
          },
        ],
      },
    ];
  }

  const postData = {
    token: SLACK_BOT_TOKEN,
    channel,
    text,
    thread_ts,
    blocks,
  };

  const response = await axios.post("https://slack.com/api/chat.postMessage", postData, {
    headers: {
      "Content-Type": "application/json; charset=utf-8",
      "Authorization": `Bearer ${SLACK_BOT_TOKEN}`,
    },
  });
  
  return response;
}

// Yes Noボタンを削除するためにメッセージを更新する
async function updateMessage(channel, text, ts) {
  const postData = {
    token: SLACK_BOT_TOKEN,
    channel,
    text,
    ts,
    blocks: JSON.stringify([
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: text,
        },
      },
    ]),
  };

  const response = await axios.post("https://slack.com/api/chat.update", postData, {
    headers: {
      "Content-Type": "application/json; charset=utf-8",
      "Authorization": `Bearer ${SLACK_BOT_TOKEN}`,
    },
  });

  return response;
}

このLambdaをSlackアプリから発火させるために関数URLを紐付ける。

Image from Gyazo

Slackアプリの準備

メンションイベントを拾えるようにする

Scopes(権限)の設定

Image from Gyazo

権限設定完了後Slackワークスペースにインストール

Image from Gyazo

Event Subscriptionsに登録

Image from Gyazo

ボタンイベントを拾えるようにする

Interactivityを設定

Image from Gyazo

2
1
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
2
1