この記事は フリューAdvent Calendar 2018 の12/14分です。
こんにちは。ピクトリンク事業部開発部の荒木です。普段はピクトリンクというアプリのAndroid版を開発しています。最近発売されたスマブラSPが気になっていますが、時間が溶けるのが怖いので買うかどうか悩んでいます。
今回の記事では、Google Apps Scriptを使って勤怠管理用のSlack Botを作った話をしたいと思います。
作ったもの
Slackの勤怠管理チャンネルに、今日誰が休むのかを投稿してくれるBotを作りました。これまで、今日誰が休むのかはSlackチャンネルを遡らないと分かりませんでしたが、このBotによってその問題が解決されました。
以下のように、勤怠の情報を勤怠管理チャンネルに投稿しておくと

毎日、始業前に今日の勤怠情報を投稿してくれます。

※ FTはフレックスタイムのことです。
使っているもの
勤怠管理Botで使っているものは、以下の2つです。
Slack Outgoing Webhooks
Slack Outgoing Webhooksは、Slack上の特定の文字列をトリガーとして指定したURLにPOSTリクエストを投げられる機能です。POSTリクエストには、投稿者や投稿した本文といった情報が含まれています。
Google Apps Script (GAS)
Google Apps Script(以下ではGASと呼びます)は、Javascript互換のスクリプト言語です。特徴は、Google Apps(Googleドキュメントやスプレッドシートなど)を操作するためのAPIが用意されていることです。また、GASはGoogleドライブ上で保管され、時間やHTTPリクエストをトリガーにして動作させることが可能です。
システム構成
勤怠管理Botのシステム構成は以下のようになっています。動作は、勤怠記録と勤怠集計に分かれます。

勤怠記録

上記のような勤怠に関する投稿をスプレッドシートに記録します。
Slack Outgoing Webhooksによって、GASの勤怠記録コードにこの投稿の情報が含まれたPOSTリクエストが投げられます。
勤怠記録コードは、
- 勤怠対象日:上記の投稿では 12/11
- 勤怠種別:FT
- ユーザー名:araki
- 本文:【FT申請】2018/12/11(火) 10:30 私用のため
- SlackのユーザーID:POSTリクエストに含まれているSlackのユーザーID
を記録します。勤怠対象日と勤怠種別については、投稿の本文から正規表現で抽出します。
実際に勤怠情報をスプレッドシートに記録する部分は以下のようになっています。最後の行で、GASのAPIを呼び出しています。
/**
 * 勤怠を登録する
 *
 * @param kintai 勤怠情報
 */
register(kintai: KintaiInfo) {
  var maxRowCount = 10000; // マジックナンバーです。。とりあえず1万行とってます。
  var kintaiValues = this.sheet.getSheetValues(1, 1, maxRowCount, 3);
  var newLineRow = -1;
  for (var row = 0; row < maxRowCount; row++) {
    var dateCell = kintaiValues[row][0];
    if (dateCell == '') {
      // 空行が来たら終了
      newLineRow = row + 1;
      break;
    }
  }
  var arrData = [
    [
      kintai.getTargetDate(),
      kintai.getType(),
      kintai.getUserName(),
      kintai.getBodyText(),
      kintai.getUserId()
    ]
  ];
  // getRange, setValuesはGASのAPIです。
  this.sheet.getRange(newLineRow, 1, 1, 5).setValues(arrData);
}
※ GASではなくTypeScriptで書かれています。claspというツールで、GASに変換して使っています。
勤怠集計

「Reminder: 今日の勤怠は?」という文字列をトリガーにして、Slack Outgoing WebhooksでGASの勤怠集計コードにPOSTリクエストを投げています。
今日の勤怠情報のみを集計する部分は以下のようになっています。
/**
 * 勤怠情報を取得する
 *
 * @param targetDate 取得対象日
 */
getKintai(targetDate: Date): Array<KintaiInfo> {
  var targetDateText = `${targetDate.getFullYear()}/${targetDate.getMonth() + 1}/${targetDate.getDate()}`;
  var kintaiInfoArray = new Array<KintaiInfo>();
  var maxRowCount = 10000; // これもマジックナンバー。。とりあえず1万行
  // getSheetValuesはGASのAPI
  var kintaiValues = this.sheet.getSheetValues(1, 1, maxRowCount, 5);
  for (var row = 1; row < maxRowCount; row++) {
    var cellData = kintaiValues[row][0];
    if (cellData == '') {
      break;
    }
    var date = cellData as Date;
    // 今日の勤怠情報か?
    if (
      date.getFullYear() == targetDate.getFullYear() &&
      date.getMonth() == targetDate.getMonth() &&
      date.getDate() == targetDate.getDate()
    ) {
      var type = KintaiType.convert(kintaiValues[row][1] as string);
      var name = kintaiValues[row][2] as string;
      var text = kintaiValues[row][3] as string;
      var userId = kintaiValues[row][4] as string;
      kintaiInfoArray.push(new KintaiInfo(targetDateText, type, userId, name, text));
    }
  }
  return kintaiInfoArray;
}
※ このコードもGASではなくTypeScriptで書かれています。
作ってからのこと
自分や一緒に働くメンバーからどんどん要望が出てきたので、少しずつ叶えていきました。
- 勤怠種別ごとに出力してほしい
- 出力のインデントを整えたい
- 登録できたことを通知して欲しい
- 現在登録している勤怠情報を出せるようにしたい
まだ叶えていない要望もあります。
- 間違えて登録した勤怠情報を削除したい
- 曜日も出して欲しい
これだけ要望が出てくるということは、みんなにあるのが当たり前と思ってもらえるようになったのかなと思います。
さいごに
今回、勤怠管理Botを作ってみて、GASで気軽にいろんなことができるということがわかりました。何より、自分が作ったものが一緒に働いているみんなに使ってもらえて、直接フィードバックがもらえるというのがとても嬉しい体験でした。
みなさんも、Google Apps Scriptで何かを作ってみてはいかがでしょうか?