GASで自動通知ツールを開発した時のメモ

GASを使って、GoogleSpreadSheet、Gmail、Chatwork を連携した自動通知ツールを作成した時の備忘録です。
一瞬、IFTTTで何とかなりそうと思いましたが、スクレイピング的なことをする必要があったのでGASを挟みました。
（GASのトリガーがcron的なことをやってくれて最高！

## 処理概要

* 一定時間ごとに、Gmailに受信したメールの内容を分析、GoogleSpreadSheetに記載されたChatoworkアカウントおよびroom_idを参照し、それに対して通知を送信、タスクを追加する


## メモ

### スクリプトロック

#### スクリプトをロックし、多重実行を回避する

```
var lock = LockService.getScriptLock();
```

#### スクリプトのロック状況を確認し、後続の処理を実行する

* ロックされている場合は、指定ミリ秒後にタイムアウト

```
if (lock.tryLock(1000)) // 引数はタイムアウトするまでの秒数
{
	// 処理を実行
	exec();

	// ロック解除
	lock.releaseLock();
}
else
{
	// ポップアップを表示
	Browser.msgBox("現在、別の処理が実行中の為、実行できませんでした。\\n\\n時間をおいて、再度実行して下さい。");
}
```


### Gmail連携

#### Gmailを指定した検索文字列で検索し、スレッドを取得する

```
// 検索文字列
var search_string = "is:unread ";

var threads = GmailApp.search(search_string, 0, 500);
```

* 検索文字列は、[Gmail](https://mail.google.com/)の画面上部の検索ボックスで作成できます

#### スレッドの内容を確認、既読処理を実行する

```
for (var i = 0; i < threads.length; i++)
{
	var msgs = GmailApp.getMessagesForThread(threads[i]);

	for (var j = 0; j < msgs.length; j++)
	{
		var tmpBody = msgs[j].getBody();
		Logger.log(tmpBody);

		// スクレイピング的に文字列を取得、使用する処理
		hoge(tmpBody);
	}

	// 既読にする
	threads[i].markRead();
}
```


### 汎用

#### 時間取得

* 時間を取得する
	* タイムゾーン : `Asia/Tokyo`
	* フォーマット : `yyyy/M/d`

```
var endDate = Utilities.formatDate(sheet.getRange('A1').getValue(), 'Asia/Tokyo', 'yyyy/M/d');
```

#### 指定範囲の最終入力行を取得

```
var lastRowNumRangeAA = sheet.getRange('A:A').getValues().filter(String).length;
```

#### 指定範囲の値を取得し配列化

```
var values = sheet.getRange('A1:A1000').getValues();
values = Array.prototype.concat.apply([],values);
```


### チャットワークAPI実行

#### タスク化

```
var CHATWORK_API_TOKEN = "hogehoge";

// 期限は現在日時
var limit = Math.floor( (new Date()).getTime() / 1000 ) ;
// 期限タイプ（none, date, time）
var limit_type = "time";

var method = "post";
var room_id = 11111111;
var body = encodeURI("メールを確認して下さい。\n※期限 : " + endDate + "まで※");
var to_ids = user_ids;
var url = "https://api.chatwork.com/v2/rooms/"+room_id+"/tasks?body="+body+"&limit="+limit+"&limit_type="+limit_type+"&to_ids="+to_ids;

execChatworkApi(method, url);

function execChatworkApi(method, url)
{
  var _url = url;
  var _method = method;
  var params = {
    headers : {"X-ChatWorkToken" : CHATWORK_API_TOKEN},
    method : _method
  };
  var strResponse = UrlFetchApp.fetch(_url, params);
  var json = JSON.parse(strResponse.getContentText());
  return json;
}
```

* Chatwork API のテストに関しては、Talendなどのテストツールを使えば簡単にテストできます
    * [Talendで始めるREST APIテスト](https://qiita.com/hfuruya/items/d4e0a19723ef50328880)

### 定期実行の設定

* Googleスプレッドシート > ツール > スクリプトエディタ > 現在のオブジェクトのトリガー のアイコンをクリック > トリガーを追加

![qiita_gas_trigger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74924/cbda216e-b52a-8b3a-9efb-c102be87165d.png)

### GAS実行アカウントの移行に関して

* GASの実行対象となるスプレッドシートのオーナー権限を変更する
* 上記で設定したトリガーの権限を変更することはできない（2020/03/01 現在）
    * トリガーはアカウント単位の設定になる
    * 移行前の設定内容を確認しつつ、移行後のアカウントで設定し直すしかない？

## 参考

* [Google App Script 公式ドキュメント](https://developers.google.com/apps-script/reference)
* [Chatwork API ドキュメント](https://developer.chatwork.com/ja/)


## 次

* つい最近、GASでV8ランタイムを使えるようになったとのことで、次にGASを使うことがあれば、 `let` とか `const` を使っていきたい（`var`は使いたくない）
    * [V8 Runtime Overview - Google Apps Script](https://developers.google.com/apps-script/guides/v8-runtime)