Last active
February 1, 2022 14:40
-
-
Save lavoiesl/c5dde3970aae5a6cda4d53313435c8f6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Adapted from https://developers.google.com/apps-script/articles/vacation-calendar | |
var TEAM_CALENDAR_ID = '[email protected]'; | |
var MONTHS_IN_ADVANCE = 2; | |
var WHOLE_DAY_HOURS_THRESHOLD = 6; | |
var USER_EMAILS = [ | |
]; | |
// The maximum script run time under Apps Script Pro is 30 minutes; this setting | |
// will be used to report when the script is about to reach that limit. | |
var MAX_PRO_RUNTIME_MS = 29 * 60 * 1000; | |
/** | |
* Look through the domain users' public calendars and add any | |
* 'vacation' or 'out of office' events to the team calendar. | |
*/ | |
function syncTeamVacationCalendar() { | |
// Define the calendar event date range to search. | |
var today = new Date(); | |
var startDate = new Date(); | |
startDate.setDate(startDate.getDate() - 7) // Last week | |
var endDate = new Date(); | |
endDate.setMonth(endDate.getMonth() + MONTHS_IN_ADVANCE); | |
// For each user, find events having one or more of the keywords in the event | |
// summary in the specified date range. Import each of those to the team | |
// calendar. | |
var count = 0; | |
var timeout = false; | |
for (var i = 0; i < USER_EMAILS.length; i++) { | |
if (isTimeUp(today, new Date())) { | |
timeout = true; | |
break; | |
} | |
var user = USER_EMAILS[i]; | |
var username = user.split('@')[0]; | |
var lastRun = PropertiesService.getScriptProperties().getProperty('lastRun-' + user); | |
lastRun = lastRun ? new Date(lastRun) : null; | |
findEvents(user, startDate, endDate, lastRun).forEach(function(event) { | |
if (event.start.dateTime) { | |
// Convert long events to day-events to reduce clutter in shared calendars | |
var start = new Date(event.start.dateTime) | |
var end = new Date(event.end.dateTime) | |
var durationHours = (end - start) / 1000 / 60 / 60 | |
if (durationHours >= WHOLE_DAY_HOURS_THRESHOLD) { | |
event.start.date = formatDate(start) | |
delete event.start.dateTime | |
if (end.getHours() >= 12) { | |
// End is exclusive, so it must be the date after | |
// However, if the coming back time is before 10am, don't count it. | |
end.setDate(end.getDate() + 1) | |
} | |
event.end.date = formatDate(end) | |
delete event.end.dateTime | |
} | |
} | |
event.summary = '[' + username + '] ' + event.summary; | |
event.organizer = { | |
id: TEAM_CALENDAR_ID | |
}; | |
event.attendees = []; | |
Logger.log('Importing: %s', event.summary); | |
try { | |
Calendar.Events.import(event, TEAM_CALENDAR_ID); | |
PropertiesService.getScriptProperties().setProperty('lastRun-' + user, today); | |
count++; | |
} catch (e) { | |
Logger.log('Error attempting to import event: %s. Skipping.', e.toString()); | |
} | |
}); | |
} | |
Logger.log('Imported ' + count + ' events'); | |
if (timeout) { | |
Logger.log('Execution time about to hit quota limit; execution stopped.'); | |
} | |
var executionTime = ((new Date()).getTime() - today.getTime()) / 1000.0; | |
Logger.log('Total execution time (s) : ' + executionTime); ; | |
} | |
/** | |
* In a given user's calendar, look for occurrences of the given keyword | |
* in events within the specified date range and return any such events | |
* found. | |
* @param {string} user the user's primary email String. | |
* @param {string} keyword the keyword String to look for. | |
* @param {Date} start the starting Date of the range to examine. | |
* @param {Date} end the ending Date of the range to examine. | |
* @param {Date} opt_since a Date indicating the last time this script was run. | |
* @return {object[]} an array of calendar event Objects. | |
*/ | |
function findEvents(user, start, end, opt_since) { | |
var params = { | |
timeMin: formatDateTime(start), | |
timeMax: formatDateTime(end), | |
maxAttendees: 1, | |
showDeleted: true, | |
}; | |
// Logger.log('Importing user %s %s-%s', user, start, end); | |
if (opt_since) { | |
// This prevents the script from examining events that have not been | |
// modified since the specified date (that is, the last time the | |
// script was run). | |
params['updatedMin'] = formatDateTime(opt_since); | |
} | |
try { | |
var responses = Calendar.Events.list(user, params) | |
return responses.items.filter(function(item) { | |
return item.eventType == 'outOfOffice'; | |
}); | |
} catch (e) { | |
Logger.log('Error retriving events for %s: %s; skipping', user, e.toString()); | |
return []; | |
} | |
} | |
function eventMatches(event, keywords) { | |
for (var i = 0; i < length(keywords); i++) { | |
if (event.summary.toLowerCase().indexOf(keywords[i]) != -1) { | |
return true; | |
} | |
} | |
return false; | |
} | |
function formatDate(date) { | |
var d = new Date(date), | |
month = '' + (d.getMonth() + 1), | |
day = '' + d.getDate(), | |
year = d.getFullYear(); | |
if (month.length < 2) | |
month = '0' + month; | |
if (day.length < 2) | |
day = '0' + day; | |
return [year, month, day].join('-'); | |
} | |
/** | |
* Return an RFC3339 formated date String corresponding to the given | |
* Date object. | |
* @param {Date} date a Date. | |
* @return {string} a formatted date string. | |
*/ | |
function formatDateTime(date) { | |
return Utilities.formatDate(date, 'UTC', 'yyyy-MM-dd\'T\'HH:mm:ssZ'); | |
} | |
/** | |
* Compares two Date objects and returns true if the difference | |
* between them is more than the maximum specified run time. | |
* | |
* @param {Date} start the first Date object. | |
* @param {Date} now the (later) Date object. | |
* @return {boolean} true if the time difference is greater than | |
* MAX_PROP_RUNTIME_MS (in milliseconds). | |
*/ | |
function isTimeUp(start, now) { | |
return now.getTime() - start.getTime() > MAX_PRO_RUNTIME_MS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment