Bolt+jsx-slack+Glitchで伝書鳩botをつくってみた


はじめに

@75asa さんの誘いで入部した社内部活「OSS部」の活動の一貫として作成する事になりました。
Slackbotは以前Hubotを少し触ったことがある程度で、ほぼ初チャレンジです。

使用技術

  • 環境
    • macOS 10.15.7
  • 言語
    • Node.js
    • JavaScript
  • FrameWork
    • Slack Bolt for JS
  • PaaS
    • Glitch

実装

まず今回のSlackAppを作成するにあたって、下記の記事を参考にさせていただきました。
jsx-slackの開発者様の記事で、初めてでも非常に分かりやすかったです。感謝。

参考:実践 jsx-slack: jsx-slack + Bolt で Slack のモーダルを自在に操ろう

ディレクトリ構成はこんな感じ。

./
├── .env
├── .gitignore
├── app.js
├── node_modules
├── package-lock.json
└── package.json

package.json

{
  "name": "pigeon-message",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "sync": "sync-glitch"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@slack/bolt": "^2.4.1",
    "@speee-js/jsx-slack": "^2.6.0",
    "dotenv": "^8.2.0"
  },
  "devDependencies": {
    "sync-glitch-cli": "^2.0.1"
  }
}

app.js

基本構造としてはこんな感じ


const { App } = require('@slack/bolt');
const { jsxslack } = require('@speee-js/jsx-slack');
require('dotenv').config();

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET
});

// ここに処理を書いていく

(async () => {
  await app.start(process.env.PORT || 3000);
  console.log('⚡️ Bolt app is running!');
})();

TimePickerコンポーネント部分で参考記事の通りに進まなかった点が2つほどありました。


const options = (count, start, suffix) => {
    return [...Array(count)].map((_, i) => { // returnを追記
        const s = (i + start).toString();
        return jsxslack`
            <Option value="${s}">${s.padStart(2, '0')}${suffix}</Option>
        `
    });
};

const TimePicker = props => jsxslack` // fragmentは不要
    <Section>
        <b>${props.label}</b>
    </Section>
    <Actions id="${props.id}">
        <Select name="hour" value="${props.hour}" placeholder="時">
            <Optgroup label="午前">${options(12, 0, '')}</Optgroup>
            <Optgroup label="午後">${options(12, 12, '')}</Optgroup>
        </Select>
        <Select name="minute" value="${props.minute}" placeholder="分">
            ${options(60, 0, '')}
        </Select>
    </Actions>

    <!-- error message -->
    ${props.error & jsxslack`<Context>:warning: <b>${props.error}</b></Context>`}

    <Input type="hidden" name="hour" value="${props.hour}" />
    <Input type="hidden" name="minute" value="${props.minute}" />
`

カスタマイズ

元記事から追加した点としては、ポスト先のチャンネルを指定できるように、ConversationsSelectコンポーネントをモーダル内に追加したのと、ショートカットでモーダルを展開できるようにしました。


const modal = props => jsxslack`
    <Modal title="伝言を送る" callbackId="post">
        <Section>
            私にお任せ下さい!
            <Image src="https://source.unsplash.com/ic-13C3QhAI/256x256" alt="鳩" />
        </Section>

        <Textarea id="message" name="message" label="伝言" placeholder="伝言をどうぞ…" required />
        <UsersSelect id="users" name="users" label="送付先" multiple required />
        <ConversationsSelect
            id="channel"
            name="channel"
            label="チャンネル"
            required
            include="public im"
            excludeBotUsers
            responseUrlEnabled
        />
        <DatePicker id="date" name="date" label="日付" required />

        <${TimePicker}
            id="time"
            label="時刻"
            hour="${props.hour}"
            minute="${props.minute}"
            error="${props.timePickerError}"
        />

        <Input type="hidden" name="userId" value="${props.userId}" />
    </Modal>
`

ショートカットはSlackAPIのAppsページにある[Interactivity & Shortcuts]から追加できました。


app.shortcut('open_modal', ({ ack, body, context }) => {
    ack();

    app.client.views.open({
        token: context.botToken,
        trigger_id: body.trigger_id,
        view: modal({ userId: body.user.id }),
    });
});

Glitchにデプロイ

SlackAppが完成したのでGlitchにデプロイします。
ちなみに開発中のWebサーバーはngrokを使ってました。

GitHubにリポジトリを作っておけばGlitchから簡単にImportできるのですが、コード変更のたびにImportしなおすのが面倒なので自動化しました。

最初はsync-glitch-cliを使わせてもらったのですが、git pushした後にコマンドラインでsync-glitchを実行する必要がありました。

mainブランチにpushされた時点で自動デプロイが理想でしたので、最終的にはGitHub Actionsにworkflowを追加することにしました。

参考:リポジトリの変更を Glitch に転送する GitHub Actions


name: Deploy To Glitch
on:
  push:
    branches:
      - main
    workflow_dispatch:
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy To Glitch
        uses: kanadgupta/glitch-sync@master
        with:
          project-id: ${{ secrets.PROJECT_ID }}
          auth-token: ${{ secrets.AUTH_TOKEN }}

はじめbranchesmasterと記載しているのに気づかずActionsが実行されませんでしたが、なんとかpushと同時にGlitchへデプロイすることができました。

参考リンク

Bolt for JS
Bolt フレームワークを使って Slack Bot を作ろう
Reference: Block elements
chat.scheduleMessage
Block Kit Builder
jsx-slack→JSON
実践 jsx-slack: jsx-slack + Bolt で Slack のモーダルを自在に操ろう
Bolt + jsx-slack + TypeScript を使って Slack App をつくる
ブラウザだけで完結するウェブアプリ作成環境 Glitch