Создайте надстройку Google Workspace с помощью Apps Script.

Это краткое руководство по созданию простого дополнения к Google Workspace, демонстрирующего домашние страницы, контекстные триггеры и подключение к сторонним API.

Дополнение создаёт контекстные и неконтекстные интерфейсы в Gmail, Календаре и Диске. Дополнение отображает случайное изображение кошки с текстом поверх него. Текст может быть статическим для главных страниц или брать из контекста хост-приложения для контекстных триггеров.

Цели

  • Настройте свою среду.
  • Настройте сценарий.
  • Запустите скрипт.

Предпосылки

Для использования этого образца вам необходимы следующие предварительные условия:

  • Учетная запись Google (для учетных записей Google Workspace может потребоваться одобрение администратора).
  • Веб-браузер с доступом в Интернет.

  • Проект Google Cloud .

Настройте свою среду

Откройте свой облачный проект в консоли Google Cloud.

Если проект Cloud, который вы собираетесь использовать для этого примера, еще не открыт, откройте его:

  1. В консоли Google Cloud перейдите на страницу выбора проекта .

    Выберите облачный проект

  2. Выберите нужный проект Google Cloud. Или нажмите «Создать проект» и следуйте инструкциям на экране. При создании проекта Google Cloud может потребоваться включить для него оплату .

Для дополнений Google Workspace требуется настройка экрана согласия. Настройка экрана согласия OAuth для вашего дополнения определяет, что Google будет показывать пользователям.

  1. В консоли Google Cloud перейдите в > > Брендинг .

    Перейти к брендингу

  2. Если вы уже настроили , вы можете настроить следующие параметры экрана согласия OAuth в разделах «Брендинг» , «Аудитория» и «Доступ к данным» . Если вы видите сообщение: пока не настроено , нажмите «Начать» :
    1. В разделе «Информация о приложении» в поле «Имя приложения » введите имя приложения.
    2. В поле Адрес электронной почты службы поддержки пользователей выберите адрес электронной почты службы поддержки, по которому пользователи смогут связаться с вами, если у них возникнут вопросы относительно их согласия.
    3. Нажмите кнопку «Далее» .
    4. В разделе Аудитория выберите Внутренняя .
    5. Нажмите кнопку «Далее» .
    6. В разделе «Контактная информация» введите адрес электронной почты , на который вы можете получать уведомления о любых изменениях в вашем проекте.
    7. Нажмите кнопку «Далее» .
    8. В разделе Готово ознакомьтесь с Политикой обработки данных пользователей API служб Google и, если вы согласны, выберите Я согласен с Политикой обработки данных пользователей API служб Google .
    9. Нажмите «Продолжить» .
    10. Нажмите «Создать» .
  3. На данный момент вы можете пропустить добавление областей действия. В будущем при создании приложения для использования за пределами вашей организации Google Workspace необходимо изменить тип пользователя на «Внешний» . Затем добавьте области действия авторизации, необходимые вашему приложению. Подробнее см. в полном руководстве по настройке согласия OAuth .

Настройте сценарий

Создайте проект Apps Script

  1. Чтобы создать новый проект Apps Script, перейдите в script.new .
  2. Нажмите Проект без названия .
  3. Переименуйте проект Apps Script в Cats и нажмите «Переименовать» .
  4. Рядом с файлом Code.gs нажмите « > «Переименовать» . Назовите файл Common .
  5. Нажмите файл > Скрипт . Назовите файл Gmail .
  6. Повторите шаг 5, чтобы создать ещё два файла скриптов с именами Calendar и Drive . После этого у вас должно получиться четыре отдельных файла скриптов.
  7. Замените содержимое каждого файла следующим соответствующим кодом:

    Common.gs

      /**  * This simple Google Workspace add-on shows a random image of a cat in the  * sidebar. When opened manually (the homepage card), some static text is  * overlayed on the image, but when contextual cards are opened a new cat image  * is shown with the text taken from that context (such as a message's subject  * line) overlaying the image. There is also a button that updates the card with  * a new random cat image.  *  * Click "File > Make a copy..." to copy the script, and "Publish > Deploy from  * manifest > Install add-on" to install it.  */  /**  * The maximum number of characters that can fit in the cat image.  */ var MAX_MESSAGE_LENGTH = 40;  /**  * Callback for rendering the homepage card.  * @return {CardService.Card} The card to show to the user.  */ function onHomepage(e) {   console.log(e);   var hour = Number(Utilities.formatDate(new Date(), e.userTimezone.id, 'H'));   var message;   if (hour >= 6 && hour < 12) {     message = 'Good morning';   } else if (hour >= 12 && hour < 18) {     message = 'Good afternoon';   } else {     message = 'Good night';   }   message += ' ' + e.hostApp;   return createCatCard(message, true); }  /**  * Creates a card with an image of a cat, overlayed with the text.  * @param {String} text The text to overlay on the image.  * @param {Boolean} isHomepage True if the card created here is a homepage;  *      false otherwise. Defaults to false.  * @return {CardService.Card} The assembled card.  */ function createCatCard(text, isHomepage) {   // Explicitly set the value of isHomepage as false if null or undefined.   if (!isHomepage) {     isHomepage = false;   }    // Use the "Cat as a service" API to get the cat image. Add a "time" URL   // parameter to act as a cache buster.   var now = new Date();   // Replace forward slashes in the text, as they break the CataaS API.   var caption = text.replace(/\//g, ' ');   var imageUrl =       Utilities.formatString('https://cataas.com/cat/says/%s?time=%s',           encodeURIComponent(caption), now.getTime());   var image = CardService.newImage()       .setImageUrl(imageUrl)       .setAltText('Meow')    // Create a button that changes the cat image when pressed.   // Note: Action parameter keys and values must be strings.   var action = CardService.newAction()       .setFunctionName('onChangeCat')       .setParameters({text: text, isHomepage: isHomepage.toString()});   var button = CardService.newTextButton()       .setText('Change cat')       .setOnClickAction(action)       .setTextButtonStyle(CardService.TextButtonStyle.FILLED);   var buttonSet = CardService.newButtonSet()       .addButton(button);    // Create a footer to be shown at the bottom.   var footer = CardService.newFixedFooter()       .setPrimaryButton(CardService.newTextButton()           .setText('Powered by cataas.com')           .setOpenLink(CardService.newOpenLink()               .setUrl('https://cataas.com')));    // Assemble the widgets and return the card.   var section = CardService.newCardSection()       .addWidget(image)       .addWidget(buttonSet);   var card = CardService.newCardBuilder()       .addSection(section)       .setFixedFooter(footer);    if (!isHomepage) {     // Create the header shown when the card is minimized,     // but only when this card is a contextual card. Peek headers     // are never used by non-contexual cards like homepages.     var peekHeader = CardService.newCardHeader()       .setTitle('Contextual Cat')       .setImageUrl('https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png')       .setSubtitle(text);     card.setPeekCardHeader(peekHeader)   }    return card.build(); }  /**  * Callback for the "Change cat" button.  * @param {Object} e The event object, documented {@link  *     https://developers.google.com/gmail/add-ons/concepts/actions#action_event_objects  *     here}.  * @return {CardService.ActionResponse} The action response to apply.  */ function onChangeCat(e) {   console.log(e);   // Get the text that was shown in the current cat image. This was passed as a   // parameter on the Action set for the button.   var text = e.parameters.text;    // The isHomepage parameter is passed as a string, so convert to a Boolean.   var isHomepage = e.parameters.isHomepage === 'true';    // Create a new card with the same text.   var card = createCatCard(text, isHomepage);    // Create an action response that instructs the add-on to replace   // the current card with the new one.   var navigation = CardService.newNavigation()       .updateCard(card);   var actionResponse = CardService.newActionResponseBuilder()       .setNavigation(navigation);   return actionResponse.build(); }  /**  * Truncate a message to fit in the cat image.  * @param {string} message The message to truncate.  * @return {string} The truncated message.  */ function truncate(message) {   if (message.length > MAX_MESSAGE_LENGTH) {     message = message.slice(0, MAX_MESSAGE_LENGTH);     message = message.slice(0, message.lastIndexOf(' ')) + '...';   }   return message; }    

    Gmail.gs

      /**  * Callback for rendering the card for a specific Gmail message.  * @param {Object} e The event object.  * @return {CardService.Card} The card to show to the user.  */ function onGmailMessage(e) {   console.log(e);   // Get the ID of the message the user has open.   var messageId = e.gmail.messageId;    // Get an access token scoped to the current message and use it for GmailApp   // calls.   var accessToken = e.gmail.accessToken;   GmailApp.setCurrentMessageAccessToken(accessToken);    // Get the subject of the email.   var message = GmailApp.getMessageById(messageId);   var subject = message.getThread().getFirstMessageSubject();    // Remove labels and prefixes.   subject = subject       .replace(/^([rR][eE]|[fF][wW][dD])\:\s*/, '')       .replace(/^\[.*?\]\s*/, '');    // If neccessary, truncate the subject to fit in the image.   subject = truncate(subject);    return createCatCard(subject); }  /**  * Callback for rendering the card for the compose action dialog.  * @param {Object} e The event object.  * @return {CardService.Card} The card to show to the user.  */ function onGmailCompose(e) {   console.log(e);   var header = CardService.newCardHeader()       .setTitle('Insert cat')       .setSubtitle('Add a custom cat image to your email message.');   // Create text input for entering the cat's message.   var input = CardService.newTextInput()       .setFieldName('text')       .setTitle('Caption')       .setHint('What do you want the cat to say?');   // Create a button that inserts the cat image when pressed.   var action = CardService.newAction()       .setFunctionName('onGmailInsertCat');   var button = CardService.newTextButton()       .setText('Insert cat')       .setOnClickAction(action)       .setTextButtonStyle(CardService.TextButtonStyle.FILLED);   var buttonSet = CardService.newButtonSet()       .addButton(button);   // Assemble the widgets and return the card.   var section = CardService.newCardSection()       .addWidget(input)       .addWidget(buttonSet);   var card = CardService.newCardBuilder()       .setHeader(header)       .addSection(section);   return card.build(); }  /**  * Callback for inserting a cat into the Gmail draft.  * @param {Object} e The event object.  * @return {CardService.UpdateDraftActionResponse} The draft update response.  */ function onGmailInsertCat(e) {   console.log(e);   // Get the text that was entered by the user.   var text = e.formInput.text;   // Use the "Cat as a service" API to get the cat image. Add a "time" URL   // parameter to act as a cache buster.   var now = new Date();   var imageUrl = 'https://cataas.com/cat';   if (text) {     // Replace forward slashes in the text, as they break the CataaS API.     var caption = text.replace(/\//g, ' ');     imageUrl += Utilities.formatString('/says/%s?time=%s',         encodeURIComponent(caption), now.getTime());   }   var imageHtmlContent = '<img style="display: block; max-height: 300px;" src="'       + imageUrl + '"/>';   var response = CardService.newUpdateDraftActionResponseBuilder()       .setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction()           .addUpdateContent(imageHtmlContent,CardService.ContentType.MUTABLE_HTML)           .setUpdateType(CardService.UpdateDraftBodyType.IN_PLACE_INSERT))       .build();   return response; }    

    Календарь.gs

      /**  * Callback for rendering the card for a specific Calendar event.  * @param {Object} e The event object.  * @return {CardService.Card} The card to show to the user.  */ function onCalendarEventOpen(e) {   console.log(e);   var calendar = CalendarApp.getCalendarById(e.calendar.calendarId);   // The event metadata doesn't include the event's title, so using the   // calendar.readonly scope and fetching the event by it's ID.   var event = calendar.getEventById(e.calendar.id);   if (!event) {     // This is a new event still being created.     return createCatCard('A new event! Am I invited?');   }   var title = event.getTitle();   // If necessary, truncate the title to fit in the image.   title = truncate(title);   return createCatCard(title); }    

    Drive.gs

      /**  * Callback for rendering the card for specific Drive items.  * @param {Object} e The event object.  * @return {CardService.Card} The card to show to the user.  */ function onDriveItemsSelected(e) {   console.log(e);   var items = e.drive.selectedItems;   // Include at most 5 items in the text.   items = items.slice(0, 5);   var text = items.map(function(item) {     var title = item.title;     // If neccessary, truncate the title to fit in the image.     title = truncate(title);     return title;   }).join('\n');   return createCatCard(text); }    
  8. Нажмите «Настройки проекта». Значок настроек проекта .

  9. Установите флажок Показывать файл манифеста «appsscript.json» в редакторе .

  10. Нажмите Редактор .

  11. Откройте файл appsscript.json и замените его содержимое следующим кодом, затем нажмите «Сохранить». Значок сохранения .

    appsscript.json

       {   "timeZone": "America/New_York",   "dependencies": {   },   "exceptionLogging": "STACKDRIVER",   "oauthScopes": [     "https://www.googleapis.com/auth/calendar.addons.execute",     "https://www.googleapis.com/auth/calendar.readonly",     "https://www.googleapis.com/auth/drive.addons.metadata.readonly",     "https://www.googleapis.com/auth/gmail.addons.current.action.compose",     "https://www.googleapis.com/auth/gmail.addons.current.message.readonly",     "https://www.googleapis.com/auth/gmail.addons.execute",     "https://www.googleapis.com/auth/script.locale"],   "runtimeVersion": "V8",   "addOns": {     "common": {       "name": "Cats",       "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/pets_black_48dp.png",       "useLocaleFromApp": true,       "homepageTrigger": {         "runFunction": "onHomepage",         "enabled": true       },       "universalActions": [{         "label": "Learn more about Cataas",         "openLink": "https://cataas.com"       }]     },     "gmail": {       "contextualTriggers": [{         "unconditional": {         },         "onTriggerFunction": "onGmailMessage"       }],       "composeTrigger": {         "selectActions": [{           "text": "Insert cat",           "runFunction": "onGmailCompose"         }],         "draftAccess": "NONE"       }     },     "drive": {       "onItemsSelectedTrigger": {         "runFunction": "onDriveItemsSelected"       }     },     "calendar": {       "eventOpenTrigger": {         "runFunction": "onCalendarEventOpen"       }     }   } }    

Скопируйте номер облачного проекта

  1. В консоли Google Cloud перейдите в > IAM и администрирование > Настройки .

    Перейти к настройкам IAM и администрирования

  2. В поле Номер проекта скопируйте значение.

Настройте облачный проект проекта Apps Script.

  1. В проекте Apps Script нажмите «Настройки проекта» . Значок настроек проекта .
  2. В разделе «Проект Google Cloud Platform (GCP)» нажмите «Изменить проект» .
  3. В поле Номер проекта GCP вставьте номер проекта Google Cloud.
  4. Нажмите Установить проект .

Установить тестовое развертывание

  1. В проекте Apps Script нажмите Редактор .
  2. Нажмите Развернуть > Тестовые развертывания .
  3. Нажмите Установить > Готово .

Запустить скрипт

  1. Перейдите в Gmail .
  2. Чтобы открыть дополнение, на правой боковой панели нажмите .
  3. При появлении соответствующего запроса разрешите установку надстройки.
  4. Дополнение отображает изображение кошки и текст. Чтобы изменить изображение, нажмите «Изменить кошку» .
  5. Если вы откроете электронное письмо, когда дополнение открыто, изображение обновится, а текст изменится на тему письма (сократится, если она слишком длинная).

Аналогичную функциональность можно найти в Календаре и Диске. Для использования дополнения в этих приложениях повторная авторизация не требуется.

Следующие шаги