[初心者歓迎] Google App Script で友人の誕生日をLINEに知らせてくれるスクリプトを作ろう

# この記事の対象者

GAS使ってみたい。GAS使ってなんか連携したい方に。
ある程度jsに慣れているとよいです。

# GAS入門良記事
いちおう慣れてない人でもコピペすれば動くようには書いていきます。

[いつも隣にITのお仕事](https://tonari-it.com/google-apps-script-manual/)

# Line Notify
登録してToken発行しておいてください。こちらの記事を参考にToken発行のところまで。

[[超簡単]LINE notify を使ってみる](https://qiita.com/iitenkida7/items/576a8226ba6584864d95)

# 下準備
* googleのアカウントがある(すでにある方はOK)
* chromeブラウザがインストールする(すでにある方はOK)
* line notifyのトークンを発行する

# 流れ
1. 作りたいものを決める
2. webアプリからspread sheetを開く
3. データの構造(表の形)を決める
4. ツールタブからスクリプトエディタを選択
5. スクリプトを作成
6. スリプトをテスト
7. トリガーを設定する

今回は3からいきます。

## データの構造を決める
作りたいものが決まればデータの構造を決めましょう。今回のサンプルはSpreadSheetに誕生日と名前を入力して30日前、7日前、3日前になると知らせてくれるものにしたいと思います。これを応用すればいろいろ作れるかも？

||A|B|
|---|---|---|
|1|名前|誕生日|
|2|山田太郎|3/23|
|3|田中花子|10/3|

こんな感じにしたいと思います。1行目はヘッダーとしてどのようなデータが入るのかのキーワードを入れます。ここに識別idを入れるひともいますが、今回は特に使わないので入れません。

## ツールタブからスクリプトエディタを選択

<img width="1382" alt="Screen Shot 2019-06-05 at 10.46.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/b37dea97-3fb6-c4f0-9760-881b5705289f.png">

するとこんな感じの画面が開くと思います。無題のプロジェクの部分をクリックして好きな名前を編集してください。

<img width="1194" alt="Screen Shot 2019-06-05 at 10.47.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/df49342c-1444-5185-79f8-e6631a85e7c3.png">

## スクリプトを作成

今回はGASに必須ともいえる便利な2つのライブラリをインストールします。日時操作に便利な[Moment.js](https://momentjs.com/)と配列操作に必須な[Underscore](https://underscorejs.org/)です。それぞれの記事はこちらを参考に。

* [日付＆時刻の便利ライブラリ「Moment.js」をGoogle Apps Scriptで使う方法](https://tonari-it.com/gas-moment-js-moment/)
* [underscore.jsリファレンス](https://qiita.com/f1000/items/47b2ace7d1fbc4795184)

### ライブラリいれるよ
リソースタブからライブラリをクリックしてください。するとモーダル(小さい画面)がでてくるので、そこのライブラリを追加という部分に``M3i7wmUA_5n0NSEaa6NnNqOBao7QLBR4j``を入力して追加ボタンを押すとつぎのような画面になるはずです。ここでバージョンはなるべく数字が大きいものを選びましょう。これでボタンを押せば無事``Underscore``が使えるようになります。

<img width="1221" alt="Screen Shot 2019-06-05 at 11.05.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/a0c6a646-4194-0688-f5d7-4f1f9cd4eb4e.png">

同様に``Moment``も入れてみましょう。プロジェクトキー``MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48``です。

### 実際のコード

実際のコードはこちらの2つです。詳しい説明は後ほどいたします。

```javascript:コード.gs
var LINE_TOKEN = 'LINEのトークンをここにコピぺ';
var SHEET_ID = 'シートのIDをここにコピペ';
var _ = Underscore.load();

function main() {
  
  // データ取得
  data = getData();
  if(data.length == 0){
    return;
  }
  
  // データから誕生日がちょうど30日前の列を取得
  var user_rest_30days = _.filter(data, function(v){
    return Moment.moment(v['誕生日'], 'MM月DD日').diff(Moment.moment(), 'days') + 1 == 30;
  });
  
  // データから誕生日がちょうど7日前の列を取得
  var user_rest_7days = _.filter(data, function(v){ 
    return Moment.moment(v['誕生日'], 'MM月DD日').diff(Moment.moment(), 'days') + 1 == 7; 
  });
  
  // データから誕生日がちょうど3日前の列を取得
  var user_rest_3days = _.filter(data, function(v){ 
    return Moment.moment(v['誕生日'], 'MM月DD日').diff(Moment.moment(), 'days') + 1 == 3; 
  });
  
  Logger.log(user_rest_30days);
  Logger.log(user_rest_7days);
  Logger.log(user_rest_3days);
  
  var user_30_mes = _.map(user_rest_30days, function(v){ return new Birthday(v['名前'], v['誕生日']).generate_message();}).join(',\n');
  var user_7_mes = _.map(user_rest_7days, function(v){ return new Birthday(v['名前'], v['誕生日']).generate_message(); }).join(',\n');
  var user_3_mes = _.map(user_rest_3days, function(v){ return new Birthday(v['名前'], v['誕生日']).generate_message(); }).join(',\n');
  
  // 全てがからの場合
  if(!user_30_mes && !user_7_mes && !user_3_mes){
    return;
  }

  var message = "\n30日前:\n" + user_30_mes + "\n7日前:\n" + user_7_mes + "\n3日前:\n" + user_3_mes;
  Logger.log(message)
  //誕生日処理
  sendMessage(message);
  
  
}

function getData(){
  var sheet = SpreadsheetApp.openById(SHEET_ID).getActiveSheet();
  var values = sheet.getDataRange().getValues(); //配列として取得
  var labels = _.first(values);
  var values = _.rest(values);
  values = _.map(values, function(items){
    var list_item = {};
    _.each(items, function(item, i){
      list_item[labels[i]] = item;
    })
    return list_item;
  })
  
  return values;
}

function sendMessage(message){
  var token = LINE_TOKEN;
  var options =
   {
     "method"  : "post",
     "payload" : "message=" + message,
     "headers" : {"Authorization" : "Bearer "+ token}
   };

   UrlFetchApp.fetch("https://notify-api.line.me/api/notify",options);
}

function myFunction(){
  var message="" ;
  sendHttpPost(message);
}

```

```javascript:Birthday
function Birthday(name, birthday){
  this.name = name;
  this.birthday = birthday;
  
  this.generate_message = function(){
    var res = name+ "(" + birthday + ") ";
    return res;
  }
}

```

### コード解説
#### sendMessage()
Lineにメッセージを送る関数です。LineNotifyを該当のグループに招待すればメッセージがくるはずです。くわしくは上記の参考URLをみてください。

```javascript
var LINE_TOKEN = 'LINEのトークンをここにコピぺ';

function main() {
    var message = "hogehoge";
    // Lineに
    sendMessage(message);
}

function sendMessage(message){
  var token = LINE_TOKEN;
  var options =
   {
     "method"  : "post",
     "payload" : "message=" + message,
     "headers" : {"Authorization" : "Bearer "+ token}
   };

   UrlFetchApp.fetch("https://notify-api.line.me/api/notify",options);
}
```

#### getData()
シートIDのシートを取得し{key: value}という形で配列に入れる関数です。シートID
はspread sheetのurlに書いてあります。

``https://docs.google.com/spreadsheets/d/シートID/edit#gid=0``

|名前|誕生日|
|---|---|
|山田太郎|3月23日|
|田中花子|10月5日|

というテーブルがきたら連想配列ができます。

```javascript
[
  {"名前": "山田太郎", "誕生日": "3月23日"},
  {"名前": "田中花子", "誕生日": "10月5日"}
]
```

```javascript
var SHEET_ID = 'シートのIDをここにコピペ';

function getData(){
  var sheet = SpreadsheetApp.openById(SHEET_ID).getActiveSheet();
  var values = sheet.getDataRange().getValues(); //配列として取得
  var labels = _.first(values);
  var values = _.rest(values);
  values = _.map(values, function(items){
    var list_item = {};
    _.each(items, function(item, i){
      list_item[labels[i]] = item;
    })
    return list_item;
  })

  return values;
}

```

#### Birthday 
クラス。名前と誕生日を一緒に出力する``generate_message``というメソッドをもつ。

ファイルタグから新規作成でスクリプトファイルを選択する。
<img width="651" alt="Screen Shot 2019-06-05 at 12.43.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/850d0684-812c-c59a-c96e-6a2494899de1.png">

名前を適当に変更したのち、コードをコピペする。



```javascript
function Birthday(name, birthday){
  this.name = name;
  this.birthday = birthday;

  this.generate_message = function(){
    var res = name+ "(" + birthday + ") ";
    return res;
  }
}
```

#### そのほか

```javascript

  // データから誕生日がちょうど30日前の列を取得
  var user_rest_30days = _.filter(data, function(v){
    return Moment.moment(v['誕生日'], 'MM月DD日').diff(Moment.moment(), 'days') + 1 == 30;
  });

```

``data``は先ほどのgetDate()の連想配列の値が入っています。それをUndersocreの``filter``メソッドを使って条件に見合うやつだけ抽出します。filterの簡単な例は以下。第二引数の関数に条件(True or Falseのなる式)を書きます。

```javascript
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
```

Underscoreの``map``メソッドは配列の各要素に何らかの処理を施して新しい配列を返します。以下では各連想配列の値を``Birthday``クラスにいれて``genrerate_message``メソッドを実行し、さらにそれを配列に入れています。最後にその配列を``join``メソッドをつかってカンマで1つのstringにしています。

```javascript
var user_30_mes = _.map(user_rest_30days, function(v){ return new Birthday(v['名前'], v['誕生日'], v['is_active']).generate_message();}).join(',\n');
```

## スクリプトをテスト

<img width="504" alt="Screen Shot 2019-06-06 at 23.16.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/99af386f-bc10-9d20-59ee-f7a66f724277.png">

関数を実行するには``関数を選択``ボタンから実行したい関数を選びます。さきほどのスクリプトの場合はmainです。上の写真は例えばつぎのようにコーディングして``Cnrl(Cmd)+S``で保存し、関数を実行した場合です。関数の実行は▶を押します。関数を実行した後``Ctrl(Cmd)+Enter``を押すとログの内容が出力されます。

```javascript
function main() {
  Logger.log("これはmainだよ");
}

function sub(){
  Logger.log("これはsubだよ");
  
}
```

するとログの内容が次のように出力されます。スクリプトのテストはこのようにいろいろなところでLogger.log()を実行して確認していきましょう。

<img width="1242" alt="Screen Shot 2019-06-06 at 23.19.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/cced597a-e6a2-dd6c-4a0f-4bd3b6b544ee.png">


## トリガーを設定
トリガーは▶のよこの時計マークになります。ここをクリックすると次のような画面が現れます。

<img width="1432" alt="Screen Shot 2019-06-06 at 23.29.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/73993015-ef1f-a19f-e9b4-1508576c01d1.png">


右下のトリガーを追加をクリックしましょう。
するとモーダルが現れるので次のように設定した後に保存ボタンをおせば無事毎日スクリプトが実行されます。

<img width="835" alt="Screen Shot 2019-06-06 at 23.30.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208338/92f0e794-08fa-7de2-8c69-e56c01f0043f.png">

# まとめ

こうはん少し雑になってすいません。GASはなれるとすごい楽しいですし、なによりも無料でネット上で動けるスクリプをかけるのがいいですね。少し難点をあげるとすればES6に対応してほしいという部分くらいでしょうか。