Slack上でG Suiteドキュメントを管理するBOTをサーバーレス（GAS）で作った

この記事はITC Advent Calendar(2) 4日目の記事です

その一
https://adventar.org/calendars/2563


その二
https://adventar.org/calendars/2640


初めまして、がっちゃんです。
本年度のITCの部長やってます。

今回はとあるイベント( https://cybozu.connpass.com/event/70773/ )でとあるLT( https://www.slideshare.net/AyaSuzuki9/gasbot-83171149 )を聞いてGAS面白そうと思って触ってみたので記事にしました。

# まず導入

GASについて〜SlackからGoogle Spread Sheetにデータを登録するまでは
素晴らしいスライド( https://www.slideshare.net/AyaSuzuki9/gasbot-83171149 )の方で書いてくださってるので是非そちらをどうぞ。

# これやってみるときにびっくりしたこと
## え、めっちゃ認証厳重やん。

ログイン認証しようと思ったらこれ出て来て…
![ログイン認証しようと思ったらこれ.png](https://qiita-image-store.s3.amazonaws.com/0/108554/5e8fb3e4-d494-d8ea-db94-f809ac8efde3.png)


詳細を開いて…
![詳細を開いて….png](https://qiita-image-store.s3.amazonaws.com/0/108554/31e7ab35-2d51-0791-ed71-e2e68d8a3514.png)

「次へ」を手入力して…
![次へを手入力して….png](https://qiita-image-store.s3.amazonaws.com/0/108554/14825cd0-bad8-4819-f54e-efeef0fd40c6.png)

やっと認証許可ができるｗ
![やっと認証許可ができるｗ.png](https://qiita-image-store.s3.amazonaws.com/0/108554/145dc315-66d3-f50b-c3e2-c9747fd6df8b.png)


## 初回にミスったせいで一生ハマってた
一発目の選択で「自分だけ」を設定してしまって、別のURLが発行されてて、それに登録しようとしまくっててそんなURL無い！って言われ続けてハマってた。

何回か設定を変えて公開し直したりしたら `/u/0/` がないURLが発行されるので、それを使えば治りました。（いまだに治った原因が定かじゃない…ｗ）

# これを一通り作ってみてから、Slackでドキュメントを管理するBOTアプリを作った
## 完成イメージ

管理させてるドキュメントを一覧でみれたり
![一覧開く.png](https://qiita-image-store.s3.amazonaws.com/0/108554/5947bb5c-fa66-33f9-af05-5c557a92ed14.png)

新しくドキュメントを管理させれたり
![新しくドキュメントを管理させれたり.png](https://qiita-image-store.s3.amazonaws.com/0/108554/8df7d99b-a1f9-d2ab-f68b-141101ecbc88.png)

ラベル名でドキュメントを検索できたり
![ラベル名で検索できたり.png](https://qiita-image-store.s3.amazonaws.com/0/108554/81b4bce1-1bf5-97ae-aa63-f43b4d053fcc.png)

必要なくなったドキュメントを管理対象から外したり
![必要なくなったドキュメントを管理対象から外したり.png](https://qiita-image-store.s3.amazonaws.com/0/108554/a58f1d60-77d9-ccdd-abec-6fa1970c0efa.png)

できるBOTアプリをサーバーレス（流行ってるから言いたい）で作りました。

## 構成
### Slack Incoming/Outgoing Webhook
- Slack入力を読み取ってもらう
- レスポンスを出力してもらう

### GAS

- 受け口
- ルーティング
- フォーマット掛け
- もろもろの管理など

### Google Spreadsheet

- データの保存

## 苦労したとことハマったとこ
### Google Apps ScriptのGUIエディタだとファイル分割ができない（と言うよりもめんどくさい）

普段のJSの感覚で `import` とか `require` とか使えると思ったら使えないっぽかった
（と言うよりも、ググった時にびっくりするほどJSの書き方がヒットしてノイズだらけで読む気が失せた）
ので、1ファイルで書くことにしました。

その結果、300行ぐらいの1ファイルコードになりました（）

次やる時か、気が向いたときにファイル分割とリファクタリングしよう…

### Arrayを与えてもよしなに指定の行にデータをぶっ込んでくれなかった…

これは、Google Spreadsheet の特性上仕方ないことなんだとは思うんですが、
行を指定して、データを並べた `Array` を与えたのですが、うまいことデータ挿入をやってくれなくって、結構はまりました。
以下の記事のおかげで解決しましたが、なかなかにややこしかった。

https://qiita.com/ShishidoToru/items/0ab9de4ea281df9358f4

### スタンドアロンで考えて設計しないとデバッグがめんどくさい。

SlackBotとしてGASアプリを作る時に気をつけておかないといけないのが、
この (https://www.slideshare.net/AyaSuzuki9/gasbot-83171149) スライドの37枚目でも書いているように、一度Webアプリケーションとして公開して、SlackBotで叩けるようにすると、更新のたびにGUIで更新ぽちぽちしないといけなくなります。

Webアプリをローカルで試さずにいちいちデプロイしてテストする感じですね。

自分は流石にめんどくさかったので、

```js

// sample request
// var sample = 'docadmin add スプレッドシート soso xxxxxxxxxxx';
// var sample = 'docadmin list';
// var sample = 'docadmin find 自己紹介プレゼン';
// var sample = 'docadmin activate active piyo';

function router(rawRequest) {
  var request = adjustValues(rawRequest /* sample */);
  // ~~~
}

function adjustValues(request) {
  var parameter = request.parameter.text.split(' ');
  // var parameter = request.split(' ');
  // ~~~
```

みたいな感じで、いくつかの入力パターンを用意して、開発中はそっちのパターンを利用して、
できる限り少ないコストで Slack 連携に切り替えれるようにしてました。

これがまた結構大事。

### 遅くなるし、メソッドを探すのが大変だったりするので無理にSpreadsheet上で操作しようとしない。

[この記事](
https://qiita.com/ryan5500/items/e72eb205fbe006c2eb6f#%E3%82%B7%E3%83%BC%E3%83%88%E5%85%A8%E4%BD%93%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E6%8E%A2%E7%B4%A2%E5%87%A6%E7%90%86%E3%81%AFjs%E5%81%B4%E3%81%A7%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E3%81%BB%E3%81%86%E3%81%8C%E9%80%9F%E3%81%84)を読んでハッと気づかされたのですが、作り始めはSpreadsheet内の行そのものを操作してデータ書き換えをしたり、走査をしたりしようとしてました。

でも、それだとSpreadsheetで提供されているメソッドを探すのに苦労したり、Spreadsheet APIを叩く分遅くなります。 **（GASは5分を超える処理はタイムアウトにされるので、実行時間にも注意）**
なので、GASではほぼJSと同じ構文で書けることが多いので、できるだけその書き方をすることをお勧めします。

### `SpreadsheetApp.openById(SPREAD_SHEET_ID).getSheets()[0]` ってしてあげた方がいい

度々出てきているのですが、このスライド ( https://www.slideshare.net/AyaSuzuki9/gasbot-83171149 ) でのスプレッドシートの取得のやり方をすると、
`Spreadsheet` オブジェクト（ファイル丸ごとみたいなイメージ）を `sheet` に代入することになり、
`getRange(row, colmun)` などのメソッドを使うことができなくなります。

原因は `getRange(row, column)` のメソッドが `Sheet` オブジェクト（ファイルの中にあるシートみたいなイメージ）に属しているためで、
これを解決するには、 `SpreadsheetApp.openById(SPREAD_SHEET_ID).getSheets()[0]` のような形で、
`Spreadsheet` オブジェクトの中の 0番目の `Sheet` オブジェクトを取得する必要があります。

自分はこれがいまいち理解できてなくって、 `getRange(row, column)` がno_methods errorを吐かれることにハマってましたｗ

# まとめ

いかがだったでしょうか。
スライドをみて、GASを触ってみたいなって思い、そのあと詰まったりハマったりしながらも大体10時間ぐらいでこれぐらいのサーバーレスBOTを作ることができました。

思った以上にお手軽にBOTを作れて楽しかったのでまた別の機会にちょっとしたところを便利にするBOT作ってみようと思います。

これを読んだみなさんもGASに興味を持って色々遊んでもらえれば、幸いです！
ありがとうございました！

# 参考リンク

- https://www.slideshare.net/AyaSuzuki9/gasbot-83171149
- https://developers.google.com/apps-script/reference/spreadsheet/
- https://qiita.com/ShishidoToru/items/0ab9de4ea281df9358f4
- https://qiita.com/ryan5500/items/e72eb205fbe006c2eb6f#%E3%82%B7%E3%83%BC%E3%83%88%E5%85%A8%E4%BD%93%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E6%8E%A2%E7%B4%A2%E5%87%A6%E7%90%86%E3%81%AFjs%E5%81%B4%E3%81%A7%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E3%81%BB%E3%81%86%E3%81%8C%E9%80%9F%E3%81%84

# 公開予定のリポジトリ（リファクタリング後にコピペしまする）
- https://github.com/ahaha0807/document-administrator