spreadsheetからcalendarに予定を作成する + slackに自動投稿する

spreadsheetに書き込んだ内容をcalendarに自動で追加するGoogle Apps Script(gas)

- [【コピペでOK！】スプレッドシートとカレンダーを連携してイベントを一括登録する方法](https://xn--t8j3bz04sl3w.xyz/spreadsheet/calendar-renkei/3703/)

を参考に, gasで試してみました. 

# 作成

## カレンダーIDを取得
- google calendarを開く
- 書き込みたいカレンダーのオーバーフローメニューをクリックし, `設定と共有`を開く
![スクリーンショット 2018-08-22 19.20.21.png](https://qiita-image-store.s3.amazonaws.com/0/102253/9a8aefae-7459-d313-4cd6-cf27a259edb9.png)

- `カレンダーの統合`の`カレンダーID`を以下のcode内で使用する
![スクリーンショット 2018-08-22 19.20.41.png](https://qiita-image-store.s3.amazonaws.com/0/102253/129509df-2a49-3809-c26a-aa9254d68311.png)


## Google Apps Scriptでcodeを書く
- speadsheetを開く
- `Tools`, `Script editor`でgasの編集画面を開く
![スクリーンショット 2018-08-22 18.59.48.png](https://qiita-image-store.s3.amazonaws.com/0/102253/5a757b43-0005-5639-b0b9-748719eee4be.png)

- codeを書いて保存. 
    - `XXXXXXXXXXXXXXXXXXXXX@group.calendar.google.com`は書き込み先のカレンダーID. 
      自分のものに書き換える. 

```js:addEventsToCalendar.js
function addEventsToCalendar(){
  var sht, i, eventStartDay, eventEndDay, eventname, place, url, added;

  sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet1");
  for(i = 2; i <= sht.getLastRow(); i++){
    added = sht.getRange(i,1).getValue();
    if(added == "登録する"){
      eventStartDay = sht.getRange(i,2).getValue();
      eventEndDay   = sht.getRange(i,3).getValue();
      eventname     = sht.getRange(i,4).getValue();
      place         = sht.getRange(i,5).getValue();
      url           = sht.getRange(i,6).getValue();
      var starttime = sht.getRange(i,7).getValue();
      var endtime   = sht.getRange(i,8).getValue();

      var startDay = Utilities.formatDate(eventStartDay,"JST","yyyy/MM/dd");
      var endDay   = Utilities.formatDate(eventEndDay,"JST","yyyy/MM/dd");

      if(starttime == ""){
        var start = new Date(startDay);　
      }else{
        var HStart = starttime.getHours();
        var MStart = starttime.getMinutes();
        var SStart = starttime.getSeconds();
        var start = new Date(startDay+" "+HStart+":"+MStart+":"+SStart);　
      }

      if(endtime == ""){
        var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
        var endTemp = new Date(endDay);
        var end = new Date(endTemp.getTime() + MILLIS_PER_DAY);
      }else{
        var HEnd = endtime.getHours();
        var MEnd = endtime.getMinutes();
        var SEnd = endtime.getSeconds();
        var end = new Date(endDay+" "+HEnd+":"+MEnd+":"+SEnd);
      }

      Cal = CalendarApp.getCalendarById("XXXXXXXXXXXXXXXXXXXXX@group.calendar.google.com");
      if(starttime == "" || endtime == ""){
        Cal.createAllDayEvent(eventname,start,end,{location:place,description:url});
      }else{
        Cal.createEvent(eventname,start,end,{location:place,description:url});
      }
      sht.getRange(i,1).setValue("登録完了");
    }
  }
}
```

![スクリーンショット 2018-08-22 19.04.12.png](https://qiita-image-store.s3.amazonaws.com/0/102253/60184015-dbab-7666-c693-69a30c50965c.png)


- triggerを設定する
    - `Time-driven`, `From spreadshhet`などでtriggerを追加
    - `Edit`, `Currentproject's triggers`を選択

![スクリーンショット 2018-08-22 19.07.05.png](https://qiita-image-store.s3.amazonaws.com/0/102253/0ed6b939-7aab-f887-9736-370d76876db3.png)
![スクリーンショット 2018-08-22 19.07.20.png](https://qiita-image-store.s3.amazonaws.com/0/102253/421e9b7c-f435-0944-1500-5de8372819d2.png)



## 予定を書く
- speadsheetに戻る
- A - H列に下記フォーマットで予定を書き込む. 

| カレンダー登録状況 | 開始日 | 終了日 | イベントの名前 | 場所 | URL | 開始時刻 | 終了時刻 |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|

![スクリーンショット 2018-08-22 18.47.34.png](https://qiita-image-store.s3.amazonaws.com/0/102253/083320cd-149d-3433-36b8-7cbf9c645ac1.png)
(予定内容は例です)

- `カレンダー登録状況`は
    - 未選択 (何も書き込んでいない際に指定)
    - 登録する (予定についての情報を書き終えて, カレンダーに登録したいと思った際に指定)
    - 登録完了 (書き込まれるとこのように変化)
の3種類にした. 

- `開始時刻`, `終了時刻`を指定していない場合は終日の予定として登録される. 

- 右にある`登録する`ボタンは手動用のボタン. デバックの時に便利というだけで作成しなくても良い. 
    - 図形を作成して, `Assign script...`で, function名(`addEventsToCalendar`)を指定すれば作成できる

![スクリーンショット 2018-08-22 19.11.06.png](https://qiita-image-store.s3.amazonaws.com/0/102253/8c3122b2-46b3-982e-a078-27c38ed1f7a6.png)
![スクリーンショット 2018-08-22 19.15.20.png](https://qiita-image-store.s3.amazonaws.com/0/102253/072f15c1-9b0f-3719-3b99-d9f4a8d85206.png)

# 実行
- `Time-driven`で指定していれば, 指定時間間隔で実行されてgoogle calendarに追加される. 
- ボタンを作成していた場合は, ボタンをクリックすれば追加される. 
- `カレンダー登録状況`を`登録する`にしている行のみ, 実行時にカレンダーに追加される(codeでそう設定しているだけ)

# references
- [【コピペでOK！】スプレッドシートとカレンダーを連携してイベントを一括登録する方法](https://xn--t8j3bz04sl3w.xyz/spreadsheet/calendar-renkei/3703/)
- [Google Apps Scriptをスマホから実行する](https://qiita.com/mkgscdakmol/items/06ba578a65f7769d1239)
- [Google Apps Script: createAllDayEvent(title, startDate, endDate, options)](https://developers.google.com/apps-script/reference/calendar/calendar-app#createAllDayEvent(String,Date,Date,Object))
- [Google スプレッドシートのセルにプルダウンリストを作成する](https://www.master-apps.jp/document/google-documents-pulldown.html)


# 追記: slackにも書き込む (2018/09/15)
- [Slack API 推奨Tokenについて](https://qiita.com/ykhirao/items/3b19ee6a1458cfb4ba21)
にてslack用のappを作成し, 

- [GASでSlackにランダムなメッセージbotを作ってみよう](http://tech.innovation.co.jp/2018/05/07/try-gas-with-slack.html)
を参考に, Incoming Webhooksを追加し, 

下記のようにgasを書き換えればslackにも自動投稿できるようになります


```js:addEventsToCalendar.js
function addEventsToCalender(){
  var sht, i, eventStartDay, eventEndDay, eventname, place, url, added;

  sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet1");
  for(i = 2; i <= sht.getLastRow(); i++){
    added = sht.getRange(i,1).getValue();
    if(added == "登録する"){
      eventStartDay = sht.getRange(i,2).getValue();
      eventEndDay   = sht.getRange(i,3).getValue();
      eventname     = sht.getRange(i,4).getValue();
      place         = sht.getRange(i,5).getValue();
      url           = sht.getRange(i,6).getValue();
      var starttime = sht.getRange(i,7).getValue();
      var endtime   = sht.getRange(i,8).getValue();

      var startDay = Utilities.formatDate(eventStartDay,"JST","yyyy/MM/dd");
      var endDay   = Utilities.formatDate(eventEndDay,"JST","yyyy/MM/dd");

      if(starttime == ""){
        var start = new Date(startDay);　
      }else{
        var HStart = starttime.getHours();
        var MStart = starttime.getMinutes();
        var SStart = starttime.getSeconds();
        var start = new Date(startDay+" "+HStart+":"+MStart+":"+SStart);　
      }

      if(endtime == ""){
        var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
        var endTemp = new Date(endDay);
        var end = new Date(endTemp.getTime() + MILLIS_PER_DAY);
      }else{
        var HEnd = endtime.getHours();
        var MEnd = endtime.getMinutes();
        var SEnd = endtime.getSeconds();
        var end = new Date(endDay+" "+HEnd+":"+MEnd+":"+SEnd);
      }

      Cal = CalendarApp.getCalendarById("XXXXXXXXXXXXXXXXXXXXXXX@group.calendar.google.com");
      if(starttime == "" || endtime == ""){
        Cal.createAllDayEvent(eventname,start,end,{location:place,description:url});
      }else{
        Cal.createEvent(eventname,start,end,{location:place,description:url});
      }

      postSlack("*" + startDay + " - " + endDay + "* \\n" + eventname + " @ " + place + "\\n" + url);
      
      sht.getRange(i,1).setValue("登録完了");
    }
  }
}


// slackにメッセージを送る
function postSlack(text){
  var url = "https://hooks.slack.com/services/XXXXXXX/XXXXXXX/XXXXXXXXXXXXXXXXXXX";
  var options = {
    "method"  : "POST",
    "headers" : {"Content-type":"application/json"},
    "payload" : '{"text":"' + text + '"}'
  };
  UrlFetchApp.fetch(url, options);
}
```