node.jsでSlackのリアクションを集計するツールを作ってみた
普段はWebのバックエンド開発をメインでやってます。
最近プライベートでWebサービスやDAppsの開発を始め、JavaScriptを扱う機会が多くググった知識だけでは戦えなくなって勉強し直しました。
一通り学習し終えたのでnode.jsでSlackのリアクションを集計するツールを作ってみました。
ざっくりとした仕様
以下のような仕様で開発しました。
- プログラムは定期的(1回/日)に実行
- 前日にリアクションされた絵文字を集計 ※publicチャンネルのみ
- 集計結果を降順でソート
- 結果を特定のチャンネルに送信
そもそもリアクションって何?って方はこちらへ。
必要なAPIを選定する
フローを簡単にまとめると
- 対象チャンネルを取得
- 各チャンネル内の会話(リアクション)を取得
- リアクションを集計→送信
となります。
1と2はAPIで取得する情報になります。
良さげなやつがありました。
channels.history method | Slack
channels.listで対象チャンネルを取得、取得したchannelコードをchannels.historyに引き渡しリアクションを取得します。
channels.historyを実行するとき取得期間を絞るため、oldestに前日0時0分、latestに当日0時0分を設定します。
※厳密にやると0時0分が重複するからダメかもしれない。
Slackにアプリを登録する
事前準備としてSlackにアプリを登録し、Botユーザを作成します。
詳しくはこちらへ。
channels.historyの実行にchannels:history readの権限が必要なので付与しておきましょう。
合わせてOAuth Access TokenとBot User OAuth Tokenが必要となるのでメモっておきます。
実装
必要なパラメータ(OAuth Access TokenとBot User OAuth Token、送信先チャンネル)は.envファイルに記載しています。
// load .env require('dotenv').config(); const SLACK_TOKEN = process.env.SLACK_TOKEN; const SLACK_BOT_TOKEN = process.env.SLACK_BOT_TOKEN; const SEND_CHANNEL = process.env.SEND_CHANNEL; const util = require('util'); const slack = require('slack'); const moment = require('moment-timezone'); const CronJob = require('cron').CronJob; function getChannels(oldest, latest) { return new Promise(function(onFulfilled, onRejected) { slack.channels.list({ token: SLACK_TOKEN }).then(response => { onFulfilled({ channels: response.channels.map(channel => channel.id), oldest: oldest, latest: latest }); }); }); } function getReactions(responses) { return new Promise(function(onFulfilled, onRejected) { reactions = []; const channels = responses.channels; const oldest = responses.oldest; const latest = responses.latest; let i = 0; channels.map(channel => { slack.channels .history({ token: SLACK_TOKEN, channel: channel, oldest: oldest, latest: latest }) .then(response => { response.messages.map(message => { if ('reactions' in message) { reactions = reactions.concat(message.reactions); } }); if (++i == channels.length) { onFulfilled(reactions); } }) .catch(error => { console.log('error!!'); }); }); }); } sortReaction = reactions => { // counter totalReaction = []; reactions.map(reaction => { name = ':' + reaction.name + ':'; if (name in totalReaction === false) { totalReaction[name] = 0; } totalReaction[name] += reaction.count; }); // convert for sort sortReaction = []; for (name in totalReaction) { sortReaction.push({ name: name, count: totalReaction[name] }); } sortReaction = sortReaction.sort((a, b) => { if (a.count > b.count) return -1; else if (a.count < b.count) return 1; else return 0; }); // create send message msg = ''; for (reaction of sortReaction) { msg += reaction.name + ' : ' + reaction.count + '\n'; } return msg; }; postMessage = () => { // oldest ※前日0時0分 oldest = moment() .subtract(1, 'days') .startOf('day'); latest = moment().startOf('day'); getChannels(oldest.unix(), latest.unix()) .then(getReactions) .then(reactions => { if (reactions.length === 0) { msg = 'Good Morning!! ' + oldest.format('M/D(ddd)') + 'のリアクションは・・・なしです。'; } else { msg = 'Good Morning!! ' + oldest.format('M/D(ddd)') + 'のリアクション集計しました。\n\n'; msg += sortReaction(reactions); } console.log(msg); slack.chat.postMessage({ token: SLACK_BOT_TOKEN, channel: SEND_CHANNEL, text: msg }); }); }; const job = new CronJob({ /* Seconds: 0-59 Minutes: 0-59 Hours: 0-23 Day of Month: 1-31 Months: 0-11 Day of Week: 0-6 */ cronTime: '0 0 9 * * *', // 毎日午前9時に送信 onTick: postMessage, start: false, timeZone: 'Asia/Tokyo' }); job.start();
正しく動けばこんな感じでBotユーザから送信されます。
GitHubにインストール手順をまとめているので、使ってみたい方はどうぞ。
まとめ
実は絶賛開発中の社内通貨プロジェクトで利用しようかなって考えてます。
当時はSlackを利用してなかったので、別のツールを利用してイイねのやり取りを行う予定でした。
社内のチャットツールをSlackに切り替えリアクションのやり取りが予想以上に活発なので、データを収集して活用する術を頭の中で妄想してます。
たぶん特定のリアクションを貰う(贈る)と通貨がもらえるような感じになりそうです。
ではまた。