登記參加會議

程式設計程度:初學者
時間長度:5 分鐘
專案類型:使用自訂選單事件驅動觸發事件的自動化動作

目標

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

認識這項解決方案

建立端對端活動登錄系統。如果您有即將舉行的活動 (例如會議),可以為會議活動建立新的日曆、建立報名表單,並自動透過電子郵件傳送個人化行程給與會者。

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

運作方式

這個解決方案會使用 Google 試算表中的自訂選單,實作自動化活動登錄系統。這個指令碼會建立日曆,並在其中列出 Google 試算表試算表中的會議活動。接著,指令碼會建立表單,列出與會者可報名的活動。參與者填妥表單後,指令碼會將他們加入日曆活動,並將行程表傳送給他們的電子郵件地址。

Apps Script 服務

本解決方案會使用下列服務:

  • 試算表服務:為其他服務提供事件資訊。
  • 日曆服務:為活動建立新的日曆、將活動新增至日曆,以及將出席者新增至他們註冊的活動。
  • Properties service:儲存日曆服務建立的日曆 ID。當使用者從自訂的「會議」選單中點選「設定會議」時,屬性服務會檢查日曆 ID 屬性是否存在,藉此確認是否已設定事件註冊系統。這麼做有助於避免建立重複的表單和日曆。
  • 表單服務:根據試算表中的資訊建立表單,讓與會者報名參加工作坊。
  • 指令碼服務:建立觸發條件,在與會者填寫表單時觸發。
  • 文件服務:取得參與者註冊的事件資訊,並將事件清單新增至新文件。指令碼會授予與會者編輯文件的權限。
  • 郵件服務:將行程文件傳送至與會者。

必要條件

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

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

設定指令碼

  1. 按一下下方按鈕,複製「建立研討會活動註冊表單」範例試算表。這個解決方案的 Apps Script 專案已附加至試算表。
    「建立副本」
  2. 依序按一下「會議」「設定會議」。您可能需要重新整理頁面,才能顯示這個自訂選單。
  3. 出現提示時,請授權執行指令碼。如果 OAuth 同意畫面顯示「This app isn't verified」警告,請依序選取「Advanced」「Go to {Project Name} (unsafe)」(前往「{Project Name}」(不安全))。

  4. 依序點選「會議」「設定會議」。

執行指令碼

  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 開發人員專家提供協助。

後續步驟