Created
November 16, 2022 23:59
-
-
Save cr0ybot/c4d21271b740bc098e79c135ba4ed766 to your computer and use it in GitHub Desktop.
SyncPersonalCalendar
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
{ | |
"timeZone": "America/New_York", | |
"dependencies": { | |
"enabledAdvancedServices": [ | |
{ | |
"userSymbol": "Calendar", | |
"version": "v3", | |
"serviceId": "calendar" | |
} | |
] | |
}, | |
"exceptionLogging": "STACKDRIVER", | |
"runtimeVersion": "V8", | |
"oauthScopes": [ | |
"https://www.googleapis.com/auth/calendar" | |
] | |
} |
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
/** | |
* Sync personal events with your work calendar. | |
* | |
* Setup: | |
* 1. From your personal calendar, add your work account in Calendar Settings > Share with specific people, you need at least "See all event details" access | |
* 2. Create an Apps Script project in your work Google account: https://script.google.com/u/0/home | |
* 3. Add this file and the appsscript.json file and customize the email addresses and other variables. | |
* 4. Add a trigger for the `sync` function: | |
* - Event source: From calendar | |
* - Event calendar details: Calendar updated | |
* - Calendar owner email: [your personal email address] | |
* | |
* @ref https://medium.com/@willroman/auto-block-time-on-your-work-google-calendar-for-your-personal-events-2a752ae91dab | |
* | |
* @todo create Out Of Office events when the API is available: https://issuetracker.google.com/issues/112063903 | |
* @todo Use sync token: https://developers.google.com/apps-script/advanced/calendar#synchronizing_events | |
*/ | |
const { GuestStatus, Visibility } = CalendarApp; | |
const fromEmail = "[email protected]"; // email of the personal calendar to pull events from | |
const toEmail = "[email protected]"; // work email | |
const daysOut = 30; // how many days in advance to monitor and block off time | |
const skipWeekends = true; // syncing should ignore events on weekends | |
const officeHours = { | |
start: 8, // start hour (8am) | |
end: 16, // end hour (4pm) | |
}; | |
const label = 'Out of Office'; // label to prepend to copied events | |
const acceptCalendars = [fromEmail, '[email protected]']; // Only process events from these calendars (prevents spam) | |
function sync() { | |
const toCal = CalendarApp.getDefaultCalendar(); | |
const fromCal = CalendarApp.getCalendarById(fromEmail); | |
const today = new Date(); | |
const enddate = new Date(); enddate.setDate(today.getDate()+daysOut); | |
const fromEvents = fromCal.getEvents(today,enddate); | |
for (let i = 0; i < fromEvents.length; i++) { | |
const ev = fromEvents[i]; | |
const startTime = ev.getStartTime(); | |
const endTime = ev.getEndTime(); | |
// Ignore events that don't come from the accepted calendars | |
const fromEventCal = ev.getOriginalCalendarId(); | |
if (!acceptCalendars.includes(fromEventCal)) continue; | |
// Ignore events that I have not responded YES to or am not the owner of | |
// NOTE: Can't use getMyStatus() because that would only work for the main calendar (toEmail) | |
// NOTE: If guestList is empty I guess it's my own event? | |
const guestList = ev.getGuestList(true); | |
if (guestList.length) { | |
const myEvent = guestList.filter((guest) => { | |
return guest.getEmail() === fromEmail || guest.getEmail() === toEmail; | |
}).reduce((mine, guest) => { | |
return mine || (guest.getGuestStatus() == GuestStatus.OWNER || guest.getGuestStatus() == GuestStatus.YES); | |
}, false); | |
if (!myEvent) continue; | |
} | |
// Ignore all-day events (for now) | |
if (ev.isAllDayEvent()) continue; | |
// Check if event is on weekend | |
const dow = startTime.getDay(); // day of week | |
if (skipWeekends && (dow < 1 || dow > 5)) continue; | |
// Check if event is during work day | |
if (startTime.getHours() >= officeHours.end || endTime.getHours() <= officeHours.start) continue; | |
// If the secondary event has already been blocked in the primary calendar, ignore it | |
let alreadyBooked = false; | |
const existing = toCal.getEvents(startTime, endTime); | |
for (let j = 0; j < existing.length; j++) { | |
const ex = existing[j]; | |
if (ex.getStartTime().getTime() == startTime.getTime() && ex.getEndTime().getTime() == endTime.getTime()) { | |
console.log(`Skipping event from ${fromEventCal} scheduled for booked timeslot on ${toCal.getId()}: ${ex.getStartTime().toISOString()}–${ex.getEndTime().toISOString()}`); | |
alreadyBooked = true; | |
break; | |
} | |
} | |
if (alreadyBooked) continue; | |
// Check if the timeslot is marked "busy" on my personal calendar | |
const checkBusy = { | |
items: [{id: fromEmail, busy: 'Active'}], | |
timeMin: ev.getStartTime().toISOString(), | |
timeMax: ev.getEndTime().toISOString(), | |
}; | |
const busyResponse = Calendar.Freebusy.query(checkBusy); | |
// If there are no entries in the busy array, don't add to work calendar | |
if (busyResponse.calendars[fromEmail].busy.length === 0) { | |
console.log(`Skipping event marked "free" from ${fromEventCal}: ${ev.getTitle()}`); | |
continue; | |
} | |
const visibility = ev.getVisibility(); | |
const public = visibility == Visibility.PUBLIC; | |
console.log(`Syncing ${public ? 'public' : 'private'} event from ${fromEventCal}: ${ev.getTitle()}`); | |
const newEvent = toCal.createEvent(public ? ev.getTitle() : label, startTime, endTime); | |
// alternative version below that copies the exact secondary event information into the primary calendar event | |
// var newEvent = toCal.createEvent(ev.getTitle(),ev.getStartTime(),ev.getEndTime(), {location: ev.getLocation(), description: ev.getDescription()}); | |
// Remove all notifications from new event | |
newEvent.removeAllReminders(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment