-
-
Save alranel/f1c9b7abb9013f4a39aa4fb12f6de4ef to your computer and use it in GitHub Desktop.
var source_calendars = [ | |
'xxx', | |
]; | |
function sync() { | |
var today = new Date(); | |
var enddate = new Date(); | |
enddate.setDate(today.getDate()+90); // how many days in advance to monitor and block off time | |
var sourceEvents = []; | |
source_calendars.forEach(function(id) { | |
var secondaryCal = CalendarApp.getCalendarById(id); | |
sourceEvents = sourceEvents.concat(secondaryCal.getEvents(today,enddate)); | |
}); | |
var thisCal = CalendarApp.getDefaultCalendar(); | |
var offEventTitle = "off"; // update this to the text you'd like to appear in the new events created in primary calendar | |
var thisCalEventsUpdated = []; // to contain primary calendar events that were updated from secondary calendar | |
var thisCalEventsCreated = []; // to contain primary calendar events that were created from secondary calendar | |
var thisCalEventsDeleted = []; // to contain primary calendar events previously created that have been deleted from secondary calendar | |
// create filtered list of events from this calendar that were previously created from the source calendar | |
var thisCalOffEvents = []; | |
for (var pEvent of thisCal.getEvents(today,enddate)) { | |
if (pEvent.getTitle() == offEventTitle) | |
thisCalOffEvents.push(pEvent); | |
} | |
// process all events in source calendar | |
for (var sev of sourceEvents) { | |
// skip events in secondary calendar that were already created by a script similar to this one | |
if (sev.getTitle() == offEventTitle) | |
continue; | |
// ignore declined events | |
if (sev.getMyStatus() == CalendarApp.GuestStatus.NO || sev.getMyStatus() == CalendarApp.GuestStatus.MAYBE) | |
continue; | |
// ignore all-day events | |
if (sev.isAllDayEvent()) | |
continue; | |
/* | |
// Unfortunately, the GSuite API does not provide access to the Transparency property | |
if (sev.getTransparency() == 'transparent') | |
continue; // Ignore events whose transparency is set to transparent | |
*/ | |
// Ignore events in the weekend | |
if (![1,2,3,4,5].includes(sev.getStartTime().getDay())) | |
continue; | |
Logger.log("Processing: " + sev.getTitle()); | |
// Does an "off" event already exist in this calendar? | |
var offEvent = null; | |
for (var pEvent of thisCalOffEvents) { | |
if (pEvent.getStartTime().getTime() == sev.getStartTime().getTime() | |
&& pEvent.getEndTime().getTime() == sev.getEndTime().getTime() | |
&& pEvent.getTitle() == offEventTitle) | |
{ | |
offEvent = pEvent; | |
break; | |
} | |
} | |
if (!offEvent) { | |
offEvent = thisCal.createEvent(offEventTitle, sev.getStartTime(), sev.getEndTime()); | |
thisCalEventsCreated.push(offEvent.getId()); | |
Logger.log(' off event created'); | |
} else { | |
thisCalEventsUpdated.push(offEvent.getId()); | |
Logger.log(' off event updated'); | |
} | |
//offEvent.setDescription(sev.getTitle() + '\n\n' + sev.getDescription()); | |
offEvent.setVisibility(CalendarApp.Visibility.DEFAULT); | |
offEvent.removeAllReminders(); | |
} | |
// if an off event previously created no longer exists in the secondary calendar, delete it | |
for (var pev of thisCalOffEvents) { | |
if (!thisCalEventsUpdated.includes(pev.getId())) { | |
thisCalEventsDeleted.push(pev.getId()); | |
Logger.log('OFF EVENT DELETED: ' + pev.getId()); | |
pev.deleteEvent(); | |
} | |
} | |
Logger.log('Off events previously created: ' + thisCalOffEvents.length); | |
Logger.log('Off events updated: ' + thisCalEventsUpdated.length); | |
Logger.log('Off events deleted: ' + thisCalEventsDeleted.length); | |
Logger.log('Off events created: ' + thisCalEventsCreated.length); | |
// Delete past events in primary calendar | |
var olddate = new Date(); | |
olddate.setDate(today.getDate()-10); | |
var pastthisCalEvents = thisCal.getEvents(olddate, today); | |
var deletedPastEvents = 0; | |
for (var pEvent of pastthisCalEvents) { | |
if (pEvent.getEndTime() > today) | |
continue; | |
if (pEvent.getTitle() == offEventTitle) { | |
pEvent.deleteEvent(); | |
deletedPastEvents++; | |
} | |
} | |
Logger.log('Past off events deleted: ' + deletedPastEvents); | |
} |
Thank you for the hint @JohnLockeNJ. For now I don't need that feature so I don't plan to add the free/busy query, but if anyone wants to contribute that change I'll be happy to merge that.
I just uploaded a new version with many cleanups and some minor changes to the logic. I removed the "Booked" event title since we're only using the (configurable) "off" string. I also made a change that ignores the events in the source calendars with a "maybe" answer. (I try to use "maybe" as I would use the "free" option). I also changed the privacy of placeholder events which are public now (not private anymore), since they don't contain details about the original event; this change prevents synchronization bugs. The script will now consider also slots blocked by private events, which were previously not taken into account.
The new version has been working great and I've been using it since you uploaded!
For anyone interested, I've found a way to use the script to sync an Outlook Exchange calendar to a Google Calendar.
If you publish your Outlook Exchange calendar and set it to "Can view all details", you then get an ICS link that you can add as an Other Calendar in one of your Google Calendar accounts. Instructions: https://www.alphr.com/sync-outlook-calendar-google-calendar/
Those instructions say it sets up syncing, but it really just lets you view the calendar in Google and doesn't include it in Google Calendar free/busy without more steps.
Once it's added as an Other Calendar, you can get the Google Calendar ID for that new calendar per Will Roman's original Medium article and put it into the script. Pick different text for the "off" blocked off time than your other Google Cal to Google Cal scripts. You now have Outlook Exchange meetings blocked off in your Google Calendar and it will replicate to other Google Calendars for which you've set up sync scripts and everyone who looks at the Google Calendar free/busy times.
Rather than find a way to sync the other direction (Google Calendar to Outlook Exchange) using client software or setting up a personal server, I just added one of my Google Calendars (that already syncs with all my other work Google Calendars) as a Personal Calendar in Outlook for the Web which lets you include those entries when people look at your free/busy time.
https://office365itpros.com/2020/02/27/adding-your-personal-calendar-owa/
@alranel
It looks to me like the main change is that you added code to skip events in the secondary calendar that are marked as "free" (ie transparent) but the code doesn't work as you noted because the Gsuite API doesn't support the expected call. Would you consider making a script tweak to truly enable that functionality using the workaround suggested here? https://stackoverflow.com/questions/61191652/how-to-return-if-google-calendar-time-or-calendar-event-is-busy?rq=1
As for other changes: