ChatGptとGASでSlackのメンバー追加をラクにした話

この記事は[PONOS Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ponos)の20日目の記事です。
前回は、@e73ryoさんでした。

# はじめに
私は社会人アカペラサークルに所属しており、そこで運営メンバーとして活動しています。
そのサークルでは全体周知事項などがある際にSlackを使用しているのですが、ライブイベント用のチャンネルを作成する際にメンバーの追加がかなり手間になっている問題が起きていました。Slackチャンネルのメンバー追加は、氏名検索や、メールアドレスを一人ずつ入力しなければいけないなど、かなり面倒くさいです。
※一回で80人以上追加することもありますし、サークルではニックネームなどがSlackで使われているため検索がしんどいです。

Slackではワークスペースに参加しているメンバーのリストをcsvで出力することが出来るため「GoogleAppScript(GAS)を使ったらいい感じに出来るんじゃないか？」と考えました。

GASについては完全に素人だったかつ時間が勿体なかったので、ChatGptに要件を伝えながら、実装をしていきました。

# 事前準備
## Slackのメンバーリストをエクスポート
Slackからチームメンバーのcsvリストを[ワークスペースのデータをエクスポートする](https://slack.com/intl/ja-jp/help/articles/201658943-%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B)
を参考にしてエクスポートします。
以下のようなリストが出力されます。※値は例です。

| username  | email                    | status | billing-active | has-2fa | has-sso | userid | fullname     | displayname | expiration-timestamp |
|-----------|--------------------------|--------|----------------|---------|---------|--------|--------------|-------------|-----------------------|
| user1     | user1@example.com        | active | true           | true    | false   | 12345  | John Doe      | JohnD        | 1640995200000        |
| user2     | user2@example.com        | inactive | false         | false   | true    | 67890  | Jane Smith    | JaneS        | 1643673600000        |
| user3     | user3@example.com        | active | true           | true    | true    | 54321  | Bob Johnson   | BobJ        | 1638806400000        |
| user4     | user4@example.com        | active | true           | false   | true    | 98765  | Alice Brown   | AliceB      | 1640995200000        |
| user5     | user5@example.com        | inactive | false         | false   | false   | 23456  | Mary White    | MaryW        | 1638806400000        |

## 抽出データ
以下のようなデータをスプレッドシートに用意します。
所属しているサークルでは、Googleフォームでライブに出演するバンドを管理しています。
Googleフォームの回答内容はスプレッドシートに出力されるため、Slackチャンネルに追加する対応もそのスプレッドシートで行えます。

| バンド名   | 出演時間 | 1人目           | 2人目          | 3人目         | 4人目           | 5人目           | 6人目           |
|------------|----------|-----------------|----------------|---------------|-----------------|-----------------|-----------------|
| バンドA     | 19:00    | ギタリストA     | ドラマーA       | ベーシストA   | キーボーディストA | ボーカリストA   | サックスプレイヤA |
| バンドB     | 20:30    | ドラマーB       | ベーシストB   | ギタリストB   | キーボーディストB | サックスプレイヤB | トランペッターB |
| バンドC     | 22:00    | ベーシストC   | ギタリストC   | キーボーディストC | ドラマーC       | トランペッターC | ボーカリストC   |

# ChatGptに実装してもらったスクリプト
ChatGptに以下の2つのスクリプトを実装してもらいました。
伝え方を間違えるととんでもない実装をしてくるため、要件の言語化はかなり重要です。

## 抽出した演者のデータから重複排除したリストを新規のシートに貼り付けるスクリプト

```
function removeDuplicatesAndPaste() {
  // 抽出対象のシート名と貼り付け先のシート名を指定
  var sourceSheetName = "出演バンド一覧"; // 抽出対象のシート名。適宜変更する。
  var targetSheetName = "チャンネル追加対象者"; // 貼り付け先のシート名。適宜変更する。

  // 対象のシート情報を取得
  var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sourceSheetName);
  var targetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(targetSheetName);

  // シートが見つからない場合はエラーメッセージを表示して処理を終了
  if (!sourceSheet || !targetSheet) {
    Browser.msgBox("指定されたシートが見つかりません。");
    return;
  }

  // 抽出対象のB列のデータを取得
  var cellRange = sourceSheet.getRange("A1:G30"); // セル範囲は適宜変更する。
  var cellValues = cellRange.getValues(); // セル範囲の値を取得

  // デバック用のためコメントアウト
  // 取得した値をコンソールに表示する
  // for (var i = 0; i < cellValues.length; i++) {
  //   for (var j = 0; j < cellValues[i].length; j++) {
  //     Logger.log("セル(" + (i + 2) + ", " + (j + 3) + "): " + cellValues[i][j]);
  //   }
  // }

  // 同じメンバーが別のバンドで参加することがあるため、重複を削除したデータを取得
  var uniqueData = removeDuplicates(cellValues);

  // 貼り付ける先のA1セルに「演者」というヘッダーを設定
  var targetRange = targetSheet.getRange("A1");
  targetRange.setValue("演者");

  // 貼り付ける先のA列に一意のデータをセット
  targetRange.offset(1, 0, uniqueData.length, 1).setValues(uniqueData);
}

// 抽出した演者のリストのデータを重複排除する関数
function removeDuplicates(arr) {
  var flattenedArr = arr.flat(); // 2次元の配列を1次元に平坦化
  var uniqueArr = [...new Set(flattenedArr)]; // 重複を削除
  var uniqueValues = [];

  for (var i = 0; i < uniqueArr.length; i++) {
    uniqueValues.push([uniqueArr[i]]);
  }

  return uniqueValues;
}
```

## Slackのメンバーリストのcsvから演者のメールアドレスを取得してコピーするスクリプト
このスクリプトでコピーされたメールアドレスをコピーして、Slackチャンネルのメンバー追加画面にペーストすると、一発で大人数のチャンネル参加を実現できます。
```
function searchAndCopyData() {
  var sourceSheetName = "slack-members"; // データを検索するシート名。適宜変更する。
  var targetSheetName = "チャンネル追加対象者"; // 結果を出力するシート名。適宜変更する。
  var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sourceSheetName);
  var targetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(targetSheetName);

  if (!sourceSheet || !targetSheet) {
    Browser.msgBox("指定されたシートが見つかりません。");
    return;
  }

  // セルの範囲は適宜変更する。
  // csv出力されたSlackメンバーの氏名があるセル範囲
  var sourceData = sourceSheet.getRange("H2:H" + sourceSheet.getLastRow()).getValues();
  // 重複排除された演者のリストのセル範囲
  var targetData = targetSheet.getRange("A2:A" + targetSheet.getLastRow()).getValues();

  for (var i = 0; i < targetData.length; i++) {
    var targetValue = targetData[i][0];
    var matchedValue = "不明";

    // ハッシュのデータと一致する場合、値を置き換える
    if (data_dict[targetValue]) {
      targetValue = data_dict[targetValue];
    }

    for (var j = 0; j < sourceData.length; j++) {
      var sourceValue = sourceData[j][0];

      if (sourceValue && targetValue && sourceValue.includes(targetValue)) {
        matchedValue = sourceSheet.getRange("B" + (j + 2)).getValue();
        break;
      }
    }

    // B2以降に該当したメールアドレスをコピーしていく
    targetSheet.getRange("B" + (i + 2)).setValue(matchedValue);
  }
}
```

# 運用の改善点
- 対象のシート名についてハードコーディングとなっているため、操作者の入力を受け付けたい
- 抽出対象とコピー先のセル範囲についてハードコーディングとなっているため、操作者の入力を受け付けたい
- 全く無知のメンバーが操作した場合、GASの実行までたどり着けない可能性が高いため、実行ボタンなどをシートに貼り付けたい

# まとめ
今回はChatGptとGASを使用して、サークル活動時に発生していたSlackチャンネルの大量メンバー追加問題を解決してみました。今後、大量のメンバーをSlackチャンネルに追加する時の運用コストがこれでグッと減ったかなと思います。
最近は、業務でJenkinsも触ることが多く、各サービスから提供されているAPIなどをスクリプトを通じて叩ければ色々な応用が効くんじゃないかなぁと模索しています。
こういった地味な改善が、日々の生産性に寄与していくと信じたいですね。

明日は@ackylaさんの「[数年ぶりに自宅サーバーを立ててKubernetesを入れてみる](https://qiita.com/ackyla/items/c25ffc00fe81b533ce15)
」です！