캘린더 회의 변경사항 동기화 중

사용자는 Google Calendar 일정을 자유롭게 업데이트하거나 삭제할 수 있습니다. 사용자가 회의를 생성한 뒤 일정을 업데이트하는 경우, 부가기능이 회의에 응답하려면 회의 데이터를 업데이트해야 합니다. 만약 서드 파티 회의 시스템은 일정 데이터를 추적해야 하므로 일정 변경으로 인해 회의를 업데이트하지 못하면 회의를 렌더링할 수 있음 사용자 경험이 저하될 수 있습니다.

변경 사항을 반영하여 컨퍼런스 데이터를 업데이트하는 프로세스를 Google 캘린더 일정을 동기화라고 합니다. 다음과 같은 방법으로 이벤트 변경사항을 동기화할 수 있습니다. Apps Script 만들기 실행되는 설치 가능한 트리거 지정된 캘린더의 일정이 변경될 때마다 아쉽게도 트리거는 보고하며 확인할 수 있습니다. 대신 광고 목록에서 마지막 동기화 이후 캘린더에 적용된 모든 변경사항을 보려면 적절하게 업데이트합니다.

일반적인 동기화 절차는 다음과 같습니다.

  1. 사용자가 회의를 처음 만들면 동기화 프로세스가 초기화됩니다.
  2. 사용자가 Calendar 일정을 만들거나 업데이트하거나 삭제할 때마다 트리거가 부가기능 프로젝트에서 트리거 함수를 실행합니다.
  3. 트리거 함수는 마지막 이벤트 발생 후의 이벤트 변경사항 집합을 검사합니다. 동기화를 실행하고 연결된 서드 파티의 업데이트가 필요한지 판단하여 회의를 진행해 보겠습니다
  4. 필요한 모든 업데이트는 서드 파티 공급업체를 통해 컨퍼런스에 API 요청
  5. 다음 트리거 실행 시에만 실행해도 되도록 새 동기화 토큰이 저장됩니다. 캘린더에 대한 최근 변경 사항을 검사할 수 있습니다.

동기화 초기화

부가기능이 서드 파티 시스템에서 회의를 성공적으로 생성하면, 설치 가능한 트리거를 만들어야 합니다. 다음과 같이 반응합니다 이벤트 변경사항 이 캘린더에 계속 표시됩니다.

트리거를 만든 후 첫 번째 트리거 매개변수를 생성하여 초기화가 완료되어야 합니다. 동기화 토큰을 사용할 수 있습니다. 트리거 함수를 직접 실행하면 됩니다.

Calendar 트리거 만들기

동기화하려면 부가기능에서 변경됩니다. 이 작업은 EventUpdated 설치 가능한 트리거. 내 부가기능 각 캘린더에 하나의 트리거만 필요하며 프로그래매틱 방식으로 트리거를 만들 수 있습니다.

트리거를 만들 때 적절한 시점은 사용자가 첫 회의를 만들 때 사용자가 부가기능을 사용하기 시작했기 때문입니다 후(After) 회의 생성 오류가 없는지 확인하면 부가기능에서 이 사용자에 대한 트리거가 존재하고, 없으면 만듭니다.

동기화 트리거 함수 구현

트리거 함수는 Apps Script에서 트리거의 원인이 되는 조건을 감지하면 실행됩니다. 실행할 트리거입니다. EventUpdated Calendar 트리거 사용자가 지정된 이벤트에서 이벤트를 생성, 수정 또는 삭제하면 있습니다.

부가기능에서 사용하는 트리거 함수를 구현해야 합니다. 이 트리거 함수는 다음을 수행해야 합니다.

  1. 다음을 사용하여 캘린더 고급 서비스 Calendar.Events.list()를 호출합니다. syncToken: 마지막 동기화할 수 있습니다. 동기화 토큰을 사용하면 부가기능에서 발생하는 이벤트 수를 줄일 수 있습니다. 살펴봤습니다

    트리거 함수가 유효한 동기화 토큰 없이 실행되면 전체 동기화로 전환합니다. 전체 동기화는 모든 이벤트를 검색하려고 시도합니다. 새로운 유효 동기화를 생성하기 위해 지정된 시간 내에 토큰입니다.

  2. 수정된 각 이벤트를 검토하여 있습니다.
  3. 일정에 회의가 있는 경우 변경된 내용을 확인하기 위해 검사됩니다. 변경사항에 따라 연결된 회의가 수정될 수 있습니다. 필요할 수 있습니다 예를 들어 이벤트가 삭제된 경우 부가기능이 회의도 삭제할 수 있습니다
  4. 컨퍼런스에 필요한 모든 변경은 서드 파티 시스템을 통해 사용할 수 있습니다
  5. 필요한 사항을 모두 변경한 후 다음에서 반환한 nextSyncToken를 저장합니다. Calendar.Events.list() 메서드 이 동기화 토큰은 Calendar.Events.list() 호출에서 반환된 결과의 페이지입니다.

Google Calendar 일정 업데이트

경우에 따라 작업을 수행할 때 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.

  }
}