Пользователи могут свободно обновлять или удалять свои события в Google Calendar. Если пользователь обновляет событие после создания конференции для него, вашему дополнению может потребоваться отреагировать на изменение, обновив данные конференции. Если ваша сторонняя система конференций зависит от отслеживания данных событий, отсутствие обновления конференции при изменении события может сделать конференцию непригодной для использования и привести к плохому пользовательскому опыту.
Процесс обновления данных конференции с учетом изменений в событии Google Calendar называется синхронизацией . Вы можете синхронизировать изменения событий, создав устанавливаемый триггер Apps Script, который срабатывает при изменении событий в заданном календаре. К сожалению, триггер не сообщает, какие события изменились, и вы не можете ограничить его только событиями с конференциями, которые вы создали. Вместо этого вы должны запросить список всех изменений, внесенных в календарь с момента последней синхронизации, отфильтровать список событий и внести соответствующие обновления.
Общая процедура синхронизации следующая:
- Когда пользователь впервые создает конференцию, инициализируется процесс синхронизации.
- Всякий раз, когда пользователь создает, обновляет или удаляет одно из событий своего календаря, триггер выполняет функцию триггера в вашем проекте надстройки.
- Функция триггера проверяет набор изменений событий с момента последней синхронизации и определяет, требуют ли какие-либо обновления связанной сторонней конференции.
- Все необходимые обновления конференций вносятся путем отправки сторонних API-запросов.
- Новый токен синхронизации сохраняется, поэтому при следующем выполнении триггера необходимо будет проверить только самые последние изменения в календаре.
Инициализировать синхронизацию
После того как дополнение успешно создало конференцию в сторонней системе, оно должно создать устанавливаемый триггер , который реагирует на изменения событий в этом календаре, если триггер еще не существует.
После создания триггера инициализация должна завершиться созданием начального токена синхронизации. Это делается путем непосредственного выполнения функции триггера.
Создать триггер календаря
Для синхронизации вашему дополнению необходимо обнаружить, когда изменяется событие Календаря, к которому прикреплена конференция. Это достигается путем создания устанавливаемого триггера EventUpdated
. Вашему дополнению требуется только один триггер для каждого календаря, и он может создавать их программно.
Хорошее время для создания триггера — когда пользователь создает свою первую конференцию, так как в этот момент пользователь начинает использовать дополнение. После создания конференции и проверки отсутствия ошибок ваше дополнение должно проверить, существует ли триггер для этого пользователя, и если нет, создать его.
Реализовать функцию синхронного триггера
Функции триггера выполняются, когда Apps Script обнаруживает условие, вызывающее срабатывание триггера. Триггеры EventUpdated
Calendar срабатывают , когда пользователь создает, изменяет или удаляет любое событие в указанном календаре.
Вы должны реализовать функцию триггера, которую использует ваше дополнение. Эта функция триггера должна делать следующее:
- Сделайте вызов расширенной службы Calendar
Calendar.Events.list()
с использованиемsyncToken
для получения списка событий, которые изменились с момента последней синхронизации. Используя токен синхронизации, вы уменьшаете количество событий, которые должна проверять ваша надстройка.Когда функция триггера выполняется без действительного токена синхронизации, она возвращается к полной синхронизации . Полная синхронизация просто пытается извлечь все события в течение заданного окна времени, чтобы сгенерировать новый действительный токен синхронизации.
- Каждое измененное событие проверяется на предмет наличия связанной с ним сторонней конференции.
- Если событие имеет конференцию, оно проверяется, чтобы увидеть, что было изменено. В зависимости от изменения может потребоваться изменение связанной конференции. Например, если событие было удалено, то дополнение, вероятно, должно удалить и конференцию.
- Все необходимые изменения в конференции вносятся путем API-вызовов сторонней системы.
- После внесения всех необходимых изменений сохраните
nextSyncToken
, возвращаемый методомCalendar.Events.list()
. Этот токен синхронизации находится на последней странице результатов, возвращаемых вызовомCalendar.Events.list()
.
Обновление события Google Календаря
В некоторых случаях вам может потребоваться обновить событие Google Calendar при выполнении синхронизации. Если вы решите сделать это, сделайте обновление события с помощью соответствующего запроса на расширенную службу Google Calendar . Обязательно используйте условное обновление с заголовком If-Match
. Это предотвращает непреднамеренную перезапись ваших изменений, сделанных пользователем в другом клиенте.
Пример
В следующем примере показано, как можно настроить синхронизацию событий календаря и связанных с ними конференций.
/** * 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. } }