LoginSignup
7
8

Slackリアクションランキング、特定のリアクションを受け取った、送った人を集計する

Last updated at Posted at 2021-12-02

この記事は移行しました!最新の内容はこちらをご覧ください😀

やってきました!12月!といえばアドベントカレンダーですね!
今年も最後まで楽しみましょう!

これは 株式会社マイホム Advent Calendar 2021 1日目の記事です。

はじめに

1年を振り返るにはSlackリアクションしかないでしょう!
ということでもう何番煎じかわからないSlackのリアクション集計!
ごにょごにょ実装したので投稿します。

※こちらの記事を大いに参考にさせていただきました。ありがとうございます!
https://qiita.com/ryosuk/items/1a18c663884d2748d4ca

なぜやるか

よく使われたリアクションを知ることで、会社の特色やどんな一年だったかがわかるのでは?😃

また、弊社はMVVのVALUE

  • User First
  • Profesional
  • Love
  • Playful

という4つのカスタム絵文字があり、
それを使った人、受け取った人を知ることで
MVVを体現している人がわかっちゃうのでは!?😃😃😃😃

できること

下記をスプレッドシートに出力します。
※プライベートチャット、スレッド内のリアクションは集計対象外。

  • リアクションランキング
  • MVVリアクションを受け取った回数(ユーザーごと)
  • MVVリアクションを使った回数(ユーザーごと)

実行方法

Slack App を作成し User OAuth Token を取得する

Slack APIを叩くために必要。

メモ:scopesを設定する必要があり、ググると昔はGUI上で設定できたっぽいが今はManifestを直接書け、みたいに言われるので直接書いた。

oauth_config:
  scopes:
    user:
      - channels:read
      - groups:read
      - im:read
      - mpim:read
      - channels:history
      - groups:history
      - im:history
      - mpim:history
      - users:read

スプレッドシートを用意する

下記3つのシートを作成しておきます。

  • ranking
  • mvv_get
  • mvv_send

GASを実行する

下記コードをコピペして、チャチャっと書き換えて、main()を実行!

// 参考: https://qiita.com/ryosuk/items/1a18c663884d2748d4ca
var API_TOKEN = "ここに取得したトークンをコピペ";

var target_year = '2021'; // 対象年
var mvv_reactions = ['らぶ','ぷろ','ゆーざー','ぷれい']; // MVVの絵文字名

var sheet_name_ranking = 'ranking';
var sheet_name_mvv_get = 'mvv_get';
var sheet_name_mvv_send = 'mvv_send';

// ページネーション
var MAX_HISTORY_PAGINATION = 1; // デバッグ用の定数になった
var HISTORY_COUNT_PER_PAGE = 200; // 対象年分とってくる。

var stamps = {};
var counts = [];
var ss = SpreadsheetApp.getActiveSpreadsheet();
var timezone = ss.getSpreadsheetTimeZone();

var slack_members = {};
var mvv_get_user = {};
var mvv_send_user = {};

function main() {
  var logger = new SlackChannelHistoryLogger();
  logger.run();

  updateRankingSheet();
  updateMvvGetSheet();
  updateMvvSendSheet();

  Logger.log(mvv_get_user);
  Logger.log(mvv_send_user);
  Logger.log(slack_members);

  function updateRankingSheet() {
    var sheet = ss.getSheetByName(sheet_name_ranking);
    if (!sheet) {
      sheet = ss.insertSheet().setName(sheet_name_ranking);
    }
    sheet.clear();

    var names = Object.keys(stamps);
    var ary = [];
    for (var i=0; i<names.length; i++) {
      ary.push([names[i]]);
    }
    sheet.getRange(1,1,ary.length,1).setValues(ary);
    for (var i=0; i<names.length; i++) {
      counts.push([stamps[names[i]]]); 
    }
    sheet.getRange(1,2,counts.length,1).setValues(counts);
    //降順でソート
    sheet.getRange(1,1,counts.length,2).sort({column: 2, ascending: false});
  }

  function updateMvvGetSheet() {
    var sheet = ss.getSheetByName(sheet_name_mvv_get);
    if (!sheet) {
      sheet = ss.insertSheet().setName(sheet_name_mvv_get);
    }
    sheet.clear();

    var data = [];
    data.push(['なまえ', ...mvv_reactions, '合計']);
    Object.entries(mvv_get_user).forEach(function([key, value]){
      var name = slack_members[key];
      if (!name) {
        return;
      }
      var tmp = Object.values(value);
      var total = tmp.reduce(function(sum, element){
        return sum + element;
      }, 0);
      data.push([name, ...tmp, total]);
    });
    sheet.getRange(1,1,data.length,6).setValues(data);

    //降順でソート
    sheet.getRange(1,1,data.length,6).sort({column: 6, ascending: false});
  }

  function updateMvvSendSheet() {
    var sheet = ss.getSheetByName(sheet_name_mvv_send);
    if (!sheet) {
      sheet = ss.insertSheet().setName(sheet_name_mvv_send);
    }
    sheet.clear();

    var data = [];
    data.push(['なまえ', '送信回数']);
    Object.entries(mvv_send_user).forEach(function([key, value]){
      data.push([slack_members[key], value]);
    });
    sheet.getRange(1,1,data.length,2).setValues(data);

    //降順でソート
    sheet.getRange(1,1,data.length,2).sort({column: 2, ascending: false});
  }
};

var SlackChannelHistoryLogger = (function () {
    function SlackChannelHistoryLogger() {
        this.memberNames = {};
    }
    SlackChannelHistoryLogger.prototype.requestSlackAPI = function (path, params) {
        if (params === void 0) { params = {}; }
        var url = "https://slack.com/api/" + path + "?";
        var qparams = [];
        for (var k in params) {
            qparams.push(encodeURIComponent(k) + "=" + encodeURIComponent(params[k]));
        }
        url += qparams.join('&');
        try{
          var headers = {
            'Authorization': 'Bearer '+ API_TOKEN
          };
          var options = {
            'headers': headers
          };
          var resp = UrlFetchApp.fetch(url, options);
          var data = JSON.parse(resp.getContentText());
          if (data.error) {
            throw "GET " + path + ": " + data.error;
          }
          return data;
        }catch(e){
          return "err";
          }
    };
    SlackChannelHistoryLogger.prototype.run = function () {
        var _this = this;
        var usersResp = this.requestSlackAPI('users.list');
        for (const member of usersResp.members) {
          // //削除済、botユーザー、Slackbotを除く
          // if (!member.deleted && !member.is_bot && member.id !== "USLACKBOT") {
            slack_members[member.id] = member.profile.display_name;
          // }
        }

        var channelsResp = this.requestSlackAPI('conversations.list');
        for (var _i = 0, _a = channelsResp.channels; _i < _a.length; _i++) {
            var ch = _a[_i];
            this.importChannelHistoryDelta(ch);
        }

    };  
    SlackChannelHistoryLogger.prototype.importChannelHistoryDelta = function (ch) {
        var _this = this;
        var now = new Date();
        // チャンネル絞って開発用
        // if (ch.name != 'hogehoge') {
        //   return;
        // }
        var messages = this.loadMessagesBulk(ch, {});
        var dateStringToMessages = {};


      if(messages != "err"){
        Logger.log(ch.name + ' messages:' + messages.length);
        messages.forEach(function (msg) {
          var date = new Date(+msg.ts * 1000);
          var reactions = msg.reactions ? msg.reactions : "";
          var m_year = Utilities.formatDate(date, timezone, 'yyyy');
          // チャンネル絞って開発用
          // if (ch.name == 'hogehoge') {
          //   // Logger.log(Utilities.formatDate(date, timezone, 'yyyy-MM-dd'));
          //   // Logger.log(msg);
          //   // Logger.log(reactions);
          // }
          if(reactions !== "" && m_year == target_year){
            reactions.forEach(function (reaction) {
              var name = reaction.name;
              if (stamps[name]) {
                stamps[name] = stamps[name] + reaction.count;
              } else {
                stamps[name] = reaction.count;
              }

              // MVVリアクションならさらにごにょごにょ
              if (mvv_reactions.includes(name)) {
                if (!mvv_get_user[msg.user]) {
                  mvv_get_user[msg.user] = {};
                  mvv_reactions.forEach(function (mvv_reaction) {
                    mvv_get_user[msg.user][mvv_reaction] = 0;
                  });
                }
                mvv_get_user[msg.user][name] = mvv_get_user[msg.user][name] + reaction.count;

                reaction.users.forEach(function (send_user) {
                  if (!mvv_send_user[send_user]) {
                    mvv_send_user[send_user] = 0;
                  }
                  mvv_send_user[send_user]++;
                });
              }
            });
          }
        });
      }
    };
    
    SlackChannelHistoryLogger.prototype.loadMessagesBulk = function (ch, options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var messages = [];
        options['limit'] = HISTORY_COUNT_PER_PAGE;
        options['channel'] = ch.id;
        var loadSince = function (cursor) {
          if (cursor) {
              options['cursor'] = cursor;
          }
          var resp = _this.requestSlackAPI('conversations.history', options);
          if(resp != "err"){
            messages = resp.messages.concat(messages);
          }
          return resp;
        };
        var resp = loadSince();
        var page = 1;
        // テスト用、取得数絞ってやる
        // while (resp.has_more && page <= MAX_HISTORY_PAGINATION) {
        // ページがあって、メッセージが対象年なら次ページを取得
        // HACK: 最初のメッセージで判定してる関係で無駄に1回多く叩いてるけど
        while (resp.has_more && target_year == Utilities.formatDate(new Date(+resp.messages[resp.messages.length-1].ts * 1000), timezone, 'yyyy')) {          
            resp = loadSince(resp.response_metadata.next_cursor);
            page++;
        }
        return messages;
    };
    return SlackChannelHistoryLogger;
})();

できあがり

ranking(利用頻度の多いリアクションランキング)

image.png

mvv_get(MVVリアクションを受け取った人)

image.png

mvv_send(MVVリアクションを使った人)

image.png

さいごに

集計って楽しくてワクワクしますよね♪
それではみなさん、MVVを意識して仕事していきましょー!

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8