ワークスペースのメンバーをチャンネルに全員招待するコマンド(/inviteall)

教員がメンバーの多いワークスペースを運営しているらしくて、そこで「新しく作ったチャンネルに全員参加させたい」という要望が出たらしい。
確かにinviteは現状ちまちまひとりずつするしかないみたいで、100人越えると大変そうです。

本記事の目次

今回はAWS Lambdaを利用してSlackのSlash Commandを実装してみました。
echo commandっていうテンプレートが存在するみたいですが、初心者すぎてコード読めないので1から作ってしまいました。

いるもの

  • slack api token (scopeはcommands, channels:write, users:read)
  • Verification Token(Basic informationで取得, requestが正しく来たものか確認するためのもの)
  • AWSアカウント

 ユーザー情報をjson形式で取得
→IDを抽出
→GET requestを送信してひとりずつinvite
という流れです。

slack側の初期設定は例によって割愛します。
slash command appを利用する手もありますが、既存のappでslash command機能を追加して作りました。
このへんのこと調べてみたけど結局なにが違うのかよくわからん。

Request URLの入力

コマンドが呼び出されたときにリクエストが送信される先のURLを決めます。
AWSで新しいLambdaをplainで作成し、トリガーをAPI Gatewayに設定したあとのところからいきます。
ググるといろんな方がもっと詳しくやってくれているので、飛ばし気味で。

LambdaMicroserviceの画面を開いて作成したリソースのANYメソッドを削除して、POSTメソッドを追加します。
統合リクエストから本文マッピングテンプレートの項目を開いて、Content-Typeに「application/x-www-form-urlencoded」と入力し、こちらのコードをコピペしました
これでイベントがjson形式でLambdaへ渡されるようになりました。

アクション→APIのデプロイを行うと、呼び出しURLが表示されます。
これにメソッド名を追加した「https://~.amazonaws.com/<デプロイしたステージ>/<メソッド名>」というのがRequest URLになります
メソッド名を追加しないといけないのが分からなくてしばらく悩んでしまいました。
このURLをslackのcommand作成画面で入力します。
あとは要求された通りに各項目を入力すればslack側の設定は終わりです。

コマンド呼び出しから関数を動かすまで

コマンドが実行されるとPOST requestでいろいろ届きます。
ここからVerified Tokenと実行されたチャンネルの情報を抜き出します。

var https = require("https");
var event_token = event["token"];
var channel = event["channel_id"];
//verified tokenが一致しなければはじく
if(event_token != <Verified Token>) return;

以上が準備で、ここから先に実際に処理を書いていきます。

全員のユーザーIDの取得

GETでユーザー情報のjsonを取得します。

var url = "https://slack.com/api/users.list?token=<slack api token>";
https.get(url, (response) => {
    let rawData = "";
    response.on('data', (chunk) => {rawData += chunk;}); //データ部を全て生データとしておく
    response.on('end', () => {
        var usr_ls = JSON.parse(rawData); //生データをJSON形式に変換

この後のコードはresponse.onのスコープの中に書いていきます。

IDを抽出する

ここで取得しているjsonこちらを参照してください。

var IDs = [];
var usr_nu = Object.keys(usr_ls["members"]).length;
for(var i = 0; i < usr_nu; i++){
    IDs.push(usr_ls["members"][i]["id"]);
}

inviteを実行する

あとは取得したIDの配列でinviteしていくだけです。
本当はPOSTリクエストしたかったのですが、うまくいかなくてGETリクエストになっています。

url = "https://slack.com/api/channels.invite";
url += "?token=" + <slack api token> + "&channel=" + channel + "&user=";
for(var j = 0; j < usr_nu; j++){
    https.get(url + IDs[j], (res) => {
        res.on("data", () => {});
    });
}

コールバックは適当に"Command Accepted!"とかにしときました。

感想

いじくるところがいろいろあって苦労度は高かったです。
なんでHTTP POSTうまくいかないんだ...
とりあえず動くものができたのでよしとしました。

6/21 追記
200人超えでタイムアウトエラーが出てしまうという報告がありました。
Lambdaの基本設定のメモリ(CPU割り当て)をMAXにする力技で解決しました。
当方は関数呼出が頻繁でないので無料枠の範囲内でした。