登記參加會議

程式設計層級:新手
時間長度:5 分鐘
專案類型:使用自訂選單事件導向觸發條件的自動化動作

目標

  • 瞭解解決方案的功能。
  • 瞭解 Apps Script 服務在這個解決方案中的功能。
  • 設定指令碼。
  • 執行指令碼。

認識這項解決方案

建立端對端活動報名系統。如果您即將舉辦會議等活動,可以為會議場次設定新日曆、建立報名表單,然後自動透過電子郵件將個人化行程傳送給參與者。

從試算表轉移至表單和日曆的資訊

運作方式

這個解決方案使用 Google 試算表中的自訂選單,導入自動事件註冊系統。這個指令碼會建立日曆,其中列出試算表試算表列出的會議活動。然後,指令碼會建立一份表單,內含參與者可註冊的事件清單。參與者填妥表單後,指令碼會將參與者新增至日曆活動,並以電子郵件寄送行程給他們。

Apps Script 服務

這項解決方案使用下列服務:

  • 試算表服務:將事件資訊提供給其他服務。
  • 日曆服務:建立活動的新日曆、在日曆中新增活動,並將參與者新增到報名的活動中。
  • Properties service:儲存日曆服務建立的日曆 ID。當使用者在自訂「會議」選單中按一下「設定會議」時,屬性服務會檢查日曆 ID 屬性是否存在,以檢查事件註冊系統是否已設定完成。這樣有助於避免建立重複的表單和日曆。
  • 表單服務:根據試算表中的資訊建立表單,讓參與者註冊課程。
  • 指令碼服務:建立觸發條件,會在參與者填寫表單時觸發。
  • 文件服務:取得參與者報名活動的活動資訊,並將事件清單新增至新文件。指令碼會授權與會者編輯文件。
  • Mail service:以電子郵件將行程文件傳送給參與者。

先備知識

如要使用這個範例,您必須具備下列先決條件:

  • Google 帳戶 (Google Workspace 帳戶可能需要管理員核准)。
  • 可存取網際網路的網路瀏覽器。

設定指令碼

  1. 按一下下列按鈕,建立「Create a sign up for a sessions」(為會議場次) 範例試算表。這個解決方案的 Apps Script 專案已附加至試算表。
    建立副本
  2. 依序按一下「Conference」>「Set upconference」。您可能需要重新整理頁面,這個自訂選單才會顯示。
  3. 系統顯示提示時,請授權指令碼。 如果 OAuth 同意畫面顯示「這個應用程式未驗證」警告,請依序選取「Advanced」>「Go to {Project Name} (unsafe)」

  4. 依序按一下「Conference」>「Set upconference」

執行指令碼

  1. 依序點選「工具」>「管理表單」>「前往即時表單」
  2. 填寫並提交表單。
  3. 前往 calendar.google.com
  4. 在左側確認已勾選「會議日曆」旁的方塊。
  5. 前往您報名參加的活動日期,確認您已將自己新增為參與者。

(選用) 重設解決方案

如要再次試用這項解決方案,或自訂解決方案來使用自己的事件資訊,必須重設初次執行指令碼時設定的某些項目。如要查看重設解決方案的步驟,請點選下方的「Reset the solution」(重設解決方案)

重設解決方案

步驟 1:重設已儲存的指令碼屬性

如果您多次嘗試執行指令碼,系統會顯示「您的會議已經設定完成。」在 Google 雲端硬碟中尋找報名表單! 這是因為會議日曆建立後,日曆 ID 會儲存為指令碼屬性。指令碼執行時,會檢查日曆 ID 屬性是否已存在;如果存在該屬性,指令碼就會停止執行。

請按照下列步驟移除現有的日曆 ID 屬性:

  1. 在試算表中依序按一下「擴充功能」>「Apps Script」
  2. 在 Apps Script 編輯器中,從函式下拉式清單中選取 resetProperties,然後按一下「Run」(執行)

步驟 2:刪除會議日曆

每次執行指令碼時,都會建立新的日曆。如果你不想保留建立的原始日曆,請按照下列步驟操作:

  1. 前往 calendar.google.com
  2. 在「會議日曆」旁邊,依序按一下「會議日曆的選項」圖示 > 「設定和共用」
  3. 捲動至設定底部,然後按一下「刪除」

步驟 3:刪除表單提交觸發條件

每次執行指令碼時,指令碼都會建立表單提交觸發條件。為避免因觸發多個觸發事件而產生重複電子郵件,請移除原始觸發條件。步驟如下:

  1. 在試算表中依序按一下「擴充功能」>「Apps Script」
  2. 在 Apps Script 專案中,按一下左側的「觸發條件」圖示
  3. 依序按一下觸發條件旁邊的「更多」圖示 >「刪除觸發條件」

每次執行指令碼時,系統都會建立新表單。如要刪除表單與試算表的連結並加以刪除,請按照下列步驟操作:

  1. 在試算表中,用滑鼠右鍵按一下「表單回應」工作表,然後依序點選「取消連結表單」>>「確定」
  2. 再次在「表單回應」工作表上按一下滑鼠右鍵,然後依序點選「刪除」>「確定」
  3. 前往 forms.google.com
  4. 在「會議表單」上按一下滑鼠右鍵,然後依序點選「移除」>「移至垃圾桶」

重設解決方案後,您可以新增自己的資料,或是繼續使用範例資料,然後再次執行指令碼。

查看程式碼

如要查看這個解決方案的 Apps Script 程式碼,請點選下方的「查看原始碼」

查看原始碼

Code.gs

solutions/automations/event-session-signup/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/event-session-signup

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Inserts a custom menu when the spreadsheet opens.
 */
function onOpen() {
  SpreadsheetApp.getUi().createMenu('Conference')
      .addItem('Set up conference', 'setUpConference_')
      .addToUi();
}

/**
 * Uses the conference data in the spreadsheet to create
 * Google Calendar events, a Google Form, and a trigger that allows the script
 * to react to form responses.
 */
function setUpConference_() {
  let scriptProperties = PropertiesService.getScriptProperties();
  if (scriptProperties.getProperty('calId')) {
    Browser.msgBox('Your conference is already set up. Look in Google Drive for your'
                   + ' sign-up form!');
                   return;
  }
  let ss = SpreadsheetApp.getActive();
  let sheet = ss.getSheetByName('Conference Setup');
  let range = sheet.getDataRange();
  let values = range.getValues();
  setUpCalendar_(values, range);
  setUpForm_(ss, values);
  ScriptApp.newTrigger('onFormSubmit').forSpreadsheet(ss).onFormSubmit()
      .create();
}

/**
 * Creates a Google Calendar with events for each conference session in the
 * spreadsheet, then writes the event IDs to the spreadsheet for future use.
 * @param {Array<string[]>} values Cell values for the spreadsheet range.
 * @param {Range} range A spreadsheet range that contains conference data.
 */
function setUpCalendar_(values, range) {
  let cal = CalendarApp.createCalendar('Conference Calendar');
  // Start at 1 to skip the header row.
  for (let i = 1; i < values.length; i++) {
    let session = values[i];
    let title = session[0];
    let start = joinDateAndTime_(session[1], session[2]);
    let end = joinDateAndTime_(session[1], session[3]);
    let options = {location: session[4], sendInvites: true};
    let event = cal.createEvent(title, start, end, options)
        .setGuestsCanSeeGuests(false);
    session[5] = event.getId();
  }
  range.setValues(values);

  // Stores the ID for the Calendar, which is needed to retrieve events by ID.
  let scriptProperties = PropertiesService.getScriptProperties();
  scriptProperties.setProperty('calId', cal.getId());
}

/**
 * Creates a single Date object from separate date and time cells.
 *
 * @param {Date} date A Date object from which to extract the date.
 * @param {Date} time A Date object from which to extract the time.
 * @return {Date} A Date object representing the combined date and time.
 */
function joinDateAndTime_(date, time) {
  date = new Date(date);
  date.setHours(time.getHours());
  date.setMinutes(time.getMinutes());
  return date;
}

/**
 * Creates a Google Form that allows respondents to select which conference
 * sessions they would like to attend, grouped by date and start time in the
 * caller's time zone.
 *
 * @param {Spreadsheet} ss The spreadsheet that contains the conference data.
 * @param {Array<String[]>} values Cell values for the spreadsheet range.
 */
function setUpForm_(ss, values) {
  // Group the sessions by date and time so that they can be passed to the form.
  let schedule = {};
  // Start at 1 to skip the header row.
  for (let i = 1; i < values.length; i++) {
    let session = values[i];
    let day = session[1].toLocaleDateString();
    let time = session[2].toLocaleTimeString();
    if (!schedule[day]) {
      schedule[day] = {};
    }
    if (!schedule[day][time]) {
      schedule[day][time] = [];
    }
    schedule[day][time].push(session[0]);
  }

  // Creates the form and adds a multiple-choice question for each timeslot.
  let form = FormApp.create('Conference Form');
  form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId());
  form.addTextItem().setTitle('Name').setRequired(true);
  form.addTextItem().setTitle('Email').setRequired(true);
  Object.keys(schedule).forEach(function(day) {
    let header = form.addSectionHeaderItem().setTitle('Sessions for ' + day);
    Object.keys(schedule[day]).forEach(function(time) {
      let item = form.addMultipleChoiceItem().setTitle(time + ' ' + day)
          .setChoiceValues(schedule[day][time]);
    });
  });
}

/**
 * Sends out calendar invitations and a
 * personalized Google Docs itinerary after a user responds to the form.
 *
 * @param {Object} e The event parameter for form submission to a spreadsheet;
 *     see https://developers.google.com/apps-script/understanding_events
 */
function onFormSubmit(e) {
  let user = {name: e.namedValues['Name'][0], email: e.namedValues['Email'][0]};

  // Grab the session data again so that we can match it to the user's choices.
  let response = [];
  let values = SpreadsheetApp.getActive().getSheetByName('Conference Setup')
      .getDataRange().getValues();
  for (let i = 1; i < values.length; i++) {
    let session = values[i];
    let title = session[0];
    let day = session[1].toLocaleDateString();
    let time = session[2].toLocaleTimeString();
    let timeslot = time + ' ' + day;

    // For every selection in the response, find the matching timeslot and title
    // in the spreadsheet and add the session data to the response array.
    if (e.namedValues[timeslot] && e.namedValues[timeslot] == title) {
      response.push(session);
    }
  }
  sendInvites_(user, response);
  sendDoc_(user, response);
}

/**
 * Add the user as a guest for every session he or she selected.
 * @param {object} user An object that contains the user's name and email.
 * @param {Array<String[]>} response An array of data for the user's session choices.
 */
function sendInvites_(user, response) {
  let id = ScriptProperties.getProperty('calId');
  let cal = CalendarApp.getCalendarById(id);
  for (let i = 0; i < response.length; i++) {
    cal.getEventSeriesById(response[i][5]).addGuest(user.email);
  }
}

/**
 * Creates and shares a personalized Google Doc that shows the user's itinerary.
 * @param {object} user An object that contains the user's name and email.
 * @param {Array<string[]>} response An array of data for the user's session choices.
 */
function sendDoc_(user, response) {
  let doc = DocumentApp.create('Conference Itinerary for ' + user.name)
      .addEditor(user.email);
  let body = doc.getBody();
  let table = [['Session', 'Date', 'Time', 'Location']];
  for (let i = 0; i < response.length; i++) {
    table.push([response[i][0], response[i][1].toLocaleDateString(),
      response[i][2].toLocaleTimeString(), response[i][4]]);
  }
  body.insertParagraph(0, doc.getName())
      .setHeading(DocumentApp.ParagraphHeading.HEADING1);
  table = body.appendTable(table);
  table.getRow(0).editAsText().setBold(true);
  doc.saveAndClose();

  // Emails a link to the Doc as well as a PDF copy.
  MailApp.sendEmail({
    to: user.email,
    subject: doc.getName(),
    body: 'Thanks for registering! Here\'s your itinerary: ' + doc.getUrl(),
    attachments: doc.getAs(MimeType.PDF),
  });
}

/**
 * Removes the calId script property so that the 'setUpConference_()' can be run again.
 */
function resetProperties(){
  let scriptProperties = PropertiesService.getScriptProperties();
  scriptProperties.deleteAllProperties();
}

協作者

這個範例是由 Google 在 Google Developers 專家的協助下維護。

後續步驟