Gather.townに誰かが浮上した際にslackで通知してくれるアプリをGASで作る

# 目的
知り合いのエンジニア間で勉強会に使っているGather.townのマップがあるのですが、誰もいなくて即抜けしてしまう人が多々いるような気がしたので誰かが勉強会に現れたら通知してくれる機能を作りました。

補足として説明するとGather.townとは複数のユーザーが別々の会話を行うことができ、また実際の生活と同じように簡単に自由に出入り出来るスペース(空間)を、ビデオ通話やチャットなどを利用可能な形で実現しているサービスです。
>引用: https://dev.classmethod.jp/articles/gather-town-as-a-virtual-office/


# どんな仕様か？

- 10分おきにGatherのオンラインユーザーの人数を確認
- 前回の人数確認時からGatherのオンラインユーザーが1人でも増えれば通知
- 反対に一人も増えなかった & 0人のまま だったら通知しない
- オンラインユーザーが1人以上の状態からオンラインユーザーが0人になったら通知

# 結論
以下のようなコードで作ることができます。トークンやAPIキーなどの定数はご自身のものを書き換えてください。(ここではTokenやAPI Keyをエディタに書き込んでいますが、環境変数にすることをオススメします。やり方はchatGPTに聞けば教えてくれるはずです)
```JavaScript
// SlackのBot Tokenを設定
const SLACK_BOT_TOKEN = 'your-slack-bot-token';
// GatherのSpace IDを設定
const GATHER_SPACE_ID = 'your-gather-space-id';
// GatherのAPI Keyを設定
const GATHER_API_KEY = 'your-gather-api-key';

async function main() {
  // Gather上のユーザー情報を取得。
  const usersCount = getUsersFromGather(GATHER_SPACE_ID, GATHER_API_KEY);
  // Googleスプレッドの「シート1」を読み込み
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  //スプレッドシートのセルA1の値を取得
  const inputCell = sheet.getRange('A1');
  let beforeCount = inputCell.getValue();
  
  // 10分前と人数に変わりがなければ処理を終了する。
  if (usersCount === beforeCount) {
    return;
  }

  // 前回のユーザー集計時と比較してユーザー数が増えれば通知。
  if (usersCount > beforeCount) {
    const message = `*新しいGatherのオンラインのユーザーがいます！*\nオンラインのユーザー: *${usersCount} 人*\n https://app.gather.town/app/${GATHER_SPACE_ID}`;
    await inputCell.setValue(usersCount);
    sendSlackNotification(message);
  } 
  // ユーザー数が1人以上の状態から0人になった場合通知
  else if (usersCount != beforeCount && usersCount === 0) 
  {
    const message = `*Gatherのオンラインのユーザーがいなくなりました*\n`;
    await inputCell.setValue(0);
    sendSlackNotification(message);
  }
  return;
}

// gatherにアクセスしてアクティブなユーザーの人数を出すメソッド
function getUsersFromGather(spaceId, apiKey) {
    // APIからスペース情報を取得
  const url = "https://api.gather.town/api/v2/users/me/owned-spaces";
  const headers = {
    "apiKey": apiKey
  };
  const options = {
    method: 'get',
    muteHttpExceptions : false,
    headers: headers
  }
  const response = UrlFetchApp.fetch(url, options);
  const data = JSON.parse(response.getContentText());
  // スペースの人数を取得
  const workSpace = data[spaceId]
  const activeUserCount = workSpace['numActive'];
  return activeUserCount;
}

// Slackにメッセージを送信
function sendSlackNotification(message) {
  // ライブラリから導入したSlackAppを定義し、トークンを設定する
  let slackApp = SlackApp.create(SLACK_BOT_TOKEN);
  // Slackボットがメッセージを投稿するチャンネルを定義する
  const channelId = "#設定したいチャンネル名";
  // SlackAppオブジェクトのpostMessageメソッドでボット投稿を行う
  slackApp.postMessage(channelId, message)
}
```

# 手順
具体的な手順は以下のとおりです。
## Slack APIを登録
Slack APIの登録は、以下の手順です。

+ Slack APIのWebサイトにアクセスし、アカウントを作成します。
+ アカウントを作成したら、[Create New App]ボタンをクリックします。
![スクリーンショット 2023-04-25 22.51.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590211/077d38e1-a139-0ee1-0b03-9305be74d8a7.png)

+ アプリを作成するための情報を入力し、[Create App]ボタンをクリックします。
### ボットユーザーを作成する
Slackアプリを作成したら、ボットユーザーを作成する必要があります。Botユーザーは、Slackアプリ内で実行される自動化されたタスクのために使用されます。

+ アプリの[Add features and functionality]ページに移動し、[Bots]をクリックします。
![スクリーンショット 2023-04-25 22.56.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590211/f4fec2eb-90e4-2e62-fa18-de7a907dba47.png)

+ [Add a Bot User]ボタンをクリックし、ボットユーザーの名前を入力します。
+ 必要に応じて、ボットユーザーに権限を付与します。権限は「OAuth & Permissions
」から設定できます。今回は[chat:write]が必要です。
![スクリーンショット 2023-04-25 22.59.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590211/47fad536-f808-7ec7-10b9-996f0916646d.png)
+ ボットユーザーのトークンを取得する


+ ボットユーザーのトークンを取得するには、以下の手順を実行します。
    + [Install App]ページに移動し、[Install App to Workspace]ボタンをクリック。
    + ボットユーザーに必要な権限を付与し、[Authorize]ボタンをクリックします。
    + トークンは、[OAuth & Permissions]ページに移動し、[Bot User OAuth Access Token]の箇所にあります。

これでslackのBotトークンが取得できます。

## Gather.townのAPI Keyを発行
Gather.townにログインしていれば以下のリンクを踏むことでAPI Keyが取得できます。
> https://app.gather.town/apikeys

## スプレッドシートの編集
スプレッドシートを開き、A1セルに0を入力してください。
A1セルの数字はGatherのオンライン状態のユーザーの人数を記録するために使います
![スクリーンショット 2023-04-26 0.05.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590211/8d8ec761-4bca-467d-440e-2cd204c039f0.png)


## GASでコーディングする
ここまでいければあとはGASでコーディングをするのみ。
### 事前準備
* ライブラリ → スクリプトIDへ進み以下入力、検索を押下
    * ```1on93YOYfSmV92R5q59NpKmsyWIQD8qnoLYk-gkQBI92C58SPyA2x1-bq```
    * IDは「SlackApp」のまま、追加を押下

* GASでコーディング
    * 最初に記載したコードをGASのスクリプトエディタに貼り付け、トークンやAPI KEYを適宜書き換えてください。

* GASのトリガー設定。
    * GASには作った関数を定期実行するトリガーを設定することができます。今回は`main`関数を`10分`おきに実行するようにします。
    * 以下の記事を参考にしてトリガーの設定をしてみてください
    >https://auto-worker.com/blog/?p=6383

* 最後に作成したSlackアプリをチャンネルに追加するのを忘れずにお願いします。
    * 追加方法は[こちら](https://reigle.info/entry/2022/10/23/100000)の記事を参考にしてください


## おわり
こんな感じのアプリケーションができたかと思います。
![スクリーンショット 2023-04-25 23.28.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590211/d8312e55-0918-0717-a8c2-653ca6a20d4b.png)
↓人がいなくなると通知してくれます。
![スクリーンショット 2023-04-25 23.29.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590211/de065586-09e6-4ccf-b1a5-a66dda6d68d7.png)

また、人数に変動がない場合や誰もいないままだった場合は通知しないので、人の出入りが激しいわけでもない限り通知が煩くなることはないはずです！

<br>
是非試しに作ってみてください。


<br>

<br>

参考：　
>Gather.townのアクティブユーザー数を自動で記録する
https://zenn.dev
Gather.townで定期的にスペースにいる人数をSlack通知するGASを作る方法
https://qiita.com/YUM_3/items/39324277f2a32fbffc3e