جدولة الاجتماعات من Google Chat

مستوى الترميز: متوسط
المدة: 25 دقيقة
نوع المشروع: تطبيق Google Chat

الأهداف

  • فهم ما يفعله الحلّ.
  • فهم ما تفعله خدمات برمجة التطبيقات ضمن الحلّ.
  • إعداد البيئة
  • قم بإعداد النص البرمجي.
  • شغِّل النص البرمجي.

لمحة عن هذا الحلّ

يمكنك تحديد موعد اجتماع في "تقويم Google" من داخل رسالة مباشرة (DM) أو مساحة في Google Chat. يمكنك تحديد تفاصيل محددة للاجتماع، مثل الموضوع أو وقت البدء أو المدة، أو استخدام الإعدادات التلقائية لجدولة الاجتماعات الفورية.

واجهة مربّع حوار لتطبيق Chat في "أداة جدولة الاجتماعات"

آلية العمل

يستخدم النص البرمجي لتطبيق Chat الأوامر التي تبدأ بشرطة مائلة ومربّعات الحوار للحصول على تفاصيل الاجتماع من المستخدمين وجدولة حدث في "تقويم Google". يتضمن النص البرمجي إعدادات الاجتماعات الافتراضية التي يمكن تخصيصها لتناسب احتياجاتك.

خدمات "برمجة تطبيقات Google"

يستخدم هذا الحلّ الخدمات التالية:

  • خدمة التقويم - تُنشئ حدث التقويم من معلومات الاجتماع المقدَّمة.
  • الخدمة الأساسية: تستخدم الفئة Session للحصول على المنطقة الزمنية للنص البرمجي. ويستخدم "تقويم Google" هذه المنطقة الزمنية عند جدولة الحدث.
  • خدمات الأدوات المساعدة: لتنسيق تاريخ حدث التقويم وترميز رقم تعريف الحدث للمساعدة في الحصول على عنوان URL الخاص بالحدث.

المتطلبات الأساسية

لاستخدام هذا النموذج، يجب استيفاء المتطلبات الأساسية التالية:

  • حساب على Google (قد تتطلب حسابات Google Workspace موافقة المشرف).
  • متصفح ويب يمكنه الوصول إلى الإنترنت.
  • مشروع على Google Cloud

إعداد البيئة

فتح مشروعك على Google Cloud في Google Cloud Console

إذا لم يكن المشروع مفتوحًا، افتح المشروع الذي تنوي استخدامه في هذا النموذج من خلال الخطوات التالية:

  1. في Google Cloud Console، انتقِل إلى صفحة اختيار مشروع.

    اختيار مشروع على السحابة الإلكترونية

  2. اختَر مشروع Google Cloud الذي تريد استخدامه. أو انقر على إنشاء مشروع واتّبِع التعليمات الظاهرة على الشاشة. إذا أنشأت مشروعًا على Google Cloud، قد تحتاج إلى تفعيل الفوترة للمشروع.

تفعيل واجهة برمجة التطبيقات

قبل استخدام Google APIs، عليك تفعيلها في مشروع على Google Cloud. يمكنك تفعيل واجهة برمجة تطبيقات واحدة أو أكثر في مشروع واحد على Google Cloud.

تتطلّب جميع تطبيقات Chat ضبط شاشة طلب الموافقة. يحدِّد ضبط شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth في تطبيقك ما تعرضه Google للمستخدمين ويسجّل تطبيقك حتى تتمكّن من نشره لاحقًا.

  1. في وحدة تحكُّم Google Cloud، انتقِل إلى القائمة > واجهات برمجة التطبيقات والخدمات > شاشة موافقة OAuth.

    الانتقال إلى شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth

  2. في حقل نوع المستخدم، اختَر داخلي، ثم انقر على إنشاء.
  3. املأ نموذج تسجيل التطبيق، ثم انقر على حفظ ومتابعة.
  4. في الوقت الحالي، يمكنك تخطّي إضافة النطاقات والنقر على حفظ ومتابعة. في المستقبل، عند إنشاء تطبيق للاستخدام خارج مؤسسة Google Workspace، عليك تغيير نوع المستخدم إلى خارجي، ثم إضافة نطاقات التفويض التي يتطلبها تطبيقك.

  5. مراجعة ملخص تسجيل التطبيق لإجراء تغييرات، انقر على تعديل. إذا كان تسجيل التطبيق يبدو جيدًا، انقر على الرجوع إلى لوحة البيانات.

إعداد النص البرمجي

إنشاء مشروع "برمجة تطبيقات Google"

  1. انقر على الزر التالي لفتح مشروع جدولة الاجتماعات من Google Chat.
    فتح المشروع
  2. انقر على رمز نظرة عامة .
  3. في صفحة النظرة العامة، انقر على رمز إنشاء نسخة رمز إنشاء نسخة.

نسخ رقم المشروع على Google Cloud

  1. في Google Cloud Console، انتقِل إلى القائمة > إدارة الهوية وإمكانية الوصول والمشرف > الإعدادات.

    الانتقال إلى "إعدادات إدارة الهوية وإمكانية الوصول والمشرف"

  2. في حقل رقم المشروع، انسخ القيمة.

ضبط مشروع السحابة الإلكترونية لمشروع برمجة التطبيقات

  1. في مشروع برمجة التطبيقات المنسوخ، انقر على إعدادات المشروع أيقونة إعدادات المشروع.
  2. ضمن مشروع Google Cloud Platform (GCP)، انقر على تغيير المشروع.
  3. في رقم مشروع Google Cloud Platform، الصِق رقم مشروع Google Cloud.
  4. انقر على ضبط المشروع.

إنشاء نشر تجريبي

  1. في مشروع "برمجة تطبيقات Google" المنسوخ، انقر على نشر > اختبار عمليات النشر.
  2. انسخ رقم تعريف نشر الرأس لاستخدامه في خطوة لاحقة وانقر على تم.

ضبط Chat API

  1. في Google Cloud Console، انتقِل إلى صفحة Chat API.
    الانتقال إلى Chat API
  2. انقر على الإعدادات.
  3. اضبط Chat API باستخدام المعلومات التالية:
    • الاسم: Meeting Scheduler
    • عنوان URL للصورة الرمزية: أضِف عنوان URL يشير إلى صورة لا يقلّ حجمها عن 256×256 بكسل.
    • الوصف: Quickly create meetings.
    • الوظائف: ضَع علامة في المربّعين للسماح للمستخدمين بمراسلة التطبيق مباشرةً وإضافته إلى المساحات.
    • إعدادات الاتصال: انقر على برمجة التطبيقات وأدخِل رقم تعريف النشر الرئيسي.
    • أوامر الشرطة المائلة: يمكنك إضافة أوامر تبدأ بشرطة مائلة /help و/schedule_Meeting من خلال اتّباع الخطوات التالية:
      1. انقر على إضافة أمر شرطة مائلة واضبطه باستخدام المعلومات التالية:
        • الاسم: /help
        • رقم تعريف الطلب: 1
        • الوصف: Learn what this app does.
      2. انقر على إضافة أمر شرطة مائلة مرة أخرى واضبطه باستخدام المعلومات التالية:
        • الاسم: /schedule_Meeting
        • رقم تعريف الطلب: 2
        • الوصف: Schedule a meeting.
        • ضَع علامة في المربّع يفتح مربّع حوار.
    • الأذونات: اختَر أشخاص محدَّدين ومجموعات محدَّدة في نطاقك وأدخِل عنوان بريدك الإلكتروني.
  4. انقر على حفظ وأعِد تحميل الصفحة.
  5. في صفحة الضبط، ضمن حالة التطبيق، اضبط الحالة على مباشر - متاح للمستخدمين.
  6. انقر على حفظ.

تشغيل النص البرمجي

  1. افتح Google Chat.
  2. انقر على رمز بدء محادثة .
  3. ابحث عن اسم التطبيق، Meeting Scheduler.
  4. أرسِل رسالة أولية، مثل hello، لطلب الإذن.
  5. عندما يردّ التطبيق، انقر على ضبط وفوّض التطبيق. إذا عرضت شاشة موافقة OAuth التحذير، لم يتم التحقّق من هذا التطبيق، يمكنك المتابعة من خلال اختيار إعدادات متقدّمة > الانتقال إلى {Project Name} (اسم المشروع) (غير آمن).

  6. إرسال /schedule_Meeting إلى التطبيق

  7. في مربّع الحوار، أضِف عنوان بريد إلكتروني واحدًا على الأقل للمدعو. ويمكنك تعديل الحقول الأخرى أو استخدام الإدخالات التلقائية

  8. انقر على إرسال.

  9. لعرض الاجتماع، انقر على فتح حدث "تقويم Google".

مراجعة الرمز

لمراجعة رمز برمجة التطبيقات لهذا الحلّ، انقر على عرض رمز المصدر أدناه:

عرض رمز المصدر

Code.gs

solutions/chat-bots/schedule-meetings/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/chat-bots/schedule-meetings

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

// Application constants
const BOTNAME = 'Chat Meeting Scheduler';
const SLASHCOMMAND = {
  HELP: 1, // /help
  DIALOG: 2, // /schedule_Meeting
};

/**
 * Responds to an ADDED_TO_SPACE event in Google Chat.
 * Called when the bot is added to a space. The bot can either be directly added to the space
 * or added by a @mention. If the bot is added by a @mention, the event object includes a message property. 
 * Returns a Message object, which is usually a welcome message informing users about the bot.
 *
 * @param {Object} event The event object from Google Chat
 */
function onAddToSpace(event) {
  let message = '';

  // Personalizes the message depending on how the bot is called.
  if (event.space.singleUserBotDm) {
    message = `Hi ${event.user.displayName}!`;
  } else {
    const spaceName = event.space.displayName ? event.space.displayName : "this chat";
    message = `Hi! Thank you for adding me to ${spaceName}`;
  }

  // Lets users know what they can do and how they can get help.
  message = message + '/nI can quickly schedule a meeting for you with just a few clicks.' +
    'Try me out by typing */schedule_Meeting*. ' +
    '/nTo learn what else I can do, type */help*.'

  return { "text": message };
}

/**
 * Responds to a MESSAGE event triggered in Chat.
 * Called when the bot is already in the space and the user invokes it via @mention or / command.
 * Returns a message object containing the bot's response. For this bot, the response is either the
 * help text or the dialog to schedule a meeting.
 * 
 * @param {object} event The event object from Google Chat
 * @return {object} JSON-formatted response as text or Card message
 */
function onMessage(event) {

  // Handles regular onMessage logic.
  // Evaluates if and handles for all slash commands.
  if (event.message.slashCommand) {
    switch (event.message.slashCommand.commandId) {

      case SLASHCOMMAND.DIALOG: // Displays meeting dialog for /schedule_Meeting.

        // TODO update this with your own logic to set meeting recipients, subjects, etc (e.g. a group email).
        return getInputFormAsDialog_({
          invitee: '',
          startTime: getTopOfHourDateString_(),
          duration: 30,
          subject: 'Status Stand-up',
          body: 'Scheduling a quick status stand-up meeting.'
        });

      case SLASHCOMMAND.HELP: // Responds with help text for /help.
        return getHelpTextResponse_();

      /* TODO Add other use cases here. E.g:
      case SLASHCOMMAND.NEW_FEATURE:  // Your Feature Here
        getDialogForAddContact(message);
      */

    }
  }
  else {
    // Returns text if users didn't invoke a slash command.
    return { text: 'No action taken - use Slash Commands.' }
  }
}

/**
 * Responds to a CARD_CLICKED event triggered in Chat.
 * @param {object} event the event object from Chat
 * @return {object} JSON-formatted response
 * @see https://developers.google.com/chat/api/guides/message-formats/events
 */
function onCardClick(event) {
  if (event.action.actionMethodName === 'handleFormSubmit') {
    const recipients = getFieldValue_(event.common.formInputs, 'email');
    const subject = getFieldValue_(event.common.formInputs, 'subject');
    const body = getFieldValue_(event.common.formInputs, 'body');

    // Assumes dialog card inputs for date and times are in the correct format. mm/dd/yyy HH:MM
    const dateTimeInput = getFieldValue_(event.common.formInputs, 'date');
    const startTime = getStartTimeAsDateObject_(dateTimeInput);
    const duration = Number(getFieldValue_(event.common.formInputs, 'duration'));

    // Handles instances of missing or invalid input parameters.
    const errors = [];

    if (!recipients) {
      errors.push('Missing or invalid recipient email address.');
    }
    if (!subject) {
      errors.push('Missing subject line.');
    }
    if (!body) {
      errors.push('Missing event description.');
    }
    if (!startTime) {
      errors.push('Missing or invalid start time.');
    }
    if (!duration || isNaN(duration)) {
      errors.push('Missing or invalid duration');
    }
    if (errors.length) {
      // Redisplays the form if missing or invalid inputs exist.
      return getInputFormAsDialog_({
        errors,
        invitee: recipients,
        startTime: dateTimeInput,
        duration,
        subject,
        body
      });
    }

    //  Calculates the end time via duration.
    const endTime = new Date(startTime.valueOf());
    endTime.setMinutes(endTime.getMinutes() + duration);

    // Creates calendar event with notification.
    const calendar = CalendarApp.getDefaultCalendar()
    const scheduledEvent = calendar.createEvent(subject,
      startTime,
      endTime,
      {
        guests: recipients,
        sendInvites: true,
        description: body + '\nThis meeting scheduled by a Google Chat App!'
      });

    // Gets a link to the Calendar event.
    const url = getCalendarEventURL_(scheduledEvent, calendar)

    return getConfirmationDialog_(url);

  } else if (event.action.actionMethodName === 'closeDialog') {

    // Returns this dialog as success.
    return {
      actionResponse: {
        type: 'DIALOG',
        dialog_action: {
          actionStatus: 'OK'
        }
      }
    }
  }
}

/**
 * Responds with help text about this chat bot.
 * @return {string} The help text as seen below
 */
function getHelpTextResponse_() {
  const help = `*${BOTNAME}* lets you quickly create meetings from Google Chat. Here\'s a list of all its commands:
  \`/schedule_Meeting\`  Opens a dialog with editable, preset parameters to create a meeting event
  \`/help\`  Displays this help message

  Learn more about creating Google Chat bots at https://developers.google.com/chat.`

  return { 'text': help }
}

Dialog.gs

solutions/chat-bots/schedule-meetings/Dialog.js
/**
 * 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
 *
 *      http://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.
 */

/**
* Form input dialog as JSON.
* @return {object} JSON-formatted cards for the dialog.
*/
function getInputFormAsDialog_(options) {
  const form = getForm_(options);
  return {
    'actionResponse': {
      'type': 'DIALOG',
      'dialogAction': {
        'dialog': {
          'body': form
        }
      }
    }
  };
}

/**
* Form JSON to collect inputs regarding the meeting.
* @return {object} JSON-formatted cards.
*/
function getForm_(options) {
  const sections = [];

  // If errors present, display additional section with validation messages.
  if (options.errors && options.errors.length) {
    let errors = options.errors.reduce((str, err) => `${str}• ${err}<br>`, '');
    errors = `<b>Errors:</b><br><font color="#ba0000">${errors}</font>`;
    const errorSection = {
      'widgets': [
        {
          textParagraph: {
            text: errors
          }
        }
      ]
    }
    sections.push(errorSection);
  }
  let formSection = {
    'header': 'Schedule meeting and send email to invited participants',
    'widgets': [
      {
        'textInput': {
          'label': 'Event Title',
          'type': 'SINGLE_LINE',
          'name': 'subject',
          'value': options.subject
        }
      },
      {
        'textInput': {
          'label': 'Invitee Email Address',
          'type': 'SINGLE_LINE',
          'name': 'email',
          'value': options.invitee,
          'hintText': 'Add team group email'
        }
      },
      {
        'textInput': {
          'label': 'Description',
          'type': 'MULTIPLE_LINE',
          'name': 'body',
          'value': options.body
        }
      },
      {
        'textInput': {
          'label': 'Meeting start date & time',
          'type': 'SINGLE_LINE',
          'name': 'date',
          'value': options.startTime,
          'hintText': 'mm/dd/yyyy H:MM'
        }
      },
      {
        'selectionInput': {
          'type': 'DROPDOWN',
          'label': 'Meeting Duration',
          'name': 'duration',
          'items': [
            {
              'text': '15 minutes',
              'value': '15',
              'selected': options.duration === 15
            },
            {
              'text': '30 minutes',
              'value': '30',
              'selected': options.duration === 30
            },
            {
              'text': '45 minutes',
              'value': '45',
              'selected': options.duration === 45
            },
            {
              'text': '1 Hour',
              'value': '60',
              'selected': options.duration === 60
            },
            {
              'text': '1.5 Hours',
              'value': '90',
              'selected': options.duration === 90
            },
            {
              'text': '2 Hours',
              'value': '120',
              'selected': options.duration === 120
            }
          ]
        }
      }
    ],
    'collapsible': false
  };
  sections.push(formSection);
  const card =  {
    'sections': sections,
    'name': 'Google Chat Scheduled Meeting',
    'fixedFooter': {
      'primaryButton': {
        'text': 'Submit',
        'onClick': {
          'action': {
            'function': 'handleFormSubmit'
          }
        },
        'altText': 'Submit'
      }
    }
  };
  return card;
}

/**
* Confirmation dialog after a calendar event is created successfully.
* @param {string} url The Google Calendar Event url for link button
* @return {object} JSON-formatted cards for the dialog
*/
function getConfirmationDialog_(url) {
  return {
    'actionResponse': {
      'type': 'DIALOG',
      'dialogAction': {
        'dialog': {
          'body': {
            'sections': [
              {
                'widgets': [
                  {
                    'textParagraph': {
                      'text': 'Meeting created successfully!'
                    },
                    'horizontalAlignment': 'CENTER'
                  },
                  {
                    'buttonList': {
                      'buttons': [
                        {
                          'text': 'Open Calendar Event',
                          'onClick': {
                            'openLink': {
                              'url': url
                            }
                          }
                        }

                      ]
                    },
                    'horizontalAlignment': 'CENTER'
                  }
                ]
              }
            ],
            'fixedFooter': {
              'primaryButton': {
                'text': 'OK',
                'onClick': {
                  'action': {
                    'function': 'closeDialog'
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Utilities.gs

solutions/chat-bots/schedule-meetings/Utilities.js
/**
 * 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
 *
 *      http://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.
 */

/**
* Helper function that gets the field value from the given form input.
* @return {string} 
*/
function getFieldValue_(formInputs, fieldName) {
  return formInputs[fieldName][''].stringInputs.value[0];
}

// Regular expression to validate the date/time input.
const DATE_TIME_PATTERN = /\d{1,2}\/\d{1,2}\/\d{4}\s+\d{1,2}:\d\d/;

/**
* Casts date and time from string to Date object.
* @return {date} 
*/
function getStartTimeAsDateObject_(dateTimeStr) {
  if (!dateTimeStr || !dateTimeStr.match(DATE_TIME_PATTERN)) {
    return null;
  }

  const parts = dateTimeStr.split(' ');
  const [month, day, year] = parts[0].split('/').map(Number);
  const [hour, minute] = parts[1].split(':').map(Number);


  Session.getScriptTimeZone()

  return new Date(year, month - 1, day, hour, minute)
}

/** 
* Gets the current date and time for the upcoming top of the hour (e.g. 01/25/2022 18:00).
* @return {string} date/time in mm/dd/yyy HH:MM format needed for use by Calendar
*/
function getTopOfHourDateString_() {
  const date = new Date();
  date.setHours(date.getHours() + 1);
  date.setMinutes(0, 0, 0);
  // Adding the date as string might lead to an incorrect response due to time zone adjustments.
  return Utilities.formatDate(date, Session.getScriptTimeZone(), 'MM/dd/yyyy H:mm');
}


/** 
* Creates the URL for the Google Calendar event.
*
* @param {object} event The Google Calendar Event instance
* @param {object} cal The associated Google Calendar 
* @return {string} URL in the form of 'https://www.google.com/calendar/event?eid={event-id}'
*/
function getCalendarEventURL_(event, cal) {
  const baseCalUrl = 'https://www.google.com/calendar';
  // Joins Calendar Event Id with Calendar Id, then base64 encode to derive the event URL.
  let encodedId = Utilities.base64Encode(event.getId().split('@')[0] + " " + cal.getId()).replace(/\=/g, '');
  encodedId = `/event?eid=${encodedId}`;
  return (baseCalUrl + encodedId);

}

المساهمون

تحتفظ Google بهذا النموذج بمساعدة خبراء التطوير في Google.

الخطوات التالية