来週の会議室を使うかSlackでリマインドして、使わない曜日は自動で解除するGAS
仕様
カレンダーの予定を自動的に削除する。
-
FORMから使用する曜日を入力してもらう
名前(またはメールアドレス)、使用する曜日はチェックボックスでチェックをしてもらう。
A列:タイムスタンプ
B列:申請者名(またはメールアドレス)
C列:確保する曜日(カンマ区切り) -
入力完了後(毎週金曜日16時ぐらい)になったらGASを起動
-
使用する曜日以外の「会議室確保」を削除する。
誰も入力してなければ全部削除する。 -
完了後、Slackに「会議室確保の削除はおこニャったけど、あんまりワイを信じないで担当者はチェックするニャよ。」を通知する。
削除した曜日もメッセージに含む。
ソース
// =================================================================
// 設定項目:ここから
// =================================================================
// 1. あなたのGoogleカレンダーID
// Googleカレンダーの設定画面で確認できます。「マイカレンダーの設定」>「カレンダーの統合」にあります。
const CALENDAR_ID = ''; // ★★★ここにカレンダーIDを入力してください★★★
// 2. あなたのSlack Webhook URL
// Slackの設定で取得できます。
const SLACK_WEBHOOK_URL = ''; // ★★★ここにSlack Webhook URLを入力してください★★★
// 3. 削除対象の予定のタイトル
const EVENT_TITLE = ''; // ★★★ここに削除対象の予定件名を入力してください★★★
// 4. Slackへの通知メッセージ
const SLACK_MESSAGE_BASE = '会議室確保の削除はおこニャったけど、あんまりワイを信じないで担当者はチェックするニャよ。';
// =================================================================
// 設定項目:ここまで
// =================================================================
/**
* メインの処理を実行する関数
*/
function deleteUnusedTrainingSchedules() {
try {
// 1. スプレッドシートから「実行日当日」の「すべての」回答を取得し、曜日を合算する
const executionDate = new Date();
const executionDateOnly = new Date(executionDate);
executionDateOnly.setHours(0, 0, 0, 0);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
const allValues = sheet.getDataRange().getValues();
let allUsedWeekdays = []; // 全員の使用曜日を一時的に格納する配列
// シートのすべての行をチェックして、実行日と一致する回答をすべて集める
for (let i = 1; i < allValues.length; i++) { // 1行目はヘッダーなので i = 1 からスタート
const timestamp = new Date(allValues[i][0]); // A列(インデックス0)がタイムスタンプ
if (isNaN(timestamp.getTime())) continue;
const submissionDateOnly = new Date(timestamp);
submissionDateOnly.setHours(0, 0, 0, 0);
// 実行日と回答の日付が一致するかチェック
if (submissionDateOnly.getTime() === executionDateOnly.getTime()) {
const weekdaysStr = allValues[i][2]; // C列(インデックス2)の曜日文字列
if (weekdaysStr) {
const weekdays = weekdaysStr.split(', '); // 「月曜日, 水曜日」のような文字列を配列に変換
allUsedWeekdays = allUsedWeekdays.concat(weekdays); // 見つかった曜日を配列に追加していく
}
}
}
// 集めた曜日リストから重複を削除して、最終的な「使用する曜日」のリストを作成
// 例: ['月', '水', '火', '月'] -> ['月', '水', '火']
const usedWeekdays = [...new Set(allUsedWeekdays)];
// 実行日当日の回答が見つかったかどうかでログメッセージを分ける
if (usedWeekdays.length === 0) {
console.log('実行日当日の回答が見つからなかったため、翌週のすべての「' + EVENT_TITLE + '」を削除対象とします。');
// この場合は return せずに処理を続行する
} else {
console.log('合算された使用曜日: ' + usedWeekdays.join(', '));
}
// 2. 削除対象の期間(実行日の翌週月曜日から日曜日まで)を計算
const nextMonday = new Date(executionDate);
nextMonday.setDate(executionDate.getDate() + (8 - executionDate.getDay()) % 7);
nextMonday.setHours(0, 0, 0, 0);
const nextSunday = new Date(nextMonday);
nextSunday.setDate(nextMonday.getDate() + 6);
nextSunday.setHours(23, 59, 59, 999);
console.log('削除対象期間: ' + nextMonday + ' ~ ' + nextSunday);
// 3. カレンダーから指定期間のイベントを取得
const calendar = CalendarApp.getCalendarById(CALENDAR_ID);
const events = calendar.getEvents(nextMonday, nextSunday, {search: EVENT_TITLE});
if (events.length === 0) {
console.log('対象期間内に「' + EVENT_TITLE + '」の予定は見つかりませんでした。');
sendSlackNotification('ニャ? 削除対象の「' + EVENT_TITLE + '」の予定が一件も見つからなかったニャ。');
return;
}
// 4. 使用しない曜日のイベントを削除 & 削除した曜日を記録
const weekdayMap = {'日曜日': 0, '月曜日': 1, '火曜日': 2, '水曜日': 3, '木曜日': 4, '金曜日': 5, '土曜日': 6};
const dayNumberToName = ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'];
const usedWeekdayNumbers = usedWeekdays.map(day => weekdayMap[day]);
let deletedCount = 0;
const deletedWeekdayNames = new Set(); // 削除した曜日の名前を記録する(重複なし)
events.forEach(event => {
const eventDate = event.getStartTime();
const eventWeekdayNumber = eventDate.getDay();
if (!usedWeekdayNumbers.includes(eventWeekdayNumber)) {
console.log('削除対象イベント: ' + event.getTitle() + ' (' + event.getStartTime() + ')');
// 削除した曜日の名前をSetに追加
deletedWeekdayNames.add(dayNumberToName[eventWeekdayNumber]);
event.deleteEvent();
deletedCount++;
}
});
console.log(deletedCount + '件のイベントを削除しました。');
// 5. 削除結果に応じたSlackメッセージを作成して送信
let finalSlackMessage;
if (deletedCount > 0) {
// 削除した曜日を「日,月,火...」の順に並び替え
const sortedDeletedDays = Array.from(deletedWeekdayNames).sort((a, b) => weekdayMap[a] - weekdayMap[b]);
// メッセージを組み立て
finalSlackMessage = SLACK_MESSAGE_BASE + '\n> 削除した曜日: `' + sortedDeletedDays.join(', ') + '`';
} else {
// 1件も削除しなかった場合
finalSlackMessage = 'ニャーン!今週は削除対象の会議室解除予定は1件もなかったニャ。スケジュールは変更なしだニャ。';
}
sendSlackNotification(finalSlackMessage);
} catch (e) {
console.error('エラーが発生しました: ' + e.toString());
sendSlackNotification('ニャーン!エラーが発生して処理が止まってしまったニャ…。\n' + e.toString());
}
}
/**
* Slackに通知を送信する関数
*/
function sendSlackNotification(message) {
if (!SLACK_WEBHOOK_URL || SLACK_WEBHOOK_URL === 'YOUR_SLACK_WEBHOOK_URL') {
console.log('Slack Webhook URLが設定されていません。');
return;
}
const payload = {
'text': message,
};
const options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(payload),
};
try {
UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
console.log('Slackへの通知を送信しました。');
} catch (e) {
console.error('Slackへの通知送信中にエラーが発生しました: ' + e.toString());
}
}
後はコレを指定した時間に動かすように設定するだけ。
苦労した点
チェックボックスで月〜金のFormを出しているのですが、ワンホットエンコーディングで出力されるかと思ってたのですが、「月曜日,火曜日,水曜日…」となるとは思ってなかった。
複数人入れた場合の最終的に残すべき曜日をやる方法が地味にめんどくさいな…と思って、生成AIに相談したらすぐに回答してくれた。凄い。