朝会のfacilitatorをランダムに決めるslack bot

## これは何か
- 平日の決まった時間に、randomに1人、Daily Scrum (≒ 朝会)のFacilitatorを決めるslack botの作り方

## 背景
- Scrum開発を円滑に進めていく上で、Scrum Masterに依存した運用体制はScrum teamの目指すべき姿ではない
- その課題を解決する1つの手段として、Daily ScrumのFacilitatorを回すような運用を入れてみたら、メンバーが能動的になった

## アウトプットイメージ
- 平日の決まった時間に、SpreadSheetから1人randomに選択し、特定のSlackにpostする

### SpreadSheet

<img width="492" alt="スクリーンショット 2020-01-12 20.45.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237015/c6663367-1bd2-61f0-4d3f-ae11c81237ad.png">

### Slack Channel
<img width="429" alt="スクリーンショット 2020-01-12 20.42.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237015/8f409d56-d75c-5734-e02b-92a306ffc464.png">


## ソースコード
```javascript

var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var lastrow = sheet.getLastRow();
var lastcol = sheet.getLastColumn();
var sheetdata = sheet.getSheetValues(1, 1, lastrow, lastcol);
var calJa = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');

function Facilitator(){
  var today = new Date();
  var weekInt = today.getDay();
  if(weekInt == 0 || weekInt == 6){
    return false;
  }
  else if(calJa.getEventsForDay(today).length > 0){ 
    return false;
  }
  else{ 
    var row = Math.floor(Math.random() * 7) + 2;
    var Name = sheetdata[row][0];  
    var row2 = Math.floor(Math.random() * 7) + 2;
    var Face = sheetdata[row2][1];
    var slackAccessToken = 'xxxxx(slack workspaceで一意に持っているので、要確認)';
    var slackApp = SlackApp.create(slackAccessToken);
    var channelId = "xxx-yyy-2020(postしたいslack channel名)";
    var Message = slackApp.postMessage(channelId,"Today's facilitator is…" + Name +"-san"+ " " + "Let's GoGo！" + Face);
  }
}
```

## ざっくり構成解説
### SpreadSheetにアクセスして、記述してある内容を取得する
```javascript
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var lastrow = sheet.getLastRow();
var lastcol = sheet.getLastColumn();
var sheetdata = sheet.getSheetValues(1, 1, lastrow, lastcol);
var calJa = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
```
- `SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()`でGASからアクティブなSpreadSheetにアクセスします
- `getLastRow()`で、アクセスしたSpreadSheetの最後の行を取得します
- `getLastColumn()`で、同様に最後の列を取得します
- `getSheetValues(startrow, startcol, lastrow, lastcol)`で、アクセスしているSpreadSheet内の値全体を取得します
    - 前述の`getLastRow(), getLastColumn()`で**対象範囲内の最後の行と列を動的に取得できる**ので、メンバーが増える or 減る(行++ or 行--)、投稿したい要素が増える or 減る(列++ or 列--)場合でも大丈夫
- `CalendarApp.getCalendarById('省略')`では、Google Calenderの **日本の祝日カレンダー**にアクセスしています

### SpreadSheetから、特定のNameとFaceを選択して、Slack Channelに送る

```javascript

function Facilitator(){
  var today = new Date();
  var weekInt = today.getDay();
  if(weekInt == 0 || weekInt == 6){
    return false;
  }
  else if(calJa.getEventsForDay(today).length > 0){ 
    return false;
  }
  else{ 
    var row = Math.floor(Math.random() * 8) + 2;
    var Name = sheetdata[row][0];  
    var row2 = Math.floor(Math.random() * 8) + 2;
    var Face = sheetdata[row2][1];
    var slackAccessToken = 'xxxxx(slack workspaceで一意に持っているので、要確認)';
    var slackApp = SlackApp.create(slackAccessToken);
    var channelId = "xxx-yyy-2020(postしたいslack channel名)";
    var Message = slackApp.postMessage(channelId,"Today's facilitator is…" + Name +"-san"+ " " + "Let's GoGo！" + Face);
  }
}
```
- `today.getDay()`で、指定された日付の「曜日」を取得している
    - 返される値は0~6で、`0 == 日曜日, 1 == 月曜日... ,6 == 土曜日`となります
- `weekInt == 0 || weekInt == 6`で、**休日(土曜日 or 日曜日)は送らない**ようにしている
- `calJa.getEventsForDay(today).length > 0`で、**祝日のイベントがカレンダー上に1つでもある時は送らない**ようにしている
- `Math.floor(Math.random() * 8) + 2`では、**最大で9、最小で2となる行番号**を1つ取得して、1列目に適用している
    - `Math.floor()`で、()内の値を小数点以下を切り捨てる
    - `Math.random()`で、0以上1未満 (0は含むが1は含まない)の間でrandomな値を返す
    - 次に出てくる`row2`の中身も同じことをしている
- `slackAccessToken`周りは、[GASとSlackではじめるチャットボット〜初心者プログラマ向け〜](https://qiita.com/yukihirai0505/items/cbb9832d42dc627800fb)辺りを参考にする
- `channelId = "xxx-yyy-2020(postしたいslack channel名)"`ではpostしたいSlack Channel名を**#抜き** で記述する
- `slackApp.postMessage(channelId,"Today's facilitator is…" + Name +"-san"+ " " + "Let's GoGo！" + Face)`で、実際に該当のSlack Channelにpostするが、textで直接記述している部分は変更してもらって大丈夫(ex. `"Today's facilitator is…"`, `"-san"` etc)

## トリガー
- Daily Scrumが毎朝12:30~12:45だったので、余裕を持って、10:00~11:00の間に発火するように設定してます

<img width="720" alt="スクリーンショット 2020-01-12 21.46.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237015/dd26c3cc-7fe0-db1a-88f1-4d769c89591d.png">


## 参考
- [毎週のお掃除当番をSlackへランダムで通知する](https://qiita.com/Yamotty/items/b0eb3d855c4266b18b39)
    - 基本構成は上記をかなり参考にさせていただきましたmm
- [掃除当番の割当を Google Apps Script で自動化して Slack の BOT として通知](https://qiita.com/amotz/items/332b26a1c9237b215f1e) 
    - 筆者は上記のpostを参考にしていたので、先にそちらを確認するとスムーズかもしれません