slackメンバー表をつくった

# したかったこと
- slackのメンバー表を作成する
    - 氏名やメールアドレスからslackのidを検索できるようにする
    - slackのidから氏名を検索する

# つくったもの
slackの情報を反映するspreadsheet(複数のワークスペースに対応しています)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172695/2f03a870-62e8-3fca-0fcf-0e5e0c399d2f.png)

### statusの種類
- プライマリーオーナー	
- オーナー	
- 管理者	
- メンバー
- マルチチャネルゲスト
- アーカイブ	
- シングルチャネルゲスト	
- ボット

# 使うには
## 1. slackアプリを作成する
[参照](https://qiita.com/yuukiw00w/items/94e4495fc593cfbda45c)
権限は[users:reads](https://api.slack.com/scopes/users:read)を指定してください。
tokenはこの後使います。

## 2. シートを用意する

1. [spreadsheet](https://docs.google.com/spreadsheets/d/1INOM1qAUniBG8dcoav9VHDg0PzXXghw0pp_rucQ6ic4/edit?usp=sharing)をコピーする
2. wsシートに名前とtokenを設定する。名前は任意です。
3. 概要シートの実行を押下


また、夜間にmain()を定期実行するようにすると、最新のメンバー情報で更新され続ける。

# スクリプト

```javascript:main.gs
function main(){
  const wsList = getWorkSpaceList();
  const memberList = wsList.reduce((memberList, ws) => {
    return memberList.concat(getMemberList(ws));
  }, []);

  refreshSheet(
    SHEET_MEMBER.name,
    SHEET_MEMBER.row.data,
    SHEET_MEMBER.column.ws,
    memberList.map(m => m.getOutList())
  );
}
```
```javascript:sheet.gs
var SHEET_WS = {
  name : 'ws',
  row : {
    data : 2,
  },
  column : {
    name : 1,
    token : 2,
  },
};

var SHEET_MEMBER = {
  name : 'member',
  row : {
    data : 2,
  },
  column : {
    ws : 1,
    id : 2,
    name : {
      real : 3,
      display : 4,
    },
    email : 5,
    status : 6,
  },
};


function refreshSheet(sheetName, startRow, startColumn, outList){
  if(!outList.length) return;
  const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
  sheet.getRange(
    startRow,
    startColumn,
    sheet.getLastRow() - startRow,
    sheet.getLastColumn()
  ).clear();

  sheet.getRange(
    startRow,
    startColumn,
    outList.length,
    outList[0].length
  ).setValues(outList);
}

function getWorkSpaceList(){
  const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_WS.name);
  let data = sheet.getDataRange().getValues();
  [...Array(SHEET_WS.row.data - 1)].forEach(_ => data.shift());

  return data.map(row => new WorkSpace(row));
}

```
```javascript:slack.gs
var NO_MEMBER = 'メンバーhitせず';

function getMemberList(ws){
  // https://api.slack.com/methods/users.list

  let memberList = [];
  let nextCursor = '';
  do{
    let fetchUrl = 'https://slack.com/api/users.list?token='
      + ws.token
      + '&limit=999';
    
    if(nextCursor !== ''){
      fetchUrl += '&cursor=' + nextCursor;
    }

    let res = UrlFetchApp.fetch(fetchUrl);
    res = JSON.parse(res);
    memberList = memberList.concat(res.members);
    nextCursor = res.response_metadata.next_cursor;
  }while(nextCursor !== '');

  return memberList.map(m => new Member(m, ws));
}

function getStatus(responce){
  // https://api.slack.com/types/user
  if(responce.deleted) return 'アーカイブ';
  if(responce.is_ultra_restricted) return 'シングルチャネルゲスト';
  if(responce.is_restricted) return 'マルチチャネルゲスト';
  if(responce.is_bot || 'USLACKBOT' === responce.id) return 'ボット';
  if(responce.is_primary_owner) return 'プライマリーオーナー';
  if(responce.is_owner) return 'オーナー';
  if(responce.is_admin) return '管理者';
  return 'メンバー';
}

```
```javascript:class/WorkSpace.gs
class WorkSpace{
  constructor(row){
    this.name = row[SHEET_WS.column.name - 1];
    this.token = row[SHEET_WS.column.token - 1];
  }
}

```
```javascript:class/Member.gs
class Member{
  constructor(res, ws){
    this.ws = ws.name;
    this.id = res.id;
    this.name = {
      display : res.profile.display_name,
      real : res.real_name,
    };
    this.email = res.profile.email;
    this.status = getStatus(res);
  }

  getName(){
    const name = (this.name.display) ? this.name.display : this.name.real;
    return name;
  }

  getOutList(){
    return [
      this.ws,
      this.id,
      this.name.real,
      this.name.display,
      this.email,
      this.status
    ];
  }
}

```