📘

【slack api (Block kit)】×【GAS】で投票アプリを作る:2回目

2023/01/10に公開

前回はslackにボタン付きメッセージを投稿するところまで行いました。

前回作成したボタンを押した場合、ボタンに処理が設定されていないため
警告アイコンが表示されて、インタラクティブな応答処理(ボタン押下に応じて実行される処理)が設定されていませんといった旨のメッセージが表示されます。

今回はインタラクティブ処理として投票画面の表示処理を設定することで、ボタンが押されたら投票画面が表示されるようにします。

ボタン押下時のインタラクティブ処理の実装イメージとしては次の通りです。

上記の処理を実現するために
①GASでHTTPリクエストを受け付けるdoPost関数を作成
②GASをウェブアプリとしてデプロイし、URLを発行
③slackの投票開始ボタンを押したら②のURLにHTTPリクエストするように設定
を行います。

1. GASでHTTPリクエスト受付処理を作成する

はじめにGASでSlackからのHTTPリクエストを受け付けるdoPost関数を作成します。

まずはセキュリティ的に最低限必要な
・リクエスト検証
をdoPost関数に実装します。

リクエスト検証を行うための準備としてslack appに設定されているトークン情報を控えます。
トークン情報はSlack App設定画面の
Settings > Basic Information > App
で確認できます。
https://api.slack.com/apps/

次にGASファイルを新しく作成します。
作成したら、スクリプトプロパティを次のように設定します。
(GASの作成方法、スクリプトプロパティの設定方法がわからない方は前回を参照してください。)

プロパティ名・・・SLACK_VERIFICATION_TOKEN
値・・・先ほど控えたトークン情報

スクリプトプロパティを設定後、次のようにコーディングします。

コード.gs
const legacyVerificationToken = PropertiesService.getScriptProperties().getProperty("SLACK_VERIFICATION_TOKEN");

/**
 * インタラクティブ処理
 *  (投票開始ボタンに紐づいて動作する処理)
 */
const doPost = (e) => {
  // JSON形式のリクエスト情報を取得
  const json = JSON.parse(e.parameter.payload);

  //リクエスト検証
  try {
    if (json.token != legacyVerificationToken) throw new Error('Invalid Token')
  } catch (e) {
    return ContentService.createTextOutput(e.message);
  }

  return ContentService.createTextOutput();
}

ポイントはリクエスト情報のトークンとプロパティのトークン情報を突き合わせる判定処理を行っているところです。
この条件判定がTRUEの場合に限り、slackからの通信とみなして処理を継続するようにしています。

doPost関数を作成したらGASをデプロイします。
画面右上のデプロイメニューで「新しいデプロイ」を選択してください

歯車アイコンをクリックして「ウェブアプリ」を選択します

各設定欄を設定します

説明・・・任意のコメント(空欄でもOK)
次のユーザーとして実行・・・自分
アクセスできるユーザー・・・全員(デフォルトは「自分のみ」なので必ず全員に変更するようにしてください)

上記を3つ設定内容を確認したらデプロイボタンを押下します

デプロイされたら、ウェブアプリとしてのURL(下の方)が発行されますので、こちらのURLを控えておきます。

2. Slack側でボタン押下時のリクエスト先URLを設定する

投票開始ボタンが押下されたら先ほど作成したGASが実行されるようにSlackAppで設定を行います。

https://api.slack.com/apps/

Features > Interactivity & Shortcuts
でInteractivityをONにします

「Request URL」に先ほど控えたURLを設定して、画面下部の「Save Changes」を押下します。

これで投票開始ボタンが押下されたら、GASに対してHTTPリクエストが行われるようになりました。
試しに前回作成した投票開始ボタンを押してみましょう。

ボタンを押すと見かけ上は何も起こりませんが、正常に処理が完了したという応答処理がGASから返却されるため、記事冒頭のエラーメッセージが表示されなくなります。

ここまで問題ないことが確認出来たら、次はGASのdoPost関数に投票画面を表示する処理を追加します。

3.投票画面をBlock kit builderで作成する

モーダル画面をBlock kit builderで作成します。

今回作成したBlock kitがこちらです。

https://app.slack.com/block-kit-builder/T82AV4UBA#{"type":"modal","title":{"type":"plain_text","text":"XXXの投票","emoji":true},"submit":{"type":"plain_text","text":"投票を確定","emoji":true},"close":{"type":"plain_text","text":"キャンセル","emoji":true},"blocks":[{"type":"section","text":{"type":"plain_text","text":"XXXの投票です","emoji":true}},{"type":"divider"},{"type":"input","block_id":"block_vote_getter","label":{"type":"plain_text","text":"得票者","emoji":true},"element":{"type":"users_select","placeholder":{"type":"plain_text","text":"得票者を選んでください","emoji":true},"action_id":"action_vote_getter"}},{"type":"input","block_id":"block_vote_reason","label":{"type":"plain_text","text":"投票理由"},"element":{"type":"plain_text_input","placeholder":{"type":"plain_text","text":"投票理由を記載してください"},"multiline":true,"action_id":"action_vote_reason"}}]}

上記のBlockKitをGASに変数として定義します。

先ほど作成したGASを開いて
+> スクリプト
でファイルを追加します。

ファイル名は「モーダル」とし、ここに先ほどのBlockKitを変数として定義します。

モーダル.gs
// 投票画面のBlockKit
const MAIN_MODAL = {
  "type": "modal",
  "title": {
    "type": "plain_text",
    "text": "XXXの投票",
    "emoji": true
  },
  "submit": {
    "type": "plain_text",
    "text": "投票を確定",
    "emoji": true
  },
  "close": {
    "type": "plain_text",
    "text": "キャンセル",
    "emoji": true
  },
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "plain_text",
        "text": "XXXの投票です",
        "emoji": true
      }
    },
    {
      "type": "divider"
    },
    {
      "type": "input",
      "block_id": "block_vote_getter",
      "label": {
        "type": "plain_text",
        "text": "得票者",
        "emoji": true
      },
      "element": {
        "type": "users_select",
        "placeholder": {
          "type": "plain_text",
          "text": "得票者を選んでください",
          "emoji": true
        },
        "action_id": "action_vote_getter"
      }
    },
    {
      "type": "input",
      "block_id": "block_vote_reason",
      "label": {
        "type": "plain_text",
        "text": "投票理由"
      },
      "element": {
        "type": "plain_text_input",
        "placeholder": {
          "type": "plain_text",
          "text": "投票理由を記載してください"
        },
        "multiline": true,
        "action_id": "action_vote_reason"
      }
    }
  ]
}

4.GASに投票画面を表示する処理を追加する

投票画面の表示実装にあたり
SlackAppのBot User OAuth Tokenという権限トークン情報が必要となるので、
こちらをSlackApp管理画面から控えておきます。

先ほど作成したGASに戻り
次のスクリプトプロパティを追加します。

プロパティ名・・・SLACK_BOT_USER_OAUTH_TOKEN
値・・・先ほど控えたBot User OAuth Token

1.で作成したGASを次の通りに修正します。

コード.gs
const legacyVerificationToken = PropertiesService.getScriptProperties().getProperty("SLACK_VERIFICATION_TOKEN");
const botUserOAuthToken = PropertiesService.getScriptProperties().getProperty("SLACK_BOT_USER_OAUTH_TOKEN");

/**
 * インタラクティブ処理
 *  (投票開始ボタンに紐づいて動作する処理)
 */
const doPost = (e) => {
  // JSON形式のリクエスト情報を取得
  const json = JSON.parse(e.parameter.payload);

  //リクエスト検証
  try {
    if (json.token != legacyVerificationToken) throw new Error('Invalid Token')
  } catch (e) {
    return ContentService.createTextOutput(e.message);
  }

  // 表示するモーダル画面情報をpayload(転送データの本体)として設定する
  const payload = {
    "trigger_id": json.trigger_id, //投票開始ボタンに設定されているトリガーID
    "view": MAIN_MODAL , //投票画面のBlockKit
  }

  // モーダル画面を表示する際のオプションを設定する
  const options = {
    "headers": { "Authorization": "Bearer " + botUserOAuthToken },
    "method": "post",
    "contentType": "application/json",
    "payload": JSON.stringify(payload),
  };

  // 投票モーダル画面として表示する
  UrlFetchApp.fetch('https://slack.com/api/views.open', options);

  // HTTP ステータスコード 200 OK を返却する
  return ContentService.createTextOutput();
}

ポイントは
モーダル表示にあたり、slack apiサービスのWeb Apiを使用しているところです。
slackのWeb APIではHTTP通信を行うことでメッセージ投稿、ユーザー登録等の様々なslack上の操作ができるAPIであり、今回はそのうちのモーダル表示を行うAPIであるviews.openを使用しています

https://api.slack.com/methods/views.open

views.openを呼び出すにあたり、
・ボタン押下時に発行されるトリガーID
・モーダル画面(BlockKit)
・SlackAppのBot User OAuth Token
が必要なため、これらを設定してviews.openにリクエストしています。

GASを修正したら、再デプロイを行います。

デプロイメニューで「デプロイを管理」を選択します。

デプロイ画面で右上の編集(鉛筆)アイコンをクリックして編集モードにしてから
バージョンを「新バージョン」に変更して、デプロイボタンを押下します。

デプロイボタンを押すと、次のように承認を求められます。
これはGoogleからみて外部サービスにあたるslack apiを利用するようにするように修正したためです。
slack apiはslackの公式サービスであり信頼できるものであるため、承認を行います。

承認が完了したら、再度デプロイを行ってください。
バージョンを新バージョンにするのを忘れないようにしてください。

これで投票開始ボタンが押されたら投票画面が表示されるようになりました。
試しに投票開始ボタンを押してみましょう。
ボタンを押すと、投票画面が表示されるはずです。

Discussion