正在同步日历会议更改

用户可以自由更新或删除其 Google 日历活动。如果用户 在创建会议后更新了活动,您的插件可能需要 通过更新会议数据来响应更改。如果您的 第三方会议系统依赖于对活动数据的跟踪 如果在活动更改时未能更新会议,则会显示会议 会导致糟糕的用户体验。

根据 Google 日历活动称为同步。您可以通过以下方式同步事件更改: 创建 Apps 脚本 可安装触发器 指定日历中的活动。很遗憾,触发器 报告哪些事件发生了变化,而您不能将其限制为仅报告 已创建的会议数量而是必须请求一个 自上次同步以来对日历所做的所有更改, 事件列表,并进行相应的更新。

常规同步过程如下:

  1. 用户首次创建会议时,系统会初始化同步过程。
  2. 每当用户创建、更新或删除某个日历活动时 触发器在插件项目中执行触发器函数
  3. 触发器函数检查自上次触发、 并确定是否需要更新相关联的第三方 会议
  4. 任何必要的更新都会通过将第三方分配给会议 API 请求。
  5. 系统存储了新的同步令牌,因此下一次触发器执行只需 检查日历的最新更改。

初始化同步

当该插件在第三方系统上成功创建会议后, 系统应创建一个可安装的触发器 可响应 事件更改 此日历中(如果该触发器尚不存在)。

创建触发器后,应通过创建初始 同步令牌。具体方法是直接执行触发器函数。

创建日历触发器

如要进行同步,您的插件需要检测包含附加 会议已更改。这是通过创建一个 EventUpdated 来实现的。 可安装触发器。您的插件 每个日历只需要一个触发器,并且可以以编程方式创建触发器。

创建触发器的理想时机是在用户创建第一场会议、 因为这时候用户就开始使用相应插件了更新后 创建会议 并确认没有错误,您的插件应检查 已存在此触发器,如果未创建该触发器。

实现同步触发器函数

当 Apps 脚本检测到导致以下错误的条件时,就会执行触发器函数: 要触发的触发器。 EventUpdated 个日历触发器 在用户创建、修改或删除指定 日历。

您必须实现插件使用的触发器函数。此触发器函数 应执行以下操作:

  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.

  }
}