From 5fb478e4d2c199583d545cacca89a306d0368aa1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2019 09:16:25 +0000 Subject: [PATCH 01/20] Bump lodash from 4.17.5 to 4.17.15 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.5 to 4.17.15. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.5...4.17.15) Signed-off-by: dependabot[bot] --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index cc2612ead..eba405cba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -501,8 +501,8 @@ levn@^0.3.0, levn@~0.3.0: type-check "~0.3.2" lodash@^4.17.4, lodash@^4.3.0: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" lru-cache@^4.0.1: version "4.1.2" From 1ad82ae41fc1835793d180dd716530b483c80927 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Fri, 20 Mar 2020 14:51:20 -0700 Subject: [PATCH 02/20] Fix filename casing in notifications quickstart --- forms/notifications/notification.gs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/forms/notifications/notification.gs b/forms/notifications/notification.gs index c63a05c24..ce49bbdc5 100644 --- a/forms/notifications/notification.gs +++ b/forms/notifications/notification.gs @@ -220,7 +220,7 @@ function sendReauthorizationRequest() { if (lastAuthEmailDate != today) { if (MailApp.getRemainingDailyQuota() > 0) { var template = - HtmlService.createTemplateFromFile('AuthorizationEmail'); + HtmlService.createTemplateFromFile('authorizationEmail'); template.url = authInfo.getAuthorizationUrl(); template.notice = NOTICE; var message = template.evaluate(); @@ -255,7 +255,7 @@ function sendCreatorNotification() { var addresses = settings.getProperty('creatorEmail').split(','); if (MailApp.getRemainingDailyQuota() > addresses.length) { var template = - HtmlService.createTemplateFromFile('CreatorNotification'); + HtmlService.createTemplateFromFile('creatorNotification'); template.sheet = DriveApp.getFileById(form.getDestinationId()).getUrl(); template.summary = form.getSummaryUrl(); @@ -290,7 +290,7 @@ function sendRespondentNotification(response) { .getResponse(); if (respondentEmail) { var template = - HtmlService.createTemplateFromFile('RespondentNotification'); + HtmlService.createTemplateFromFile('respondentNotification'); template.paragraphs = settings.getProperty('responseText').split('\n'); template.notice = NOTICE; var message = template.evaluate(); From ac466d733b44160c1a788e0a31e6c9d9539eb5ff Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Fri, 20 Mar 2020 14:54:47 -0700 Subject: [PATCH 03/20] and make HTML file casing consistent --- forms/notifications/notification.gs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forms/notifications/notification.gs b/forms/notifications/notification.gs index ce49bbdc5..0c4f756d4 100644 --- a/forms/notifications/notification.gs +++ b/forms/notifications/notification.gs @@ -75,7 +75,7 @@ function onInstall(e) { * configuring the notifications this add-on will produce. */ function showSidebar() { - var ui = HtmlService.createHtmlOutputFromFile('Sidebar') + var ui = HtmlService.createHtmlOutputFromFile('sidebar') .setTitle('Form Notifications'); FormApp.getUi().showSidebar(ui); } @@ -85,7 +85,7 @@ function showSidebar() { * this add-on. */ function showAbout() { - var ui = HtmlService.createHtmlOutputFromFile('About') + var ui = HtmlService.createHtmlOutputFromFile('about') .setWidth(420) .setHeight(270); FormApp.getUi().showModalDialog(ui, 'About Form Notifications'); From 6ebd14ed82eb1127d9b7dd0811c7392389921503 Mon Sep 17 00:00:00 2001 From: Kara Ireland Date: Wed, 1 Apr 2020 11:13:15 -0600 Subject: [PATCH 04/20] Added new sample for upcoming onSelectionChange trigger. Change-Id: I2ef4e3cf6c2b8ed7602259d2990e493cbd447a8c --- triggers/triggers.gs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/triggers/triggers.gs b/triggers/triggers.gs index 006dfe16e..0ec52f4ae 100644 --- a/triggers/triggers.gs +++ b/triggers/triggers.gs @@ -24,6 +24,23 @@ function onEdit(e) { } // [END apps_script_triggers_onedit] +// [START apps_script_triggers_onselectionchange] +/** + * The event handler triggered when the selection changes in the spreadsheet. + * @param {Event} e The onSelectionChange event. + */ +function onSelectionChange(e) { + // Set background to red if a single empty cell is selected. + var range = e.range; + if(range.getNumRows() == 1 + && range.getNumColumns() == 1 + && range.getCell(1, 1).getValue() == "") { + range.setBackground("red"); + } +} +// [END apps_script_triggers_onselectionchange] + + // [START apps_script_triggers_oninstall] /** * The event handler triggered when installing the add-on. From 0aba537903b108adeaa0bad5b0bf9c104bdcd68f Mon Sep 17 00:00:00 2001 From: Gus Wiedey Date: Fri, 3 Apr 2020 22:53:09 -0400 Subject: [PATCH 05/20] Fix spelling errors in dateAddAndSubtract.gs --- sheets/dateAddAndSubtract/dateAddAndSubtract.gs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sheets/dateAddAndSubtract/dateAddAndSubtract.gs b/sheets/dateAddAndSubtract/dateAddAndSubtract.gs index 427531417..f17fd19ad 100644 --- a/sheets/dateAddAndSubtract/dateAddAndSubtract.gs +++ b/sheets/dateAddAndSubtract/dateAddAndSubtract.gs @@ -52,7 +52,7 @@ function use() { var title = 'Date Custom Functions'; var message = 'The functions DATEADD and DATESUBTRACT are now available in ' + 'this spreadsheet. More information is available in the function help ' + - 'box that appears when you start using them in a forumula.'; + 'box that appears when you start using them in a formula.'; var ui = SpreadsheetApp.getUi(); ui.alert(title, message, ui.ButtonSet.OK); } @@ -113,7 +113,7 @@ function DATESUBTRACT(date, unit, amount) { /** * Validates that the date, unit, and amount supplied are compatible with - * Momnent, throwing an exception if any of the parameters are invalid. + * Moment, throwing an exception if any of the parameters are invalid. * @param {Date} date The date to add to or subtract from. * @param {string} unit The unit of time to add/subtract. * @param {number} amount The amount of the specified unit to add/subtract. From f21462a38c271c38f6b0a20563cb74f0e24e74f6 Mon Sep 17 00:00:00 2001 From: Steve Bazyl Date: Thu, 23 Apr 2020 14:31:37 -0600 Subject: [PATCH 06/20] Delint triggers.gs Change == to === where appropriate. --- triggers/triggers.gs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/triggers/triggers.gs b/triggers/triggers.gs index 0ec52f4ae..a404116f4 100644 --- a/triggers/triggers.gs +++ b/triggers/triggers.gs @@ -32,9 +32,9 @@ function onEdit(e) { function onSelectionChange(e) { // Set background to red if a single empty cell is selected. var range = e.range; - if(range.getNumRows() == 1 - && range.getNumColumns() == 1 - && range.getCell(1, 1).getValue() == "") { + if(range.getNumRows() === 1 + && range.getNumColumns() === 1 + && range.getCell(1, 1).getValue() === "") { range.setBackground("red"); } } From d23b10f76cbb9e44fc4eda40f9631b46ca02d54c Mon Sep 17 00:00:00 2001 From: Amit Agarwal Date: Mon, 4 May 2020 12:36:09 +0530 Subject: [PATCH 07/20] replaceMethod is deprecated Deprecated: use imageReplaceMethod instead. If you specify both a replaceMethod and an imageReplaceMethod , the imageReplaceMethod takes precedence. --- slides/api/Snippets.gs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slides/api/Snippets.gs b/slides/api/Snippets.gs index caff40eee..8ffe32459 100644 --- a/slides/api/Snippets.gs +++ b/slides/api/Snippets.gs @@ -250,7 +250,7 @@ Snippets.prototype.imageMerging = function(templatePresentationId, imageUrl, cus var requests = [{ replaceAllShapesWithImage: { imageUrl: logoUrl, - replaceMethod: 'CENTER_INSIDE', + imageReplaceMethod: 'CENTER_INSIDE', containsText: { text: '{{company-logo}}', matchCase: true @@ -259,7 +259,7 @@ Snippets.prototype.imageMerging = function(templatePresentationId, imageUrl, cus }, { replaceAllShapesWithImage: { imageUrl: customerGraphicUrl, - replaceMethod: 'CENTER_INSIDE', + imageReplaceMethod: 'CENTER_INSIDE', containsText: { text: '{{customer-graphic}}', matchCase: true From 6abacf00ddf0da42985983b35463b2638aa5ca2a Mon Sep 17 00:00:00 2001 From: Kara <62033369+kar320@users.noreply.github.com> Date: Mon, 4 May 2020 09:57:34 -0600 Subject: [PATCH 08/20] Update structpayload to jsonPayload in comment --- utils/logging.gs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/logging.gs b/utils/logging.gs index 400c82c47..e214e2702 100644 --- a/utils/logging.gs +++ b/utils/logging.gs @@ -8,7 +8,7 @@ function measuringExecutionTime() { // Log a JSON object at a DEBUG level. The log is labeled // with the message string in the log viewer, and the JSON content - // is displayed in the expanded log structure under "structPayload". + // is displayed in the expanded log structure under "jsonPayload". var parameters = { isValid: true, content: 'some string', From 4d73a1eaf946b9ee3dcabe091bc39cbca62655fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2020 00:08:51 +0000 Subject: [PATCH 09/20] Bump lodash from 4.17.15 to 4.17.19 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index eba405cba..7e3016150 100644 --- a/yarn.lock +++ b/yarn.lock @@ -501,8 +501,8 @@ levn@^0.3.0, levn@~0.3.0: type-check "~0.3.2" lodash@^4.17.4, lodash@^4.3.0: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" lru-cache@^4.0.1: version "4.1.2" From 47655e63204c66265aa8e22ad86c4015e2a9103f Mon Sep 17 00:00:00 2001 From: Lesley Cordero Date: Thu, 10 Sep 2020 22:14:40 -0400 Subject: [PATCH 10/20] Create patchCourse.gs Adds snippet to patch the section and room attributes of a course --- classroom/snippets/patchCourse.gs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 classroom/snippets/patchCourse.gs diff --git a/classroom/snippets/patchCourse.gs b/classroom/snippets/patchCourse.gs new file mode 100644 index 000000000..6bf9bb07c --- /dev/null +++ b/classroom/snippets/patchCourse.gs @@ -0,0 +1,31 @@ +/** + * Copyright 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. + */ +// [START classroom_patch_course] +/** + * Updates the section and room of Google Classroom. + */ +function coursePatch(course_id) { + var course = { + 'section': 'Period 3', + 'room': '302' + }; + var mask = { + updateMask: 'section,room' + }; + var course = Classroom.Courses.patch(body=course, id=course_id, updateMask=mask); + Logger.log('Course "%s" updated.', course.name); +} +// [END classroom_patch_course] From cb67fe15807b595f3d3012cb311e26e19f69c11e Mon Sep 17 00:00:00 2001 From: Lesley Cordero Date: Thu, 10 Sep 2020 22:55:33 -0400 Subject: [PATCH 11/20] Create addAlias.gs --- classroom/snippets/addAlias.gs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 classroom/snippets/addAlias.gs diff --git a/classroom/snippets/addAlias.gs b/classroom/snippets/addAlias.gs new file mode 100644 index 000000000..4ed0a85c8 --- /dev/null +++ b/classroom/snippets/addAlias.gs @@ -0,0 +1,31 @@ +/** + * Copyright 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. + */ +// [START classroom_add_alias] +/** + * Updates the section and room of Google Classroom. + */ +function addAlias(course_id) { + var alias = { + 'alias': 'p:bio_101' + } + try { + var course_alias = Classroom.Courses.Aliases.create(resource=alias, courseId=course_id); + Logger.log('%s successfully added as an alias!', course_alias.alias) + } catch (err) { + Logger.log("Request to add alias %s failed.", alias.alias) + } +} +// [END classroom_add_alias] From d6d28047ddd6d7d166997f04407cc32da1f3c44e Mon Sep 17 00:00:00 2001 From: Lesley Cordero Date: Sun, 13 Sep 2020 02:11:06 -0400 Subject: [PATCH 12/20] Create createAlias.gs creates course with alias at the same time --- classroom/snippets/createAlias.gs | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 classroom/snippets/createAlias.gs diff --git a/classroom/snippets/createAlias.gs b/classroom/snippets/createAlias.gs new file mode 100644 index 000000000..aae4e6563 --- /dev/null +++ b/classroom/snippets/createAlias.gs @@ -0,0 +1,34 @@ +/** + * Copyright 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. + */ +// [START classroom_create_alias] +/** + * Creates Course with an alias specified + */ +function createAlias() { + var course = { + id: 'p:10th_bio', + name: '10th Grade Biology', + section: 'Period 2', + descriptionHeading: 'Welcome to 10th Grade Biology', + description: "We'll be learning about about the structure of living creatures from a combination of textbooks, guest lectures, and lab work. Expect to be excited!", + room: '301', + ownerId: 'me', + courseState: 'PROVISIONED' + }; + var course = Classroom.Courses.create(course); + Logger.log('Course created: %s (%s)', course.name, course.id) +} +// [END classroom_create_alias] From 12f4dccb8d34591f44a1d3aedde413460f1999e3 Mon Sep 17 00:00:00 2001 From: Minhaz Kazi Date: Thu, 8 Oct 2020 12:53:17 -0700 Subject: [PATCH 13/20] Added PATH_USER_PASS examples --- data-studio/auth.gs | 74 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/data-studio/auth.gs b/data-studio/auth.gs index 829b74b58..ed6b3d7f2 100644 --- a/data-studio/auth.gs +++ b/data-studio/auth.gs @@ -27,6 +27,20 @@ function getAuthType() { } // [END apps_script_data_studio_get_auth_type_oauth2] +// [START apps_script_data_studio_get_auth_type_path_user_pass] +/** + * Returns the Auth Type of this connector. + * @return {object} The Auth type. + */ +function getAuthType() { + var cc = DataStudioApp.createCommunityConnector(); + return cc.newAuthTypeResponse() + .setAuthType(cc.AuthType.PATH_USER_PASS) + .setHelpUrl('https://www.example.org/connector-auth-help') + .build(); +} +// [END apps_script_data_studio_get_auth_type_path_user_pass] + // [START apps_script_data_studio_get_auth_type_user_pass] /** * Returns the Auth Type of this connector. @@ -91,6 +105,18 @@ function resetAuth() { } // [END apps_script_data_studio_auth_reset_oauth2] +// [START apps_script_data_studio_auth_reset_path_user] +/** + * Resets the auth service. + */ +function resetAuth() { + var userProperties = PropertiesService.getUserProperties(); + userProperties.deleteProperty('dscc.path'); + userProperties.deleteProperty('dscc.username'); + userProperties.deleteProperty('dscc.password'); +} +// [END apps_script_data_studio_auth_reset_path_user] + // [START apps_script_data_studio_auth_reset_user] /** * Resets the auth service. @@ -133,6 +159,22 @@ function isAuthValid() { } // [END apps_script_data_studio_auth_valid_oauth2] +// [START apps_script_data_studio_auth_valid_path_user_pass] +/** + * Returns true if the auth service has access. + * @return {boolean} True if the auth service has access. + */ +function isAuthValid() { + var userProperties = PropertiesService.getUserProperties(); + var path = userProperties.getProperty('dscc.path'); + var userName = userProperties.getProperty('dscc.username'); + var password = userProperties.getProperty('dscc.password'); + // This assumes you have a validateCredentials function that + // can validate if the userName and password are correct. + return validateCredentials(path, userName, password); +} +// [END apps_script_data_studio_auth_valid_path_user_pass] + // [START apps_script_data_studio_auth_valid_user_pass] /** * Returns true if the auth service has access. @@ -221,6 +263,38 @@ function get3PAuthorizationUrls() { } // [END apps_script_data_studio_auth_urls] +// [START apps_script_data_studio_auth_set_credentials_path_user_pass] +/** + * Sets the credentials. + * @param {Request} request The set credentials request. + * @return {object} An object with an errorCode. + */ +function setCredentials(request) { + var creds = request.userPass; + var path = creds.path; + var username = creds.username; + var password = creds.password; + + // Optional + // Check if the provided path, username and password are valid through + // a call to your service. You would have to have a `checkForValidCreds` + // function defined for this to work. + var validCreds = checkForValidCreds(path, username, password); + if (!validCreds) { + return { + errorCode: 'INVALID_CREDENTIALS' + }; + } + var userProperties = PropertiesService.getUserProperties(); + userProperties.setProperty('dscc.path', path); + userProperties.setProperty('dscc.username', username); + userProperties.setProperty('dscc.password', password); + return { + errorCode: 'NONE' + }; +} +// [END apps_script_data_studio_auth_set_credentials_path_user_pass] + // [START apps_script_data_studio_auth_set_credentials_user_pass] /** * Sets the credentials. From b4158b777ca0d9181806c7b9b6ec6cff3f380446 Mon Sep 17 00:00:00 2001 From: Kara <62033369+kar320@users.noreply.github.com> Date: Mon, 9 Nov 2020 10:10:29 -0700 Subject: [PATCH 14/20] Update logging.gs Updates logger to console. --- utils/logging.gs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/logging.gs b/utils/logging.gs index e214e2702..a3dc27ebb 100644 --- a/utils/logging.gs +++ b/utils/logging.gs @@ -35,11 +35,11 @@ function measuringExecutionTime() { * @param {string} email The email to send with the row data. */ function emailDataRow(rowNumber, email) { - Logger.log('Emailing data row ' + rowNumber + ' to ' + email); + console.log('Emailing data row ' + rowNumber + ' to ' + email); var sheet = SpreadsheetApp.getActiveSheet(); var data = sheet.getDataRange().getValues(); var rowData = data[rowNumber-1].join(" "); - Logger.log('Row ' + rowNumber + ' data: ' + rowData); + console.log('Row ' + rowNumber + ' data: ' + rowData); MailApp.sendEmail(email, 'Data in row ' + rowNumber, rowData); From 4ddd239ca58bbd67a4779c18314044c6ffc0ef66 Mon Sep 17 00:00:00 2001 From: Harry Waye Date: Sun, 22 Nov 2020 12:47:44 +0000 Subject: [PATCH 15/20] Resolve getActivePresentation Authorization issue This resolves an issue I was seeing when walking through the quickstart guide here: https://developers.google.com/gsuite/add-ons/editors/slides/quickstart/progress-bar Essentially I am seeing the following in StackDriver Logs for a "Simple Trigger" when I refresh my Google Presentation browser window as directed to do in the guide: ``` Exception: Authorization is required to perform that action. at [unknown function](progress:6:30) ``` This change is to avoid running `getActivePresentation` in the global scope. Note that there are some references to fixing this by running any function in the Apps Script editor see https://developers.google.com/apps-script/guides/support/troubleshooting#execution_transcript, which appears to have resolve others experiencing this issue, but there are also some suggesting that this no longer works, see https://webapps.stackexchange.com/a/136707 and the comment from kurokirasama. I'm unsure as to what has changed to require this, but this at least resolves my immediate issue. --- slides/progress/progress.gs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slides/progress/progress.gs b/slides/progress/progress.gs index 9463cb1a1..002da0289 100644 --- a/slides/progress/progress.gs +++ b/slides/progress/progress.gs @@ -19,7 +19,6 @@ */ var BAR_ID = 'PROGRESS_BAR_ID'; var BAR_HEIGHT = 10; // px -var presentation = SlidesApp.getActivePresentation(); /** * Runs when the add-on is installed. @@ -49,6 +48,7 @@ function onOpen(e) { */ function createBars() { deleteBars(); // Delete any existing progress bars + var presentation = SlidesApp.getActivePresentation(); var slides = presentation.getSlides(); for (var i = 0; i < slides.length; ++i) { var ratioComplete = (i / (slides.length - 1)); @@ -68,6 +68,7 @@ function createBars() { * Deletes all progress bar rectangles. */ function deleteBars() { + var presentation = SlidesApp.getActivePresentation(); var slides = presentation.getSlides(); for (var i = 0; i < slides.length; ++i) { var elements = slides[i].getPageElements(); From 5094bdfb24ee1b2ff9d1a4549afa3e5e3a9d0635 Mon Sep 17 00:00:00 2001 From: Steven Bazyl Date: Wed, 27 Jan 2021 14:21:03 -0700 Subject: [PATCH 16/20] Rename gsuitedevs->googleworkspace --- README.md | 2 +- sheets/next18/README.md | 2 +- sheets/next18/Salesforce.gs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fc1f748fd..70619b56d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Google Apps Script Samples [![Build Status](https://travis-ci.org/gsuitedevs/apps-script-samples.svg?branch=master)](https://travis-ci.org/gsuitedevs/apps-script-samples) +# Google Apps Script Samples [![Build Status](https://travis-ci.org/googleworkspace/apps-script-samples.svg?branch=master)](https://travis-ci.org/googleworkspace/apps-script-samples) Various sample code and projects for the Google Apps Script platform, a JavaScript platform in the cloud. diff --git a/sheets/next18/README.md b/sheets/next18/README.md index d98a68ef1..6b9621f88 100644 --- a/sheets/next18/README.md +++ b/sheets/next18/README.md @@ -5,7 +5,7 @@ on the Docs Editors: APIs and Apps Script". It is an implementation of a Google Sheets add-on that: * Authenticates with Salesforce via OAuth2, using the -[Apps Script OAuth2 library](https://github.com/gsuitedevs/apps-script-oauth2). +[Apps Script OAuth2 library](https://github.com/googleworkspace/apps-script-oauth2). * Runs [SOQL](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_sosl_intro.htm) queries against Salesforce and outputs the results into a new sheet * Creates invoices in Google Docs and a sample presentation in Google Slides diff --git a/sheets/next18/Salesforce.gs b/sheets/next18/Salesforce.gs index f5e90b59d..73fad8593 100644 --- a/sheets/next18/Salesforce.gs +++ b/sheets/next18/Salesforce.gs @@ -63,7 +63,7 @@ function showLinkDialog(url, message, title) { /** * Creates a Salesforce OAuth2 service, using the Apps Script OAuth2 library: - * https://github.com/gsuitedevs/apps-script-oauth2 + * https://github.com/googleworkspace/apps-script-oauth2 * * @return {Object} a Salesforce OAuth2 service */ From 1d0203e507a1f524b6b82e3c12a56cc53f066b07 Mon Sep 17 00:00:00 2001 From: ikuleshov Date: Mon, 16 Aug 2021 16:38:30 -0700 Subject: [PATCH 17/20] Google Analytics Data API apps script sample app --- advanced/analyticsData.gs | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 advanced/analyticsData.gs diff --git a/advanced/analyticsData.gs b/advanced/analyticsData.gs new file mode 100644 index 000000000..16551f53e --- /dev/null +++ b/advanced/analyticsData.gs @@ -0,0 +1,84 @@ +/** + * Copyright 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. + */ +// [START apps_script_analyticsdata] +/** + * Runs a report of a Google Analytics 4 property ID. Creates a sheet with the + * report. + */ +function runReport() { + /** + * TODO(developer): Uncomment this variable and replace with your + * Google Analytics 4 property ID before running the sample. + */ + const propertyId = 'YOUR-GA4-PROPERTY-ID'; + + var metric = AnalyticsData.newMetric(); + metric.name = 'activeUsers'; + + var dimension = AnalyticsData.newDimension(); + dimension.name = 'city'; + + var dateRange = AnalyticsData.newDateRange(); + dateRange.startDate = '2020-03-31'; + dateRange.endDate = 'today'; + + var request = AnalyticsData.newRunReportRequest(); + request.dimensions = [ dimension ]; + request.metrics = [ metric ]; + request.dateRanges = dateRange; + + var report = AnalyticsData.Properties.runReport(request, + 'properties/' + propertyId); + if (report.rows) { + var spreadsheet = SpreadsheetApp.create('Google Analytics Report'); + var sheet = spreadsheet.getActiveSheet(); + + // Append the headers. + var dimensionHeaders = report.dimensionHeaders.map( + function(dimensionHeader) { + return dimensionHeader.name; + }); + var metricHeaders = report.metricHeaders.map( + function(metricHeader) { + return metricHeader.name; + }); + var headers = [ ...dimensionHeaders, ...metricHeaders]; + + sheet.appendRow(headers); + + // Append the results. + var rows = report.rows.map( function(row) { + var dimensionValues = row.dimensionValues.map( + function(dimensionValue) { + return dimensionValue.value; + }); + var metricValues = row.metricValues.map( + function(metricValues) { + return metricValues.value; + }); + return [ ...dimensionValues, ...metricValues]; + }); + + sheet.getRange(2, 1, report.rows.length, headers.length) + .setValues(rows); + + Logger.log('Report spreadsheet created: %s', + spreadsheet.getUrl()); + } else { + Logger.log('No rows returned.'); + } +} +// [END apps_script_analyticsdata] From c3cb209cda1b75088a7a044dd385fe9bec1ef535 Mon Sep 17 00:00:00 2001 From: ikuleshov Date: Tue, 17 Aug 2021 17:29:45 -0400 Subject: [PATCH 18/20] Update advanced/analyticsData.gs Co-authored-by: Alex Hong <9397363+hongalex@users.noreply.github.com> --- advanced/analyticsData.gs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/analyticsData.gs b/advanced/analyticsData.gs index 16551f53e..bd2212699 100644 --- a/advanced/analyticsData.gs +++ b/advanced/analyticsData.gs @@ -1,5 +1,5 @@ /** - * Copyright Google LLC + * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 9d1f3f24a4d5f8ba9e79b8d72977eff6802df23e Mon Sep 17 00:00:00 2001 From: Kara <62033369+kar320@users.noreply.github.com> Date: Tue, 31 Aug 2021 14:08:50 -0600 Subject: [PATCH 19/20] Update gmail.gs Add code sample for returning message data and converting it from byte array to base-64 string. --- advanced/gmail.gs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/advanced/gmail.gs b/advanced/gmail.gs index 1cfbb277b..d866e05f6 100644 --- a/advanced/gmail.gs +++ b/advanced/gmail.gs @@ -97,3 +97,17 @@ function logRecentHistory() { }); } // [END apps_script_gmail_history] + +// [START apps_script_gmail_raw] +function getRawMessage() { + var messageId = Gmail.Users.Messages.list('me').messages[0].id; + console.log(messageId); + var message = Gmail.Users.Messages.get('me', messageId, { + 'format': 'raw' + }); + + // Get raw content as base64url encoded string. + var encodedMessage = Utilities.base64Encode(message.raw); + console.log(encodedMessage); +} +// [END apps_script_gmail_raw] From 35afc05244effad172632d5c008c6f6b7a1809fc Mon Sep 17 00:00:00 2001 From: Malcolm Rowe Date: Mon, 27 Sep 2021 14:59:13 +0100 Subject: [PATCH 20/20] Update adsense.gs for adsense v2. This updates the sample code to use v2 of the AdSense Management API rather than deprecated-and-soon-to-be-removed v1.4, including adding a new sample to list accounts (the v1.4 API picked an account if one was not specified; v2 requires the account to be specified explicitly). This also modernizes some of the JavaScript used here, and formats the code using semistandard. --- advanced/adsense.gs | 138 ++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/advanced/adsense.gs b/advanced/adsense.gs index e6599823c..df7b896b7 100644 --- a/advanced/adsense.gs +++ b/advanced/adsense.gs @@ -13,31 +13,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +// [START apps_script_adsense_list_accounts] +/** + * Lists available AdSense accounts. + */ +function listAccounts () { + let pageToken; + do { + const response = AdSense.Accounts.list({ pageToken: pageToken }); + if (response.accounts) { + for (const account of response.accounts) { + Logger.log('Found account with resource name "%s" and display name "%s".', + account.name, account.displayName); + } + } else { + Logger.log('No accounts found.'); + } + pageToken = response.nextPageToken; + } while (pageToken); +} +// [END apps_script_adsense_list_accounts] + // [START apps_script_adsense_list_ad_clients] /** - * Logs a lists Ad clients. + * Logs available Ad clients for an account. + * + * @param {string} accountName The resource name of the account that owns the collection of ad clients. */ -function listAdClients() { - // Retrieve ad client list in pages and log data as we receive it. - var pageToken; - var adClients; +function listAdClients (accountName) { + let pageToken; do { - adClients = AdSense.Adclients.list({ - maxResults: 50, + const response = AdSense.Accounts.Adclients.list(accountName, { pageToken: pageToken }); - if (adClients.items) { - for (var i = 0; i < adClients.items.length; i++) { - var adClient = adClients.items[i]; - Logger.log('Ad client for product "%s" with ID "%s" was found.', - adClient.productCode, adClient.id); - Logger.log('Supports reporting: %s', - adClient.supportsReporting ? 'Yes' : 'No'); + if (response.adClients) { + for (const adClient of response.adClients) { + Logger.log('Found ad client for product "%s" with resource name "%s".', + adClient.productCode, adClient.name); + Logger.log('Reporting dimension ID: %s', + adClient.reportingDimensionId ?? 'None'); } } else { - Logger.log('No ad clients found.'); + Logger.log('No ad clients found for this account.'); } - pageToken = adClients.nextPageToken; + pageToken = response.nextPageToken; } while (pageToken); } // [END apps_script_adsense_list_ad_clients] @@ -45,72 +64,66 @@ function listAdClients() { // [START apps_script_adsense_list_ad_units] /** * Lists ad units. - * @param {string} adClientId The ad client ID. + * @param {string} adClientName The resource name of the ad client that owns the collection of ad units. */ -function listAdUnits(adClientId) { - var pageToken; - var adUnits; +function listAdUnits (adClientName) { + let pageToken; do { - adUnits = AdSense.Adunits.list(adClientId, { - maxResults: 50, + const response = AdSense.Accounts.Adclients.Adunits.list(adClientName, { + pageSize: 50, pageToken: pageToken }); - if (adUnits.items) { - for (var i = 0; i < adUnits.items.length; i++) { - var unit = adUnits.items[i]; - Logger.log('Ad unit with code "%s" and name "%s" was found.', - unit.code, unit.name); + if (response.adUnits) { + for (const adUnit of response.adUnits) { + Logger.log('Found ad unit with resource name "%s" and display name "%s".', + adUnit.name, adUnit.displayName); } } else { - Logger.log('No ad units found.'); + Logger.log('No ad units found for this ad client.'); } - pageToken = adUnits.nextPageToken; + pageToken = response.nextPageToken; } while (pageToken); } // [END apps_script_adsense_list_ad_units] // [START apps_script_adsense_generate_report] /** - * Generates a spreadsheet report for an ad client. - * @param {string} adClientId The ad client ID + * Generates a spreadsheet report for a specific ad client in an account. + * @param {string} accountName The resource name of the account. + * @param {string} adClientName The reporting dimension ID of the ad client. */ -function generateReport(adClientId) { +function generateReport (accountName, adClientReportingDimensionId) { // Prepare report. - var today = new Date(); - var oneWeekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); - - var timezone = Session.getTimeZone(); - var startDate = Utilities.formatDate(oneWeekAgo, timezone, 'yyyy-MM-dd'); - var endDate = Utilities.formatDate(today, timezone, 'yyyy-MM-dd'); + const today = new Date(); + const oneWeekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); - var report = AdSense.Reports.generate(startDate, endDate, { + const report = AdSense.Accounts.Reports.generate(accountName, { // Specify the desired ad client using a filter. - filter: ['AD_CLIENT_ID==' + escapeFilterParameter(adClientId)], - metric: ['PAGE_VIEWS', 'AD_REQUESTS', 'AD_REQUESTS_COVERAGE', 'CLICKS', - 'AD_REQUESTS_CTR', 'COST_PER_CLICK', 'AD_REQUESTS_RPM', - 'EARNINGS'], - dimension: ['DATE'], + filters: ['AD_CLIENT_ID==' + escapeFilterParameter(adClientReportingDimensionId)], + metrics: ['PAGE_VIEWS', 'AD_REQUESTS', 'AD_REQUESTS_COVERAGE', 'CLICKS', + 'AD_REQUESTS_CTR', 'COST_PER_CLICK', 'AD_REQUESTS_RPM', + 'ESTIMATED_EARNINGS'], + dimensions: ['DATE'], + ...dateToJson('startDate', oneWeekAgo), + ...dateToJson('endDate', today), // Sort by ascending date. - sort: ['+DATE'] + orderBy: ['+DATE'] }); if (report.rows) { - var spreadsheet = SpreadsheetApp.create('AdSense Report'); - var sheet = spreadsheet.getActiveSheet(); + const spreadsheet = SpreadsheetApp.create('AdSense Report'); + const sheet = spreadsheet.getActiveSheet(); // Append the headers. - var headers = report.headers.map(function(header) { - return header.name; - }); - sheet.appendRow(headers); + sheet.appendRow(report.headers.map(header => header.name)); // Append the results. - sheet.getRange(2, 1, report.rows.length, headers.length) - .setValues(report.rows); + sheet.getRange(2, 1, report.rows.length, report.headers.length) + .setValues(report.rows.map(row => row.cells.map(cell => cell.value))); Logger.log('Report spreadsheet created: %s', - spreadsheet.getUrl()); + spreadsheet.getUrl()); } else { Logger.log('No rows returned.'); } @@ -121,7 +134,22 @@ function generateReport(adClientId) { * @param {string} parameter The parameter to be escaped. * @return {string} The escaped parameter. */ -function escapeFilterParameter(parameter) { +function escapeFilterParameter (parameter) { return parameter.replace('\\', '\\\\').replace(',', '\\,'); } + +/** + * Returns the JSON representation of a Date object (as a google.type.Date). + * + * @param {string} paramName the name of the date parameter + * @param {Date} value the date + */ +function dateToJson (paramName, value) { + return { + [paramName + '.year']: value.getFullYear(), + [paramName + '.month']: value.getMonth() + 1, + [paramName + '.day']: value.getDate() + }; +} + // [END apps_script_adsense_generate_report]