正在同步處理日曆活動變更

使用者可以自由更新或刪除自己的 Google 日曆活動。如果使用者 而是在建立會議後更新活動。此外,外掛程式可能需要 更新會議資料來回應異動內容。如果您的 第三方會議系統需要定期追蹤事件資料 無法在活動變更時更新會議 會導致使用者體驗不佳,並導致使用者體驗不佳。

將會議資料與 Google 日曆活動變更保持同步的程序稱為「同步」。您可以建立 Apps Script 可安裝的觸發事件,在指定日曆中的活動發生變更時觸發,藉此同步處理活動變更。不過,觸發條件並未 回報哪些活動發生變更,且無法將報告限制為僅限含有 您建立的會議。您必須改為要求清單,列出自上次同步處理後,對日曆所做的所有變更,然後篩選事件清單,並據此更新。

一般同步程序如下:

  1. 使用者第一次建立會議時,系統會初始化同步處理程序。
  2. 每當使用者建立、更新或刪除他們的日曆活動 觸發條件會在外掛程式專案中執行觸發條件函式
  3. 觸發事件函式會檢查自上次同步處理以來的事件變更集合,並判斷是否需要更新相關的第三方會議。
  4. 如需更新會議,請透過第三方 API 要求。
  5. 系統會儲存新的同步權杖,以便下次觸發事件執行時,只需檢查日曆的最新變更。

初始化同步處理作業

一旦外掛程式成功在第三方系統中建立會議 即會建立一個可安裝的觸發條件 會回應 活動變更 (如果觸發條件不存在)。

建立觸發事件後,系統應會建立初始同步權杖,完成初始化程序。方法是直接執行觸發事件函式。

建立日曆觸發條件

如要同步處理,您的外掛程式必須偵測附加會議的 Google 日曆活動是否有變更。這可透過建立 EventUpdated 可安裝的觸發條件來達成。你的加購內容 每個日曆只需要一個觸發條件,可以透過程式建立。

建立觸發條件的好時機,就是使用者第一次發起會議時。 因為使用者開始使用外掛程式更新後 建立會議 並確認沒有任何錯誤,您的外掛程式應該檢查 觸發條件存在,而非建立該名使用者。

實作同步處理觸發條件函式

當 Apps Script 偵測到造成這種情況的條件時,就會執行觸發條件函式 要觸發的觸發條件 EventUpdated 日曆觸發條件 會在使用者於指定事件建立、修改或刪除事件時觸發 日曆。

您必須實作外掛程式使用的觸發事件函式。這項觸發條件函式 應執行以下操作:

  1. 使用 syncToken 發出日曆進階服務 Calendar.Events.list() 呼叫,擷取自上次同步處理後變更的事件清單。使用同步權杖可減少外掛程式的事件數量 皆須檢查。

    在沒有有效的同步權杖的情況下執行觸發函式時,觸發條件就會傳回 切換成完整同步處理。完整同步作業只會在規定的時間範圍內嘗試擷取所有事件,以產生新的有效同步權杖。

  2. 系統會檢查每個修改過的事件,以判斷是否具有相關 以及第三方會議通訊
  3. 如果活動有會議,我們會檢查變更內容。 視變更內容而定,修改關聯會議時可能會 不一定。舉例來說,如果活動已刪除,外掛程式應 這個會議可能也會刪除
  4. 如需變更會議,請向第三方系統發出 API 呼叫。
  5. 完成所有必要變更後,請儲存 Calendar.Events.list() 方法傳回的 nextSyncToken。這個同步處理權杖出現在上次 頁。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.

  }
}