创建第三方会议

您在脚本项目清单中定义的每个会议解决方案都有一个关联的 onCreateFunction。每当用户尝试选择某个会议解决方案事件时,该插件都会调用此函数来创建会议。

您必须实现插件清单中所述的每个 onCreateFunction。通常,这些函数必须执行以下操作:

  1. 检索第三方会议系统可能需要的 Google 日历活动信息,例如活动 ID 或参加者列表,以便创建会议。
  2. 连接到第三方会议服务,并使用 Google 日历活动信息创建新的会议。
  3. 如果会议创建请求由于某种原因失败,请使用错误信息构建并返回包含 ConferenceErrorConferenceData 对象。否则,请完成以下步骤。
    1. 初始化会议同步
    2. 使用第三方会议服务返回的信息构建并返回新的 ConferenceData 对象。

检索事件信息

如需创建第三方会议,您需要关于相应 Google 日历活动的某些信息。所需的确切活动信息因第三方会议系统而异,但通常包括活动开始时间、结束时间、摘要、参加者列表和 ID。

被调用时,系统会向您定义的每个 onCreateFunction 传递一个包含日历 ID 和事件 ID 的参数。您可以使用这些日历 ID 通过日历高级服务检索完整的活动信息。

Google 日历可以在活动存在之前将其添加到活动中。在这种情况下,Google 日历会向 onCreateFunction 传递有效的 eventId,但后续调用 Calendar.Events.get() 可能会导致错误响应,指出事件不存在。在这些情况下,最好使用占位符数据创建第三方会议;在活动下次同步时,系统会替换这些数据。

创建第三方会议

onCreateFunction 检索必要的事件数据后,必须连接到第三方会议系统才能创建会议。通常情况下,可以通过发出第三方会议系统支持的 API 请求来完成此操作。请参阅第三方会议解决方案的相关文档,确定您可以使用哪些 API 请求来创建会议。

在 Apps 脚本中,处理外部 API 请求的最简单方法是使用 OAuth2 for Apps ScriptOAuth1 for Apps Script 开源库。您还可以使用 UrlFetch 服务连接到外部 API,但这需要明确处理授权详细信息。

请求创建会议后,您可能需要发出其他请求以检索新的会议详细信息。

初始化会议同步

插件在第三方系统上成功创建会议后,应该采取一些步骤来启用同步功能,以便对 Google 日历活动所做的更改反映在会议中。

如需详细了解如何在会议创建后设置同步,请参阅同步日历更改

构建会议数据响应

然后,onCreateFunction 必须使用第三方服务返回的会议信息构建并返回 ConferenceData 对象;会议数据部分介绍了此对象的内容。会议开始后,Google 日历会使用这些信息将用户定向到会议。

构建 ConferenceData 对象时,请注意字段长度、入口点 URI 的格式以及允许的入口点组合存在一些限制。例如,单个 ConferenceData 中最多只能有一个 VIDEO 入口点。这些限制与针对相应 conferenceData 字段的 Calendar API 事件中所述的限制相同,不过这里介绍的所有 API 事件字段在 Apps 脚本中都不提供。

处理错误

在某些情况下,由于第三方会议系统返回的错误,会议创建无法完成。在这些情况下,您的插件应该通过构建并返回包含 ConferenceError 详细信息的 ConferenceData 对象来应对错误情况,以便 Google 日历可以相应地执行操作。

构造 ConferenceData 对象以报告错误时,除了 ConferenceError 对象之外,您无需添加任何 ConferenceData 组件。ConferenceErrors 可以包含 ConferenceErrorType 和错误消息,以及身份验证问题发出网址时(允许用户登录第三方会议系统)。

示例

下面显示了一个 onCreateFunction 示例(请注意,函数的名称可以是任意名称;您只需在插件项目清单中定义该函数即可)。

函数 create3rdPartyConference() 与第三方系统联系以在该会议中创建会议,getAuthenticationUrl() 函数创建第三方系统身份验证网址。这些变更不会在此处完全实现,因为它们高度依赖于第三方系统详细信息。

函数 initializeSyncing() 在这里未显示;它会处理同步所需的任何初步工作。如需了解详情,请参阅同步日历更改

/**
 *  Creates a conference, then builds and returns a ConferenceData object
 *  with the corresponding conference information. This method is called
 *  when a user selects a conference solution defined by the add-on that
 *  uses this function as its 'onCreateFunction' in the add-on manifest.
 *
 *  @param {Object} arg The default argument passed to a 'onCreateFunction';
 *      it carries information about the Google Calendar event.
 *  @return {ConferenceData}
 */
function createConference(arg) {
  const eventData = arg.eventData;
  const calendarId = eventData.calendarId;
  const eventId = eventData.eventId;

  // Retrieve the Calendar event information using the Calendar
  // Advanced service.
  var calendarEvent;
  try {
    calendarEvent = Calendar.Events.get(calendarId, eventId);
  } catch (err) {
    // The calendar event does not exist just yet; just proceed with the
    // given event ID and allow the event details to sync later.
    console.log(err);
    calendarEvent = {
      id: eventId,
    };
  }

  // Create a conference on the third-party service and return the
  // conference data or errors in a custom JSON object.
  var conferenceInfo = create3rdPartyConference(calendarEvent);

  // Build and return a ConferenceData object, either with conference or
  // error information.
  var dataBuilder = ConferenceDataService.newConferenceDataBuilder();

  if (!conferenceInfo.error) {
    // No error, so build the ConferenceData object from the
    // returned conference info.

    var phoneEntryPoint = ConferenceDataService.newEntryPoint()
        .setEntryPointType(ConferenceDataService.EntryPointType.PHONE)
        .setUri('tel:+' + conferenceInfo.phoneNumber)
        .setPin(conferenceInfo.phonePin);

    var adminEmailParameter = ConferenceDataService.newConferenceParameter()
        .setKey('adminEmail')
        .setValue(conferenceInfo.adminEmail);

    dataBuilder.setConferenceId(conferenceInfo.id)
        .addEntryPoint(phoneEntryPoint)
        .addConferenceParameter(adminEmailParameter)
        .setNotes(conferenceInfo.conferenceLegalNotice);

    if (conferenceInfo.videoUri) {
      var videoEntryPoint = ConferenceDataService.newEntryPoint()
          .setEntryPointType(ConferenceDataService.EntryPointType.VIDEO)
          .setUri(conferenceInfo.videoUri)
          .setPasscode(conferenceInfo.videoPasscode);
      dataBuilder.addEntryPoint(videoEntryPoint);
    }

    // Since the conference creation request succeeded, make sure that
    // syncing has been enabled.
    initializeSyncing(calendarId, eventId, conferenceInfo.id);

  } else if (conferenceInfo.error === 'AUTH') {
    // Authenentication error. Implement a function to build the correct
    // authenication URL for the third-party conferencing system.
    var authenticationUrl = getAuthenticationUrl();
    var error = ConferenceDataService.newConferenceError()
        .setConferenceErrorType(
            ConferenceDataService.ConferenceErrorType.AUTHENTICATION)
        .setAuthenticationUrl(authenticationUrl);
    dataBuilder.setError(error);

  } else {
    // Other error type;
    var error = ConferenceDataService.newConferenceError()
        .setConferenceErrorType(
            ConferenceDataService.ConferenceErrorType.TEMPORARY);
    dataBuilder.setError(error);
  }

  // Don't forget to build the ConferenceData object.
  return dataBuilder.build();
}


/**
 *  Contact the third-party conferencing system to create a conference there,
 *  using the provided calendar event information. Collects and retuns the
 *  conference data returned by the third-party system in a custom JSON object
 *  with the following fields:
 *
 *    data.adminEmail - the conference administrator's email
 *    data.conferenceLegalNotice - the conference legal notice text
 *    data.error - Only present if there was an error during
 *         conference creation. Equal to 'AUTH' if the add-on user needs to
 *         authorize on the third-party system.
 *    data.id - the conference ID
 *    data.phoneNumber - the conference phone entry point phone number
 *    data.phonePin - the conference phone entry point PIN
 *    data.videoPasscode - the conference video entry point passcode
 *    data.videoUri - the conference video entry point URI
 *
 *  The above fields are specific to this example; which conference information
 *  you add-on needs is dependent on the third-party conferencing system
 *  requirements.
 *
 * @param {Object} calendarEvent A Calendar Event resource object returned by
 *     the Google Calendar API.
 * @return {Object}
 */
function create3rdPartyConference(calendarEvent) {
  var data = {};

  // Get the add-on settings information to pass to the third-party system.
  // Alternatively, store the add-on setting information on the third-party
  // system.
  var props = PropertiesService.getUserProperties();
  var disableVideo = props.getProperty('disableVideo') || "false";
  var namePrefix = props.getProperty('namePrefix')

  // Implementation details dependent on the third-party system API.
  // Typically one or more API calls are made to create the conference and
  // acquire its relevant data, which is then put in to the returned JSON
  // object.

  return data;
}

/**
 *  Return the URL used to authenticate the user with the third-party
 *  conferencing system.
 *
 *  @return {String}
 */
function getAuthenticationUrl() {
  var url;
  // Implementation details dependent on the third-party system.

  return url;
}