GASを使ってSlackのチャンネルの情報を楽に共有しよう！

![Top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/827115dc-6888-3d43-7c92-cbe0386a74fa.png)



## はじめに
こんにちは、18卒のおでんとよばれているものです。
今回は弊社で実際に使われているGASを使ってSlackのチャンネル情報を楽に共有する方法を紹介したいと思います。


## こんな感じで共有しています
全社員がアクセスできるスプレッドシートにGASでチャンネルの情報を書き込んで共有をしています。
お見せできる例として、こんな感じでクラブ活動のチャンネルをまとめたシートをパッと一覧で見れるようにしてあります！

![List.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/2b7610c6-32ab-565e-6a25-18b8f5923a1b.png)



## どうやってやるの？
手順としてこの3つことを行いました。
1. 全てのプライベートチャンネルにシステム用のアカウントが入っている状態にする
2. SlackAppの作成
3. GASを実行
これに関してどうやってやったかを紹介させていただきます。

### 1. 全てのプライベートチャンネルにシステム用のアカウントが入っている状態にする
今回 [conversations.list API](https://api.slack.com/methods/conversations.list)を使って実装をしたのですが、APIの仕様上Privateチャンネルの情報は、**Access Token**を発行したユーザーが入っているチャンネルしか獲得できなかったです。
[Legacy token](https://api.slack.com/custom-integrations/legacy-tokens)で対応することも検討したのですが、全ての権限を持っているtokenは、全てのSlackの操作ができてしまう危険な物なので、
`channels:read （Publicチャンネルの情報）` と `groups:read（Privateチャンネルの情報）` に絞って**Access Token**を発行しました。
皆さんに協力していただき、全てのプライベートチャンネルにシステム用のアカウントが入っている状態にした結果、**Legacy token**を使わずに、Privateチャンネルの情報も全社員が見ることができるようになりました。


### 2. Access Tokenの発行
次にAccess Tokenを発行するための準備をします。

#### Appの作成
システム用のアカウントでSlackにログインしていることを確認して、https://api.slack.com/ にアクセスして **Start Building**を選択します。

![content_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/d37f1f0d-1f9e-9db2-bb8a-d7fe7093cdde.png)


選択した後、**Create a Slack App**が表示されますので、任意の名前と導入するワークスペースを選択して **Creat App**で作成をします。
※ 2. Access Tokenの発行に載せている画像は自分のプライベートSlackにインストールした例になります。

![content_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/d9ed75bb-12e4-c792-1c02-abf17379ab71.png)



#### Tokenの発行
**OAuth & Permissions** の **Scopes** で今回利用する`channels:read （Publicチャンネルの情報）` と `groups:read（Privateチャンネルの情報）` を選択します。
**Scopes**で上記2つの権限が与えられていることを確認して、**Install App to Workspace** を選択します。

![content_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/204249f4-55e2-8f37-c4c0-9af9acae66bf.png)


**Install App to Workspace**を選択したら、許可しても良いかが表示されるので、**許可する**を選択してワークスペースにアプリをインストールします。
![content_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/f8d3e284-d7fc-81e2-0a9f-127038876f12.png)


インストールが完了したら、画像のように `xoxp-`から始まる**Access Token**が発行されます。
APIを利用する際にこのAccess Tokenを利用します。

![content_4_fix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/0cb9630d-3a49-9afb-9f2c-b1619497a208.png)



### 3. GASを実行
#### GASの準備
こんな感じでスプレッドシートを作成して、**スクリプトエディタ**を開いてGASを作っていきます。
![content_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/fc199a82-db25-54b2-552e-7a0163b7ffcb.png)



#### 実行方法
利用する関数は3つです。
1. slackApi //SlackのAPIから情報を取ってくる
2. getChannelList //特定のシートにPublicチャンネルリストを書き込む
3. getPrivateChannelList //特定のシートにPrivateチャンネルリストを書き込む

slackApi関数を用意しておけば、他のAPIを利用するときも使い回せるので一度作ってしまえば超便利です！！

#### プログラム

```js:slackApi.gs
function slackApi(token, path, options) {
  if (!options) options = {};
  var url = "https://slack.com/api/" + path;
  var q = "?token=" + encodeURIComponent( token );
  for (var key in options) {
    q += "&" + encodeURIComponent( key ) + "=" + encodeURIComponent( options[ key ] );
  }
  url += q;
  var res = UrlFetchApp.fetch(url);
  var ret = JSON.parse(res.getContentText());
  if (ret.error) {
    throw "GET " + path + ": " + ret.error;
  }
  return ret;
}
```

```js:getChannelList.gs
function getChannelList() {
  const token = PropertiesService.getScriptProperties().getProperty("slackApiToken");
  var options = { "limit" : 200 };
  var channels = slackApi(token, "conversations.list", options);
  
  const spreadsheet = SpreadsheetApp.openById('スプレッドシートのID入れてね！');
  const sheet = spreadsheet.getSheetByName('PublicList');
  const archivedSheet = spreadsheet.getSheetByName('アーカイブPublicList');
  
  sheet.getRange("A1").setValue("チャンネル名");
  sheet.getRange("B1").setValue("目的");
  sheet.getRange("C1").setValue("トピック");
  
  archivedSheet.getRange("A1").setValue("チャンネル名");
  archivedSheet.getRange("B1").setValue("目的");
  archivedSheet.getRange("C1").setValue("トピック");
  
  var targetCellNumber = 2;
  var targetArchivedCellNumber = 2;
  
  while (true) {
    channels.channels.forEach( function (ch) {
      if(!ch.is_archived) {
        sheet.getRange("A"+targetCellNumber).setValue(ch.name);
        sheet.getRange("B"+targetCellNumber).setValue(ch.purpose.value);
        sheet.getRange("C"+targetCellNumber).setValue(ch.topic.value);
        targetCellNumber = targetCellNumber + 1;
      } else {
        archivedSheet.getRange("A"+targetArchivedCellNumber).setValue(ch.name);
        archivedSheet.getRange("B"+targetArchivedCellNumber).setValue(ch.purpose.value);
        archivedSheet.getRange("C"+targetArchivedCellNumber).setValue(ch.topic.value);
        targetArchivedCellNumber = targetArchivedCellNumber + 1;
      }
    });
    
    if (channels.response_metadata.next_cursor == "") break;

    options = { "limit" : 200, "cursor" : channels.response_metadata.next_cursor };
    channels = slackApi(token, "conversations.list", options);
  }
}
```

```js:getPrivateChannelList.gs
function getPrivateChannelList() {
  const token = PropertiesService.getScriptProperties().getProperty("slackApiToken");
  var options = { "limit" : 200, "types" : "private_channel" };
  var channels = slackApi(token, "conversations.list", options);
  
  const spreadsheet = SpreadsheetApp.openById('スプレッドシートのID入れてね！');
  const sheet = spreadsheet.getSheetByName('PrivateList');
  const archivedSheet = spreadsheet.getSheetByName('アーカイブPrivateList');
  
  sheet.getRange("A1").setValue("チャンネル名");
  sheet.getRange("B1").setValue("目的");
  sheet.getRange("C1").setValue("トピック");
  
  archivedSheet.getRange("A1").setValue("チャンネル名");
  archivedSheet.getRange("B1").setValue("目的");
  archivedSheet.getRange("C1").setValue("トピック");

  var targetCellNumber = 2;
  var targetArchivedCellNumber = 2;
  
  while(true) {
    channels.channels.forEach( function (ch) {
      if(!ch.is_archived) {
        sheet.getRange("A"+targetCellNumber).setValue(ch.name);
        sheet.getRange("B"+targetCellNumber).setValue(ch.purpose.value);
        sheet.getRange("C"+targetCellNumber).setValue(ch.topic.value);
        targetCellNumber = targetCellNumber + 1;
      } else {
        archivedSheet.getRange("A"+targetArchivedCellNumber).setValue(ch.name);
        archivedSheet.getRange("B"+targetArchivedCellNumber).setValue(ch.purpose.value);
        archivedSheet.getRange("C"+targetArchivedCellNumber).setValue(ch.topic.value);
        targetArchivedCellNumber = targetArchivedCellNumber + 1;
      }
    });
    
    if(channels.response_metadata.next_cursor == "") break;
    
    options = { "limit" : 200, "types" : "private_channel", "cursor" : channels.response_metadata.next_cursor };
    channels = slackApi(token, "conversations.list", options);
  }
}
```

#### プログラムの注意事項
**Access Token**をコードに乗せるのは危ないので、**GASのスクリプトのプロパティ**にTokenを置くようにして、`getProperty` から読みだすようにしてあります。
```
const token = PropertiesService.getScriptProperties().getProperty("slackApiToken");
```
以下の画像のように【2. Access Token】の発行で獲得した**Access Token**の値を入れてあげればプログラムを実行することができます。

![content_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/1cb875ae-fcba-acbb-6f51-2fad01c555b6.png)


#### トリガーを設定して自動で更新をしよう！
毎日手動で実行するのは手間なので、GASの特権であるトリガーで毎日実行するようにしましょう！！
画像のように、実行したい関数を選んで保存をすれば、毎日スプレッドシートにSlackのチャンネルのリストが更新されます。

![content_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282719/cf052201-e798-83b9-be09-bed08d2b58a8.png)


## 終わりに
いかがでしたでしょうか。
GASは、サーバー代もかからないかつスプレッドシートと連携がしやすいので、一覧化して全社員に共有するのに凄く簡単にできます。
皆さんも是非試していただけると嬉しいです！！