kuboon
11/21/2016 - 2:25 AM

Slack の channel で点呼をとる

Slack の channel で点呼をとる

// Description:
//   Slack の channel で点呼をとる
//   https://gist.github.com/kuboon/8c66bf61a170bc49f99e5fe91352bb6f
// Commands:
//   hubot 点呼
// Dependencies:
//   "aa": "^0.1.40"
//   "slack-node": "^0.1.3"
//   "hubot-redis-brain"

"use strict"

const aa = require('aa'),
      Slack = require('slack-node'),
      slack = new Slack(process.env.HUBOT_SLACK_TOKEN),
      slack_api = aa.promisify(slack, slack.api)

function sleep(msec) {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, msec);
  })
}

// "点呼とりまーす" に reaction した全ユーザのリスト
function all_reactioned_users(res){
  let users = res.message.reactions.map((a) => a.users)
  users = users.reduce((a, b) => a.concat(b)) // users.flatten!
  return users.filter((e, p) => users.indexOf(e) == p) // users.uniq!
}

function* tenko(channel, all_users){
  const postMessage = (text) => {
          return slack_api('chat.postMessage', {
            text: text,
            channel: channel,
            as_user: true,
            link_names: 1
          })
        }

  const message_ts = yield postMessage('点呼とりまーす @channel').then((res) => res.message.ts)

  slack.api('reactions.add', {
    name: 'raising_hand',
    channel: channel,
    timestamp: message_ts
  })

  // channel の全メンバ (deleted user も含まれているのであとで除外)
  const members = yield slack_api('channels.info', {channel: channel}).then((res) => res.channel.members)

  var sec = 0
  do {
    yield sleep(5 * 1000)
    sec += 5

    const reacted = yield slack_api('reactions.get', {channel: channel, timestamp: message_ts}).then(all_reactioned_users)

    // channel の全メンバから、 reaction したユーザを引き算
    const diff = members.filter((e) => reacted.indexOf(e) < 0)

    // slack の member id から user object へ変換。ついでに deleted user と bot を除外
    const users = diff.map((id) => all_users[id]).filter((u) => !u.slack.deleted && !u.slack.is_bot)

    if(users.length == 0){
      postMessage('全員集合しました!')
      break
    }
    const names_str = users.map((u) => '@' + u.name).join(', ')
    if (sec == 30) {
      postMessage('反応ない人: ' + names_str)
    } else if (sec >= 60) {
      postMessage('反応なかった人: ' + names_str + "\n点呼を終了します。")
      break
    }
  }while(true)
}

module.exports = (robot) => {
  robot.respond(/点呼$/i, (res) => {
    // hubot-slack@3.4.2 では以下のコードで動いたが、
    // >4 では res.message.rawMessage.channel の代わりに res.message.room にする
    aa(tenko(res.message.rawMessage.channel, robot.brain.data.users))
  })
}