休暇を取っているスタッフにslackでmentionしたときに教えてくれるbotを作った

弊社では、スタッフが社外を飛び回っていることが多く、他のスタッフの休日認識が少し大変です。もちろんGoogleカレンダーを開けばわかるのですが、それなりの人数になってくると当人のカレンダーを見るというのも現実的ではありません。
かといって、休みの日なのに朝slackに一言入れなきゃならないというのもナンセンスだよなと思ってしまいます。

そこで、Googleカレンダー(他の出退勤管理システムでも当然良いと思います)からデータを引っ張ってくることで休日判定を行い、休日だったら教えてくれるような機能をbotにつけてみました。

## botの機能
botはbotkitを使ってnode.jsで動かしています。
bot本体のjs自体はシンプルです。 @だれかのID とメンションしたときに、その人が休日だったらレスポンスを返します。
コードは一般的なサンプルと同じです。

```holidaybot.js
var Botkit = require('botkit');
var controller = Botkit.slackbot();
var bot = controller.spawn({
  token: 'botのトークン'
}).startRTM(function(err,bot,payload) {
  if (err) {
    throw new Error('Could not connect to Slack');
  }
});
//ここから個人判定部分
controller.hears(['ここに休日な人のslackID'],['ambient','direct_message','direct_mention','mention'],function(bot,message) {
  bot.reply(message,  '山田 花子 は本日お休みです');
});
//ここまで個人判定部分
//以下、休みの人数分コードを記述する
```
SlackIDはここから確認が出来ます：https://api.slack.com/methods/users.list

## botの運用方法
`forever start holidaybot.js`
foreverを使って永続化しています。
休日判定をするのは一日一回始業前です。
永続化されている場合に、動的にbotのコマンドを書き換えることはできなさそうなので、cronを使ってプロセスを落とし、holidaybot.jsを書き換えてまたスタートする処理にします。

```$ crontab -e
`# 毎朝7時にファイル書き換え用のスクリプトが起動します。今回はPHPで実装します
0 7 * * * /usr/bin/forever stop 2 && /usr/bin/php /path to phpfile/makeHolidayBotJS.php>> /path to log/makeHolidayBotJS.log 2>&1
`# 上記処理が終わったら、生成されたjsファイルをstartします
3 7 * * * /usr/bin/forever start /path to js/holidaybot.js >> /path to log/holidaybot.log 2>&1
```
##js書き換え用PHP

```makeHolidayBotJS.php
<?php
  $file_name = 'holidaybot.js';
  $dels = 'rm -f /path to js/' + $file_name;
  echo unlink($dels);//稼働中のファイルを削除：ログファイル記録用にecho
  // jsファイルの作成
  touch( '/path to js/' + $file_name );

  // Googleカレンダーや勤怠管理システムから休みのスタッフを判定してリストに突っ込む
  // GoogleカレンダーAPIはこちらのコードを参照：https://developers.google.com/calendar/quickstart/php
  // カレンダー情報の取得と、上述したslackIDをセットにしたCSVを作って読み込んでいます
  // Email,名前,slackID
  $file = new SplFileObject('/path to csv/staffList.csv');
  $file->setFlags(SplFileObject::READ_CSV);
  // CSV内の情報を一行ずつ処理していく
  $uid = 0;
  date_default_timezone_set('Asia/Tokyo'); //タイムゾーンを日本にする
  $today = date('Y-m-d');//今日の日付を取得
  $timeMin = $today.'T00:00:00+09:00';//日本の場合
  $timeMax = $today.'T23:59:59+09:00';//時差がある場合は+9の部分を変更する

  $slackIDs = [];//休日スタッフのslackIDを入れる
  $userNames;//休日スタッフの名前を入れる

  foreach ($file as $line) {
    $records[] = $line;
    $calendarId = $records[$uid][0];
    $calendarName = $records[$uid][1];
    $slackID = $records[$uid][2];

    if ($calendarId) {
    //カレンダーID(メアド)を使ってその日の予定を取得する処理
      $optParams = array(
        'maxResults' => 20,//一日に20件以上入っている人は見たこと無い
        'orderBy' => 'startTime',
        'singleEvents' => true,
        'timeMin' => $timeMin,//取得開始時間
        'timeMax' => $timeMax,//取得終了時間
      );

    //イベント取得
    $results = $service->events->listEvents($calendarId, $optParams);

    //処理開始
    $holidayFlag = false;//初期化
    if (count($results->getItems()) == 0) { //イベントがない場合
       print "本日の予定は有りません\n";//ログ出力用なのでなくても良い
    } else {
       foreach ($results->getItems() as $event) {
         if (strpos($event->getSummary(), '振替休日') !== false or strpos($event->getSummary(), '休暇') !== false or strpos($event->getSummary(), '休み') !== false or strpos($event->getSummary(), 'off') !== false) { // 休みの人が入れているキーワードを設定してるので要調整
           $holidayFlag = true;//フラグを立てる
           $holidayName = $event->getSummary();//何休暇なのかを書き出す場合はこれも使う
         }
     }
    //全イベント処理終了
    if( $holidayFlag == true ) {
      array_push($slackIDs , $slackID);//あとでループで使う
      $userNames[$slackID] = $calendarName;//あとで呼び出すのでslackIDをキーにした連想配列に入れる
    }
    //uidのインクリメント
    ++$uid;
  }
 //CSVファイル一行(ユーザ単位)ずつ実行ここまで
}


//最後にholidaybot.jsを生成する
$input1 = <<<EOT
var Botkit = require('botkit');
var controller = Botkit.slackbot();
var bot = controller.spawn({
  token: 'your bot token'
}).startRTM(function(err,bot,payload) {
  if (err) {
    throw new Error('Could not connect to Slack');
  }
});

EOT; // 最初のbotのtoken使う部分をまとめる

$inputs = [];//プログラム一行ずつを配列にして格納する

//休みスタッフのslackIDsでループ処理
foreach ( $slackIDs as $id){
  array_push($inputs ,"controller.hears(['$id'],['ambient','direct_message','direct_mention','mention'],function(bot,message) {");
  array_push($inputs ,"bot.reply(message,  '$userNames[$id] は本日お休みです');";
  array_push($inputs ,"});";
}
$input2 = implode("\n",$inputs);//配列に入ってる文字列を改行して全部結合
$output = $input1.$input2; //最終的に上部と下部を結合
//ファイルに書き込み
var_dump( file_put_contents( '/path to js/holidaybot.js' , $output));

```
ここまで書いたらcronを起動して毎朝処理させると、簡単にお休みな人がわかります。

<img width="433" alt="holiday.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/22294/ed3bab41-b224-f925-2df8-e86152bb3cb3.jpeg">