弊社猫会長に日直当番を任命していただくbotを作った

##概要

弊社は一軒家をオフィスにしており、自分たちでオフィスの掃除をしている。
最初の頃は毎月カレンダーを作って日直を決めていたのだが、カレンダーを作るのも、カレンダーを確認するのも手間だよねということになり、Slackに専用のチャンネルを作り、そこに日直当番を通知するようにした。
実は今回紹介するのはv2で、v1より格段に進化している（大げさ）

##参考にさせていただいた記事

手順はほぼこちらの記事と同じです。

[掃除当番の割当を Google Apps Script で自動化して Slack の BOT として通知](http://qiita.com/amotz/items/332b26a1c9237b215f1e)


##Googleスプレッドーシートで当番表を作る

弊社の場合は、下記のようなものを作った。

|担当|
|---|
|<@milk>|
|<@hana>|
|<@chimaki>|
|<@ribbon>|
|<@sakura>|
|<@mii>|

`@hoge` はSlackのユーザーアカウント名。
`<@hoge>` とすることで、Slack投稿時にメンションが飛ぶようになる。
ただし、そのアカウントが存在しないと `. . .` と投稿される模様。

##Slack Web API tokenを取得する

Slackの仕様が変わっていました。
詳しくは下記記事を参照ください。
[Slack APIのTokenの取得・場所](http://qiita.com/ykhirao/items/0d6b9f4a0cc626884dbb)
[Slack API 推奨Tokenについて](http://qiita.com/ykhirao/items/3b19ee6a1458cfb4ba21)

##Google Apps Scriptでプログラムを書く

Googleスプレッドシートを開いて、「メニュー＞ツール＞スクリプトエディタ...」を選択。
スクリプトエディタが開くので、そこにプログラムを書く。

###SlackAppライブラリを導入

どんなものかは下記を参照。
[Slack BotをGASでいい感じで書くためのライブラリを作った](http://qiita.com/soundTricker/items/43267609a870fc9c7453)

スクリプトエディタの「リソース＞ライブラリ...」を選択。
「ライブラリを検索」の入力欄に下記のLibrary Keyをコピペ。

```bash:LibraryKey
M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO
```

バージョンを選択して「保存」をクリック。
私はバージョン22を使用しています。

###ソースコード

参照させていただいた記事をベースにしているので、メソッド名がそのままです。。。
変数名も適当。

```javascript:コード
//slack定義
var slack = {
    postUrl: "https://slack.com/api/chat.postMessage",
    token: "xoxp-your-token",  //取得したSlackWebAPIのtoken
    ChannelId: "general",  //投稿するチャンネルのChannelId
    userName: "Futaba",  //botの名前
    iconEmoji: ":futaba:"  //botのアイコン
}

//メンバー・役割のデータをスプレッドシートから取得
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lastrow = sheet.getLastRow();

var members = sheet.getSheetValues(2, 1, lastrow-1, 1);  //データ行のみを取得する

var days = ["月：", "火：", "水：", "木：", "金："];

//当日の日直を通知
function notifyTodayCleaningRole() {
  //平日のみ実行
  var currentDate = new Date();
  if (!isWeekDay(currentDate)) {
    return;
  }

  //祝日は実行しない
  if (isEventsForDay(currentDate)) {
    return;
  }

  var title = " 本日の日直よ！ 私の遊び相手も忘れずにね！\n\n";
  var member = selectMember();
  updateMembersSheet();
  sendMessageToSlack(title, member);
}

//明日の日直を通知
function notifyTomorrowCleaningRole() {
  //平日のみ実行
  var currentDate = new Date();
  if (!isWeekDay(currentDate)) {
    return;
  }

  //祝日は実行しない
  if (isEventsForDay(currentDate)) {
    return;
  }
  var title = " 次の日直は貴方よ！ みるくに食べさせすぎないでね！\n\n";
  var member = selectMember();
  sendMessageToSlack(title, member);
}

// 今週の日直一覧を通知（トリガーで月曜日に起動するようにしている）
function notifyCurrentWeekCleaningRole() {
  var member = "";
  for (var i = 0; i < 5; i++) {
      var currentDate = new Date();
      currentDate.setDate(currentDate.getDate() + i);
      if (isEventsForDay(currentDate)) {
        member += days[i] + "休日のためなし" + "\n";
      } else {
        var rotateMembers = rotate(members);  
        member += days[i] + rotateMembers[0] + "\n";
      }
  }
  var title = " 今週の日直一覧よ！ みんながんばってね！\n\n";
  sendMessageToSlack(title, member);
}


function selectMember() {
  //当番を割り当てる
  var selectMembers = ""; 
  var rotateMembers = rotate(members);  
  selectMembers = selectMembers + rotateMembers[0] + "\n";

  return selectMembers;
}

//配列の要素を後ろにずらして、最後の要素を先頭に移動する
function rotate(array){
  array.unshift(array[array.length-1])
  array.pop();
  return array;
}

// 平日か判定
function isWeekDay(currentDate) {
  var weekday = currentDate.getDay();
  if (weekday == 0 || weekday == 6) {
    return false;
  }
  return true;
}

// 祝日か判定
function isEventsForDay(currentDate) {
  var calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  if (calendar.getEventsForDay(currentDate, {max: 1}).length > 0) {
    return true;
  }
  return false;
}

//Slackにメッセージを送る
function sendMessageToSlack(title, member) {
  var testSuffix = "";
  var slackApp = SlackApp.create(slack["token"]);
  var Message = slackApp.postMessage(
      slack["ChannelId"], testSuffix + title + member + "", {
      username : slack["userName"],
      icon_emoji: slack["iconEmoji"]
    } 
  ); 
}

//割り当てた結果をスプレッドシートにも反映させる
function updateMembersSheet() {
//  var rotateMembers = rotate(members);  
  for(var i = 0; i < members.length; i++){
    sheet.getRange(i+2, 1).setValue(members[i]);
  } 
}
```

###機能説明

説明というほどのものでもないけど。

**notifyTodayCleaningRole()**
当日に通知を行うためのメソッド。
平日のみ稼働。

**notifyTomorrowCleaningRole**
明日の当番の通知を行うためのメソッド。
平日のみ稼働。

**notifyCurrentWeekCleaningRole**
一週間分の当番の通知を行うためのメソッド。
祝日が含まれる場合は「休日のため当番なし」といった形で通知を行う。

v1は `notifyTodayCleaningRole()` だけだったんだけど、v2で機能を追加した。

###実行はトリガーで行う

スクリプトエディタの「リソース＞現在のプロジェクトのトリガー」を選択。
弊社の場合は下記のように設定。

![スクリーンショット 2016-12-08 19.21.00.png](https://qiita-image-store.s3.amazonaws.com/0/81221/df3eba65-bed1-8543-36af-7428db3d14e5.png "サンプル1.png")

トリガーの時間指定はほんとに一時間の間のどこか、なので、10:59に通知が行われてドギマギすることもあるｗ

##実行してみた

猫社員のアカウントがないので、メンションじゃないけど。

![スクリーンショット 2016-12-08 19.19.09.png](https://qiita-image-store.s3.amazonaws.com/0/81221/fdb83355-c97b-b807-9ab8-3aa230b9def8.png "サンプル2.png")

##まとめ

ふたば会長に任命いただき光栄であります！
きりきり掃除いたします！