規劃會議議程

程式設計層級:入門
時間長度:15 分鐘
專案類型:透過事件導向觸發條件執行自動化動作

目標

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

認識這項解決方案

自動在 Google 文件中建立議程文件,然後附加到 Google 日曆會議。

已新增到日曆活動的螢幕截圖

運作方式

指令碼會為議程建立文件範本,當您更新 日曆,指令碼會檢查您是否有活動包含「#agenda」英吋 例如說明如果有這個標記,指令碼就會複製範本 將日曆新增至日曆活動,然後與活動參與者分享。

Apps Script 服務

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

  • 雲端硬碟服務:檢查範本是否違規 文件,如果沒有,請為範本建立新資料夾 文件。 為每項新議程建立範本文件副本。
  • 文件服務:建立議程 範本。
  • 日曆服務:檢查含有以下內容的活動: 「#agenda」標記並更新活動說明,同時附上議程連結 文件。
  • 基礎服務:使用 Session 類別取得 使用者的電子郵件。這有助於為目前的使用者建立觸發條件。
  • 指令碼服務:建立會啟動的觸發條件 這類事件。

必要條件

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

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

設定指令碼

  1. 點選下方按鈕即可開啟「製作會議議程」範例 Apps Script 專案。
    開啟專案
  2. 按一下「總覽」圖示
  3. 在總覽頁面中,按一下「建立副本」圖示 用來建立副本的圖示
  4. 在複製的專案中,選取函式下拉式選單中的「setUp」setUp
  5. 按一下「執行」
  6. 出現提示時,請授權指令碼。 如果 OAuth 同意畫面顯示「這個應用程式未經驗證」警告, 如要繼續,請選取「進階」圖示 > 前往 {Project Name} (不安全)

執行指令碼

  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 雲端硬碟。
  2. 開啟「待辦事項製作工具 - 應用程式」資料夾。
  3. 開啟「待辦事項 TEMPLATE##」文件並進行編輯。

貢獻者

這個範例是由產品管理與平台的 Jeremy Glassenberg 所製作 策略顧問。在 Twitter 尋找 Jeremy:@jglassenberg

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

後續步驟