お久しぶりです。本間です。
またSlackのBotを作ったので紹介したいと思います。
今回はまだ使ったことのない「Interactive buttons」を使ってアンケートができるBotを作ってみました。
使い方
HubotのいるチャンネルにJSON形式で作成したアンケートを投稿します。
ダイレクトメッセージでアンケートが届きます。
ボタンを押してアンケートに答えます。
Hubotのいるチャンネルでアンケートの集計を行います。
集計結果はJSONで出力されます。
事前知識
Slack Appの作成
ここからSlack Appを作成します。
次に、Bot Userのtokenを発行するために。認証後のリダイレクトURLを設定します。
Bot Userの名前とオンラインの設定を行います。
Bot Userのtokenを発行
ここの手順に従ってtokenを発行します。
1.認証 下記URLを作成して認証を行います。
https://slack.com/oauth/authorize?client_id={client_id}&scope=bot&redirect_uri={redirect_uri}
2.token発行 1で取得したコードを利用してtokenを発行します。 下記URLにアクセスするとtokenを取得できます。
https://slack.com/api/oauth.access?client_id={client_id}&client_secret={client_secret}&code={code}&redirect_uri={redirect_uri}
redirect_uriは先ほど設定したリダイレクトURLを使用してください。
client_idとclient_secretはSlack Appから取得できます。
Slack Appのエンドポイントの作成
今回はNode.jsのExpressを使って実装します。
このエンドポイントには「Interactive buttons」が押される度にリクエストがきます。
エンドポイントのURLはSlack Appに設定します。
JSON形式のアンケートから「Interactive buttons」を作成する処理
アンケートの作成はHubotを通してSlackから行います。
メイン処理
module.exports = (robot) => { // ここの正規表現でJSONを取得します。 robot.respond(/enquete[\s\S]```[\s\S]((?:[\s\S]?.*)+)[\s\S]```/i, async (res) => { let slack = new Slack(config.slack); let inquiryJson = res.match[1]; try { let inquiry = JSON.parse(inquiryJson); // ダイレクトメッセージのチャンネルを作成します。 // 今回はアンケート作成者にアンケートを投稿します。 let channel_id = (await slack.openDirectMessage(res.envelope.user.id)).channel.id; // アンケート回答用のAttachmentsを投稿します。 await slack.postAttachments(Inquiry.object2attachments(inquiry), channel_id); // アンケート集計用のAttachmentsを投稿します。 await slack.postAttachments(Inquiry.getAggregateAttachments(), res.envelope.room); res.send(); } catch(e) { console.log(e); } }); }
JSONからAttachmentsに変換する処理と集計用のAttachmentsを作成する処理
export class Inquiry { static object2attachments(object) { return object.questions.map( (question, index) => { return { fallback: object.notice, title: question.title, callback_id: index, color: '#0000FF', attachment_type: 'default', actions: question.choices.map( (choice, index) => { return { name: index, text: choice, type: 'button', value: choice }}) }}); } static getAggregateAttachments() { return [ { fallback: '集計する', title: '集計する', callback_id: 'aggregate', color: '#0000FF', attachment_type: 'default', actions: [ { name: 'aggregate', text: '集計する', type: 'button', value: 'aggregate' } ] } ]; } }
アンケート回答時の処理
アンケート回答時の処理は作成したエンドポイントで行います。
メイン処理
let answers = {}; router.post('/', async (req, res) => { let params = JSON.parse(req.body.payload); // 集計時の処理 if (/^aggregate$/.test(params.callback_id)) { await aggregateProcess(params); } // アンケート回答時の処理 else { await answerProcess(params); } res.send(); });
アンケート回答時の処理
async function answerProcess(params) { let index = params.callback_id; let original_attachments = params.original_message.attachments; // アンケートの質問を取得します。 let question = original_attachments[index].title; // アンケートの回答を取得します。 let answer = params.actions[0].value; // アンケート結果をオブジェクトに保持しておきます。 let userAnswers = answers[params.user.name] || {}; userAnswers[question] = answer; answers[params.user.name] = userAnswers; // アンケート回答箇所だけSlackの表示を書き換えます。 original_attachments[index] = { title: question, text: answer, color: '#00FF00' } // Slack Web APIにリクエストを送ってSlackのメッセージを更新します。 await new Slack(config.slack).updateAttachments( params.message_ts, original_attachments, params.channel.id ); }
アンケート集計時の処理
アンケート集計のトリガーを「Interactive buttons」にしているので、集計の処理は作成したエンドポイントで行います。
メイン処理
let answers = {}; router.post('/', async (req, res) => { let params = JSON.parse(req.body.payload); // 集計時の処理 if (/^aggregate$/.test(params.callback_id)) { await aggregateProcess(params); } // アンケート回答時の処理 else { await answerProcess(params); } res.send(); });
アンケート集計時の処理
async function aggregateProcess(params) { // JSONを整形してSlackに投稿します。 await new Slack(config.slack).postMessage( "```\n" + JSON.stringify(answers, null, ' ') + "\n```", params.channel.id ); answers = {}; }
おわりに
今回はHubotとExpressで実装をしましたが、HubotはHTTPのリッスンもできるのでHubotにまとめたいと思いました。しかし、HubotのtokenとSlack Appのtokenが別ものなので個人的にあまりしっくりきません。。(Hubotから「Interactive buttons」を投稿する方法をご存知の方がいたら教えていただきたいです)
SlackのBot作成フレームワークにはHubotの他にもBotkitというものがあり、こちらはBot Userのtokenを使用するのでSlack Appのtoken一つでできそうです。また、HTTPのリッスンもHubot同様にできるので一つにまとまってすごいしっくりきます。今度はBotkitを使ってこのアンケートBotをさらに使いやすくしてみたです。