👀
Slackを手軽に監視したい(Event APIをつかってみたよ)
@tosqです こんにちはこんにちは!!
Aidemyでえんじにゃーしてます
What
我々はSlackに取り憑かれている。
故にSlackでなにが起こっているのか、知りたいのである。
ということで、Slackを手軽に監視できるアプリをつくっていきます
TL;DR
- BoltでFirebase Functionsにbotを作成する
- emojiの追加やチャンネル作成を検知して自動投稿できるようにする
背景
元々Real Time Messaging APIでemojiの追加やチャンネルの作成などを検知して自動投稿するbotがありましたが、現在新しくつくるアプリでは利用できません
また、WebSocketサーバが必要であり、サーバ稼働コストもかかってしまうのでCloud Functions + Boltへの移行を行いました
手順
bot作成
- https://api.slack.com/apps [Create New App] でbot(App)を作成する
- [Install your app] からWorkspaceにインストールします
firebase cliのインストール
- [Mac] curl -sL https://firebase.tools | bash で firebase cliのインストール
ログイン
$ firebase login
プロジェクト一覧参照
$ firebase projects:list
利用するプロジェクト指定
$ firebase use slack-bot
firebaseにSlack Appの設定をする
- 登録したアプリの [OAuth & Permissions] から Signing Secret と Bot User OAuth Token を取得してfirebaseのconfigに登録する
$ firebase functions:config:set slack.signing_secret=xoxb-xxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx
$ firebase functions:config:set slack.bot_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
アプリの作成
- 参考リンク
- 手軽にやるには下記で
$ git clone git@github.com:tosaka-n/cloud-function-slack-bolt.git
- 上記のレポジトリでは、複数のアプリをまとめて管理できるようにindex.jsでエンドポイントを集約しています
- src/index.jsに設定してあるexportsがエンドポイントになります
ex)
index.js
exports.slack = functions.https.onRequest(slack.app);
slack.js
const expressReceiver = new ExpressReceiver({
signingSecret: config.slack.signing_secret,
endpoints: '/',
processBeforeResponse: true
});
// 中略
exports.app = expressReceiver.app;
の場合は https://xxx.cloudfunctions.net/slack になります
デプロイ
$npm run deploy
or
$ firebase deploy --only functions
でデプロイできます
エンドポイントの登録
- Slackに作成したアプリの [Add features and functionality] → [Event Subscriptions] から登録します
- 下部の緑[Save Changes]をクリックしないと保存されないので注意
注記
- cf) https://api.slack.com/events/url_verification
- 上記によると challenge パラメータを返す必要があるかもしれません
- 実装時に必要だったか失念したため、必要そうであれば challenge の値をそのまま返すように追記してください
アプリのpermission設定
- Slack Appの [Subscribe to bot events] から指定します
- 特に message.channels を指定しないと投稿に反応できないので必ず登録してください
ここまでで、下準備が完了です
適当なchannelに作成したアプリをiviteして 「hello」 と投稿するとbotが 「hello」 を返してくれるはずです
監視について
- 利用可能なEventについては下記にまとまっています
- 利用したいEventについて
app.event
で受け取ることでSlackに起こったできごとを監視することができます
サンプル
emojiの追加/削除
app.event('emoji_changed', async ({ event, client }) => {
if (event.subtype == "add") {
await client.chat.postMessage({
channel,
text: `\`:${event.name}:\` が追加されました`,
attachments: [
{
pretext: `:${event.name}:`,
image_url: event.value
}
]
});
} else if (event.subtype == "remove") {
await Promise.all(event.names.map(name => client.chat.postMessage({ channel, text: `${name}が消えました` })));
}
});
チャンネル作成
app.event("channel_created", async ({ event, client }) => {
const user = await client.users.info({user: event.channel.creator});
await client.chat.postMessage({ channel, text: `チャンネル <#${event.channel.id}|${event.channel.name}> が作成されました` });
});
ユーザの追加
- ユーザにはworkflow/bot/userの3種類あるため、分岐します
app.event("team_join", async ({ event, client }) => {
const userInfo = await client.users.info({ user: event.user.id });
if (userInfo.user.is_bot) {
if (userInfo.user.is_workflow_bot) {
await client.chat.postMessage({ channel, text: `${userInfo.user.real_name}というワークフローが作成されました` });
} else {
await client.chat.postMessage({ channel, text: `${userInfo.user.name}が追加されました` });
}
} else {
await client.chat.postMessage({ channel, text: `${userInfo.user.name}[${userInfo.user.profile.last_name} ${userInfo.user.profile.first_name}]さんが参加しました` });
}
});
備考
- Real Time Messaging APIでは非公式ながら下記のEventも流れてきていましたが、Event APIには存在しないため、移行の際に元々のコードから削除しました
- apps_installed: botの作成
- channel_updated: Public channelのprivate化
終わりに
Aidemyではエンジニアを募集してます!!!!!! (エンジニア以外も)
こちらから
それではみなさん、よいSlack Lifeを〜
Discussion