Los usuarios pueden actualizar o borrar sus eventos del Calendario de Google. Si un usuario actualiza un evento después de crear una conferencia para él, es posible que tu complemento de Google Workspace deba responder al cambio actualizando los datos de la conferencia. Si tu sistema de conferencias de terceros depende del seguimiento de los datos de eventos, no actualizar la conferencia ante un cambio de evento puede hacer que la conferencia sea inutilizable.
El proceso de mantener actualizados los datos de la conferencia con los cambios en el evento del Calendario se denomina sincronización. Sincroniza los cambios de eventos creando un activador instalable de Google Apps Script que se active cada vez que cambien los eventos en un calendario determinado. El activador no informa qué eventos cambiaron y no puedes limitarlo solo a los eventos con conferencias que creaste. Solicita una lista de todos los cambios realizados en un calendario desde la última sincronización, filtra la lista de eventos y realiza las actualizaciones correspondientes.
El procedimiento general de sincronización es el siguiente:
- La primera vez que un usuario crea una conferencia, se inicializa el proceso de sincronización.
- Cada vez que el usuario crea, actualiza o borra uno de sus eventos del Calendario, el activador ejecuta una función de activación en tu proyecto de complemento.
- La función de activación examina el conjunto de cambios de eventos desde la última sincronización y determina si alguno requiere la actualización de una conferencia de terceros asociada.
- Las actualizaciones necesarias se realizan en las conferencias a través de solicitudes a la API de terceros.
- Se almacena un nuevo token de sincronización para que la próxima ejecución del activador solo examine los cambios más recientes del calendario.
Inicializa la sincronización
El proceso de inicialización garantiza que tu complemento esté listo para responder a los cambios del calendario. Una vez que el complemento haya creado correctamente una conferencia en un sistema de terceros, debe crear un activador instalable que responda a los cambios de eventos en este calendario, si el activador aún no existe.
Después de crear el activador, la inicialización debería finalizar con la creación del token de sincronización inicial. Esto se hace ejecutando la función de activación directamente.
Crea un activador de Calendario
Para sincronizar, tu complemento debe detectar cuándo se cambia un evento de Calendario que tiene una conferencia adjunta. Esto se logra creando un EventUpdated
activador instalable. Tu complemento solo necesita un activador para cada calendario y puede crearlos de forma programática.
Se recomienda crear un activador cuando el usuario crea su primera conferencia, ya que, en ese momento, comienza a usar el complemento. Después de crear una conferencia y verificar que no haya errores, tu complemento debe verificar si existe el activador para este usuario y, si no es así, crearlo.
Para crear activadores, el complemento debe tener los alcances https://www.googleapis.com/auth/calendar.readonly y https://www.googleapis.com/auth/script.scriptapp.
En el caso de los complementos de Google Workspace creados con endpoints HTTP, crea un activador devolviendo CalendarSubscriptionActionMarkup con operation: CREATE (por ejemplo, junto con los datos de creación de la conferencia en createConferenceDataActionMarkup). A diferencia de los activadores instalables de Apps Script, la creación de suscripciones en los tiempos de ejecución HTTP es idempotente: devolver esta acción varias veces para el mismo usuario y calendario garantiza que la suscripción permanezca activa sin crear activadores duplicados ni notificaciones de eventos redundantes.
Implementa una función de activación de sincronización
Las funciones de activador se ejecutan cuando Apps Script detecta una condición que hace que se active un activador.
Los EventUpdated activadores de Calendar se activan cuando un usuario crea, modifica o borra cualquier evento en un calendario especificado.
Implementa la función de activación que usa tu complemento. Esta función de activación debe hacer lo siguiente:
Realiza una llamada al servicio avanzado de Calendar
Calendar.Events.listcon unsyncTokenpara recuperar una lista de los eventos que cambiaron desde la última sincronización. Si usas un token de sincronización, reduces la cantidad de eventos que debe examinar tu complemento.Cuando la función de activación se ejecuta sin un token de sincronización válido, se recurre a una sincronización completa. Las sincronizaciones completas intentan recuperar todos los eventos dentro de un período prescrito para generar un token de sincronización nuevo y válido.
Se examina cada evento modificado para determinar si tiene una conferencia de terceros asociada.
Si un evento tiene una conferencia, se examina para ver qué se cambió. Según el cambio, es posible que se deba modificar la conferencia asociada. Por ejemplo, si se borró un evento, el complemento debería borrar la conferencia.
Los cambios necesarios en la conferencia se realizan a través de llamadas a la API del sistema de terceros.
Después de realizar todos los cambios necesarios, almacena el
nextSyncTokenque devuelve el métodoCalendar.Events.list. Este token de sincronización se encuentra en la última página de resultados que muestra la llamada aCalendar.Events.list.
Actualiza el evento de Calendario
En algunos casos, es posible que desees actualizar el evento del Calendario cuando realices una sincronización. Si decides hacerlo, actualiza el evento con la solicitud apropiada del servicio avanzado de Calendar. Asegúrate de usar la actualización condicional con un encabezado If-Match. Esto evita que tus cambios reemplacen los cambios simultáneos que el usuario realizó en un cliente diferente.
Ejemplo
En el siguiente ejemplo, se muestra cómo puedes configurar la sincronización de los eventos de calendario y sus conferencias asociadas.
/** * Initializes syncing of conference data by creating a sync trigger and * sync token if either does not exist yet. * * @param {String} calendarId The ID of the Google Calendar. */ function initializeSyncing(calendarId) { // Create a syncing trigger if it doesn't exist yet. createSyncTrigger(calendarId); // Perform an event sync to create the initial sync token. syncEvents({'calendarId': calendarId}); } /** * Creates a sync trigger if it does not exist yet. * * @param {String} calendarId The ID of the Google Calendar. */ function createSyncTrigger(calendarId) { // Check to see if the trigger already exists; if does, return. var allTriggers = ScriptApp.getProjectTriggers(); for (var i = 0; i < allTriggers.length; i++) { var trigger = allTriggers[i]; if (trigger.getTriggerSourceId() == calendarId) { return; } } // Trigger does not exist, so create it. The trigger calls the // 'syncEvents()' trigger function when it fires. var trigger = ScriptApp.newTrigger('syncEvents') .forUserCalendar(calendarId) .onEventUpdated() .create(); } /** * Sync events for the given calendar; this is the syncing trigger * function. If a sync token already exists, this retrieves all events * that have been modified since the last sync, then checks each to see * if an associated conference needs to be updated and makes any required * changes. If the sync token does not exist or is invalid, this * retrieves future events modified in the last 24 hours instead. In * either case, a new sync token is created and stored. * * @param {Object} e If called by a event updated trigger, this object * contains the Google Calendar ID, authorization mode, and * calling trigger ID. Only the calendar ID is actually used here, * however. */ function syncEvents(e) { var calendarId = e.calendarId; var properties = PropertiesService.getUserProperties(); var syncToken = properties.getProperty('syncToken'); var options; if (syncToken) { // There's an existing sync token, so configure the following event // retrieval request to only get events that have been modified // since the last sync. options = { syncToken: syncToken }; } else { // No sync token, so configure to do a 'full' sync instead. In this // example only recently updated events are retrieved in a full sync. // A larger time window can be examined during a full sync, but this // slows down the script execution. Consider the trade-offs while // designing your add-on. var now = new Date(); var yesterday = new Date(); yesterday.setDate(now.getDate() - 1); options = { timeMin: now.toISOString(), // Events that start after now... updatedMin: yesterday.toISOString(), // ...and were modified recently maxResults: 50, // Max. number of results per page of responses orderBy: 'updated' } } // Examine the list of updated events since last sync (or all events // modified after yesterday if the sync token is missing or invalid), and // update any associated conferences as required. var events; var pageToken; do { try { options.pageToken = pageToken; events = Calendar.Events.list(calendarId, options); } catch (err) { // Check to see if the sync token was invalidated by the server; // if so, perform a full sync instead. if (err.message === "Sync token is no longer valid, a full sync is required.") { properties.deleteProperty('syncToken'); syncEvents(e); return; } else { throw new Error(err.message); } } // Read through the list of returned events looking for conferences // to update. if (events.items && events.items.length > 0) { for (var i = 0; i < events.items.length; i++) { var calEvent = events.items[i]; // Check to see if there is a record of this event has a // conference that needs updating. if (eventHasConference(calEvent)) { updateConference(calEvent, calEvent.conferenceData.conferenceId); } } } pageToken = events.nextPageToken; } while (pageToken); // Record the new sync token. if (events.nextSyncToken) { properties.setProperty('syncToken', events.nextSyncToken); } } /** * Returns true if the specified event has an associated conference * of the type managed by this add-on; retuns false otherwise. * * @param {Object} calEvent The Google Calendar event object, as defined by * the Calendar API. * @return {boolean} */ function eventHasConference(calEvent) { var name = calEvent.conferenceData.conferenceSolution.name || null; // This version checks if the conference data solution name matches the // one of the solution names used by the add-on. Alternatively you could // check the solution's entry point URIs or other solution-specific // information. if (name) { if (name === "My Web Conference" || name === "My Recorded Web Conference") { return true; } } return false; } /** * Update a conference based on new Google Calendar event information. * The exact implementation of this function is highly dependant on the * details of the third-party conferencing system, so only a rough outline * is shown here. * * @param {Object} calEvent The Google Calendar event object, as defined by * the Calendar API. * @param {String} conferenceId The ID used to identify the conference on * the third-party conferencing system. */ function updateConference(calEvent, conferenceId) { // Check edge case: the event was cancelled if (calEvent.status === 'cancelled' || eventHasConference(calEvent)) { // Use the third-party API to delete the conference too. } else { // Extract any necessary information from the event object, then // make the appropriate third-party API requests to update the // conference with that information. } }