今年もらったSlackのリアクションを集計してニヤニヤしよう


はじめまして、こんにちわ。

はじめに

Slack Advent Calendar7日目、初めてアドベントカレンダーに参加します。

ちょうど1年前に、2018年に一番使われたSlackの絵文字を調べるアプリケーションを作りました。その内容を記事にしようと思ってほったらかしにして1年が過ぎました。1年でSlackのAPIも結構変わりましたので、最新の仕組みに乗っかるように作り替えてみます。

作ったもの

こんなメッセージを送るApp(Bot)です。

期間を1年に設定すれば年間ランキングが作れます。
毎週月曜日に送るようにすると、先週に頑張った人が見えるようになります。

Botと言っても現状はSlashコマンドの実装はしていなく、普通のPHP(Laravel)のスタンドアロンアプリケーションです。

使ったもの

今回もWindows環境です。

まず、作戦会議

まず、リアクションの捕まえ方を調べます。

会話データからリアクションのとらえ方

conversations.historyを叩いて、APIの結果を眺めてみます。

conversations.historyのサンプル
{
    "ok": true,
    "latest": "1585158399.000000",
    "oldest": "1546300800.000000",
    "messages": [
        {
            "client_msg_id": "7c0272bf-4222-46b3-b10d-9bc5ca8a9d37",
            "type": "message",
            "text": "\u306f\u308d\u30fc",
            "user": "UNUGXMXQQ",
            "ts": "1575207922.000600",
            "team": "TDWRKFV0S",
            "blocks": [
                {
                    "type": "rich_text",
                    "block_id": "p1411",
                    "elements": [
                        {
                            "type": "rich_text_section",
                            "elements": [
                                {
                                    "type": "text",
                                    "text": "\u306f\u308d\u30fc"
                                }
                            ]
                        }
                    ]
                }
            ],
            "reactions": [
                {
                    "name": "grinning",
                    "users": [
                        "UDX2143CM"
                    ],
                    "count": 1
                },
                {
                    "name": "grin",
                    "users": [
                        "UDX2143CM",
                        "UNUGXMXQQ"
                    ],
                    "count": 2
                },
               (省略)
            ]
        },

messagesという配列の中にmessageのオブジェクトがあり、これが1つ分の発言(チャットのポスト)を表現しています。メッセージにリアクションが付くと、messageの中のreactionsという配列が設定されます。reactions配列には、リアクションアイコンのオブジェクトが入っていて、さらにその中にリアクションをしたユーザIdがusersの配列に入っている形です。

メッセージの送信主がmessage.userでとれるので、message.userをリアクションの受信者(TO)とし、reaction.usersをリアクションを送った人(FROM)として関係性を積み上げていけばよさそうです。

上のサンプルでいうと、以下のような表にまとめればいいわけです。

from to icon
UDX2143CM UNUGXMXQQ
UDX2143CM UNUGXMXQQ
UNUGXMXQQ UNUGXMXQQ

UNUGXMXQQさんが投げたメッセージに対し、UDX2143CMのリアクションをし、UDX2143CMさんとUNUGXMXQQさんがのリアクションをしたので、以下のような関係になります。自分から自分のリアクションもあり得るので、そこは集計時に考慮しましょう。

ユーザIDからユーザ名への変換

SlackのAPIはユーザIDを返すので、これでサマリーしても誰のことだかわからないです。今回はいったんSlackの全ユーザを取り出してIDから名前に変換する処理をしています。ユーザ数が多いときはちょっと考慮が必要になりそうです。

環境準備

では、今回の環境を作ります。

開発環境の準備

laravelの最新版を入れて、Guzzleパッケージのインストールし、laravelのコマンドラインクラスを作るところまで。

コマンドライン

> cd \
> mkdir reactionman
> cd reactionman
> composer create-project laravel/laravel --prefer-dist .
(省略)
Application key set successfully.

> composer require guzzlehttp/guzzle
Using version ^6.4 for guzzlehttp/guzzle
(省略)
Package manifest generated successfully.

> php -v
PHP 7.2.11 (cli) (built: Oct 10 2018 02:39:52) ( ZTS MSVC15 (Visual C++ 2017) x86 )

> php artisan -V
Laravel Framework 6.6.0

> php artisan make:command ReactionMan\ReactionManStart
Console command created successfully.

C:\reactionman\app\Console\Commands\ReactionManにPHPのファイルができていればOK。

Slack Appの設定

ReactionManを新規のAppとして作ります。

https://api.slack.com/
右上のYourAppをクリック

https://api.slack.com/apps
Create New App をクリック

Appの定義画面
適当に入力してCreate Appを押す

BotUserを足しましたが、要らなかったかも。

OAuthのメニューでAppのスコープを追加しておく。
channels:history, channels:read, chat:write:bot, users:readの4つのスコープを追加します。

Install App to Workspaceでアプリの登録を忘れずに。

ここまでで準備完了です

プログラムを作る

今回はLaravelのCommandインターフェイスでバッチプログラムを作りました。4ファイルだけなのでgithubにあげときます。 https://github.com/kanaxx/reactionman

以下のようなことをやっています。

  1. 引数のチェック
  2. Slackの全チャンネルデータを取得
  3. Slackの全ユーザデータを取得
  4. 指定のチャンネルの会話データを取得
  5. 会話の中のリアクションを集計
  6. 集計結果をBlock Kitの形式に変換
  7. 結果をSlackにPOST

リアクションマンの使い方

--helpで使い方が出ます。Laravel賢い

コマンドライン

>  php artisan reactionman:start --help
Description:
  Slackのリアクションを集計してレポートするかわいいやつ

Usage:
  reactionman:start [options]

Options:
      --days[=DAYS]        集計日数
      --start[=START]      集計の開始日 2019-11-11形式
      --end[=END]          集計の終了日 2019-11-11形式
      --channel[=CHANNEL]  集計対象チャネル(publicのみ)
      --sendto[=SENDTO]    通知先チャンネル名(publicのみ).指定がないときは結果をPostしないで終わる
      --token[=TOKEN]      結果をpostMessage可能なユーザトークン
  -h, --help               Display this help message
  -q, --quiet              Do not output any message
  -V, --version            Display this application version
      --ansi               Force ANSI output
      --no-ansi            Disable ANSI output
  -n, --no-interaction     Do not ask any interactive question
      --env[=ENV]          The environment the command should run under
  -v|vv|vvv, --verbose     Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

使い方

こんな感じで叩くといいでしょう。


#過去7日間のchannel2のリアクションを集計してgeneralチャンネルに送る
php artisan reactionman:start --days=7 --channel=channel2 --sendto=general --token=xoxp-xxx

#2019年のchannel2のリアクションを集計してchannel2送る
php artisan reactionman:start --start=2019-01-01 --end=2019-12-31 --channel=channel2 --sendto=channel2 --token=xoxp-xxx

パラメータの説明

トークン

全部のSlack APIに使うトークン。ボットトークンだとconversations.historyができないのでユーザトークンが必要。

期間の指定

過去7日分の集計の場合は --days=7
期間を指定するときは、--start=2019-11-01--end=2019-12-01のように指定

両方指定するとdaysのほうが優先されます。

調べるチャンネル

--channel=チャンネル名で指定。チャンネルIDを調べなくてOK

結果を送るチャンネル

--sendto=チャンネル名で指定。こちらもチャンネルIDでなくてOK。sendtoが指定されないとき、もしくは指定されたチャンネルが存在しないときは、集計はするけど送信はしない。

まとめ

Slackが推奨する気軽なコミュニケーションがどれくらい使われているのかが分かるようになります。一年でどれだけ絵文字が飛び交ったのか、確認してみてはいかがでしょうか。

複数チャンネルの集計をできるようにすると、会社全体の絵文字ランキングが作れますね。