Синхронизация изменений конференции в календаре

Пользователи могут свободно обновлять или удалять свои мероприятия Календаря Google. Если пользователь обновляет событие после создания для него конференции, вашему надстройке может потребоваться отреагировать на это изменение, обновив данные конференции. Если ваша сторонняя система конференц-связи зависит от отслеживания данных о событиях, отсутствие обновления конференции при изменении события может сделать конференцию непригодной для использования и ухудшить взаимодействие с пользователем.

Процесс обновления данных конференции с учетом изменений в мероприятии Календаря Google называется синхронизацией . Вы можете синхронизировать изменения событий, создав устанавливаемый триггер Apps Script, который срабатывает при каждом изменении событий в данном календаре. К сожалению, триггер не сообщает, какие события изменились, и вы не можете ограничить его только событиями с созданными вами конференциями. Вместо этого вы должны запросить список всех изменений, внесенных в календарь с момента последней синхронизации, отфильтровать список событий и внести соответствующие обновления.

Общая процедура синхронизации следующая:

  1. Когда пользователь впервые создает конференцию, инициализируется процесс синхронизации.
  2. Всякий раз, когда пользователь создает, обновляет или удаляет одно из событий своего календаря, триггер выполняет функцию триггера в вашем дополнительном проекте.
  3. Функция триггера проверяет набор изменений событий с момента последней синхронизации и определяет, требуют ли они обновления связанной сторонней конференции.
  4. Любые необходимые обновления вносятся в конференции посредством запросов стороннего API.
  5. Новый токен синхронизации сохраняется, поэтому при следующем выполнении триггера необходимо будет проверить только самые последние изменения в календаре.

Инициализировать синхронизацию

После того как надстройка успешно создала конференцию в сторонней системе, она должна создать устанавливаемый триггер , который реагирует на изменения событий в этом календаре, если триггер еще не существует.

После создания триггера инициализация должна завершиться созданием исходного токена синхронизации. Это делается путем непосредственного выполнения функции триггера.

Создайте триггер календаря

Для синхронизации вашему дополнению необходимо обнаруживать изменения в событии Календаря, к которому прикреплена конференция. Это достигается путем создания устанавливаемого триггера EventUpdated . Вашему дополнению нужен только один триггер для каждого календаря, и вы можете создавать их программно.

Хорошее время для создания триггера — это когда пользователь создает свою первую конференцию, поскольку в этот момент пользователь начинает использовать надстройку. После создания конференции и проверки отсутствия ошибок ваше дополнение должно проверить, существует ли триггер для этого пользователя, и, если нет, создать его.

Реализация функции триггера синхронизации

Триггерные функции выполняются, когда Apps Script обнаруживает условие, вызывающее срабатывание триггера. EventUpdated Calendar срабатывает , когда пользователь создает, изменяет или удаляет любое событие в указанном календаре.

Вы должны реализовать функцию триггера, которую использует ваше дополнение. Эта триггерная функция должна делать следующее:

  1. Выполните вызов расширенной службы календаря Calendar.Events.list() с использованием syncToken , чтобы получить список событий, которые изменились с момента последней синхронизации. Используя токен синхронизации, вы уменьшаете количество событий, которые должно проверять ваше дополнение.

    Когда триггерная функция выполняется без действительного токена синхронизации, она переключается на полную синхронизацию . Полная синхронизация просто пытается получить все события в течение заданного периода времени, чтобы создать новый действительный токен синхронизации.

  2. Каждое измененное событие проверяется на наличие связанной с ним сторонней конференции.
  3. Если событие имеет конференцию, оно проверяется на предмет изменений. В зависимости от изменения может потребоваться модификация соответствующей конференции. Например, если событие было удалено, надстройке, вероятно, следует удалить и конференцию.
  4. Любые необходимые изменения в конференции вносятся путем вызова API сторонней системы.
  5. После внесения всех необходимых изменений сохраните nextSyncToken возвращенный методом Calendar.Events.list() . Этот токен синхронизации находится на последней странице результатов, возвращаемых вызовом Calendar.Events.list() .

Обновление события Календаря Google

В некоторых случаях вам может потребоваться обновить событие Календаря Google при выполнении синхронизации. Если вы решите это сделать, обновите мероприятие с помощью соответствующего запроса на расширенное обслуживание Календаря Google . Обязательно используйте условное обновление с заголовком 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.

  }
}