Servizio Calendar avanzato

Script per accedere ai calendari degli utenti e modificarli con funzionalità aggiuntive.

Il servizio Calendar avanzato ti consente di utilizzare l'API Google Calendar pubblica in Google Apps Script. Analogamente al servizio Calendar integrato di Apps Script, questa API consente agli script di accedere e modificare Google Calendar dell'utente, inclusi i calendari aggiuntivi a cui l'utente è iscritto. Nella maggior parte dei casi, il servizio integrato è più facile da utilizzare, ma questo servizio avanzato offre alcune funzionalità aggiuntive, tra cui l'impostazione del colore di sfondo per i singoli eventi.

Questo è un servizio avanzato che deve essere abilitato prima dell'uso.

Riferimento

Per informazioni dettagliate su questo servizio, consulta la documentazione di riferimento dell'API Calendar pubblica. Come tutti i servizi avanzati di Apps Script, il servizio Calendar avanzato utilizza gli stessi oggetti, metodi e parametri dell'API pubblica. Per saperne di più, consulta la sezione Come vengono determinate le firme dei metodi.

Per segnalare problemi e trovare altro supporto, consulta la guida di assistenza di Calendar.

Intestazioni delle richieste HTTP

Il servizio Calendar avanzato può accettare le intestazioni delle richieste HTTP If-Match e If-None-Match. Per i dettagli, consulta la documentazione di riferimento.

Codice campione

Il seguente codice campione utilizza la versione 3 dell' API.

Creare eventi

Il seguente esempio mostra come creare un evento nel calendario predefinito dell'utente.

advanced/calendar.gs
/**
 * Creates an event in the user's default calendar.
 * @see https://developers.google.com/calendar/api/v3/reference/events/insert
 */
function createEvent() {
  const calendarId = "primary";
  const start = getRelativeDate(1, 12);
  const end = getRelativeDate(1, 13);
  // event details for creating event.
  let event = {
    summary: "Lunch Meeting",
    location: "The Deli",
    description: "To discuss our plans for the presentation next week.",
    start: {
      dateTime: start.toISOString(),
    },
    end: {
      dateTime: end.toISOString(),
    },
    attendees: [
      { email: "gduser1@workspacesample.dev" },
      { email: "gduser2@workspacesample.dev" },
    ],
    // Red background. Use Calendar.Colors.get() for the full list.
    colorId: 11,
  };
  try {
    // call method to insert/create new event in provided calandar
    event = Calendar.Events.insert(event, calendarId);
    console.log(`Event ID: ${event.id}`);
  } catch (err) {
    console.log("Failed with error %s", err.message);
  }
}

/**
 * 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;
}

Elencare i calendari

Il seguente esempio mostra come recuperare i dettagli dei calendari visualizzati nell'elenco dei calendari dell'utente.

advanced/calendar.gs
/**
 * Lists the calendars shown in the user's calendar list.
 * @see https://developers.google.com/calendar/api/v3/reference/calendarList/list
 */
function listCalendars() {
  let calendars;
  let pageToken;
  do {
    calendars = Calendar.CalendarList.list({
      maxResults: 100,
      pageToken: pageToken,
    });
    if (!calendars.items || calendars.items.length === 0) {
      console.log("No calendars found.");
      return;
    }
    // Print the calendar id and calendar summary
    for (const calendar of calendars.items) {
      console.log("%s (ID: %s)", calendar.summary, calendar.id);
    }
    pageToken = calendars.nextPageToken;
  } while (pageToken);
}

Elencare gli eventi

Il seguente esempio mostra come elencare i prossimi 10 eventi imminenti nel calendario predefinito dell'utente.

advanced/calendar.gs
/**
 * Lists the next 10 upcoming events in the user's default calendar.
 * @see https://developers.google.com/calendar/api/v3/reference/events/list
 */
function listNext10Events() {
  const calendarId = "primary";
  const now = new Date();
  const events = Calendar.Events.list(calendarId, {
    timeMin: now.toISOString(),
    singleEvents: true,
    orderBy: "startTime",
    maxResults: 10,
  });
  if (!events.items || events.items.length === 0) {
    console.log("No events found.");
    return;
  }
  for (const event of events.items) {
    if (event.start.date) {
      // All-day event.
      const start = new Date(event.start.date);
      console.log("%s (%s)", event.summary, start.toLocaleDateString());
      continue;
    }
    const start = new Date(event.start.dateTime);
    console.log("%s (%s)", event.summary, start.toLocaleString());
  }
}

Modificare un evento in modo condizionale

Il seguente esempio mostra come aggiornare in modo condizionale un evento di Calendar utilizzando l'intestazione If-Match. Lo script crea un nuovo evento, attende 30 secondi e poi aggiorna l'evento solo se i dettagli dell'evento non sono stati modificati dalla sua creazione.

advanced/calendar.gs
/**
 * Creates an event in the user's default calendar, waits 30 seconds, then
 * attempts to update the event's location, on the condition that the event
 * has not been changed since it was created.  If the event is changed during
 * the 30-second wait, then the subsequent update will throw a 'Precondition
 * Failed' error.
 *
 * The conditional update is accomplished by setting the 'If-Match' header
 * to the etag of the new event when it was created.
 */
function conditionalUpdate() {
  const calendarId = "primary";
  const start = getRelativeDate(1, 12);
  const end = getRelativeDate(1, 13);
  let event = {
    summary: "Lunch Meeting",
    location: "The Deli",
    description: "To discuss our plans for the presentation next week.",
    start: {
      dateTime: start.toISOString(),
    },
    end: {
      dateTime: end.toISOString(),
    },
    attendees: [
      { email: "gduser1@workspacesample.dev" },
      { email: "gduser2@workspacesample.dev" },
    ],
    // Red background. Use Calendar.Colors.get() for the full list.
    colorId: 11,
  };
  event = Calendar.Events.insert(event, calendarId);
  console.log(`Event ID: ${event.getId()}`);
  // Wait 30 seconds to see if the event has been updated outside this script.
  Utilities.sleep(30 * 1000);
  // Try to update the event, on the condition that the event state has not
  // changed since the event was created.
  event.location = "The Coffee Shop";
  try {
    event = Calendar.Events.update(
      event,
      calendarId,
      event.id,
      {},
      { "If-Match": event.etag },
    );
    console.log(`Successfully updated event: ${event.id}`);
  } catch (e) {
    console.log(`Fetch threw an exception: ${e}`);
  }
}

Recuperare un evento in modo condizionale

Il seguente esempio mostra come recuperare in modo condizionale un evento di Calendar utilizzando l'intestazione If-None-Match. Lo script crea un nuovo evento, quindi esegue il polling dell'evento per rilevare le modifiche per 30 secondi. Ogni volta che l'evento viene modificato, viene recuperata la nuova versione.

advanced/calendar.gs
/**
 * Creates an event in the user's default calendar, then re-fetches the event
 * every second, on the condition that the event has changed since the last
 * fetch.
 *
 * The conditional fetch is accomplished by setting the 'If-None-Match' header
 * to the etag of the last known state of the event.
 */
function conditionalFetch() {
  const calendarId = "primary";
  const start = getRelativeDate(1, 12);
  const end = getRelativeDate(1, 13);
  let event = {
    summary: "Lunch Meeting",
    location: "The Deli",
    description: "To discuss our plans for the presentation next week.",
    start: {
      dateTime: start.toISOString(),
    },
    end: {
      dateTime: end.toISOString(),
    },
    attendees: [
      { email: "gduser1@workspacesample.dev" },
      { email: "gduser2@workspacesample.dev" },
    ],
    // Red background. Use Calendar.Colors.get() for the full list.
    colorId: 11,
  };
  try {
    // insert event
    event = Calendar.Events.insert(event, calendarId);
    console.log(`Event ID: ${event.getId()}`);
    // Re-fetch the event each second, but only get a result if it has changed.
    for (let i = 0; i < 30; i++) {
      Utilities.sleep(1000);
      event = Calendar.Events.get(
        calendarId,
        event.id,
        {},
        { "If-None-Match": event.etag },
      );
      console.log(`New event description: ${event.start.dateTime}`);
    }
  } catch (e) {
    console.log(`Fetch threw an exception: ${e}`);
  }
}

Sincronizzare gli eventi

Il seguente esempio mostra come recuperare gli eventi utilizzando i token di sincronizzazione. Quando includi un token di sincronizzazione in una richiesta del servizio Calendar avanzato, la risposta risultante include solo gli elementi modificati dalla generazione del token, consentendo un'elaborazione più efficiente. Per ulteriori dettagli sulla procedura di sincronizzazione, consulta la sezione Sincronizzare le risorse in modo efficiente.

Il seguente esempio utilizza lo stesso metodo getRelativeDate(daysOffset, hour) definito negli esempi precedenti.

advanced/calendar.gs
/**
 * Retrieve and log events from the given calendar that have been modified
 * since the last sync. If the sync token is missing or invalid, log all
 * events from up to a month 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 logSyncedEvents(calendarId, 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 thirty days in the past.
    options.timeMin = getRelativeDate(-30, 0).toISOString();
  }
  // Retrieve events one page at a time.
  let events;
  let pageToken;
  do {
    try {
      options.pageToken = pageToken;
      events = Calendar.Events.list(calendarId, options);
    } 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");
        logSyncedEvents(calendarId, true);
        return;
      }
      throw new Error(e.message);
    }
    if (events.items && events.items.length === 0) {
      console.log("No events found.");
      return;
    }
    for (const event of events.items) {
      if (event.status === "cancelled") {
        console.log("Event id %s was cancelled.", event.id);
        return;
      }
      if (event.start.date) {
        const start = new Date(event.start.date);
        console.log("%s (%s)", event.summary, start.toLocaleDateString());
        return;
      }
      // Events that don't last all day; they have defined start times.
      const start = new Date(event.start.dateTime);
      console.log("%s (%s)", event.summary, start.toLocaleString());
    }
    pageToken = events.nextPageToken;
  } while (pageToken);
  properties.setProperty("syncToken", events.nextSyncToken);
}