Closed21

Slack Boltをためす

nus3nus3

Boltのチュートリアル 作業手順

  1. slack app作成
  2. slack boltのパッケージインストール
  3. slack appのevent subscriptionsを設定
  4. 動作確認
  5. アクションの追加

まとめ

BoltでAppインスタンス作り、そのappが何をするのか定義する
app.startするとサーバーが立ち上がってる感じになる

app.startしたサーバーのurlをEvent Subscriptionsのrequest urlとして設定することで
listenしたイベントをBoltで定義したappへ渡してくれる

nus3nus3

slack app作成

普通にslack app作ればいいだけだけど、workspaceにインストールするときに
App HomeでDisplay Nameとか設定しないとインストールできないので注意

https://api.slack.com/apps

nus3nus3

slack appのevent subscriptionsを設定

slack appの設定画面でevent subscriptionsを選択
localhostで検証できるようにrequest Urlはngorkでhttpsの値をセット

request urlはeventをどこにリクエスト送るか
slack boltのデフォルトのpathは/slack/eventsになってるっぽい
boltの定義側で変更できそう

Subscribe to bot eventsでslack appがどんな時にsubscribeするか(slack appをaddしたチャネルでメッセージがpostされた瞬間とか)設定できるしここでaddすると必要なscopeも自動で足してくれる

nus3nus3

動作確認

helloって発言すると発言した人に対してHey there <@${message.user}>!って言ってくれる

app.message("hello", async ({ message, say }) => {
  await say(`Hey there <@${message.user}>!`);
});
nus3nus3

アクションの追加

インタラクティブ機能の設定

slackメッセージで使えるボタンや日付ピッカーなどの機能を利用できるように
slack appのInteractivity & Shortcutsの設定をONにする
request urlはEvent Subscriptionsと同じものを使用する

実装

helloと発言したらボタン付きのメッセージを返信する

app.message("hello", async ({ message, say }) => {
  await say({
    blocks: [
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: `Hey there <@${message.user}>!`,
        },
        accessory: {
          type: "button",
          text: {
            type: "plain_text",
            text: "Click Me",
          },
          action_id: "button_click",
        },
      },
    ],
    text: `Hey there <@${message.user}>!`,
  });
});

ボタン付きメッセージのボタンが押された時のアクション

app.action("button_click", async ({ body, ack, say }) => {
  await ack();
  await say(`<@${body.user.id}> clicked the button`);
});
nus3nus3

Slack Boltの基本的な概念を読む
https://slack.dev/bolt-js/ja-jp/concepts#basic

nus3nus3

message()

第一引数に文字列か正規表現を受け取り、メッセージイベントで受け取った値と合致した場合に
第二引数で定義した処理を実行する

nus3nus3

client

slackのweb apiを呼び出すときに使用する

import { App } from "@slack/bolt";

const app = new App({
  // tokenの設定
});

app.client.(web apiのメソッド)

で呼び出せる

nus3nus3

action()

第一引数で定義したaction_idがトリガーされると、第二引数の内容が実行される
action_idの設定はインタラクティブコンポーネント(ボタンとかモーダルとか)のトリガーとして設定できる

全てのアクション(command, options)でack()を呼ぶ必要がある
ack()を実行するとslack側にイベントが正常に受信されたことを知らせることができる
ack()はerrorを渡すこともできる

nus3nus3

shortcut()

ショートカットの設定場所

メッセージショートカット

  1. Create New Shortcut する
  2. On messagesを選ぶ
  3. ショートカットの名前と説明とcallback idを設定

グローバルショートカット

メッセージショートカットと同じ工程
On messageGlobalに変更するだけ

実装

app.shortcut()の第一引数にcallbackId、第二引数でショートカットが呼ばれた際の実装をする

app.shortcut("{callback idをいれる}", async ({ shortcut, ack, context }) => {
  ack();

  try {
    const result = await app.client.views.open({
      token: context.botToken,
      trigger_id: shortcut.trigger_id,
      view: {
        type: "modal",
        title: {
          type: "plain_text",
          text: "foobar",
        },
        close: {
          type: "plain_text",
          text: "Close",
        },
        blocks: [
          {
            type: "section",
            text: {
              type: "mrkdwn",
              text: "I like Apple",
            },
          },
          {
            type: "context",
            elements: [
              {
                type: "mrkdwn",
                text:
                  "",
              },
            ],
          },
        ],
      },
    });
    console.log(result);
  } catch (error) {
    console.log(error);
  }
});
nus3nus3

command()

Slach CommandsからCreate New Commandする

command、request urlを入力する
request urlはhttps://{ドメイン}/slack/eventsで良さげ

app.command("/command-name", async ({ command, ack, say }) => {
  await ack();
  await say(`${command.text}`);
});
nus3nus3

モーダル

アクションするモーダルを作る

ショートカットが選択されたら表示するモーダルを定義
modalのjson定義はめんどくさいので用意されてるblock-kit-builder使う
https://app.slack.com/block-kit-builder

app.shortcut("open_modal_hada_g", async ({ shortcut, ack, context }) => {
  ack();

  try {
    const result = await app.client.views.open({
      token: context.botToken,
      trigger_id: shortcut.trigger_id,
      view: {
        type: "modal",
        // NOTE: submitからcallback idをとりたい場合はここに定義する
        callback_id: "submit_modal",
        title: {
          type: "plain_text",
          text: "ハツジからの質問です",
          emoji: true,
        },
        submit: {
          type: "plain_text",
          text: "送信する",
          emoji: true,
        },
        close: {
          type: "plain_text",
          text: "キャンセル",
          emoji: true,
        },
        blocks: [
          {
            type: "divider",
          },
          {
            type: "section",
            text: {
              type: "plain_text",
              text: "何か一言喋ってみて",
              emoji: true,
            },
          },
          {
            type: "input",
            block_id: "text_input",
            element: {
              type: "plain_text_input",
              action_id: "plain_text_input-action",
            },
            label: {
              type: "plain_text",
              text: "ラベル",
              emoji: true,
            },
          },
        ],
      },
    });
    console.log(result);
  } catch (error) {
    console.log(error);
  }
});

こんな感じのモーダルできる

nus3nus3

モーダル2

作ったモーダルからcallback idを受け取って処理する
app.view()の第一引数にcallback idをいれる

app.view("submit_modal", async ({ ack, view, body, client }) => {
  await ack();

  const input =
    view["state"]["values"]["text_input"]["plain_text_input-action"]["value"];

  const user = body["user"]["id"];

  try {
    await client.chat.postMessage({
      channel: user,
      text: input,
    });
  } catch (error) {
    console.error(error);
  }
});

inputの値取るのがview["state"]["values"]["text_input"]["plain_text_input-action"]["value"]かなりめんどかったけど、console.logでviewの中身を解読すればいける

nus3nus3

TODO: api gateway + lambdaにデプロイする

余裕があればoptions()メソッドも調べる

nus3nus3
nus3nus3
import { App, ExpressReceiver } from "@slack/bolt";
import { APIGatewayProxyEvent, Context } from "aws-lambda";
// TODO: バージョンアップデート
// TODO: https://github.com/vendia/serverless-express/tree/mainline
import * as awsServerlessExpress from "aws-serverless-express";

// レシーバーの定義
const processBeforeResponse = true;
const expressReceiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET || "",
  processBeforeResponse,
});
expressReceiver.app.options("*", (req, res) => {
  res.sendStatus(202);
});

// レシーバをlambdaとapi gatewayでよしなに扱えるようにしてくれる
const server = awsServerlessExpress.createServer(expressReceiver.app);
export const ProxyStart = (event: APIGatewayProxyEvent, context: Context) => {
  awsServerlessExpress.proxy(server, event, context);
};

// boltのapp設定
export const app = new App({
  token: process.env.SLACK_BOT_TOKEN || "",
  receiver: expressReceiver,
  processBeforeResponse,
});

// botでやることの定義
app.message()
このスクラップは2021/03/02にクローズされました