見出し画像

(Slack x GAS)Slackグループの参加者一覧を取得する

こんにちわ。ヤスムラです。

今回は副業でお世話になっているAnyTech株式会社の依頼でSlackグループ整理のために参加者一覧を取得するGASを作成してみたので紹介したいと思います。

使用するAPI

今回は以下3つのSlack APIを使用しました。

手順

実際の作成方法は以下の通りです。

1.Slackアプリ作成

1)Slack apiのページを開く
2)Your Appsにて「Create New App」>「From scratch」クリック

3)”Name app & ~”画面にて以下設定後「CreateApp」クリック

- App Name > お好みの名前(Slack_Group_Listとか)
- Pick a workspace to develop your app in: 対象ワークスペースを選択

4)左メニュー「OAuth & Permissions」をクリック、Scopesにて以下を追加

Bot Token Scopes
 usergroups:read
 users:read
 users:read.email

5)OAuth Tokens for Your Workspaceにて「Install to Workspace」クリック

6)ワークスペースのアクセス権限リクエスト画面にて「許可する」クリック

7)Bot User OAuth Tokenが払い出されるので控えておいて下さい。

2.スプレットシート作成

 1)スプレットシートを新規作成
 2)シートを2つ作成してそれぞれ以下にシート名に変更

  • groups

  • user

3)メニューから[拡張機能] > [Apps Script] クリック
4)プロジェクト名を入力(名前は任意)
5)コードに以下GAS(スクリプト)をコピーして貼り付け

function main(){
  let slack_token = PropertiesService.getScriptProperties().getProperty('slackToken');
  let activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  let sheet1 = activeSpreadSheet.getSheetByName('groups');
  let sheet2 = activeSpreadSheet.getSheetByName('user');

  //シートの内容をクリア
    sheet1.clear();
    sheet2.clear();

    console.log('STEP1 Slackグループ一覧取得')
    getSlackGroups(sheet1,slack_token)

    console.log('STEP2 Slackユーザー一覧取得')
    getSlackUser(sheet2,slack_token,activeSpreadSheet)

    console.log('STEP3 各グループの参加者一覧取得')
    getSlackUserGroups(slack_token,sheet1,sheet2)
}


//STEP1 Slackグループ一覧取得
function getSlackGroups(sheet1,slack_token){
  let group_url = 'https://slack.com/api/usergroups.list';
  let json = {
      'token' : slack_token
  };
  let options = {
      'method' : 'GET',
      'payload' : json
  };
  let result_group = UrlFetchApp.fetch(group_url,options);
  let object = JSON.parse(result_group.getContentText());
  let groupArr = new Array();

  sheet1.appendRow(['id','handle','name','description','user_count','mail']);

  for(i=0; i < object['usergroups'].length; i++){
      let id = object['usergroups'][i]['id']
      let handle = object['usergroups'][i]['handle']
      let name = object['usergroups'][i]['name']
      let description = object['usergroups'][i]['description']
      let user_count = object['usergroups'][i]['user_count']

      groupArr.push([ id,handle,name,description,user_count]);
  }

  try{
    sheet1.getRange( sheet1.getLastRow()+1,1, groupArr.length, groupArr[0].length).setValues(groupArr);
  }
  catch(e){
    console.log('Error');
    console.log('Error='+e.message);
  }
}


//STEP2 Slackユーザー一覧取得
function getSlackUser(sheet2,slack_token,activeSpreadSheet){
  let userlist_url = 'https://slack.com/api/users.list';
  let limit =900;
  let options = {
   'method' : 'get',
   'contentType': 'application/x-www-form-urlencoded',
   'payload' : { 
     'token': slack_token,
     'limit':limit
    }
  };
  let response = UrlFetchApp.fetch(userlist_url, options);
  let members = JSON.parse(response.getContentText()).members;

  sheet2.appendRow(['ID','email','real_name','name']);

  let userArr = [];
    for(let i = 0;i < members.length;i++){
      if(members[i]?.is_bot == false && members[i]?.deleted == false){    //BOT以外の有効なユーザーのみ抽出
        let id = members[i].id;
        let email = members[i].profile.email
        let real_name = members[i].profile.real_name; //氏名
        let name = members[i].name; //ユーザー名

      userArr.push([ id,email,real_name, name]); //配列に挿入
    } 
  }

  try{
    sheet2.getRange( sheet2.getLastRow()+1,1, userArr.length, userArr[0].length).setValues(userArr);
  }
  catch(e){
    console.log('Error');
    console.log('Error='+e.message);
  }
}


//STEP3 各グループの参加者一覧取得
function getSlackUserGroups(slack_token,sheet1,sheet2){
  let lastRow1 = sheet1.getLastRow();

  for(let j = 2;j < lastRow1+1;j++){
    getSlackUserGroups_sub(slack_token,sheet1,sheet2,j)
  }
}


//STEP3.5 参加者のSlackIDをメールアドレスに変換
function getSlackUserGroups_sub(slack_token,sheet1,sheet2,j){
  let lastRow2 = sheet2.getLastRow();
  let group_user_url = 'https://slack.com/api/usergroups.users.list';
  let groups_id = sheet1.getRange(j,1).getDisplayValue();

  let json = {
      'token' : slack_token,
      'usergroup' : groups_id
  };
  let options = {
      'muteHttpExceptions' : true,
      'method' : 'POST',
      'payload' : json
  };
  let result_group = UrlFetchApp.fetch(group_user_url,options);

  //Error 429 Too Many Requests
  if (result_group.getResponseCode() === 429 ) {
    console.log('Error_429 Wait 60s')
    Utilities.sleep(60000);
    return getSlackUserGroups_sub(slack_token,sheet1,sheet2,j);
  }
  let object = JSON.parse(result_group.getContentText());

  let number_arrays = object.users.length; //参加者の数(要素数)を取得
  let userlist = new Array();

  //Get email address from SlackID
  for(k=0; k < number_arrays;k++){
      let userid = object.users[k]
      
      for(let l = 2;l <= lastRow2 ;l++){ //該当するものがあったら要素に追加
        let userid2 = sheet2.getRange('A'+ l).getValue(); //A列の i 行目のグループID
        if(userid == userid2){
          let match_user = sheet2.getRange(l,2).getValue();
          userlist.push([match_user]);
          break;
        }else if (l == lastRow2){
          console.log('IDがありません')
          userlist.push([userid]);
        }     
      }
    }
  let maillist = userlist.join();
  sheet1.getRange(j, 6).setValue(maillist);
}

6)左メニューの歯車アイコン(プロジェクトの設定)を開く
7)スクリプト プロパティに以下登録して保存

  • プロパティ : slackToken

  • 値 : Slackアプリ作成時に払い出したBot User OAuth Token

8)スクリプト[main]を実行して動作することを確認。

GAS(スクリプト)の流れ

  1. usergroups.listを使ってグループの一覧とそれぞれのグループIDを収集してスプレットシートに登録します。

  2. users.listを使ってSlackに登録されているユーザーのメンバーID(User ID)を事前に収集してスプレットシートに登録します。[有効なメンバーのみ抽出]

  3. usergropus.users.listを使って各グループに参加しているユーザーを取得して反映させます。ただしメンバーIDしか取得できないため、users.listで収集したメンバーIDと突合を行いメールアドレスに変換していきます。

補足

usergropus.users.listは1グループづつしかチェック出来ないため、全グループをループさせて取得させていくんですが、数が多いとAPIリクエストが多すぎてAPI 制限(429エラー)が発生してしまいます。

  if (result_group.getResponseCode() === 429 ) {
    console.log('Error_429 Wait 60s')
    Utilities.sleep(60000);
    return getSlackUserGroups_sub(slack_token,sheet1,sheet2,j);
  }

そのためAPI制限が発生した場合は60秒待機してからリトライするようにしています。

またメールアドレス変換は、メンバーIDが一致した場合はループ終了、すべて突合して一致がない場合は、メンバーIDのままリストに記載するよう処理しています。

for(let l = 2;l <= lastRow2 ;l++){ //該当するものがあったら要素に追加
        let userid2 = sheet2.getRange('A'+ l).getValue(); //A列の i 行目のグループID
        if(userid == userid2){
          let match_user = sheet2.getRange(l,2).getValue();
          userlist.push([match_user]);
          break;
        }else if (l == lastRow2){
          console.log('IDがありません')
          userlist.push([userid]);
        }     
      } 

まとめ

Slackグループはアクセス権等に利用することがないので、今まで一覧取得や棚卸しは行なってこなかったんですが、今回のツールを定期実行してイントラ等に貼り付ければ社員がどんなグループがあるのは把握しやすくなってより円滑なコミュニケーションが出来ると思いました。

これからも引き続き副業情シスとして会社に貢献していきたいと思います。


この記事が気に入ったらサポートをしてみませんか?