Last active
November 8, 2023 23:10
-
-
Save hmarr/01cf506c0400b5ff35a59e053b1f94cb to your computer and use it in GitHub Desktop.
Google Apps Script to automatically color calendar events
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
// Setup instructions | |
// | |
// Copy and paste into a Google Apps Script project. Feel free to change the colors below. | |
// | |
// Add a trigger to run the colorUpdatedCalendarEvents function the on the "Calendar updated" event of | |
// your calendar. | |
const PERSONAL_COLOR = CalendarApp.EventColor.GRAY; | |
const IN_PERSON_COLOR = CalendarApp.EventColor.BLUE; | |
const EXTERNAL_COLOR = CalendarApp.EventColor.RED; | |
const INTERNAL_COLOR = undefined; // Default blue color | |
function colorUpdatedCalendarEvents(e) { | |
const calendarId = e?.calendarId ?? "primary"; | |
const calendar = Calendar.Calendars.get(calendarId); | |
const updatedEvents = getUpdatedCalendarEvents(calendar.id, false); | |
for (const event of updatedEvents) { | |
if (event.status === 'cancelled') { | |
continue; | |
} | |
if (event.eventType === "default") { | |
setEventColor(calendar.id, event); | |
} | |
} | |
} | |
function setEventColor(calendarId, event) { | |
const calendarDomain = calendarId.split("@")[1]; | |
console.log("Setting color for", event.summary ?? event.id); | |
const attendees = [event.organizer, ...(event.attendees ?? [])]; | |
const guestEmails = attendees.filter(a => !a.self).map(a => a.email); | |
const hasExternalGuest = guestEmails.some(e => e.split("@")[1] !== calendarDomain); | |
if (event.location && event.location !== "") { | |
console.log(`${event.summary}: in-person`); | |
event.colorId = IN_PERSON_COLOR; | |
} else if (guestEmails.length === 0) { | |
console.log(`${event.summary}: personal`) | |
event.colorId = PERSONAL_COLOR; | |
} else if (hasExternalGuest) { | |
console.log(`${event.summary}: external`) | |
event.colorId = EXTERNAL_COLOR; | |
} else { | |
console.log(`${event.summary}: internal`) | |
event.colorId = INTERNAL_COLOR; | |
} | |
try { | |
Calendar.Events.update(event, calendarId, event.id); | |
} catch (err) { | |
console.error("error updating event %s: %s", event.id, err.message); | |
} | |
} | |
/** | |
* Find and return events in the given calendar that have been modified | |
* since the last sync. If the sync token is missing or invalid, return all | |
* events from up to a week ago (a full sync). | |
* | |
* @param {string} calendarId The ID of the calender to retrieve events from. | |
* @param {boolean} fullSync If true, throw out any existing sync token and | |
* perform a full sync; if false, use the existing sync token if possible. | |
*/ | |
function getUpdatedCalendarEvents(calendarId, fullSync) { | |
console.log("Fetching updated calendar events, full sync =", fullSync); | |
const properties = PropertiesService.getUserProperties(); | |
const options = { maxResults: 100 }; | |
const syncToken = properties.getProperty('syncToken'); | |
if (syncToken && !fullSync) { | |
options.syncToken = syncToken; | |
} else { | |
// Sync events up to seven days in the past. | |
options.timeMin = getRelativeDate(-7, 0).toISOString(); | |
} | |
// Retrieve events one page at a time. | |
let events = []; | |
let pageToken; | |
let response; | |
do { | |
try { | |
options.pageToken = pageToken; | |
response = Calendar.Events.list(calendarId, options); | |
events = events.concat(response.items); | |
} catch (e) { | |
// Check to see if the sync token was invalidated by the server; | |
// if so, perform a full sync instead. | |
if (e.message === 'Sync token is no longer valid, a full sync is required.') { | |
properties.deleteProperty('syncToken'); | |
return getUpdatedCalendarEvents(calendarId, true); | |
} | |
throw new Error(e.message); | |
} | |
pageToken = response.nextPageToken; | |
} while (pageToken); | |
properties.setProperty('syncToken', response.nextSyncToken); | |
return events; | |
} | |
/** | |
* Helper function to get a new Date object relative to the current date. | |
* @param {number} daysOffset The number of days in the future for the new date. | |
* @param {number} hour The hour of the day for the new date, in the time zone | |
* of the script. | |
* @return {Date} The new date. | |
*/ | |
function getRelativeDate(daysOffset, hour) { | |
const date = new Date(); | |
date.setDate(date.getDate() + daysOffset); | |
date.setHours(hour); | |
date.setMinutes(0); | |
date.setSeconds(0); | |
date.setMilliseconds(0); | |
return date; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment