BotにSlackのプライベートチャンネルリストを教えてもらう(Node.jsのBotkitとIBM Cloudを用いた対応)

課題

自分が属している団体のSlackで運営スタッフだけのプライベートチャンネルがいくつかあるが、プライベートチャンネルのため、どのような運営用チャンネルが存在しているかわからなくなるという問題がある。一度誤って抜けてしまうと、誰かに頼まないと戻れなくなるのだが、誰に頼んで良いのかもわからなくなることもある。

この問題を解決するためにBotを開発した。ただし、プライベートチャンネルのため、Botもそのプライベートチャンネルに所属していないとならない。

運用イメージ

  • 運営用プライベートチャンネルはBotをメンバーとして登録する
  • 運営スタッフはそのBotにメンションかDMかで話しかけることにより、Botが属しているプライベートチャンネルの全リストをその作成者名とともに取得できる
  • 自分が入るべきプライベートチャンネルがあったならば、その作成者にコンタクトし、招待してもらう。ここにはBotは介在しない

Botの開発

BotはNode.jsで開発し、IBM Cloudで運用することにした。

Botkit

Node.jsで作られたBotkitを利用した。Slackとの連携も極めて簡単。

使ったものは、

ソースコードは以下。

const Botkit = require('botkit');
const async = require('async');

if (!process.env.token) {
  console.log('Error: Missing API Token');
  process.exit(1);
}

const controller = Botkit.slackbot({
    debug: false,
    retry: Infinity // 常駐させるため
});

controller.spawn({
    token: process.env.token
}).startRTM((err, bot, payload) => {
    if (err) {
        throw new Error(err);
    }
});

// pubchlistと聞かれたら
controller.hears('pubchlist',['direct_message','direct_mention','mention'],(bot,message) => {
    bot.api.channels.list({}, (err, res) => {
        async.each(res.channels, (channel, callback) => {
            if(!channel.is_archived){
                bot.api.users.info({user:channel.creator}, (err,res) => {
                bot.reply(message, channel.name + ' created by ' + res['user']['name']);
                })
            }
        })
    })
});

// prchlistと聞かれたら
controller.hears('prchlist',['direct_message','direct_mention','mention'], (bot,message) => {
    bot.api.groups.list({}, (err, res) => {
        async.each(res.groups, (groups, callback) => {
            if(!groups.is_archived){
                bot.api.users.info({user:groups.creator}, (err,res) => {
                bot.reply(message, groups.name + ' created by ' + res['user']['name']);
                })
            }
        })
    })
});

// それ以外を聞かれたら
controller.hears(['(.*)'], ['direct_message','direct_mention','mention'], (bot,message) => {
    bot.reply(message, 'Usage: type prchlist to get private channels list OR publist to get public channels');
});

Botに話しかけられるコマンドは2つだけ。

  • pubchlist: パブリックチャンネルの一覧をその作成者とともに表示
  • prchlist: Botが所属しているプライベートチャンネルの一覧をその作成者とともに表示

【追記】Admin権限を持つ人だけがプライベートチャンネルリストを見れるようにする

プライベートチャンネルリストが見れる人をAdmin権限を持つ人だけに絞るには、prchlisthearsしている部分を以下のように変更する。

// prchlistと聞かれたら
controller.hears('test',['direct_message','direct_mention','mention'], (bot,message) => {
    var currentUser; 
    bot.api.users.info({user:message.user},function(err,response) {
        if (err) {
            throw new Error(err);
        }
        currentUser = response['user'];
        if (!currentUser['is_admin']) {
            bot.reply(message, 'Only Admin can see the list of private channels');
        }
        bot.api.groups.list({}, (err, res) => {
            async.each(res.groups, (groups, callback) => {
                if(!groups.is_archived){
                    bot.api.users.info({user:groups.creator}, (err,res) => {
                    bot.reply(message, groups.name + ' created by ' + res['user']['name']);
                    })
                }
            })
        })        
    })
});

Slack APIusers.infoでBotkitから代えるmessage.user情報を取得し、Admin権限があるかどうかを確認している。

Slack側の準備

プログラムの中でSlackのBot用のAPI Tokenを利用している。これは環境変数で引き渡すことになる。

Sign in | Slack にアクセスし、API Tokenを発行する。

f:id:takoratta:20180109155043p:plain

ローカル環境での動作

$ token=<API Token> node app.js

これでSlack側でBotにDMするか、Inviteしたチャンネルでメンションし、話しかけてテストできる。

Botの運用

BotはNode.jsが動かせる環境ならなんでも良かったのだが、IBM Cloudライトアカウントの無料枠の範囲で十分そうだったので、それを使った。

$ cf api https://api.ng.bluemix.net/
$ cf login
$ cf push itdartbot --no-route -u none -m 256M
$ cf cf set-env itdartbot token <api token>
$ cf restage itdartbot

cf pushでの--no-route-u noneはワーカーとして動作させ、Health Check不要のため。また、-m 256MIBM Cloudライトアカウントではメモリが256MBに制限されているため。

参考にしたもの