【GAS×LINEMessagingAPI】明日の自分にメッセージを残すLINEbot！

#はじめに
Advent Calendar 2020の18日目を担当します、 DMM WEBCAMPメンターの松尾です！

新しい何かに挑戦しようと思い、面白そうだと思ったLINEbotの世界に飛び込んでみたのでその内容を共有していきます！
この記事で作成するLINEbotは<b>「リマインダーのアプリを開くのが面倒くさいLINEヘビーユーザー」</b>向けです！


#このBOTの流れ
botの流れを簡単に表すと以下になります。
###①botにメッセージを送信します
![スクリーンショット 2020-12-15 17.06.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/cc4856b3-768d-ebba-a315-6eaceca10bde.png)

###②そのメッセージを送信日時と共にスプレッドシートに保存します
![スクリーンショット 2020-12-15 17.02.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/50850b14-3781-9e00-7829-297bcd64fdf7.png)

###③指定時間になると、保存してあるメッセージが送信されます。
![スクリーンショット 2020-12-15 17.04.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/5cf290ac-717a-8908-572d-bedf4b31ea60.png)
#作り方
まず、このLINEbotを作るためには「LINEdevelopers」に登録する必要があります
この記事ではここを割愛します
登録方法は、こちらの記事を参考にされるといいかと思います。
[LINEのBot開発 超入門（前編） ゼロから応答ができるまで](https://qiita.com/nkjm/items/38808bbc97d6927837cd)

次に、スプレッドシートを用意し<b>「ツール」</b>から<b>「スクリプトエディタ」</b>を選択してください。
![スクリーンショット 2020-12-15 17.19.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/b25146a3-29e4-3c8e-c6b2-2078fadc33be.png)

このスクリプトエディタ内の<b>「コード.gs」</b>にコードを書いていくことになります。

まずは、<b>送信したメッセージをスプレッドシートに保存するプログラム</b>を書いていきましょう。
##工程１：送信したメッセージをスプレッドシートに保存する/削除する
この工程のコードはこのようになります。

```js:コード.gs
var ACCESS_TOKEN = '自分のトークン';
var url = 'https://api.line.me/v2/bot/message/reply';
var USER_ID = "自分のラインのID"; //(LINE Developersの「あなたのユーザーID」に書いているもの)

function doPost(e) {
  var sheet = SpreadsheetApp.openById("シートのID").getSheetByName("シートの名前");//シートの取得
  var lastRow = sheet.getLastRow();//シートの最終行の取得
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;// WebHookで受信した応答用Token
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;// ユーザーのメッセージを取得
  var date = new Date();//今日の日付の取得

  if(userMessage == "取り消し"){ //「取り消し」と送信された時
    sheet.getRange(lastRow, 1,1, 2).deleteCells(SpreadsheetApp.Dimension.COLUMNS);//シートの最終行のデータを消す
    UrlFetchApp.fetch(url, { //消した後に「取り消しました」と送信
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
      },
      'method': 'post',
      'payload': JSON.stringify({
        'replyToken': replyToken,
        'messages': [{
          'type': 'text',
          'text': "取り消しました",
        }],
      }),
    });
  }else{ //「取り消し」以外のメッセージが送信された時
    sheet.getRange(lastRow + 1, 1).setValue(date); //「最終行+１」の「１列目」のところ（一番上にある空白部分）にメッセージが送信された時の日時を入れる
    sheet.getRange(lastRow + 1, 2).setValue(userMessage);//同じ行の「2列目」に、送られたメッセージを入れる
    
    UrlFetchApp.fetch(url, { //メッセージが送られた時に「送信されたメッセージを・・・」を送信
      'headers': {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
      },
      'method': 'post',
      'payload': JSON.stringify({
        'replyToken': replyToken,
        'messages': [{
          'type': 'text',
          'text': "送信されたメッセージを保存しました。明日の朝７時に通知されます。\n取り消すには「取り消し」と送信してください。",
        }],
      }),
    });
  }
}
```
大体のコードの説明は、コード内のコメントに書いてあります。
この工程は、シートへの書き込み、削除さえできてしまえば簡単だと思います。
LINEとのやりとり部分の詳細は[公式リファレンス](https://developers.line.biz/ja/reference/messaging-api/)から確認していただければと思います。

この工程が上手くいくと、スプレッドシートにこのような感じで保存されているはずです。
![スクリーンショット 2020-12-15 17.02.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/599a906c-6999-9307-16df-3c29f09a8ecd.png)

##工程2：送信したメッセージをスプレッドシートに保存する
この工程のコードはこのようになります。

```js:コード.gs
function push_message() { //一定時刻になったら発火させる関数
  var sheet = SpreadsheetApp.openById("1I_J21bTarjZGNfsvQOVJOfvV5h-NhuHJhG4_Z0bE0p0").getSheetByName("TALK"); //シートの取得
  var lastRow = sheet.getLastRow(); //最終行の取得
  var today = new Date(); //今日の日付の取得
  var yesterday = new Date(); 
  yesterday.setDate(yesterday.getDate() - 1);//昨日の取得
  var allData = sheet.getRange(2,1,lastRow-1, 2).getValues();//スプレッドシートの全てのデータを取得
  var sendData = "昨日からのメッセージはこちらです!\n"; //送信するメッセージを作る
  allData.forEach(function(e){ //全てのデータを回す
    if(e[0].getFullYear() == today.getFullYear() && e[0].getMonth() == today.getMonth() && e[0].getDate() == today.getDate() && e[0].getHours() < 5.0){ 
      sendData += "\n\n・"+e[1];
    }else if(e[0].getFullYear() == yesterday.getFullYear() && e[0].getMonth() == yesterday.getMonth() && e[0].getDate() == yesterday.getDate() && e[0].getHours() >= 5.0){
      sendData += "\n\n・"+e[1];
    }else{
      sendData += "";
    }
  });
  if(sendData == "昨日からのメッセージはこちらです!\n"){ //sendDataの中身に何も追加されていないとき（今日送る分のメッセージがない時）
    sendData = "昨日からのメッセージはありません。\n今日もがんばりましょう！"; //sendDataの中身を置き換える
  }
  
  var postData = {
    "to": USER_ID,
    "messages": [{
      "type": "text",
      "text": sendData,
    }]
  };

  var url = "https://api.line.me/v2/bot/message/push";
  var headers = {
    "Content-Type": "application/json",
    'Authorization': 'Bearer ' + ACCESS_TOKEN,
  };

  var options = {
    "method": "post",
    "headers": headers,
    "payload": JSON.stringify(postData)
  };
  var response = UrlFetchApp.fetch(url, options);
}

```
こちらもコード内のコメントに説明を書いていますが、更なる説明が必要な部分はこちらかと思います。

```js:コード.gs
allData.forEach(function(e){ //全てのデータを回す
    if(e[0].getFullYear() == today.getFullYear() && e[0].getMonth() == today.getMonth() && e[0].getDate() == today.getDate() && e[0].getHours() < 5.0){ 
      sendData += "\n\n・"+e[1];
    }else if(e[0].getFullYear() == yesterday.getFullYear() && e[0].getMonth() == yesterday.getMonth() && e[0].getDate() == yesterday.getDate() && e[0].getHours() >= 5.0){
      sendData += "\n\n・"+e[1];
    }else{
      sendData += "";
    }
  });
```
まず、forEachでスプレッドシート内の全てのデータを回していきます。
そして、この記事の目的である<b>「明日の自分にメッセージを残す」</b>ために、前日の朝５時から、今日の朝５時までのデータをとってきています。(これは自分の生活リズムに合わせて時間を変えてください)
<br>


```js:コード.gs
if(e[0].getFullYear() == today.getFullYear() && e[0].getMonth() == today.getMonth() && e[0].getDate() == today.getDate() && e[0].getHours() < 5.0){ 
      sendData += "\n\n・"+e[1];
    }
```
こちらのif文の説明ですが

```js
e[0].getFullYear() == today.getFullYear() && e[0].getMonth() == today.getMonth() && e[0].getDate() == today.getDate()
```
forEachで取り出されたメッセージデータ(<b>e</b>)の中から日付(<b>e[0]</b>)を取り出し、今日の日付と比較していきます。(もっといい書き方があるかも。。。)

「年」「月」「日」と比較していき最後に、時間を「朝５時以内」と設定します。

```js
e[0].getHours() < 5.0
```
これらを全て日本語化すると<b>「今日の朝５時以内に送信されたメッセージ」</b>となります。



```js
sendData += "\n\n・"+e[1];
```
そして、この部分で送信するメッセージ(sendData)に、シートに保存しているメッセージ（<b>e[1]</b>）を入れています。
メッセージが送信された時に見やすくするために、メッセージの前に改行を入れています。

次のelse ifの部分で同様に<b>「昨日の朝５時以降に送信されたメッセージ」</b>を条件としています。

```js
else if(e[0].getFullYear() == yesterday.getFullYear() && e[0].getMonth() == yesterday.getMonth() && e[0].getDate() == yesterday.getDate() && e[0].getHours() >= 5.0){
      sendData += "\n\n・"+e[1];
    }
```

これらから<b>「昨日の朝５時〜今日の朝5時までに送信されたメッセージを送信」</b>となるわけです。

##工程３：指定時間に送信されるようにする
最後に、GASのトリガーを使って送信する時間を指定していきます。

![スクリーンショット 2020-12-15 19.32.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/eaca8dda-fbf1-36da-924a-bae1225bf0f8.png)
「編集」から「現在のプロジェクトのトリガー」を選択してください。

するとトリガー一覧の画面になるので、左下の「トリガーを追加」を押してください。

![スクリーンショット 2020-12-15 19.33.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552691/a7a3ef1c-4071-44c7-2085-f2a0b3b943a0.png)
そして、この画像のように設定していただければ、保存したメッセージが「午前7時〜8時」の間に送信されます。
1時間のブレ幅がありますが、自分的にはこの時間帯にきてくれれば十分なのでこうしています。
完璧な時間指定をしたい場合は、こちらのサイト
[Google Apps Script で毎日決まった時刻にスクリプトを実行するトリガー設定](https://tonari-it.com/gas-trigger-set/)
が参考になるかと思います。

これで上手くいけば、毎朝メッセージが届きます！！

##最後に
初めてのLINEbot作成で、アドベントカレンダーの日付までに間に合わない気がしていましたが、なんとか間に合いました笑

コードの内容についてですが、そこまで複雑なものではなく、応用が効くと思うので色々な方法で活用していただければと思います！

ちなみに、自分は寝る前に急にモチベが上がる時があるので、次の日の朝にもモチベを維持してくれそうな文章を送ってます笑