COMPANY SERVICE STAFF BLOG NEWS CONTACT

STAFF BLOG

スタッフブログ

TECHNICAL

テクログ

2024.12.13

Google Apps ScriptでGoogleカレンダーの予定をChatWorkに自動投稿する

テクログ

はじめに

下記、2つのスクリプトを作成しました。

・毎週月曜日に、その週(月, 火, …, 日)の予定を自動投稿する
・毎日、その日の予定を自動投稿する(土日を除く)

図1:自動投稿されるメッセージ

ソースコード

コピペするだけで使えるようになっています。
下記、3つの定数を自分の環境に合わせて変更してください。(ソースコード上部に書かれている定数です。)

・SENDER_ACCOUNT_TOKEN
・RECEIVER_ROOM_ID
・YOUR_MAIL_ADDRESS

/**
 * 定数
 */
const SENDER_ACCOUNT_TOKEN = ''; // 送信元アカウントのトークン (チャットワーク画面右上の名前 > サービス連携 > APIトークン)
const RECEIVER_ROOM_ID     = ''; // 送信先チャット部屋のID (URLの「#!rid」以降の数字)
const YOUR_MAIL_ADDRESS    = ''; // あなたのメールアドレス (Googleカレンダーから予定を取得するために使用)

/**
 * 今週(月,火,...,日)の予定をお知らせ
 *
 * @return {void}
 */
function notifyWeeklyEvents() {
  // 今週の開始日と終了日を取得
  const today     = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd 00:00:00');
  const startDate = new Date(today);
  const endDate   = new Date(today);
  endDate.setDate(endDate.getDate() + 7);

  // Googleカレンダーに登録されている予定を取得
  const events = getCalendarEvents(YOUR_MAIL_ADDRESS, startDate, endDate);

  // 送信するメッセージの整形
  const lastWeekEventMessages = [];
  const thisWeekEventMessages = [...Array(7)].map(() => ([]));

  events.forEach((event) => {
    if (event.getStartTime() < startDate) {
      // 先週から継続している予定の場合
      lastWeekEventMessages.push(convMessage(event, startDate));
    } else {
      // 今週の予定の場合
      if (event.getTitle() !== '自宅' && event.getTitle() !== 'オフィス') {
        thisWeekEventMessages[event.getStartTime().getDay()].push(convMessage(event, startDate));
      }
    }
  });

  // 予定がない場合
  let existsEvent = lastWeekEventMessages.length ? true : false;
  for (let i = 0; i < 7; ++i) {
    if (thisWeekEventMessages[i].length) {
      existsEvent = true;
    }
  }
  if (!existsEvent) {
    // チャットワークにメッセージを送信
    sendChatworkMessage(SENDER_ACCOUNT_TOKEN, RECEIVER_ROOM_ID, '※自動投稿\n今週の予定はありません!');
    return;
  }

  let message = '';
  message += '※自動投稿\n'
  message += '今週の予定です!\n';
  message += '[info][title]今週の予定[/title]\n';

  // 今週より前から継続している予定
  if (lastWeekEventMessages.length) {
    message += '▼継続している予定\n';
    lastWeekEventMessages.forEach((msg) => {
      message += `${msg}\n`;
    });
    message += '[hr]\n';
  }

  // 今週の予定
  const eventDate = new Date(startDate.getTime());
  for (let i = 0; i < 7; ++i, eventDate.setDate(eventDate.getDate() + 1)) {
    const day = (startDate.getDay() + i) % 7;
    if (thisWeekEventMessages[day].length) {
      message += Utilities.formatDate(eventDate, 'Asia/Tokyo', `▼MM/dd(${getDayOfWeek(eventDate)})\n`);
      thisWeekEventMessages[day].forEach((msg) => {
        message += `${msg}\n`;
      });
      message += '[hr]\n';
    }
  }
  message += '[/info]\n';

  // チャットワークにメッセージを送信
  sendChatworkMessage(SENDER_ACCOUNT_TOKEN, RECEIVER_ROOM_ID, message);
}

/**
 * 今日の予定をお知らせ
 *
 * @return {void}
 */
function notifyDailyEvents() {
  // 今日の開始日と終了日を取得
  const today     = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd 00:00:00');
  const startDate = new Date(today);
  const endDate   = new Date(today);
  endDate.setDate(endDate.getDate() + 1);

  // 今日が休日なら通知しない
  if (isHoliday(startDate)) {
    return;
  }

  // Googleカレンダーに登録されている予定を取得
  const events = getCalendarEvents(YOUR_MAIL_ADDRESS, startDate, endDate);

  // 送信するメッセージの整形
  const lastWeekEventMessages = [];
  const thisWeekEventMessages = [];

  events.forEach((event) => {
    if (event.getStartTime() < startDate) {
      // 先週から継続している予定の場合
      lastWeekEventMessages.push(convMessage(event, startDate));
    } else {
      // 今日の予定の場合
      if (event.getTitle() !== '自宅' && event.getTitle() !== 'オフィス') {
        thisWeekEventMessages.push(convMessage(event, startDate));
      }
    }
  });

  // 予定がない場合
  if (!lastWeekEventMessages.length && !thisWeekEventMessages.length) {
    // チャットワークにメッセージを送信
    sendChatworkMessage(SENDER_ACCOUNT_TOKEN, RECEIVER_ROOM_ID, '※自動投稿\n今日の予定はありません!');
    return;
  }

  let message = '';
  message += '※自動投稿\n'
  message += '今日の予定です!\n';
  message += '[info][title]今日の予定[/title]\n';

  // 今日より前から継続している予定
  if (lastWeekEventMessages.length) {
    message += '▼継続している予定\n';
    lastWeekEventMessages.forEach((msg) => {
      message += `${msg}\n`;
    });
    message += '[hr]\n';
  }

  // 今日の予定
  if (thisWeekEventMessages.length) {
    message += Utilities.formatDate(startDate, 'Asia/Tokyo', `▼MM/dd(${getDayOfWeek(startDate)})\n`);
    thisWeekEventMessages.forEach((msg) => {
      message += `${msg}\n`;
    });
  }
  message += '[/info]\n';

  // チャットワークにメッセージを送信
  sendChatworkMessage(SENDER_ACCOUNT_TOKEN, RECEIVER_ROOM_ID, message);
}

/**
 * 予定のメッセージを整形
 *
 * @param {CalendarEvent} event - Googleカレンダーの予定
 * @param {Date} startDate - Googleカレンダーから予定を取得するときの開始日
 * @param {string}
 */
function convMessage(event, startDate) {
  // 開始日の翌日
  const startTimeNextDate = new Date(Utilities.formatDate(event.getStartTime(), 'Asia/Tokyo', 'yyyy/MM/dd 00:00:00'));
  startTimeNextDate.setDate(startTimeNextDate.getDate() + 1);

  // 終日の予定の場合
  if (event.isAllDayEvent()) {
    // 複数日にまたがる場合
    if (event.getStartTime() < startDate || startTimeNextDate < event.getEndTime()) {
      const eventDate = new Date(event.getEndTime().getTime());
      eventDate.setDate(eventDate.getDate() - 1);
      const endDateMessage = Utilities.formatDate(eventDate, 'Asia/Tokyo', `MM/dd(${getDayOfWeek(eventDate)})`);
      return `~${endDateMessage}:${event.getTitle()}`;
    }
    return event.getTitle();
  }

  const startDateMessage = Utilities.formatDate(event.getStartTime(), 'Asia/Tokyo', event.getStartTime() < startDate ? `MM/dd(${getDayOfWeek(event.getStartTime())})HH:mm` : 'HH:mm');
  const endDateMessage   = Utilities.formatDate(event.getEndTime(), 'Asia/Tokyo', startTimeNextDate <= event.getEndTime() ? `MM/dd(${getDayOfWeek(event.getEndTime())})HH:mm` : 'HH:mm');
  return `${startDateMessage}~${endDateMessage}:${event.getTitle()}`;
}

/**
 * 曜日を取得
 *
 * @param {Date} date - 曜日を取得したい日付オブジェクト
 * @return {string}
 */
function getDayOfWeek(date) {
  const dayOfWeek = ['日', '月', '火', '水', '木', '金', '土'];
  return dayOfWeek[date.getDay()];
}

/**
 * 休日か判定
 *
 * @param {Date} date - 休日か判定したい日付オブジェクト
 * @return {boolean}
 */
function isHoliday(date) {
  const saturday = 6;
  const sunday = 0;
  return date.getDay() === saturday || date.getDay() === sunday;
}

/**
 * チャットワークにメッセージを送信
 *
 * @param {string} token - 送信元アカウントのトークン
 * @param {string} roomId - 送信先チャット部屋のID
 * @param {string} message - 送信するメッセージ
 * @return {void}
 */
function sendChatworkMessage(token, roomId, message) {
  const payload = {
    body: message
  };
  const headers = {
    'X-ChatWorkToken': token
  };
  const options = {
    method: 'POST',
    payload,
    headers,
  };
  const url = `https://api.chatwork.com/v2/rooms/${roomId}/messages`;
  UrlFetchApp.fetch(url, options);
}

/**
 * Googleカレンダーに登録されている予定を取得
 *
 * @param {string} mailAddress - 取得したいGoogleカレンダーに紐づくメールアドレス
 * @param {Date} startDate - 開始日
 * @param {Date} endDate - 終了日(この日時を含まない)
 * @return {CalendarEvent[]}
 */
function getCalendarEvents(mailAddress, startDate, endDate) {
  // Googleカレンダーを取得
  const calendar = CalendarApp.getCalendarById(mailAddress);

  // 開始日~終了日の間に登録されている予定を取得
  return calendar.getEvents(startDate, endDate);
}

スクリプト使用手順

1.Google Driveから「Google Apps Script」ファイルを作成
2.作成したファイルを開いて、先ほどのソースコードを貼り付ける
3.ソースコード上部に書かれている3つの定数の値を自分の環境に合わせて変更する
4.「Ctrl+S」でファイルを保存する

ここで、正常に関数が実行できるか確認します。

関数を実行するとチャットワークにメッセージが送信されます。
「送信して問題ないこと」と「送信先に問題がないこと」を再度ご確認ください。

実行する関数を選択するセレクトボックスから「notifyDailyEvents」を選択して、「実行」ボタンを押します。
承認を求められたら、承認してから再度「実行」ボタンを押してください。

図2:実行する関数を選択するセレクトボックスと、実行ボタン

チャットワークに今日の予定が投稿されたら、正常に関数が実行できていることになります。

自動投稿の設定

1.画面左側のツールバーから「トリガー」を押下
2.画面右下の「トリガーを追加」を押下
3.下記、2つのトリガーを追加します

notifyWeeklyEvents

・実行する関数を選択:notifyWeeklyEvents
・実行するデプロイを選択:Head
・イベントのソースを選択:時間主導型
・時間ベースのトリガーのタイプを選択:週ベースのタイマー
・曜日を選択:月曜日
・時刻を選択:{あなたの好きな時間を選択してください}

notifyDailyEvents

・実行する関数を選択: notifyDailyEvents
・実行するデプロイを選択:Head
・イベントのソースを選択:時間主導型
・時間ベースのトリガーのタイプを選択:日付ベースのタイマー
・時刻を選択:{あなたの好きな時間を選択してください}

それぞれ設定が完了したら、画面右下の「保存」ボタンを押してください。
これで設定した日時になったら自動で関数が実行されます。

おわりに

投稿するメッセージは自由にカスタマイズしてください。

この記事を書いた人

ノコ

入社年2021年

出身地岩手

業務内容Web開発

特技・趣味ゲーム、競プロ、数学

テクログに関する記事一覧

TOP