会議の議題を作成する

コーディング レベル: 初級
所要時間: 15 分
プロジェクトの種類: イベントドリブン トリガーによる自動化

目標

  • ソリューションの機能について理解する。
  • ソリューション内での Apps Script サービスの役割を理解する。
  • スクリプトを設定します。
  • スクリプトを実行します。

このソリューションについて

Google ドキュメントで議題ドキュメントを自動的に作成し、Google カレンダーの会議に添付します。

カレンダーの予定に追加された議題のスクリーンショット

仕組み

このスクリプトは、議題のドキュメント テンプレートを作成します。カレンダーを更新すると、スクリプトは、所有する予定の説明に「#agenda」が含まれているかどうかを確認します。タグが存在する場合、スクリプトはテンプレートのコピーを作成し、カレンダーの予定に追加して、イベントの参加者と共有します。

Apps Script サービス

このソリューションでは、次のサービスを使用します。

  • ドライブ サービス - テンプレート ドキュメントが存在するかどうかを確認し、存在しない場合はテンプレート ドキュメント用の新しいフォルダを作成します。新しい議題ごとにテンプレート ドキュメントのコピーを作成します。
  • ドキュメント サービス - 議題テンプレートを作成します。
  • カレンダー サービス - 「#agenda」タグが付いた予定をチェックし、予定の説明を更新して、議題のドキュメントへのリンクを追加します。
  • ベースサービス - Session クラスを使用してユーザーのメールアドレスを取得します。これにより、現在のユーザーのトリガーを構築できます。
  • スクリプト サービス - ユーザーのカレンダーに変更があるたびにトリガーを実行します。

前提条件

このサンプルを使用するには、次の前提条件を満たしている必要があります。

  • Google アカウント(Google Workspace アカウントの場合、管理者の承認が必要となる可能性があります)。
  • インターネットに接続できるウェブブラウザ。

スクリプトを設定する

  1. 下のボタンをクリックして、サンプルの 会議の議題を作成する Apps Script プロジェクトを開きます。
    プロジェクトを開く
  2. [概要] をクリックします。
  3. 概要ページで、[コピーを作成] コピーを作成するアイコン をクリックします。
  4. コピーしたプロジェクトの関数プルダウンで、[setUp] を選択します。
  5. [実行] をクリックします。
  6. プロンプトが表示されたら、スクリプトを承認します。OAuth 同意画面に [このアプリは確認されていません] という警告が表示された場合は、[詳細] > [{プロジェクト名} に移動(安全でない)] を選択して続行します。

スクリプトを実行する

  1. Google カレンダーを開きます。
  2. 新しい予定を作成するか、既存の予定を編集します。
  3. 説明に #agenda を追加して、予定を保存します。
  4. ドキュメントが共有されたことを知らせるメール通知が届いているか確認します。または、カレンダーを更新して、もう一度予定をクリックして、議題ドキュメントへのリンクを表示します。

すべての参加者に、議題を表示するためのメール通知が届きます。このスクリプトにより、参加者に編集権限が付与されますが、スクリプトを編集して参加者の議題ドキュメントの権限を更新できます。

コードを確認する

このソリューションの Apps Script コードを確認するには、下の [ソースコードを表示] をクリックします。

ソースコードを表示

コード.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. [Agenda Maker - App] というフォルダを開きます。
  3. Agenda TEMPLATE## ドキュメントを開いて編集します。

寄稿者

このサンプルは、プロダクト管理およびプラットフォーム戦略コンサルタントの Jeremy Glassenberg によって作成されました。Jeremy の Twitter アカウントは @jglassenberg です。

このサンプルは、Google デベロッパー エキスパートの協力を得て Google によって管理されています。

次のステップ