ブログ

FLYWHEEL アドベントカレンダーを支える技術

FLYWHEEL のエンジニア兼、アドベントカレンダーの編集長、太田です。
弊社のエンジニアが苦しみ楽しみながら書いているアドベントカレンダーですが、編集長としては少しでも原稿を落とすリスクとみんなの苦労を減らしたい……。悩んだ結果、アドベントカレンダーの予定を皆さんのカレンダーに追加することで自分の順番がいつなのかわかるようにしてみました。今回は、Google Apps Script を使ってスプレッドシートから自動的にGoogleカレンダーの予定を作成する仕組みを紹介したいと思います。
アドベントカレンダーのスケジュールは以下のようなスプレッドシートで管理しているのですが、

それを元にスクリプトが自動で Google カレンダーを作成します。

さらに各担当者を予定に追加することで、自分の担当日をわかりやすくしています。

アドベントカレンダーに限らず、予定をスプレッドシートでまとめて作りたいとき、例えば1 on 1 ミーティングのスケジュールをスプレッドシートで管理したり、「結婚何周年」といったイベントをスプレッドシートで作ってまとめて登録したりと、いろいろと応用できるはずです。

準備

スケジュール管理用スプレッドシートの作成:最低でも予定の日付とタイトルの入ったスプレッドシートを作成しましょう。
カレンダーの作成:予定を追加するためのカレンダーを作成しましょう。既存のカレンダーを使ってもいいですし、Google カレンダーの[+]ボタン→[新しいカレンダー]から専用のカレンダーを新しく作ることもできます。カレンダーの設定から [カレンダー ID] を控えておいてください。

Google Apps Script

Google カレンダーやスプレッドシートをチョチョイと使って自動化したい! というときに便利なのが 「Google Apps Script」 です。今回は特定のスプレッドシートに紐付いたスクリプトを作りたいので、スプレッドシートのメニューの [ツール] 、 [<>スクリプトエディタ] から作成します。
今回使う API は Calendar Service APISpreadsheet Service API です。APIの詳細は各リファレンスを参照してください。スプレッドシート上のアドベントカレンダーの予定をGoogleカレンダーにコピーするコードは以下のようになります。

var CALENDAR_ID = '${your_calendar_id}'; // Option 1
var SHEET_NAME = '${your_sheet_name}'; // Option 2
var DATE_COLUMN = 1;
var TITLE_COLUMN = 2;
var GUEST_COLUMN = 3;
var STATUS_COLUMN = 5;
var EVENT_ID_COLUMN = 6;
function syncCalendar() {
  // Get the calendar object.
  var calendar = CalendarApp.getCalendarById(CALENDAR_ID);
  // Fetch the calendar data from the spreadsheet.
  var sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
  var range = sheet.getRange(2,2,25,6); // Option 3
  // Iterate over entries.
  for (var i = 1; i <= range.getNumRows(); i++) {
    // Get data from columns.
    var date = range.getCell(i, DATE_COLUMN).getValue();
    var status = range.getCell(i, STATUS_COLUMN).getValue();
    var title = range.getCell(i, TITLE_COLUMN).getValue() || '未定';
    if (status != '') {
      title = status + ': ' + title;
    }
    var eventCell = range.getCell(i, EVENT_ID_COLUMN);
    var eventId = eventCell.getValue();
    var event = calendar.getEventById(eventId);
    var author = range.getCell(i, GUEST_COLUMN).getValue();
    if (event == null) {
      createEvent(calendar, title, date, author, eventCell);
    } else {
      var guest = event.getGuestList()[0];
      if (guest.getEmail() != author) {
        // Recreate the event in order to send the invitation.
        event.deleteEvent();
        createEvent(calendar, title, date, author, eventCell);
        continue;
      }
      // Update the event.
      if (event.getAllDayStartDate() != date) {
        event.setAllDayDate(date);
      }
      if (event.getTitle() != title) {
        event.setTitle(title);
      }
    }
  }
}
function createEvent(calendar, title, date, author, eventCell) {
  var options = { guests: author, sendInvites: true };
  var event = calendar.createAllDayEvent(title, date, options);
  eventCell.setValue(event.getId())
}

使う際には

  1. カレンダーのID
  2. アドベントカレンダーを管理しているシートの名前
  3. カレンダーの予定の入っている範囲

を設定してください。
上記のスクリプトは大まかに解説しますと、スプレッドシートの各行ごとに

  1. 日付、タイトル、担当者、状態を取得
  2. 予定が存在しなければ作成
  3. 予定が存在したら更新

を行っています。
ポイントは

  • イベントのIDをスプレッドシートに保存することで、予定の存在確認や更新を簡単にする。
  • 著者が変わった場合は、予定を再作成することで招待メールを送る。(予定の更新時に通知する方法が見つからず)

点です。
初回の実行時に CalendarApp と SpreadsheetApp のアクセス権限を確認されます。承認すると以降は `syncCalendar` 関数を実行するたびに、あなたの代わりにスプレッドシートを読み、予定を作成してくれます。

トリガーを設定する

アドベントカレンダーに予定の遅れや内容の変更はつきものです。トリガーを設定して、常に最新情報を反映させるようにしましょう。
スクリプトエディタの ⏰アイコンをクリックすると、トリガーを追加できます。 “syncCalendar” をスプレッドシートの編集時に実行することで、カレンダーを常に最新状態に保つことができます。

まとめ

今回はスプレッドシートで管理されているスケジュールを自動でGoogleカレンダーの予定に落とし込む方法を紹介しました。
FLYWHEELでは、同僚の、延いては社会全体のプロダクティビティを改善することに興味がある人材を募集中です!