회의 세션 신청 만들기

코딩 수준: 초급
소요 시간: 5분
프로젝트 유형: 맞춤 메뉴이벤트 기반 트리거를 사용한 자동화

목표

  • 솔루션의 작동 방식을 이해합니다.
  • 솔루션 내에서 Apps Script 서비스가 하는 작업을 이해합니다.
  • 스크립트를 설정합니다.
  • 스크립트를 실행합니다.

이 솔루션 정보

엔드 투 엔드 이벤트 등록 시스템을 만듭니다. 회의와 같은 예정된 이벤트가 있는 경우 회의 세션을 위한 새 캘린더를 설정하고, 가입 양식을 만들고, 참석자에게 맞춤 일정을 자동으로 이메일로 보낼 수 있습니다.

Sheets의 정보가 양식 및 Calendar로 전송됨

작동 방식

이 솔루션은 Google Sheets의 맞춤 메뉴를 사용하여 자동 이벤트 등록 시스템을 구현합니다. 이 스크립트는 Sheets 스프레드시트에 나열된 회의 일정이 포함된 캘린더를 만듭니다. 그런 다음 스크립트는 참석자가 등록할 수 있는 이벤트 목록이 포함된 양식을 만듭니다. 참석자가 양식을 작성하면 스크립트가 참석자를 캘린더 일정에 추가하고 일정을 이메일로 보냅니다.

Apps Script 서비스

이 솔루션은 다음 서비스를 사용합니다.

  • 스프레드시트 서비스: 다른 서비스에 이벤트 정보를 제공합니다.
  • Calendar 서비스: 일정의 새 캘린더를 만들고, 캘린더에 일정을 추가하고, 참석자가 등록한 일정에 참석자를 추가합니다.
  • 속성 서비스: Calendar 서비스에서 만든 캘린더의 ID를 저장합니다. 사용자가 맞춤 회의 메뉴에서 회의 설정을 클릭하면 속성 서비스는 캘린더 ID 속성이 있는지 확인하여 이벤트 등록 시스템이 이미 설정되었는지 확인합니다. 이렇게 하면 중복 양식과 캘린더가 생성되지 않습니다.
  • 양식 서비스: 참석자가 세션에 등록할 수 있는 양식을 스프레드시트의 정보로 만듭니다.
  • 스크립트 서비스: 참석자가 양식을 작성할 때 실행되는 트리거를 만듭니다.
  • 문서 서비스: 참석자가 등록한 일정의 이벤트 정보를 가져와 새 문서에 일정 목록을 추가합니다. 이 스크립트는 참석자에게 문서를 수정할 수 있는 권한을 부여합니다.
  • 우편 서비스: 참석자에게 일정 문서를 이메일로 보냅니다.

기본 요건

이 샘플을 사용하려면 다음 기본 요건이 필요합니다.

  • Google 계정 (Google Workspace 계정의 경우 관리자 승인이 필요할 수 있음)
  • 인터넷에 액세스할 수 있는 웹브라우저

스크립트 설정

  1. 다음 버튼을 클릭하여 회의 세션 등록 만들기 샘플 스프레드시트의 사본을 만듭니다. 이 솔루션의 Apps Script 프로젝트가 스프레드시트에 첨부되어 있습니다.
    사본 만들기
  2. 회의 > 회의 설정을 클릭합니다. 이 맞춤 메뉴가 표시되도록 페이지를 새로고침해야 할 수도 있습니다.
  3. 메시지가 표시되면 스크립트를 승인합니다. OAuth 동의 화면에 이 앱은 확인되지 않았습니다라는 경고가 표시되면 고급 > {프로젝트 이름}으로 이동(안전하지 않음)을 선택하여 계속 진행합니다.

  4. 회의 > 회의 설정을 다시 클릭합니다.

스크립트 실행

  1. 도구 > 양식 관리 > 실시간 양식으로 이동을 클릭합니다.
  2. 양식을 작성하여 제출합니다.
  3. calendar.google.com으로 이동합니다.
  4. 왼쪽에서 회의 캘린더 옆의 체크박스가 선택되어 있는지 확인합니다.
  5. 등록한 이벤트 날짜로 이동하여 참석자로 추가되었는지 확인합니다.

(선택사항) 솔루션 재설정

이 솔루션을 다시 시도하거나 자체 이벤트 정보를 사용하도록 맞춤설정하려면 스크립트를 처음 실행할 때 설정된 일부 항목을 재설정해야 합니다. 솔루션을 재설정하는 단계를 보려면 아래의 솔루션 재설정을 클릭합니다.

솔루션 재설정

1단계: 저장된 스크립트 속성 재설정

스크립트를 두 번 이상 실행하려고 하면 회의가 이미 설정되었습니다. Google Drive에서 가입 양식을 확인하세요. 이는 회의 캘린더가 생성되면 캘린더 ID가 스크립트 속성으로 저장되기 때문입니다. 스크립트가 실행되면 캘린더 ID 속성이 이미 있는지 확인하고 있는 경우 실행을 중지합니다.

기존 캘린더 ID 속성을 삭제하려면 다음 단계를 따르세요.

  1. 스프레드시트에서 확장 프로그램 > Apps Script를 클릭합니다.
  2. Apps Script 편집기에서 함수 드롭다운 목록에서 resetProperties를 선택하고 실행을 클릭합니다.

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 개발자 전문가의 도움을 받아 유지관리합니다.

다음 단계