Slack APIで「いいね！」リアクションを集計するシェルスクリプト

# Slack APIで「いいね！」リアクションを集計するシェルスクリプト

## 動機

社内でも利用しているチャットツールSlackで2015年7月9日からメッセージに絵文字リアクションがつけられるようになりました。

[「Slack」に投票や参加表明に使える絵文字利用の新ツール「Emoji Reactions」 - ITmedia ニュース](http://www.itmedia.co.jp/news/articles/1507/10/news086.html)

絵文字リアクションを使ってお互いに「いいね！」というイイ感じの文化が生まれてきたので、さらなる活性化を目論んで、全員が参加するチャンネルで一番「いいね！」のリアクション(+1またはthumbsup)を獲得しているメッセージをSlack APIを使って集計して報告する仕組みをcron+シェルスクリプトで作ってみました。

## 準備

まず、Slack APIで使うトークンを以下のページから取得してきます。

[Slack Web API | Slack](https://api.slack.com/web)

また、集計するチャンネル・報告するチャンネルのIDが必要なので、以下のページからIDを確認します。

[channels.list method | Slack](https://api.slack.com/methods/channels.list/test)

cron+シェルスクリプトを実行するLinuxマシンを用意します。以下のものをインストールします。curlとjqにパスが通っているか確認してください。

- cron
- curl
- jq


## シェルスクリプト

以下のスクリプトをcronで一日一回実行するようにします。

```bash
#!/bin/bash

# 作業用の一時ファイル格納先を設定します
MY_WORKSPACE=/tmp

# 取得したトークンを設定します
MY_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# 集計対象のチャンネルのID・名称を設定します
MY_CHANNEL=yyyyyyyyy
MY_CHANNEL_NAME=all
# 集計対象の期間はスクリプト実行時の前日になります
MY_DATE=$(date +"%Y年%m月%d日" --date "1 day ago")
MY_LATEST=$(date +"%s" --date "$(date +"%Y-%m-%d 00:00:00")")
MY_OLDEST=$(date +"%s" --date "$(date +"%Y-%m-%d 23:59:59" --date "2 day ago")")

# 集計結果を報告するチャンネルのIDを設定します
MY_POST_CHANNEL=zzzzzzzzz

# 前日のメッセージを取得してファイルに保存します
\rm -f ${MY_WORKSPACE}/my_history_${MY_CHANNEL_NAME}.json
curl -s -F token=${MY_TOKEN} -F channel=${MY_CHANNEL} -F latest=${MY_LATEST} -F oldest=${MY_OLDEST} https://slack.com/api/channels.history > ${MY_WORKSPACE}/my_history_${MY_CHANNEL_NAME}.json

# 変数初期化
MY_TOP_LINK=
MY_TOP_COUNT=0

while :
do
  # 取得したメッセージごとに処理
  for i in $(cat ${MY_WORKSPACE}/my_history_${MY_CHANNEL_NAME}.json | jq -r '.messages[].ts'); do
    # APIの実行制限回避のために1秒スリープします
    sleep 1
    # メッセージのリアクションを取得してファイルに保存します
    \rm -f ${MY_WORKSPACE}/my_reactions_get_${MY_CHANNEL_NAME}.json
    curl -s -F token=${MY_TOKEN} -F channel=${MY_CHANNEL} -F timestamp=${i} https://slack.com/api/reactions.get > ${MY_WORKSPACE}/my_reactions_get_${MY_CHANNEL_NAME}.json
    # リアクションから:+1:または:thumbsup:の数を取得します
    MY_TMP_COUNT=
    MY_TMP_COUNT=$(cat ${MY_WORKSPACE}/my_reactions_get_${MY_CHANNEL_NAME}.json | jq '.message | select(has("reactions")).reactions[] | select(.name=="+1" or .name=="thumbsup").count')
    # 最大数を更新します
    if test -n "${MY_TMP_COUNT}" ; then
      if test ${MY_TMP_COUNT} -gt 0 -a ${MY_TOP_COUNT} -lt ${MY_TMP_COUNT} ; then
        MY_TOP_LINK=$(cat my_reactions_get_${MY_CHANNEL_NAME}.json | jq -r '.message.permalink')
        MY_TOP_COUNT=${MY_TMP_COUNT}
      elif test ${MY_TMP_COUNT} -gt 0 -a ${MY_TOP_COUNT} -eq ${MY_TMP_COUNT} ; then
        MY_TOP_LINK="${MY_TOP_LINK}
$(cat ${MY_WORKSPACE}/my_reactions_get_${MY_CHANNEL_NAME}.json | jq -r '.message.permalink')"
      fi
    fi
  done

  # メッセージに続きがなければ終了します
  if test "$(cat ${MY_WORKSPACE}/my_history_${MY_CHANNEL_NAME}.json | jq '.has_more')" != "true" ; then
    break
  fi

  # メッセージに続きがあれば続きを取得します
  MY_TMP_OLDEST=$(cat ${MY_WORKSPACE}/my_history_${MY_CHANNEL_NAME}.json | jq -r '.messages[].ts' | tail -n1)
  \rm -f my_history.json
  curl -s -F token=${MY_TOKEN} -F channel=${MY_CHANNEL} -F latest=${MY_TMP_OLDEST} -F oldest=${MY_OLDEST} https://slack.com/api/channels.history > ${MY_WORKSPACE}/my_history_${MY_CHANNEL_NAME}.json
done

# 報告するメッセージをファイルに準備します
\rm -f ${MY_WORKSPACE}/my_post_message_${MY_CHANNEL_NAME}.txt
if test ${MY_TOP_COUNT} -gt 0 ; then
  echo "${MY_DATE}のベスト:+1:獲得数 in #${MY_CHANNEL_NAME}: ${MY_TOP_COUNT}
${MY_TOP_LINK}" > ${MY_WORKSPACE}/my_post_message_${MY_CHANNEL_NAME}.txt
else
  echo "${MY_DATE}のベスト:+1:獲得数 in #${MY_CHANNEL_NAME}: 0" > ${MY_WORKSPACE}/my_post_message_${MY_CHANNEL_NAME}.txt
fi

# 報告するメッセージを送信します
curl -s --data-urlencode token=${MY_TOKEN} --data-urlencode channel=${MY_POST_CHANNEL} --data-urlencode text@${MY_WORKSPACE}/my_post_message_${MY_CHANNEL_NAME}.txt --data-urlencode username=reaction_report --data-urlencode as_user=false --data-urlencode icon_emoji=:+1: --data-urlencode unfurl_links=true https://slack.com/api/chat.postMessage >/dev/null 2>&1

```

## 実行結果

報告メッセージがこんな感じになります。

![fig01.png](https://qiita-image-store.s3.amazonaws.com/0/54004/61a8f839-5589-3cba-5ff9-c1cc38cd3d3b.png)

## 注意点

メッセージごとにリアクションを取得するAPIを実行するので、メッセージ数が多くなると集計が遅くなるのと、APIの実行制限(1リクエスト/秒)にひっかかりやすくなるのでご注意ください。