スプレッドシートのそれ、Slackに通知させようぜ！

## ある日のパイセン「あれ、トニーって今日休みかい？」

え、ゴシップ好きのトニーが今日休みかって？

いや確かに今日は雑談のチャンネルに出没してないし
休みなのかもしれないな

そう思ったけど、
そのときは総務のキャサリンが教えてくれて解決したんだ

「トニー？ああ、休みよ休み、ずっと休みだったらいいのにね」

おいおい、トニー、嫌われてるな。

さては最近、キャサリンについて何かゴシップをでっち上げたな？
まったく困ったやつだよ


## キャサリン「これ、どうにかSlackに通知とかできないわけ？」


ウチはまだ小さい会社だから、`有給申請はGoogleフォームでやっていて`
集計されるスプレッドシートは総務しか見られないんだ
（どうやら申請系が全部まとまったシートらしい）

だから休む人は別にカレンダーに登録しておかないといけないし
今回みたいに、「あれ？今日休みだっけ？」みたいなことが起きるんだ！


キャサリンが半ギレになるのも無理はないさ。

トニーにあることないこと、でっち上げられたあげく
トニーの有給申請の尻拭いをさせられてるんだからね！


**ああ、愛しのキャサリン**
**任せておけ！**

僕がBotを作って解決してやろう！


## GAS、JS書けたらピースオブケーク！


知っている人も使ったことある人も多いだろう`Google Apps Script`

そして`SlackのIncoming webhook`を使ってBotをつくり、

キャサリンに捧げるんだ！


[Google Apps Script](https://workspace.google.co.jp/intl/ja/products/apps-script/) 通称、GASは
Javascriptを使えるFaaS（Function as a Service）だ

何言っとんじゃ、という人は、ぜひ調べてみてくれ！


簡単に言えば、サーバーを用意しなくてもプログラムを実行できて
いろんな便利なメソッドも用意してくれているワークスペースってことさ！



[SlackのIncoming webhook](https://api.slack.com/messaging/webhooks)は、
他のアプリからSlackにメッセージを送るためのものだ

Botが作れると思っておけばいいだろう！


ああ、それから…
すまないが、これらの基本的な使い方は、この記事では書かないんだ！

なぜかって？
書いている時間がないんだ
キャサリンとのディナーがあるからさ！




## キャサリンを落とす、Slack Botができるまで


キャサリンにもらった、スプレッドシートの、有給申請のシートはこんな形式になっていた

![Screen Shot 2021-12-03 at 20.42.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/d9326463-fe54-6f3d-e7b9-5ce7df705b0d.png)


整理してみよう！


**実現したいこと**
今日、有給で休みの人の名前を、朝9時から10時くらいにSlackの挨拶チャンネルに通知する



**必要なこと**
1. 申請一覧のスプレッドシートから有給申請シートを取得する
2. 有給申請シートにある、すべてのデータの開始と終了を取得する
3. 2のそれぞれのデータに対して、今日が有給かどうかを判定する
4. 3で有給だったら、そのデータの氏名を取得して、保持する
5. 全部のデータについて2〜4が終わったら、Slack用のメッセージに整形して送信する

こんな感じだろう！

そして、忘れちゃいけない
6. そもそも休日や祝日だったらBotに通知させない

これは大事だ、休日に通知がくるとキャサリンが怒ってしまうからね！


必要なこと、を順に実行していくメソッドはこんな感じになった！


```.js

function notifyHolidayStaffToSlack() {
  const currentDate = new Date();
  if(isHoliday(currentDate)) return; // 休日や祝日だったらBotに通知させない

  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(),
    sheet = spreadsheet.getSheetByName('有給申請'),
    dataCnt = sheet.getLastRow(),
    nameCell = 2, // 氏名のセル
    fromCell = 3, // 開始のセル
    toCell = 4; // 終了のセル

  let absenceMembers = []
  for(let i = 2; i <= dataCnt; i++){
    const holidayFrom = new Date(sheet.getRange(i, fromCell).getValue()),
      holidayTo = new Date(sheet.getRange(i, toCell).getValue()),
      is_absence = isAbsenceToday(currentDate, holidayFrom, holidayTo) // 今日が有給かどうかの判定

      if(is_absence) absenceMembers.push(sheet.getRange(i, nameCell).getValue()) // 有給だったら、そのデータの氏名を取得して保持
  }
  
  const message = formatMessage(absenceMembers, currentDate) // Slackへのメッセージに整形
  notifyToSlack(message) // Slackに通知
}

```

メッセージの整形は、キャサリンが喜んでくれるように
少し明るくしておいたんだ！

```.js

function formatMessage(items) {
  let  message = 'おはようございます🙌　本日お休みのメンバーはいません！\n今日も1日よろしくお願いします🎉';
  if(items.length == 0) return message;
  
  message = 'おはようございます🙌　本日お休みのメンバーは\n';
  items.forEach(item => {
    message = `${message}${item}さん\n`
  })
  message = `${message}です！　今日も1日よろしくお願いします🎉`

  return message 
}

```

一応、slackへの通知のメソッドも載せておこう
シンプルで、普通にPOSTすればようさそうだったよ！

```.js

function notifyToSlack(body) {
  const endpoint = 'Incoming webhookで取得したURL',
    data = {
      'channel' : '#チャンネル名',
      'username' : '本日のお休みメンバーBot',
      'attachments': [{
        'text' : body,
      }]
    };

  const payload = JSON.stringify(data),
    options = {
      'method' : 'POST',
      'contentType' : 'application/json',
      'payload' : payload
    };
  UrlFetchApp.fetch(endpoint, options);
}
```


## その後

ここまで読んでくれてありがとう！

Botは、こんな感じで送られてくるようになった！
（これはテストの時の画像だから、日付を変えて2回送っているが、運用後はちゃんと毎日定時に教えてくれている！）

![Screen Shot 2021-12-03 at 21.05.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/ace61d5f-9432-d11a-d4b3-243859ed7289.png)


え？なに？
その後って、Botじゃなくてキャサリンとどうなったんだって？

まったく、キミも知りたがりだな！

Botが大成功したお陰で、キャサリンにディナーに誘われたんだ！
なんでも、お礼がしたいんだってさ！

これからどうなるか？

急遽、明日に有給申請いれるかもしれないから
Botが流れてきたら、察してくれよな！


**Follow ME !!!**
**I'm sure to follow you back!**
twitter: [@marty_ojiya](https://twitter.com/marty_ojiya)