Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @fileoverview This script automates the scheduling of "Prep Time" and "Follow Up" events
- * around events in a specified Google Calendar based on invitations from specified email addresses.
- * It is designed for users needing dedicated time before and after meetings with specific attendees.
- *
- * This script manages fetching recent event updates, identifying relevant events,
- * and automatically creating "Prep Time" and "Follow Up" events.
- * It avoids duplicate scheduling by marking events as processed using extended properties.
- *
- * @author u/IAmMoonie
- * @version 1.0
- * @license Apache-2.0
- *
- * @requires Google Apps Script built-in services for Calendar and PropertiesService.
- *
- * @description This script monitors Google Calendar events originating from specific email addresses,
- * adding configurable buffer times before and after events to ensure adequate preparation and
- * follow-up time. When a relevant event is accepted by the user, the script automatically schedules
- * "Prep Time" and "Follow Up" events based on specified time offsets.
- *
- * The script uses the Google Calendar API to manage events and PropertiesService
- * for tracking processed events and trigger email lists. It also includes a mechanism to mark
- * events as processed, preventing redundant triggers.
- *
- * @example
- * // Expected event structure and execution flow:
- * // 1. User receives an invitation from a specified email address.
- * // 2. Upon accepting the invitation, "Prep Time" and "Follow Up" events are automatically added.
- * // 3. If the event is rescheduled, it is marked as processed to prevent duplicate additions.
- *
- * @see {@link https://developers.google.com/calendar/api/v3/reference|Google Calendar API Reference}
- * @see {@link https://developers.google.com/apps-script/reference/properties/properties-service|Google Apps Script PropertiesService Reference}
- *
- * @since 1.0
- *
- */
- /**
- * Configuration object for script settings.
- * @type {Object}
- * @property {string[]} defaultEmails - List of email addresses to monitor for event invites.
- * @property {number} prepTimeOffsetMins - Time in minutes before the main event to schedule prep time.
- * @property {number} followUpOffsetMins - Time in minutes to schedule follow-up after the main event.
- * @property {string} userEmail - The user's email address, used to check acceptance status of events.
- */
- const CONFIG = {
- prepTimeOffsetMins: 30,
- followUpOffsetMins: 15,
- userEmail: "[email protected]"
- };
- const scriptProperties = PropertiesService.getScriptProperties();
- /**
- * Initializes or updates the TRIGGER_EMAILS property in PropertiesService with default emails.
- * Run this whenever you make a change to the CONFIG defaultEmails (so adding or removing email addresses)
- */
- const initializeProperties = () => {
- const storedEmails = scriptProperties.getProperty("TRIGGER_EMAILS");
- const configEmailsSet = new Set(CONFIG.defaultEmails);
- if (!storedEmails) {
- scriptProperties.setProperty(
- "TRIGGER_EMAILS",
- CONFIG.defaultEmails.join(",")
- );
- } else {
- const storedEmailsSet = new Set(storedEmails.split(","));
- const isUpdated =
- CONFIG.defaultEmails.some((email) => !storedEmailsSet.has(email)) ||
- [...storedEmailsSet].some((email) => !configEmailsSet.has(email));
- if (isUpdated) {
- scriptProperties.setProperty(
- "TRIGGER_EMAILS",
- CONFIG.defaultEmails.join(",")
- );
- }
- }
- };
- /**
- * Main function triggered by onEventUpdated. Fetches recent events and processes each.
- * @param {object} e - The event trigger object containing calendarId.
- */
- const onEventUpdated = (e) => {
- const calendarId = e.calendarId || "primary";
- const events = fetchRecentEvents_(calendarId);
- if (events.length === 0) return;
- events.forEach((event) => processEvent_(event, calendarId));
- };
- /**
- * Fetches recent calendar events updated within the past hour.
- * @param {string} calendarId - The ID of the calendar.
- * @returns {object[]} Array of recent event objects.
- */
- const fetchRecentEvents_ = (calendarId) => {
- const now = new Date();
- const pastHour = new Date(now.getTime() - 1000 * 60 * 60).toISOString();
- const params = {
- timeMin: pastHour,
- showDeleted: false,
- singleEvents: true,
- orderBy: "updated",
- updatedMin: pastHour
- };
- const response = Calendar.Events.list(calendarId, params);
- return response.items || [];
- };
- /**
- * Processes an individual event and creates prep and follow-up events if conditions are met.
- * @param {object} event - The event object.
- * @param {string} calendarId - The ID of the calendar.
- */
- const processEvent_ = (event, calendarId) => {
- let _extendedProperties$p;
- const {
- summary: eventTitle,
- attendees,
- start,
- end,
- id: eventId,
- extendedProperties
- } = event;
- if (eventTitle.includes("Prep Time") || eventTitle.includes("Follow Up"))
- return;
- const alreadyProcessed =
- (extendedProperties === null ||
- extendedProperties === void 0 ||
- (_extendedProperties$p = extendedProperties.private) === null ||
- _extendedProperties$p === void 0
- ? void 0
- : _extendedProperties$p.processed) === "true";
- if (alreadyProcessed) return;
- const startEventTime = start.dateTime ? new Date(start.dateTime) : null;
- const endEventTime = end.dateTime ? new Date(end.dateTime) : null;
- if (!startEventTime || !endEventTime) return;
- const triggerEmails = getConfigEmails_();
- const isRelevantSender =
- attendees === null || attendees === void 0
- ? void 0
- : attendees.some(({ email }) => triggerEmails.includes(email));
- if (!isRelevantSender) return;
- const userAttending =
- attendees === null || attendees === void 0
- ? void 0
- : attendees.some(
- ({ email, responseStatus }) =>
- email === CONFIG.userEmail &&
- (responseStatus === "accepted" || responseStatus === "tentative")
- );
- if (!userAttending) return;
- addPrepAndFollowUpEvents_(
- calendarId,
- eventTitle,
- startEventTime,
- endEventTime,
- start.timeZone,
- eventId
- );
- markEventAsProcessed_(calendarId, eventId);
- };
- /**
- * Marks an event as processed by adding an extended property.
- * @param {string} calendarId - The ID of the calendar.
- * @param {string} eventId - The ID of the event to mark.
- */
- const markEventAsProcessed_ = (calendarId, eventId) => {
- Calendar.Events.patch(
- {
- extendedProperties: {
- private: {
- processed: "true"
- }
- }
- },
- calendarId,
- eventId
- );
- };
- /**
- * Retrieves the synchronized list of emails from PropertiesService.
- * @returns {string[]} Array of email addresses.
- */
- const getConfigEmails_ = () => {
- const emails = scriptProperties.getProperty("TRIGGER_EMAILS");
- return emails ? emails.split(",") : [];
- };
- /**
- * Adds "Prep Time" and "Follow Up" events relative to a main event.
- * @param {string} calendarId - The ID of the calendar.
- * @param {string} eventTitle - The title of the main event.
- * @param {Date} startEventTime - Start time of the main event.
- * @param {Date} endEventTime - End time of the main event.
- * @param {string} timeZone - Time zone for the event.
- * @param {string} eventId - ID of the original event to associate.
- */
- const addPrepAndFollowUpEvents_ = (
- calendarId,
- eventTitle,
- startEventTime,
- endEventTime,
- timeZone,
- eventId
- ) => {
- const prepStart = new Date(
- startEventTime.getTime() - CONFIG.prepTimeOffsetMins * 60000
- );
- createEvent_(
- calendarId,
- `Prep Time for ${eventTitle}`,
- prepStart,
- startEventTime,
- timeZone,
- eventId,
- "Prep"
- );
- const followUpStart = new Date(endEventTime.getTime());
- const followUpEnd = new Date(
- followUpStart.getTime() + CONFIG.followUpOffsetMins * 60000
- );
- createEvent_(
- calendarId,
- `Follow Up for ${eventTitle}`,
- followUpStart,
- followUpEnd,
- timeZone,
- eventId,
- "FollowUp"
- );
- };
- /**
- * Creates a new event in Google Calendar without any attendees and stores its ID.
- * @param {string} calendarId - The ID of the calendar.
- * @param {string} summary - The event summary or title.
- * @param {Date} start - The start date and time of the event.
- * @param {Date} end - The end date and time of the event.
- * @param {string} timeZone - Time zone for the event.
- * @param {string} eventId - ID of the original event to associate.
- * @param {string} type - Type of event ("Prep" or "Follow Up").
- */
- const createEvent_ = (
- calendarId,
- summary,
- start,
- end,
- timeZone,
- eventId,
- type
- ) => {
- const createdEvent = Calendar.Events.insert(
- {
- summary,
- start: {
- dateTime: start.toISOString(),
- timeZone
- },
- end: {
- dateTime: end.toISOString(),
- timeZone
- },
- attendees: []
- },
- calendarId
- );
- scriptProperties.setProperty(`${type}_${eventId}`, createdEvent.id);
- };
Advertisement
Add Comment
Please, Sign In to add comment