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

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

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

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

##作ったもの
こんなメッセージを送るApp(Bot)です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/2cb2655f-3c56-8309-6020-f1c2ed22f0e2.png)

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

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

##使ったもの
* Slack API
  * [users.list](https://api.slack.com/methods/users.list)
  * [conversations.list](https://api.slack.com/methods/conversations.list)
  * [conversations.history](https://api.slack.com/methods/conversations.history)
  * [chat.postMessage](https://api.slack.com/methods/chat.postMessage)
* Laravel Framework 6.6.0
* Guzzle 6.4

今回もWindows環境です。


#まず、作戦会議
まず、リアクションの捕まえ方を調べます。

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

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

```json: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 | :grinning: |
| UDX2143CM  | UNUGXMXQQ | :grin: |
| UNUGXMXQQ  | UNUGXMXQQ | :grin: |

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

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


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

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

```shell:コマンドライン

> 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をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/d304baf1-9e51-921b-c442-7772373308d0.png)

**https://api.slack.com/apps**
Create New App をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/acd2cb55-3701-dd7a-0657-f05cfdad64f3.png)

**Appの定義画面**
適当に入力して`Create App`を押す
![2019-11-30_21h25_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/6e6c64b1-406d-f072-7c3f-a26d519dcb80.png)

BotUserを足しましたが、要らなかったかも。
![2019-11-30_21h38_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/ff826e90-cacf-2765-33ff-950f7744cfda.png)


**OAuth**のメニューでAppのスコープを追加しておく。
channels:history, channels:read, chat:write:bot, users:readの4つのスコープを追加します。
![2019-12-02_23h19_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/eb5ae8c3-490e-44a8-3366-06c9f77e9151.png)


**Install App to Workspace**でアプリの登録を忘れずに。
![2019-11-30_21h38_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/8e653659-9046-331d-4a83-65086004332d.png)
ここまでで準備完了です:sunflower:


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

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

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




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

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

```bash:コマンドライン

>  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

```

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

```bash

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

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