회의 주제 설정하기

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

목표

  • 솔루션의 기능을 이해합니다.
  • 솔루션 내에서 Apps Script 서비스의 기능을 이해합니다.
  • 스크립트를 설정합니다.
  • 스크립트를 실행합니다.

이 솔루션 정보

Google Docs에서 자동으로 일정목록 문서를 만들어 Google Calendar 회의에 첨부합니다.

Calendar 일정에 추가된 주제 스크린샷

사용 방법

스크립트가 의제에 대한 문서 템플릿을 만듭니다. 캘린더를 업데이트하면 스크립트가 내가 소유한 이벤트의 설명에 '#agenda'가 포함되어 있는지 확인합니다. 태그가 있는 경우 스크립트는 템플릿의 사본을 만들어 캘린더 일정에 추가하고 이벤트 참석자와 공유합니다.

Apps Script 서비스

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

  • Drive 서비스–템플릿 문서가 있는지 확인하고 없으면 템플릿 문서를 위한 새 폴더를 만듭니다. 각 새 주제에 대한 템플릿 문서의 사본을 만듭니다.
  • 문서 서비스–주제 템플릿을 만듭니다.
  • 캘린더 서비스: '#agenda' 태그가 있는 일정을 확인하고 일정목록 문서 링크로 일정 설명을 업데이트합니다.
  • 기본 서비스: Session 클래스를 사용하여 사용자의 이메일을 가져옵니다. 이는 현재 사용자를 위한 트리거를 빌드하는 데 도움이 됩니다.
  • 스크립트 서비스–사용자의 캘린더가 변경될 때마다 실행되는 트리거를 만듭니다.

기본 요건

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

  • Google 계정 (Google Workspace 계정은 관리자 승인이 필요할 수 있음)
  • 인터넷 액세스가 가능한 웹브라우저

스크립트 설정

  1. 아래 버튼을 클릭하여 회의 주제 만들기 Apps Script 프로젝트 샘플을 엽니다.
    프로젝트 열기
  2. 개요 를 클릭합니다.
  3. 개요 페이지에서 사본 만들기 사본 만들기 아이콘를 클릭합니다.
  4. 복사한 프로젝트의 함수 드롭다운에서 setUp을 선택합니다.
  5. 실행을 클릭합니다.
  6. 메시지가 표시되면 스크립트를 승인합니다. OAuth 동의 화면에 확인되지 않은 앱입니다라는 경고가 표시되면 고급 > {프로젝트 이름}(으)로 이동(안전하지 않음)을 선택하여 계속 진행합니다.

스크립트 실행

  1. Google 캘린더를 엽니다.
  2. 새 일정을 만들거나 기존 일정을 수정합니다.
  3. 설명에 #agenda을 추가하고 이벤트를 저장합니다.
  4. 이메일에서 문서가 공유되었다는 이메일 알림을 확인하거나 캘린더를 새로고침하고 이벤트를 다시 클릭하면 일정목록 문서의 링크가 표시됩니다.

모든 참석자에게 일정목록을 보라는 이메일 알림이 전송됩니다. 이 스크립트는 참석자에게 수정 권한을 부여하지만, 스크립트를 수정하여 참석자의 일정목록 문서 권한을 업데이트할 수 있습니다.

코드 검토

이 솔루션의 Apps Script 코드를 검토하려면 아래의 소스 코드 보기를 클릭하세요.

소스 코드 보기

Code.gs

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

/*
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.
*/

/**
 * Checks if the folder for Agenda docs exists, and creates it if it doesn't.
 *
 * @return {*} Drive folder ID for the app.
 */
function checkFolder() {
  const folders = DriveApp.getFoldersByName('Agenda Maker - App');
  // Finds the folder if it exists
  while (folders.hasNext()) {
    let folder = folders.next();
    if (
      folder.getDescription() ==
        'Apps Script App - Do not change this description' &&
      folder.getOwner().getEmail() == Session.getActiveUser().getEmail()
    ) {
      return folder.getId();
    }
  }
  // If the folder doesn't exist, creates one
  let folder = DriveApp.createFolder('Agenda Maker - App');
  folder.setDescription('Apps Script App - Do not change this description');
  return folder.getId();
}

/**
 * Finds the template agenda doc, or creates one if it doesn't exist.
 */
function getTemplateId(folderId) {
  const folder = DriveApp.getFolderById(folderId);
  const files = folder.getFilesByName('Agenda TEMPLATE##');

  // If there is a file, returns the ID.
  while (files.hasNext()) {
    const file = files.next();
    return file.getId();
  }

  // Otherwise, creates the agenda template.
  // You can adjust the default template here
  const doc = DocumentApp.create('Agenda TEMPLATE##');
  const body = doc.getBody();

  body
      .appendParagraph('##Attendees##')
      .setHeading(DocumentApp.ParagraphHeading.HEADING1)
      .editAsText()
      .setBold(true);
  body.appendParagraph(' ').editAsText().setBold(false);

  body
      .appendParagraph('Overview')
      .setHeading(DocumentApp.ParagraphHeading.HEADING1)
      .editAsText()
      .setBold(true);
  body.appendParagraph(' ');
  body.appendParagraph('- Topic 1: ').editAsText().setBold(true);
  body.appendParagraph(' ').editAsText().setBold(false);
  body.appendParagraph('- Topic 2: ').editAsText().setBold(true);
  body.appendParagraph(' ').editAsText().setBold(false);
  body.appendParagraph('- Topic 3: ').editAsText().setBold(true);
  body.appendParagraph(' ').editAsText().setBold(false);

  body
      .appendParagraph('Next Steps')
      .setHeading(DocumentApp.ParagraphHeading.HEADING1)
      .editAsText()
      .setBold(true);
  body.appendParagraph('- Takeaway 1: ').editAsText().setBold(true);
  body.appendParagraph('- Responsible: ').editAsText().setBold(false);
  body.appendParagraph('- Accountable: ');
  body.appendParagraph('- Consult: ');
  body.appendParagraph('- Inform: ');
  body.appendParagraph(' ');
  body.appendParagraph('- Takeaway 2: ').editAsText().setBold(true);
  body.appendParagraph('- Responsible: ').editAsText().setBold(false);
  body.appendParagraph('- Accountable: ');
  body.appendParagraph('- Consult: ');
  body.appendParagraph('- Inform: ');
  body.appendParagraph(' ');
  body.appendParagraph('- Takeaway 3: ').editAsText().setBold(true);
  body.appendParagraph('- Responsible: ').editAsText().setBold(false);
  body.appendParagraph('- Accountable: ');
  body.appendParagraph('- Consult: ');
  body.appendParagraph('- Inform: ');

  doc.saveAndClose();

  folder.addFile(DriveApp.getFileById(doc.getId()));

  return doc.getId();
}

/**
 * When there is a change to the calendar, searches for events that include "#agenda"
 * in the decrisption.
 *
 */
function onCalendarChange() {
  // Gets recent events with the #agenda tag
  const now = new Date();
  const events = CalendarApp.getEvents(
      now,
      new Date(now.getTime() + 2 * 60 * 60 * 1000000),
      {search: '#agenda'},
  );

  const folderId = checkFolder();
  const templateId = getTemplateId(folderId);

  const folder = DriveApp.getFolderById(folderId);

  // Loops through any events found
  for (i = 0; i < events.length; i++) {
    const event = events[i];

    // Confirms whether the event has the #agenda tag
    let description = event.getDescription();
    if (description.search('#agenda') == -1) continue;

    // Only works with events created by the owner of this calendar
    if (event.isOwnedByMe()) {
      // Creates a new document from the template for an agenda for this event
      const newDoc = DriveApp.getFileById(templateId).makeCopy();
      newDoc.setName('Agenda for ' + event.getTitle());

      const file = DriveApp.getFileById(newDoc.getId());
      folder.addFile(file);

      const doc = DocumentApp.openById(newDoc.getId());
      const body = doc.getBody();

      // Fills in the template with information about the attendees from the
      // calendar event
      const conf = body.findText('##Attendees##');
      if (conf) {
        const ref = conf.getStartOffset();

        for (let i in event.getGuestList()) {
          let guest = event.getGuestList()[i];

          body.insertParagraph(ref + 2, guest.getEmail());
        }
        body.replaceText('##Attendees##', 'Attendees');
      }

      // Replaces the tag with a link to the agenda document
      const agendaUrl = 'https://docs.google.com/document/d/' + newDoc.getId();
      description = description.replace(
          '#agenda',
          '<a href=' + agendaUrl + '>Agenda Doc</a>',
      );
      event.setDescription(description);

      // Invites attendees to the Google doc so they automatically receive access to the agenda
      newDoc.addEditor(newDoc.getOwner());

      for (let i in event.getGuestList()) {
        let guest = event.getGuestList()[i];

        newDoc.addEditor(guest.getEmail());
      }
    }
  }
  return;
}

/**
 * Creates an event-driven trigger that fires whenever there's a change to the calendar.
 */
function setUp() {
  let email = Session.getActiveUser().getEmail();
  ScriptApp.newTrigger("onCalendarChange").forUserCalendar(email).onEventUpdated().create();
}

수정

필요에 맞게 원하는 만큼 샘플을 수정할 수 있습니다. 다음은 선택사항으로 변경할 수 있는 몇 가지 사항입니다.

참석자의 일정목록 문서 권한 업데이트

스크립트가 참석자에게 수정 권한을 부여합니다. 보기 전용으로 권한을 제한하려면 코드의 다음 부분에서 addEditor 메서드를 addViewer 메서드로 바꿉니다.

     for (let i in event.getGuestList()) {
       let guest = event.getGuestList()[i];

       newDoc.addEditor(guest.getEmail());

일정목록 문서 템플릿 수정

주제 문서 템플릿을 업데이트하려면 다음 단계를 따르세요.

  1. 캘린더 일정에서 첫 번째 일정목록을 만든 후 Google Drive를 엽니다.
  2. Agenda Maker - App이라는 폴더를 엽니다.
  3. Agenda TEMPLATE## 문서를 열고 수정합니다.

참여자

이 샘플은 제품 관리 및 플랫폼 전략 컨설턴트인 Jeremy Glassenberg가 만들었습니다. 트위터에서 제레미를 찾아보세요(@jglassenberg).

이 샘플은 Google Developer Experts의 도움으로 Google에서 관리합니다.

다음 단계