├── .eslintignore ├── .eslintrc.js ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── linters │ ├── .htmlhintrc │ ├── .yaml-lint.yml │ └── sun_checks.xml ├── pull_request_template.md ├── scripts │ └── clasp_push.sh ├── snippet-bot.yml ├── sync-repo-settings.yaml └── workflows │ ├── automation.yml │ ├── lint.yml │ ├── publish.yaml │ └── test.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── adminSDK ├── directory │ └── quickstart.gs ├── reports │ └── quickstart.gs └── reseller │ └── quickstart.gs ├── advanced ├── README.md ├── adminSDK.gs ├── adsense.gs ├── analytics.gs ├── analyticsAdmin.gs ├── analyticsData.gs ├── bigquery.gs ├── calendar.gs ├── chat.gs ├── classroom.gs ├── docs.gs ├── doubleclick.gs ├── drive.gs ├── driveActivity.gs ├── driveLabels.gs ├── events.gs ├── gmail.gs ├── iot.gs ├── people.gs ├── sheets.gs ├── shoppingContent.gs ├── slides.gs ├── tagManager.gs ├── tasks.gs ├── test_adminSDK.gs ├── test_adsense.gs ├── test_analytics.gs ├── test_bigquery.gs ├── test_calendar.gs ├── test_classroom.gs ├── test_docs.gs ├── test_doubleclick.gs ├── test_drive.gs ├── test_gmail.gs ├── test_people.gs ├── test_sheets.gs ├── test_shoppingContent.gs ├── test_slides.gs ├── test_tagManager.gs ├── test_tasks.gs ├── test_youtube.gs ├── test_youtubeAnalytics.gs ├── test_youtubeContentId.gs ├── youtube.gs ├── youtubeAnalytics.gs └── youtubeContentId.gs ├── ai ├── autosummarize │ ├── README.md │ ├── appsscript.json │ ├── gemini.js │ ├── main.js │ ├── sidebar.html │ └── summarize.js ├── custom-func-ai-studio │ ├── Code.js │ ├── README.md │ ├── appsscript.json │ └── gemini.js ├── custom_func_vertex │ ├── Code.js │ ├── README.md │ ├── aiVertex.js │ └── appsscript.json ├── devdocs-link-preview │ ├── Cards.js │ ├── Helpers.js │ ├── Main.js │ ├── README.md │ ├── Vertex.js │ └── appsscript.json ├── drive-rename │ ├── README.md │ ├── ai.js │ ├── appsscript.json │ ├── drive.js │ ├── main.js │ └── ui.js ├── email-classifier │ ├── Cards.gs │ ├── ClassifyEmail.gs │ ├── Code.gs │ ├── Constants.gs │ ├── DraftEmail.gs │ ├── Labels.gs │ ├── README.md │ ├── Sheet.gs │ └── appsscript.json ├── gmail-sentiment-analysis │ ├── Cards.gs │ ├── Code.gs │ ├── Gmail.gs │ ├── README.md │ ├── Vertex.gs │ └── appsscript.json └── standup-chat-app │ ├── README.md │ ├── appsscript.json │ ├── db.js │ ├── gemini.js │ ├── main.js │ └── memoize.js ├── apps-script └── execute │ └── target.js ├── calendar └── quickstart │ └── quickstart.gs ├── chat ├── advanced-service │ ├── AppAuthenticationUtils.gs │ ├── Main.gs │ ├── README.md │ └── appsscript.json └── quickstart │ ├── Code.gs │ ├── README.md │ └── appsscript.json ├── classroom ├── quickstart │ └── quickstart.gs └── snippets │ ├── addAlias.gs │ ├── courseUpdate.gs │ ├── createAlias.gs │ ├── createCourse.gs │ ├── getCourse.gs │ ├── listCourses.gs │ ├── patchCourse.gs │ └── test_classroom_snippets.gs ├── data-studio ├── appsscript.json ├── appsscript2.json ├── auth.gs ├── build.gs ├── caas.gs ├── data-source.gs ├── errors.gs ├── links.gs ├── manifest.gs └── semantics.gs ├── docs ├── README.md ├── cursorInspector │ ├── README.md │ ├── cursorInspector.gs │ ├── screenshot.png │ ├── sidebar.css.html │ ├── sidebar.html │ └── sidebar.js.html ├── dialog2sidebar │ ├── Code.gs │ ├── Dialog.html │ ├── Intercom.js.html │ ├── README.md │ └── Sidebar.html ├── quickstart │ └── quickstart.gs └── translate │ ├── README.md │ ├── sidebar.html │ └── translate.gs ├── drive ├── activity-v2 │ └── quickstart.gs ├── activity │ └── quickstart.gs └── quickstart │ └── quickstart.gs ├── forms-api ├── demos │ └── AppsScriptFormsAPIWebApp │ │ ├── Code.gs │ │ ├── FormsAPI.gs │ │ ├── Main.html │ │ ├── README.md │ │ └── appsscript.json └── snippets │ ├── README.md │ └── retrieve_all_responses.gs ├── forms ├── README.md └── notifications │ ├── README.md │ ├── about.html │ ├── authorizationEmail.html │ ├── creatorNotification.html │ ├── notification.gs │ ├── respondentNotification.html │ └── sidebar.html ├── gmail-sentiment-analysis ├── .clasp.json ├── Cards.gs ├── Code.gs ├── Gmail.gs ├── README.md ├── Vertex.gs └── appsscript.json ├── gmail ├── README.md ├── add-ons │ ├── appsscript.json │ └── quickstart.gs ├── inlineimage │ └── inlineimage.gs ├── markup │ ├── Code.gs │ └── mail_template.html ├── quickstart │ └── quickstart.gs └── sendingEmails │ └── sendingEmails.gs ├── mashups ├── sheets2calendar.gs ├── sheets2chat.gs ├── sheets2contacts.gs ├── sheets2docs.gs ├── sheets2drive.gs ├── sheets2forms.gs ├── sheets2gmail.gs ├── sheets2maps.gs ├── sheets2slides.gs └── sheets2translate.gs ├── package-lock.json ├── package.json ├── people └── quickstart │ └── quickstart.gs ├── picker ├── README.md ├── appsscript.json ├── code.gs └── dialog.html ├── renovate.json ├── service ├── jdbc.gs ├── propertyService.gs ├── test_jdbc.gs └── test_propertyServices.gs ├── sheets ├── README.md ├── api │ ├── helpers.gs │ ├── spreadsheet_snippets.gs │ └── test_spreadsheet_snippets.gs ├── customFunctions │ ├── btc.gs │ └── customFunctions.gs ├── dateAddAndSubtract │ ├── README.md │ ├── dateAddAndSubtract.gs │ ├── moment.gs │ └── screenshot.png ├── forms │ └── forms.gs ├── maps │ └── maps.gs ├── next18 │ ├── .claspignore │ ├── Constants.gs │ ├── Invoice.gs │ ├── LinkDialog.html │ ├── README.md │ ├── Salesforce.gs │ ├── appsscript.json │ └── demo.gif ├── quickstart │ └── quickstart.gs └── removingDuplicates │ └── removingDuplicates.gs ├── slides ├── README.md ├── SpeakerNotesScript │ ├── README.md │ ├── appscript.json │ └── scriptGen.gs ├── api │ ├── Helpers.gs │ ├── Snippets.gs │ └── Tests.gs ├── imageSlides │ └── imageSlides.gs ├── progress │ └── progress.gs ├── quickstart │ └── quickstart.gs ├── selection │ └── selection.gs ├── style │ ├── style.gs │ └── test_style.gs └── translate │ ├── sidebar.html │ └── translate.gs ├── solutions ├── add-on │ ├── book-smartchip │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ └── share-macro │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ ├── UI.js │ │ └── appsscript.json ├── attendance-chat-app │ ├── README.md │ ├── final │ │ ├── Code.gs │ │ └── appsscript.json │ ├── step-3 │ │ ├── Code.gs │ │ └── appsscript.json │ ├── step-4 │ │ ├── Code.gs │ │ └── appsscript.json │ ├── step-5 │ │ ├── Code.gs │ │ └── appsscript.json │ └── step-6 │ │ ├── Code.gs │ │ └── appsscript.json ├── automations │ ├── agenda-maker │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── aggregate-document-content │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── Menu.js │ │ ├── README.md │ │ ├── Setup.js │ │ ├── Utilities.js │ │ └── appsscript.json │ ├── bracket-maker │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── calendar-timesheet │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── Page.html │ │ ├── README.md │ │ └── appsscript.json │ ├── content-signup │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── course-feedback-response │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── employee-certificate │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── equipment-requests │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ ├── appsscript.json │ │ ├── new-equipment-request.html │ │ └── request-complete.html │ ├── event-session-signup │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── feedback-sentiment-analysis │ │ ├── .clasp.json │ │ ├── README.md │ │ ├── appsscript.json │ │ └── code.js │ ├── folder-creation │ │ ├── Code.js │ │ ├── README.md │ │ └── appscript.json │ ├── generate-pdfs │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── Menu.js │ │ ├── README.md │ │ ├── Utilities.js │ │ └── appsscript.json │ ├── import-csv-sheets │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ ├── SampleData.js │ │ ├── SetupSample.js │ │ ├── Utilities.js │ │ └── appsscript.json │ ├── mail-merge │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── news-sentiment │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── offsite-activity-signup │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── tax-loss-harvest-alerts │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── timesheets │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── upload-files │ │ ├── Code.js │ │ ├── README.md │ │ ├── Setup.js │ │ └── appsscript.json │ ├── vacation-calendar │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ └── youtube-tracker │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ ├── appsscript.json │ │ └── email.html ├── custom-functions │ ├── calculate-driving-distance │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ ├── summarize-sheets-data │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json │ └── tier-pricing │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── README.md │ │ └── appsscript.json ├── editor-add-on │ └── clean-sheet │ │ ├── .clasp.json │ │ ├── Code.js │ │ ├── Menu.js │ │ ├── README.md │ │ └── appsscript.json ├── ooo-assistant │ ├── .clasp.json │ ├── Chat.gs │ ├── Common.gs │ ├── README.md │ └── appsscript.json ├── ooo-chat-app │ ├── Code.js │ ├── README.md │ └── appsscript.json └── schedule-meetings │ ├── .clasp.json │ ├── Code.js │ ├── Dialog.js │ ├── README.md │ ├── Utilities.js │ └── appsscript.json ├── tasks ├── quickstart │ └── quickstart.gs └── simpleTasks │ ├── README.md │ ├── appsscript.json │ ├── javascript.html │ ├── page.html │ ├── screenshot.png │ ├── simpleTasks.gs │ └── stylesheet.html ├── templates ├── README.md ├── custom-functions │ ├── Code.gs │ └── README.md ├── docs-addon │ ├── Code.gs │ ├── Dialog.html │ ├── DialogJavaScript.html │ ├── README.md │ ├── Sidebar.html │ ├── SidebarJavaScript.html │ └── Stylesheet.html ├── forms-addon │ ├── Code.gs │ ├── Dialog.html │ ├── DialogJavaScript.html │ ├── README.md │ ├── Sidebar.html │ ├── SidebarJavaScript.html │ └── Stylesheet.html ├── sheets-addon │ ├── Code.gs │ ├── Dialog.html │ ├── DialogJavaScript.html │ ├── README.md │ ├── Sidebar.html │ ├── SidebarJavaScript.html │ └── Stylesheet.html ├── sheets-import │ ├── APICode.gs │ ├── Auth.gs │ ├── AuthCallbackView.html │ ├── AuthorizationEmail.html │ ├── Configurations.gs │ ├── JavaScript.html │ ├── README.md │ ├── Server.gs │ ├── Sidebar.html │ ├── Stylesheet.html │ ├── Utilities.gs │ └── intercom.js.html ├── standalone │ └── helloWorld.gs └── web-app │ ├── Code.gs │ ├── Index.html │ ├── JavaScript.html │ ├── README.md │ └── Stylesheet.html ├── triggers ├── form │ ├── AuthorizationEmail.html │ └── Code.gs ├── test_triggers.gs └── triggers.gs ├── ui ├── communication │ ├── basic │ │ ├── code.gs │ │ └── index.html │ ├── failure │ │ ├── code.gs │ │ └── index.html │ ├── private │ │ ├── code.gs │ │ └── index.html │ ├── runner.gs │ └── success │ │ ├── code.gs │ │ └── index.html ├── dialogs │ ├── dialogs.gs │ ├── menus.gs │ └── page.html ├── forms │ ├── code.gs │ └── index.html ├── html │ ├── printing_scriptlet.html │ ├── scriptlet.html │ └── standard_scriptlet.html ├── sidebar │ ├── code.gs │ └── index.html ├── user │ ├── code.gs │ └── index.html └── webapp │ ├── code.gs │ └── index.html ├── utils ├── logging.gs └── test_logging.gs ├── wasm ├── README.md ├── hello-world │ ├── .clasp.json │ ├── .gitattributes │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── biome.json │ ├── build.js │ ├── package-lock.json │ ├── package.json │ ├── polyfill.js │ └── src │ │ ├── appsscript.json │ │ ├── lib.rs │ │ ├── main.js │ │ ├── test.js │ │ └── wasm.js ├── image-add-on │ ├── .clasp.json │ ├── .gitattributes │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── biome.json │ ├── build.js │ ├── package-lock.json │ ├── package.json │ ├── polyfill.js │ └── src │ │ ├── add-on.js │ │ ├── appsscript.json │ │ ├── lib.rs │ │ ├── main.js │ │ ├── test.js │ │ └── wasm.js └── python │ ├── .clasp.json │ ├── .gitattributes │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── biome.json │ ├── build.js │ ├── package-lock.json │ ├── package.json │ ├── polyfill.js │ └── src │ ├── appsscript.json │ ├── lib.rs │ ├── main.js │ ├── test.js │ └── wasm.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | moment.gs 2 | wasm/** -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | module.exports = { 18 | extends: 'google', 19 | parserOptions: { 20 | ecmaVersion: 2020 21 | }, 22 | env: { 23 | node: true, 24 | 'googleappsscript/googleappsscript': true 25 | }, 26 | rules: { 27 | 'comma-dangle': ['error', 'never'], 28 | 'max-len': ['error', { code: 100 }], 29 | 'camelcase': ['error', { 30 | 'ignoreDestructuring': true, 31 | 'ignoreImports': true, 32 | 'allow': ['access_type', 'redirect_uris'], 33 | }], 34 | 'guard-for-in': 'off', 35 | 'no-var': 'off', // ES3 36 | 'no-unused-vars': 'off' // functions aren't used. 37 | }, 38 | plugins: [ 39 | 'googleappsscript' 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners 16 | 17 | .github/ @googleworkspace/workspace-devrel-dpe 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | TODO 4 | 5 | ## Expected Behavior 6 | 7 | Sample URL: 8 | Description: 9 | 10 | ## Actual Behavior 11 | 12 | 13 | ## Steps to Reproduce the Problem 14 | 15 | 1. 16 | 1. 17 | 1. 18 | -------------------------------------------------------------------------------- /.github/linters/.htmlhintrc: -------------------------------------------------------------------------------- 1 | { 2 | "tagname-lowercase": true, 3 | "attr-lowercase": true, 4 | "attr-value-double-quotes": true, 5 | "attr-value-not-empty": false, 6 | "attr-no-duplication": true, 7 | "doctype-first": false, 8 | "tag-pair": true, 9 | "tag-self-close": false, 10 | "spec-char-escape": false, 11 | "id-unique": true, 12 | "src-not-empty": true, 13 | "title-require": false, 14 | "alt-require": true, 15 | "doctype-html5": true, 16 | "id-class-value": false, 17 | "style-disabled": false, 18 | "inline-style-disabled": false, 19 | "inline-script-disabled": false, 20 | "space-tab-mixed-disabled": "space", 21 | "id-class-ad-disabled": false, 22 | "href-abs-or-rel": false, 23 | "attr-unsafe-chars": true, 24 | "head-script-disabled": false 25 | } 26 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Is it been tested? 8 | - [ ] Development testing done 9 | 10 | ## Checklist 11 | 12 | - [ ] My code follows the style guidelines of this project 13 | - [ ] I have performed a self-review of my own code 14 | - [ ] I have performed a peer-reviewed with team member(s) 15 | - [ ] I have commented my code, particularly in hard-to-understand areas 16 | - [ ] I have made corresponding changes to the documentation 17 | - [ ] My changes generate no new warnings 18 | - [ ] Any dependent changes have been merged and published in downstream modules 19 | -------------------------------------------------------------------------------- /.github/scripts/clasp_push.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | export LC_ALL=C.UTF-8 17 | export LANG=C.UTF-8 18 | 19 | function contains_changes() { 20 | [[ "${*:2}" = "" ]] && return 0 21 | for f in "${@:2}"; do 22 | case $(realpath "$f")/ in 23 | $(realpath "$1")/*) return 0;; 24 | esac 25 | done 26 | return 1 27 | } 28 | 29 | changed_files=$(echo "${@:1}" | xargs realpath | xargs -I {} dirname {}| sort -u | uniq) 30 | dirs=() 31 | 32 | IFS=$'\n' read -r -d '' -a dirs < <( find . -name '.clasp.json' -exec dirname '{}' \; | sort -u | xargs realpath ) 33 | 34 | exit_code=0 35 | 36 | for dir in "${dirs[@]}"; do 37 | pushd "${dir}" > /dev/null || exit 38 | contains_changes "$dir" "${changed_files[@]}" || continue 39 | echo "Publishing ${dir}" 40 | clasp push -f 41 | status=$? 42 | if [ $status -ne 0 ]; then 43 | exit_code=$status 44 | fi 45 | popd > /dev/null || exit 46 | done 47 | 48 | if [ $exit_code -ne 0 ]; then 49 | echo "Script push failed." 50 | fi 51 | 52 | exit $exit_code -------------------------------------------------------------------------------- /.github/snippet-bot.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /.github/sync-repo-settings.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # .github/sync-repo-settings.yaml 16 | # See https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings for app options. 17 | rebaseMergeAllowed: true 18 | squashMergeAllowed: true 19 | mergeCommitAllowed: false 20 | deleteBranchOnMerge: true 21 | branchProtectionRules: 22 | - pattern: main 23 | isAdminEnforced: false 24 | requiresStrictStatusChecks: false 25 | requiredStatusCheckContexts: 26 | # .github/workflows/test.yml with a job called "test" 27 | - "test" 28 | # .github/workflows/lint.yml with a job called "lint" 29 | - "lint" 30 | # Google bots below 31 | - "cla/google" 32 | - "snippet-bot check" 33 | - "header-check" 34 | - "conventionalcommits.org" 35 | requiredApprovingReviewCount: 1 36 | requiresCodeOwnerReviews: true 37 | permissionRules: 38 | - team: workspace-devrel-dpe 39 | permission: admin 40 | - team: workspace-devrel 41 | permission: push 42 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | --- 15 | name: Lint 16 | on: [push, pull_request, workflow_dispatch] 17 | jobs: 18 | lint: 19 | concurrency: 20 | group: ${{ github.head_ref || github.ref }} 21 | cancel-in-progress: true 22 | runs-on: ubuntu-20.04 23 | steps: 24 | - uses: actions/checkout@v3.0.2 25 | with: 26 | fetch-depth: 0 27 | - uses: github/super-linter/slim@v4.9.4 28 | env: 29 | ERROR_ON_MISSING_EXEC_BIT: true 30 | VALIDATE_JSCPD: false 31 | VALIDATE_JAVASCRIPT_STANDARD: false 32 | VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' }} 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | - uses: actions/setup-node@v3 35 | with: 36 | node-version: '14' 37 | - run: npm install 38 | - run: npm run lint 39 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | --- 15 | name: Publish Apps Script 16 | on: 17 | workflow_dispatch: 18 | push: 19 | branches: 20 | - main 21 | jobs: 22 | publish: 23 | concurrency: 24 | group: ${{ github.head_ref || github.ref }} 25 | cancel-in-progress: false 26 | runs-on: ubuntu-24.04 27 | steps: 28 | - uses: actions/checkout@v3.0.2 29 | with: 30 | fetch-depth: 0 31 | - name: Get changed files 32 | id: changed-files 33 | uses: tj-actions/changed-files@v23.1 34 | - name: Write test credentials 35 | run: | 36 | echo "${CLASP_CREDENTIALS}" > "${HOME}/.clasprc.json" 37 | env: 38 | CLASP_CREDENTIALS: ${{secrets.CLASP_CREDENTIALS}} 39 | - uses: actions/setup-node@v3 40 | with: 41 | node-version: '20' 42 | - run: npm install -g @google/clasp 43 | - run: ./.github/scripts/clasp_push.sh ${{ steps.changed-files.outputs.all_changed_files }} 44 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Test 16 | on: [push, pull_request] 17 | jobs: 18 | test: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v2 22 | - run: | 23 | echo "No tests"; 24 | exit 1; 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .gradle 4 | **/dist 5 | **/node_modules 6 | **/target -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Report a security issue 2 | 3 | To report a security issue, please use [https://g.co/vulnz](https://g.co/vulnz). We use 4 | [https://g.co/vulnz](https://g.co/vulnz) for our intake, and do coordination and disclosure here on 5 | GitHub (including using GitHub Security Advisory). The Google Security Team will 6 | respond within 5 working days of your report on [https://g.co/vulnz](https://g.co/vulnz). 7 | -------------------------------------------------------------------------------- /advanced/README.md: -------------------------------------------------------------------------------- 1 | # Advanced Services Samples 2 | 3 | This directory contains samples for using Apps Script Advanced Services. 4 | 5 | > Note: These services must be [enabled](https://developers.google.com/apps-script/guides/services/advanced#enabling_advanced_services) before running these samples. 6 | 7 | Learn more at [developers.google.com](https://developers.google.com/apps-script/guides/services/advanced). 8 | -------------------------------------------------------------------------------- /advanced/analyticsAdmin.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2021 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START apps_script_analyticsadmin] 17 | /** 18 | * Logs the Google Analytics accounts accessible by the current user. 19 | */ 20 | function listAccounts() { 21 | try { 22 | accounts = AnalyticsAdmin.Accounts.list(); 23 | if (!accounts.items || !accounts.items.length) { 24 | console.log('No accounts found.'); 25 | return; 26 | } 27 | 28 | for (let i = 0; i < accounts.items.length; i++) { 29 | const account = accounts.items[i]; 30 | console.log('Account: name "%s", displayName "%s".', account.name, account.displayName); 31 | } 32 | } catch (e) { 33 | // TODO (Developer) - Handle exception 34 | console.log('Failed with error: %s', e.error); 35 | } 36 | } 37 | // [END apps_script_analyticsadmin] 38 | -------------------------------------------------------------------------------- /advanced/driveActivity.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START apps_script_drive_activity_get_users_activity] 17 | /** 18 | * Gets a file's activity and logs the list of 19 | * unique users that performed the activity. 20 | */ 21 | function getUsersActivity() { 22 | var fileId = 'YOUR_FILE_ID_HERE'; 23 | 24 | var pageToken; 25 | var users = {}; 26 | do { 27 | var result = AppsActivity.Activities.list({ 28 | 'drive.fileId': fileId, 29 | 'source': 'drive.google.com', 30 | 'pageToken': pageToken 31 | }); 32 | var activities = result.activities; 33 | for (var i = 0; i < activities.length; i++) { 34 | var events = activities[i].singleEvents; 35 | for (var j = 0; j < events.length; j++) { 36 | var event = events[j]; 37 | users[event.user.name] = true; 38 | } 39 | } 40 | pageToken = result.nextPageToken; 41 | } while (pageToken); 42 | console.log(Object.keys(users)); 43 | } 44 | // [END apps_script_drive_activity_get_users_activity] 45 | -------------------------------------------------------------------------------- /advanced/test_adsense.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Replace with correct values 18 | const accountName = 'account name'; 19 | const clientName = 'ad client name'; 20 | 21 | /** 22 | * Tests listAccounts function of adsense.gs 23 | */ 24 | function itShouldListAccounts() { 25 | console.log('> itShouldListAccounts'); 26 | listAccounts(); 27 | } 28 | 29 | /** 30 | * Tests listAdClients function of adsense.gs 31 | */ 32 | function itShouldListAdClients() { 33 | console.log('> itShouldListAdClients'); 34 | listAdClients(accountName); 35 | } 36 | 37 | /** 38 | * Tests listAdUnits function of adsense.gs 39 | */ 40 | function itShouldListAdUnits() { 41 | console.log('> itShouldListAdUnits'); 42 | listAdUnits(clientName); 43 | } 44 | 45 | /** 46 | * Run all tests 47 | */ 48 | function RUN_ALL_TESTS() { 49 | itShouldListAccounts(); 50 | itShouldListAdClients(); 51 | itShouldListAdUnits(); 52 | } 53 | -------------------------------------------------------------------------------- /advanced/test_analytics.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Replace with the required profileId 18 | const profileId = 'abcd'; 19 | 20 | /** 21 | * Tests listAccounts function of analytics.gs 22 | */ 23 | function itShouldListAccounts() { 24 | console.log('> itShouldListAccounts'); 25 | listAccounts(); 26 | } 27 | 28 | /** 29 | * Tests runReport function of analytics.gs 30 | */ 31 | function itShouldRunReport() { 32 | console.log('> itShouldRunReport'); 33 | runReport(profileId); 34 | } 35 | 36 | /** 37 | * Runs all the tests 38 | */ 39 | function RUN_ALL_TESTS() { 40 | itShouldListAccounts(); 41 | itShouldRunReport(); 42 | } 43 | -------------------------------------------------------------------------------- /advanced/test_bigquery.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Tests runQuery function of adminSDK.gs 19 | */ 20 | function itShouldRunQuery() { 21 | console.log('> itShouldRunQuery'); 22 | runQuery(); 23 | } 24 | 25 | /** 26 | * Tests loadCsv function of adminSDK.gs 27 | */ 28 | function itShouldLoadCsv() { 29 | console.log('> itShouldLoadCsv'); 30 | loadCsv(); 31 | } 32 | 33 | /** 34 | * Runs all the tests 35 | */ 36 | function RUN_ALL_TESTS() { 37 | itShouldRunQuery(); 38 | itShouldLoadCsv(); 39 | } 40 | -------------------------------------------------------------------------------- /advanced/test_classroom.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Tests listCourses function of classroom.gs 19 | */ 20 | function itShouldListCourses() { 21 | console.log('> itShouldListCourses'); 22 | listCourses(); 23 | } 24 | 25 | /** 26 | * Runs all the tests 27 | */ 28 | function RUN_ALL_TESTS() { 29 | itShouldListCourses(); 30 | } 31 | -------------------------------------------------------------------------------- /advanced/test_doubleclick.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Tests listUserProfiles function of doubleclick.gs 19 | */ 20 | function itShouldListUserProfiles() { 21 | console.log('> itShouldListUserProfiles'); 22 | listUserProfiles(); 23 | } 24 | 25 | /** 26 | * Tests listActiveCampaigns function of doubleclick.gs 27 | */ 28 | function itShouldListActiveCampaigns() { 29 | console.log('> itShouldListActiveCampaigns'); 30 | listActiveCampaigns(); 31 | } 32 | 33 | /** 34 | * Tests createAdvertiserAndCampaign function of doubleclick.gs 35 | */ 36 | function itShouldCreateAdvertiserAndCampaign() { 37 | console.log('> itShouldCreateAdvertiserAndCampaign'); 38 | createAdvertiserAndCampaign(); 39 | } 40 | 41 | /** 42 | * Run all tests 43 | */ 44 | function RUN_ALL_TESTS() { 45 | itShouldListUserProfiles(); 46 | itShouldListActiveCampaigns(); 47 | itShouldCreateAdvertiserAndCampaign(); 48 | } 49 | -------------------------------------------------------------------------------- /advanced/test_gmail.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Run All functions of gmail.gs 19 | * Add gmail services to run 20 | */ 21 | function RUN_ALL_TESTS() { 22 | console.log('> ltShouldListLabelInfo'); 23 | listLabelInfo(); 24 | console.log('> ltShouldListInboxSnippets'); 25 | listInboxSnippets(); 26 | console.log('> ltShouldLogRecentHistory'); 27 | logRecentHistory(); 28 | console.log('> ltShouldGetRawMessage'); 29 | getRawMessage(); 30 | } 31 | -------------------------------------------------------------------------------- /advanced/test_people.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Helper functions for sheets.gs testing 19 | * 20 | * to tests people.gs add people api services 21 | */ 22 | function RUN_ALL_TESTS() { 23 | console.log('> itShouldGetConnections'); 24 | getConnections(); 25 | console.log('> itShouldGetSelf'); // Requires the scope userinfo.profile 26 | getSelf(); 27 | console.log('> itShouldGetAccount'); 28 | getAccount('me'); 29 | } 30 | -------------------------------------------------------------------------------- /advanced/test_tasks.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Test functions for tasks.gs 19 | * 20 | * Add task API services to test 21 | */ 22 | 23 | /** 24 | * tests listTaskLists of tasks.gs 25 | */ 26 | function itShouldListTaskLists() { 27 | console.log('> itShouldListTaskLists'); 28 | listTaskLists(); 29 | } 30 | 31 | /** 32 | * tests listTasks of tasks.gs 33 | */ 34 | function itShouldListTasks() { 35 | console.log('> itShouldListTasks'); 36 | const taskId = Tasks.Tasklists.list().items[0].id; 37 | listTasks(taskId); 38 | } 39 | 40 | /** 41 | * tests addTask of tasks.gs 42 | */ 43 | function itShouldAddTask() { 44 | console.log('> itShouldAddTask'); 45 | const taskId = Tasks.Tasklists.list().items[0].id; 46 | addTask(taskId); 47 | } 48 | 49 | /** 50 | * run all tests 51 | */ 52 | function RUN_ALL_TESTS() { 53 | itShouldListTaskLists(); 54 | itShouldListTasks(); 55 | itShouldAddTask(); 56 | itShouldListTasks(); 57 | } 58 | -------------------------------------------------------------------------------- /advanced/test_youtube.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Run all tests 19 | */ 20 | function RUN_ALL_TESTS() { 21 | console.log('> itShouldSearchByKeyword'); 22 | searchByKeyword(); 23 | console.log('> itShouldRetrieveMyUploads'); 24 | retrieveMyUploads(); 25 | console.log('> itShouldAddSubscription'); 26 | addSubscription(); 27 | console.log('> itShouldCreateSlides'); 28 | createSlides(); 29 | } 30 | -------------------------------------------------------------------------------- /advanced/test_youtubeAnalytics.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Tests createReport function of youtubeAnalytics.gs 19 | */ 20 | function itShouldCreateReport() { 21 | console.log('> itShouldCreateReport'); 22 | createReport(); 23 | } 24 | 25 | /** 26 | * Run all tests 27 | */ 28 | function RUN_ALL_TESTS() { 29 | itShouldCreateReport(); 30 | } 31 | -------------------------------------------------------------------------------- /advanced/test_youtubeContentId.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Tests claimYourVideoWithMonetizePolicy function of youtubeContentId.gs 19 | */ 20 | function itShouldClaimVideoWithMonetizePolicy() { 21 | console.log('> itShouldClaimVideoWithMonetizePolicy'); 22 | claimYourVideoWithMonetizePolicy(); 23 | } 24 | 25 | /** 26 | * Tests updateAssetOwnership function of youtubeContentId.gs 27 | */ 28 | function itShouldUpdateAssetOwnership() { 29 | console.log('> itShouldUpdateAssetOwnership'); 30 | updateAssetOwnership(); 31 | } 32 | 33 | /** 34 | * Tests releaseClaim function of youtubeContentId.gs 35 | */ 36 | function itShouldReleaseClaim() { 37 | console.log('> itShouldReleaseClaim'); 38 | releaseClaim(); 39 | } 40 | 41 | /** 42 | * Run all tests 43 | */ 44 | function RUN_ALL_TESTS() { 45 | itShouldClaimVideoWithMonetizePolicy(); 46 | itShouldUpdateAssetOwnership(); 47 | itShouldReleaseClaim(); 48 | } 49 | -------------------------------------------------------------------------------- /ai/autosummarize/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Denver", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "dependencies": { 6 | "libraries": [ 7 | { 8 | "userSymbol": "OAuth2", 9 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", 10 | "version": "43", 11 | "developmentMode": false 12 | } 13 | ], 14 | "enabledAdvancedServices": [ 15 | { 16 | "userSymbol": "Drive", 17 | "version": "v3", 18 | "serviceId": "drive" 19 | } 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /ai/custom-func-ai-studio/Code.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | 18 | /** 19 | * Passes a prompt and a data range to Gemini AI. 20 | * 21 | * @param {range} range The range of cells. 22 | * @param {string} prompt The text prompt as a string or single cell reference. 23 | * @return The Gemini response. 24 | * @customfunction 25 | */ 26 | function gemini(range,prompt) { 27 | prompt = `For the range of cells ${range}, ${prompt}` 28 | return getAiSummary(prompt); 29 | } -------------------------------------------------------------------------------- /ai/custom-func-ai-studio/README.md: -------------------------------------------------------------------------------- 1 | # Google Sheets Custom Function with AI Studio 2 | 3 | ## Project Description 4 | 5 | Google Sheets Custom Function to be used as a bound Apps Script project with a Google Sheets Spreadsheet 6 | 7 | ## Prerequisites 8 | 9 | * Google Cloud Project (aka Standard Cloud Project for Apps Script) with billing enabled 10 | 11 | ## Set up your environment 12 | 13 | 1. Create a Cloud Project 14 | 1. Enable Generative Language API - (may skip as is automatically done in step 2) 15 | 1. Create a Google Gemini API Key 16 | 1. Navigate to https://aistudio.google.com/app/apikey 17 | 1. Create API key for existing project from step 1 18 | 1. Copy the generated key for use in the next step. 19 | 1. Open an Apps Script Project bound to a Google Sheets Spreadsheet 20 | 1. From Project Settings, change project to GCP project number of Cloud Project from step 1 21 | 1. Add a Script Property. Enter `api_key` as the property name and use the Gemini API Key as the value 22 | 1. Add the project code to Apps Script 23 | 24 | ## Usage 25 | 26 | Insert a custom function in Google Sheets, passing a range and a prompt as parameters 27 | 28 | Example: 29 | 30 | ``` 31 | =gemini(A1:A10,"Extract colors from the product description") 32 | ``` -------------------------------------------------------------------------------- /ai/custom-func-ai-studio/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /ai/custom_func_vertex/Code.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Passes a prompt and a data range to Gemini AI. 3 | * 4 | * @param {range} range The range of cells. 5 | * @param {string} prompt The text prompt as a string or single cell reference. 6 | * @return The Gemini response. 7 | * @customfunction 8 | */ 9 | function gemini(range,prompt) { 10 | prompt = `For the table of data: ${range}, Answer the following: ${prompt}. Do not use formatting. Remove all markdown.` 11 | return getAiSummary(prompt); 12 | } -------------------------------------------------------------------------------- /ai/custom_func_vertex/README.md: -------------------------------------------------------------------------------- 1 | # Google Sheets Custom Function with AI Studio 2 | 3 | ## Project Description 4 | 5 | Google Sheets Custom Function to be used as a bound Apps Script project with a Google Sheets Spreadsheet. 6 | 7 | ## Prerequisites 8 | 9 | * Google Cloud Project (aka Standard Cloud Project for Apps Script) with billing enabled 10 | 11 | ## Set up your environment 12 | 13 | 1. Create a Cloud Project 14 | 1. Enable the Vertex AI API 15 | 1. Create a Service Account and grant the role `Vertex AI User` 16 | 1. Create a private key with type JSON. This will download the JSON file for use in the next section. 17 | 1. Open an Apps Script Project bound to a Google Sheets Spreadsheet 18 | 1. From Project Settings, change project to GCP project number of Cloud Project from step 1 19 | 1. Add a Script Property. Enter `model_id` as the property name and `gemini-pro` as the value. 20 | 1. Add a Script Property. Enter `project_location` as the property name and `us-central1` as the value. 21 | 1. Add a Script Property. Enter `service_account_key` as the property name and paste the JSON key from the service account as the value. 22 | 1. Add OAuth2 v43 Apps Script Library using the ID `1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF`. 23 | 1. Add the project code to Apps Script 24 | 25 | ## Usage 26 | 27 | Insert a custom function in Google Sheets, passing a range and a prompt as parameters 28 | 29 | Example: 30 | 31 | ``` 32 | =gemini(A1:A10,"Extract colors from the product description") 33 | ``` 34 | -------------------------------------------------------------------------------- /ai/custom_func_vertex/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | "libraries": [{ 5 | "userSymbol": "OAuth2", 6 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", 7 | "version": "43" 8 | }] 9 | }, 10 | "exceptionLogging": "STACKDRIVER", 11 | "runtimeVersion": "V8" 12 | } -------------------------------------------------------------------------------- /ai/devdocs-link-preview/Helpers.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /** 18 | * Wraper around script properties to allow for a default value if unset. 19 | */ 20 | function scriptPropertyWithDefault(key, defaultValue = undefined) { 21 | const scriptProperties = PropertiesService.getScriptProperties(); 22 | const value = scriptProperties.getProperty(key); 23 | if (value) { 24 | return value; 25 | } 26 | return defaultValue; 27 | } 28 | -------------------------------------------------------------------------------- /ai/devdocs-link-preview/README.md: -------------------------------------------------------------------------------- 1 | # Google Workspace Add-on - Developer Docs Link previews 2 | 3 | 4 | ## Project Description 5 | 6 | A Google Workspace Add-on that creates custom link previews for pages on the Google developer documentation site. The link preview uses AI to generate page summaries. 7 | 8 | ## Prerequisites 9 | 10 | * Google Cloud Project (aka Standard Cloud Project for Apps Script) with billing enabled 11 | 12 | ## Set up your environment 13 | 14 | 1. Create a Cloud Project 15 | 1. Enable the Vertex AI API 16 | 1. Create a Service Account and grant the role `Vertex AI User` 17 | 1. Create a private key with type JSON. This will download the JSON file for use in the next section. 18 | 1. Open a stand alone Apps Script Project 19 | 1. From Project Settings, change project to GCP project number of Cloud Project from step 1 20 | 1. Add a Script Property. Enter `service_account_key` as the property name and paste the JSON key from the service account as the value. 21 | 1. Add OAuth2 v43 Apps Script Library using the ID `1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF`. 22 | 1. Add the project code to Apps Script 23 | 24 | -------------------------------------------------------------------------------- /ai/drive-rename/README.md: -------------------------------------------------------------------------------- 1 | # Google Workspace Add-on Drive - Name with Intelligence 2 | 3 | ## Project Description 4 | 5 | Google Workspace Add-on for Google Drive, which uses AI to recommend new names for the selected Doc in Google Drive by passing the body of the document within the AI prompt for context. 6 | 7 | ## Prerequisites 8 | 9 | * Google Cloud Project (aka Standard Cloud Project for Apps Script) with billing enabled 10 | 11 | ## Set up your environment 12 | 13 | 1. Create a Cloud Project 14 | 1. Enable the Vertex AI API 15 | 1. Enable Google Drive API 16 | 1. Configure OAuth consent screen 17 | 1. Create a Service Account and grant the role Service `Vertex AI User` role 18 | 1. Create a private key with type JSON. This will download the JSON file for use in the next section. 19 | 1. Open a standalone Apps Script project. 20 | 1. From Project Settings, change project to GCP project number of Cloud Project from step 1 21 | 1. Add a Script Property. Enter `model_id` as the property name and `gemini-pro` as the value. 22 | 1. Add a Script Property. Enter `project_location` as the property name and `us-central1` as the value. 23 | 1. Add a Script Property. Enter `service_account_key` as the property name and paste the JSON key from the service account as the value. 24 | 1. Add `Google Drive API v3` advanced service. 25 | 1. Add OAuth2 v43 Apps Script Library using the ID `1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF`. 26 | 1. Add the project code to Apps Script 27 | 28 | 29 | -------------------------------------------------------------------------------- /ai/drive-rename/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "dependencies": { 6 | "enabledAdvancedServices": [ 7 | { 8 | "userSymbol": "Drive", 9 | "serviceId": "drive", 10 | "version": "v3" 11 | } 12 | ] 13 | }, 14 | "oauthScopes": [ 15 | "https://www.googleapis.com/auth/script.external_request", 16 | "https://www.googleapis.com/auth/drive.addons.metadata.readonly", 17 | "https://www.googleapis.com/auth/drive.file", 18 | "https://www.googleapis.com/auth/drive", 19 | "https://www.googleapis.com/auth/drive.readonly", 20 | "https://www.googleapis.com/auth/documents" 21 | ], 22 | "urlFetchWhitelist": [ 23 | "https://*.googleusercontent.com/", 24 | "https://*.googleapis.com/" 25 | ], 26 | "addOns": { 27 | "common": { 28 | "name": "Name with Intelligence", 29 | "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/drive_file_rename_outline/v12/googblue-48dp/2x/gm_drive_file_rename_outline_googblue_48dp.png", 30 | "layoutProperties": { 31 | "primaryColor": "#4285f4", 32 | "secondaryColor": "#3f8bca" 33 | } 34 | }, 35 | "drive": { 36 | "homepageTrigger": { 37 | "runFunction": "onHomepageOpened" 38 | }, 39 | "onItemsSelectedTrigger": { 40 | "runFunction": "onDriveItemsSelected" 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /ai/email-classifier/Constants.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const PROJECT_ID = ''; 18 | const LOCATION = 'us-central1'; 19 | const API_ENDPOINT = `${LOCATION}-aiplatform.googleapis.com`; 20 | const MODEL = 'gemini-2.5-pro-preview-05-06'; 21 | const GENERATE_CONTENT_API = 'generateContent'; 22 | const API_URL = `https://${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/${MODEL}:${GENERATE_CONTENT_API}`; 23 | const ME = ''; 24 | -------------------------------------------------------------------------------- /ai/email-classifier/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | "enabledAdvancedServices": [ 5 | { 6 | "userSymbol": "Gmail", 7 | "version": "v1", 8 | "serviceId": "gmail" 9 | }, 10 | { 11 | "userSymbol": "Sheets", 12 | "version": "v4", 13 | "serviceId": "sheets" 14 | } 15 | ] 16 | }, 17 | "oauthScopes": [ 18 | "https://www.googleapis.com/auth/cloud-platform", 19 | "https://www.googleapis.com/auth/gmail.addons.execute", 20 | "https://www.googleapis.com/auth/gmail.modify", 21 | "https://www.googleapis.com/auth/script.external_request", 22 | "https://www.googleapis.com/auth/spreadsheets" 23 | ], 24 | "addOns": { 25 | "common": { 26 | "name": "Email Classifier", 27 | "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/label_important/v20/googblue-24dp/1x/gm_label_important_googblue_24dp.png" 28 | }, 29 | "gmail": { 30 | "homepageTrigger": { 31 | "runFunction": "onHomepageTrigger", 32 | "enabled": true 33 | } 34 | } 35 | }, 36 | "exceptionLogging": "STACKDRIVER", 37 | "runtimeVersion": "V8" 38 | } 39 | -------------------------------------------------------------------------------- /ai/gmail-sentiment-analysis/Code.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /** 18 | * Callback for rendering the homepage card. 19 | * @return {CardService.Card} The card to show to the user. 20 | */ 21 | function onHomepage(e) { 22 | return buildCard_GmailHome(); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /ai/gmail-sentiment-analysis/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "Europe/Madrid", 3 | "dependencies": { 4 | "libraries": [ 5 | { 6 | "userSymbol": "OAuth2", 7 | "version": "43", 8 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF" 9 | } 10 | ] 11 | }, 12 | "addOns": { 13 | "common": { 14 | "name": "Productivity toolbox", 15 | "logoUrl": "https://icons.iconarchive.com/icons/roundicons/100-free-solid/64/spy-icon.png", 16 | "useLocaleFromApp": true 17 | }, 18 | "gmail": { 19 | "homepageTrigger": { 20 | "runFunction": "onHomepage", 21 | "enabled": true 22 | } 23 | } 24 | }, 25 | "exceptionLogging": "STACKDRIVER", 26 | "runtimeVersion": "V8" 27 | } -------------------------------------------------------------------------------- /ai/standup-chat-app/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "dependencies": { 6 | "enabledAdvancedServices": [ 7 | { 8 | "userSymbol": "Chat", 9 | "serviceId": "chat", 10 | "version": "v1" 11 | }, 12 | { 13 | "userSymbol": "AdminDirectory", 14 | "serviceId": "admin", 15 | "version": "directory_v1" 16 | } 17 | ] 18 | }, 19 | "webapp": { 20 | "executeAs": "USER_ACCESSING", 21 | "access": "DOMAIN" 22 | }, 23 | "oauthScopes": [ 24 | "https://www.googleapis.com/auth/chat.messages", 25 | "https://www.googleapis.com/auth/spreadsheets", 26 | "https://www.googleapis.com/auth/admin.directory.user.readonly", 27 | "https://www.googleapis.com/auth/script.external_request", 28 | "https://www.googleapis.com/auth/chat.spaces.create", 29 | "https://www.googleapis.com/auth/chat.spaces", 30 | "https://www.googleapis.com/auth/chat.spaces.readonly", 31 | "https://www.googleapis.com/auth/chat.spaces.create", 32 | "https://www.googleapis.com/auth/chat.delete", 33 | "https://www.googleapis.com/auth/chat.memberships", 34 | "https://www.googleapis.com/auth/chat.memberships.app", 35 | "https://www.googleapis.com/auth/userinfo.email" 36 | ] 37 | } -------------------------------------------------------------------------------- /ai/standup-chat-app/gemini.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /** 18 | * Makes a simple content-only call to Gemini AI. 19 | * 20 | * @param {string} text Prompt to pass to Gemini API. 21 | * @param {string} API_KEY Developer API Key enabled to call Gemini. 22 | * 23 | * @return {string} Response from AI call. 24 | */ 25 | function generateContent(text, API_KEY) { 26 | const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${API_KEY}`; 27 | 28 | return JSON.parse(UrlFetchApp.fetch(url, { 29 | method: "POST", 30 | headers: { 31 | "content-type": "application/json" 32 | }, 33 | payload: JSON.stringify({ 34 | contents: [{ 35 | parts: [ 36 | {text} 37 | ] 38 | }] 39 | }), 40 | }).getContentText()) 41 | } -------------------------------------------------------------------------------- /apps-script/execute/target.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START apps_script_api_execute] 17 | /** 18 | * Return the set of folder names contained in the user's root folder as an 19 | * object (with folder IDs as keys). 20 | * @return {Object} A set of folder names keyed by folder ID. 21 | */ 22 | function getFoldersUnderRoot() { 23 | const root = DriveApp.getRootFolder(); 24 | const folders = root.getFolders(); 25 | const folderSet = {}; 26 | while (folders.hasNext()) { 27 | const folder = folders.next(); 28 | folderSet[folder.getId()] = folder.getName(); 29 | } 30 | return folderSet; 31 | } 32 | // [END apps_script_api_execute] 33 | -------------------------------------------------------------------------------- /chat/advanced-service/README.md: -------------------------------------------------------------------------------- 1 | # Google Chat API - Advanced Service samples 2 | 3 | ## Set up 4 | 5 | 1. Follow the Google Chat app quickstart for Apps Script 6 | https://developers.google.com/workspace/chat/quickstart/apps-script-app and 7 | open the resulting Apps Script project in a web browser. 8 | 9 | 1. Override the Apps Script project contents with the files `appsscript.json`, 10 | `AppAuthenticationUtils.gs`, and `Main.gs` from this code sample directory. 11 | 12 | 1. To run samples that use app credentials: 13 | 14 | 1. Create a service account. For steps, see 15 | [Authenticate as a Google Chat app](https://developers.google.com/workspace/chat/authenticate-authorize-chat-app). 16 | 17 | 1. Open `AppAuthenticationUtils.gs` and set the value of the constant `SERVICE_ACCOUNT` to 18 | the private key's JSON of the service account that you created in the previous step. 19 | 20 | ## Run 21 | 22 | In the `Main.gs` file, each function contains a sample that calls a Chat API method 23 | using either app or user authentication. To run one of the samples, select the name 24 | of the function from the dropdown menu and click `Run`. 25 | -------------------------------------------------------------------------------- /chat/advanced-service/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "oauthScopes": [ 6 | "https://www.googleapis.com/auth/chat.spaces", 7 | "https://www.googleapis.com/auth/chat.spaces.create", 8 | "https://www.googleapis.com/auth/chat.spaces.readonly", 9 | "https://www.googleapis.com/auth/chat.memberships", 10 | "https://www.googleapis.com/auth/chat.memberships.app", 11 | "https://www.googleapis.com/auth/chat.memberships.readonly", 12 | "https://www.googleapis.com/auth/chat.messages", 13 | "https://www.googleapis.com/auth/chat.messages.create", 14 | "https://www.googleapis.com/auth/chat.messages.readonly" 15 | ], 16 | "chat": {}, 17 | "dependencies": { 18 | "enabledAdvancedServices": [{ 19 | "userSymbol": "Chat", 20 | "version": "v1", 21 | "serviceId": "chat" 22 | }], 23 | "libraries": [{ 24 | "userSymbol": "OAuth2", 25 | "version": "43", 26 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF" 27 | }] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chat/quickstart/README.md: -------------------------------------------------------------------------------- 1 | # Google Chat Apps Script Quickstart 2 | 3 | Complete the steps described in the [quickstart instructions]( 4 | https://developers.google.com/workspace/chat/api/guides/quickstart/apps-script), 5 | and in about five minutes you'll have a simple Apps Script application 6 | that makes requests to the Google Chat API. 7 | 8 | ## Run 9 | 10 | After following the quickstart setup instructions, execute the function `listSpaces` 11 | from the Apps Script console. 12 | -------------------------------------------------------------------------------- /chat/quickstart/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "oauthScopes": [ 6 | "https://www.googleapis.com/auth/chat.spaces.readonly" 7 | ], 8 | "chat": {}, 9 | "dependencies": { 10 | "enabledAdvancedServices": [{ 11 | "userSymbol": "Chat", 12 | "version": "v1", 13 | "serviceId": "chat" 14 | }] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /classroom/snippets/addAlias.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START classroom_add_alias] 17 | /** 18 | * Updates the section and room of Google Classroom. 19 | * @param {string} course_id 20 | * @see https://developers.google.com/classroom/reference/rest/v1/courses.aliases/create 21 | */ 22 | function addAlias(course_id) { 23 | const alias = { 24 | 'alias': 'p:bio_101' 25 | }; 26 | try { 27 | const course_alias = Classroom.Courses.Aliases.create(resource=alias, courseId=course_id); 28 | console.log('%s successfully added as an alias!', course_alias.alias); 29 | } catch (err) { 30 | // TODO (developer) - Handle exception 31 | console.log('Request to add alias %s failed with error %s.', alias.alias, err.message); 32 | } 33 | } 34 | // [END classroom_add_alias] 35 | -------------------------------------------------------------------------------- /classroom/snippets/courseUpdate.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START classroom_update_course] 17 | /** 18 | * Updates the section and room of Google Classroom. 19 | * @param {string} courseId 20 | * @see https://developers.google.com/classroom/reference/rest/v1/courses/update 21 | */ 22 | function courseUpdate(courseId) { 23 | try { 24 | // Get the course using course ID 25 | let course = Classroom.Courses.get(courseId); 26 | course.section = 'Period 3'; 27 | course.room = '302'; 28 | // Update the course 29 | course = Classroom.Courses.update(course, courseId); 30 | console.log('Course "%s" updated.', course.name); 31 | } catch (e) { 32 | // TODO (developer) - Handle exception 33 | console.log('Failed to update the course with error %s', e.message); 34 | } 35 | } 36 | // [END classroom_update_course] 37 | -------------------------------------------------------------------------------- /classroom/snippets/getCourse.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START classroom_get_course] 17 | /** 18 | * Retrieves course by id. 19 | * @param {string} courseId 20 | * @see https://developers.google.com/classroom/reference/rest/v1/courses/get 21 | */ 22 | function getCourse(courseId) { 23 | try { 24 | // Get the course details using course id 25 | const course = Classroom.Courses.get(courseId); 26 | console.log('Course "%s" found. ', course.name); 27 | } catch (err) { 28 | // TODO (developer) - Handle Courses.get() exception of Handle Classroom API 29 | console.log('Failed to found course %s with error %s ', courseId, err.message); 30 | } 31 | } 32 | // [END classroom_get_course] 33 | -------------------------------------------------------------------------------- /classroom/snippets/patchCourse.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START classroom_patch_course] 17 | /** 18 | * Updates the section and room of Google Classroom. 19 | * @param {string} courseId 20 | * @see https://developers.google.com/classroom/reference/rest/v1/courses/patch 21 | */ 22 | function coursePatch(courseId) { 23 | let course = { 24 | 'section': 'Period 3', 25 | 'room': '302' 26 | }; 27 | const mask = { 28 | updateMask: 'section,room' 29 | }; 30 | try { 31 | // Update section and room in course. 32 | course = Classroom.Courses.patch(body=course, id=courseId, updateMask=mask); 33 | console.log('Course "%s" updated.', course.name); 34 | } catch (err) { 35 | // TODO (developer) - Handle Courses.patch() exception 36 | console.log('Failed to update the course. Error message: %s', err.message); 37 | } 38 | } 39 | // [END classroom_patch_course] 40 | -------------------------------------------------------------------------------- /data-studio/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataStudio": { 3 | "name": "Nucleus by Hooli", 4 | "company": "Hooli Inc.", 5 | "companyUrl": "https://hooli.xyz", 6 | "logoUrl": "https://hooli.xyz/middle-out-optimized/nucleus/logo.png", 7 | "addonUrl": "https://hooli.xyz/data-studio-connector", 8 | "supportUrl": "https://hooli.xyz/data-studio-connector/support", 9 | "description": "Nucleus by Hooli connector lets you connect to your data in Data Studio using Nucleus middle out optimization. You will need an account on hooli.xyz to use this connector. Create your account at https://hooli.xyz/signup", 10 | "shortDescription": "Connect to your data using Nucleus middle out optimization", 11 | "privacyPolicyUrl": "https://hooli.xyz/privacy", 12 | "termsOfServiceUrl": "https://hooli.xyz/tos", 13 | "authType": ["NONE"], 14 | "feeType": ["PAID"], 15 | "sources": ["HOOLI_CHAT_LOG", "ENDFRAME_SERVER_STREAM", "RETINABYTE_USER_ANALYTICS"], 16 | "templates": { 17 | "default": "872223s89f5fdkjnd983kjf" 18 | } 19 | }, 20 | "urlFetchWhitelist": [ 21 | "https://api.hooli.xyz/", 22 | "https://hooli.xyz/" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /data-studio/appsscript2.json: -------------------------------------------------------------------------------- 1 | { 2 | "dataStudio": { 3 | "name": "npm Downloads - Build Guide", 4 | "logoUrl": "https://raw.githubusercontent.com/npm/logos/master/%22npm%22%20lockup/npm-logo-simplifed-with-white-space.png", 5 | "company": "Build Guide User", 6 | "companyUrl": "https://developers.google.com/datastudio/", 7 | "addonUrl": "https://github.com/google/datastudio/tree/master/community-connectors/npm-downloads", 8 | "supportUrl": "https://github.com/google/datastudio/issues", 9 | "description": "Get npm package download counts.", 10 | "sources": ["npm"] 11 | } 12 | } -------------------------------------------------------------------------------- /data-studio/data-source.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // [START apps_script_data_studio_params] 18 | var configParams = [ 19 | { 20 | type: 'TEXTINPUT', 21 | name: 'ZipCode', 22 | displayName: 'ZIP Code', 23 | parameterControl: { 24 | allowOverride: true 25 | } 26 | }, 27 | { 28 | type: 'SELECT_SINGLE', 29 | name: 'units', 30 | displayName: 'Units', 31 | parameterControl: { 32 | allowOverride: true 33 | }, 34 | options: [ 35 | { 36 | label: 'Metric', 37 | value: 'metric' 38 | }, 39 | { 40 | label: 'Imperial', 41 | value: 'imperial' 42 | }, 43 | { 44 | label: 'Kelvin', 45 | value: 'kelvin' 46 | } 47 | ] 48 | }, 49 | { 50 | type: 'TEXTINPUT', 51 | name: 'Days', 52 | displayName: 'Days to forecast' 53 | } 54 | ]; 55 | // [END apps_script_data_studio_params] 56 | -------------------------------------------------------------------------------- /data-studio/links.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // [START apps_script_data_studio_links] 18 | // These variables should be filled in as necessary for your connector. 19 | var configJSON; 20 | var templateId; 21 | var deploymentId; 22 | 23 | var params = []; 24 | 25 | const jsonString = JSON.stringify(configJSON); 26 | const encoded = encodeURIComponent(jsonString); 27 | params.push('connectorConfig=' + encoded); 28 | 29 | params.push('reportTemplateId=' + templateId); 30 | 31 | params.push('connectorId=' + deploymentId); 32 | 33 | const joinedParams = params.join('&'); 34 | const URL = 'https://datastudio.google.com/datasources/create?' + joinedParams; 35 | // [END apps_script_data_studio_links] 36 | -------------------------------------------------------------------------------- /data-studio/manifest.gs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googleworkspace/apps-script-samples/9d4f74231bd86a6c0f12adf81ad7f0352ee11361/data-studio/manifest.gs -------------------------------------------------------------------------------- /data-studio/semantics.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // [START apps_script_data_studio_manual] 18 | var schema = [ 19 | { 20 | 'name': 'Income', 21 | 'label': 'Income (in USD)', 22 | 'dataType': 'NUMBER', 23 | 'semantics': { 24 | 'conceptType': 'METRIC', 25 | 'semanticGroup': 'CURRENCY', 26 | 'semanticType': 'CURRENCY_USD' 27 | } 28 | }, { 29 | 'name': 'Filing Year', 30 | 'label': 'Year in which you filed the taxes.', 31 | 'dataType': 'STRING', 32 | 'semantics': { 33 | 'conceptType': 'METRIC', 34 | 'semanticGroup': 'DATE_OR_TIME', 35 | 'semanticType': 'YEAR' 36 | } 37 | } 38 | ]; 39 | // [END apps_script_data_studio_manual] 40 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Google Docs Add-ons 2 | 3 | ## Cursor Inspector 4 | 5 | This add-on allows you to inspect the current state of the cursor or selection within a document. The information is presented in a sidebar and updates automatically every few seconds. 6 | 7 | ## Translate 8 | 9 | This add-on allows you to translate selected text from a set of source languages to a set of destination languages. 10 | -------------------------------------------------------------------------------- /docs/cursorInspector/README.md: -------------------------------------------------------------------------------- 1 | # Cursor Inspector 2 | 3 | Cursor Inspector is a sample script for Google Docs that allows you to inspect 4 | the current state of the cursor or selection within a document. The information 5 | is presented in a sidebar and updates automatically every few seconds. The data 6 | presented corresponds with the 7 | [`Cursor`](https://developers.google.com/apps-script/reference/document/cursor) 8 | and 9 | [`Selection`](https://developers.google.com/apps-script/reference/document/selection) 10 | classes of the API. 11 | 12 | ![Cursor Inspector screenshot](screenshot.png) 13 | 14 | ## Try it out 15 | 16 | For your convience we have deployed the script into a Google Docs 17 | [document](https://docs.google.com/document/d/1v6S7IkDL_YIaVn1rBcVbqFr3rbNUX9_kLfFc00WTtx8/view) 18 | that you can copy and use. Follow the instructions in the document to get 19 | started. 20 | -------------------------------------------------------------------------------- /docs/cursorInspector/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googleworkspace/apps-script-samples/9d4f74231bd86a6c0f12adf81ad7f0352ee11361/docs/cursorInspector/screenshot.png -------------------------------------------------------------------------------- /docs/dialog2sidebar/README.md: -------------------------------------------------------------------------------- 1 | # Dialog to Sidebar Communication in Apps Script 2 | 3 | This script demonstrates a method of setting up a communication channel between 4 | a dialog and a sidebar in Apps Script. This helps solve the common problem 5 | of having your sidebar know when a dialog is opened, is submitted, closed, etc. 6 | 7 | With the introduction of the IFRAME sandbox mode, HtmlService UIs can take 8 | advantage of the 9 | [HTML5 localStorage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). 10 | The open source library [intercom.js](https://github.com/diy/intercom.js/) 11 | builds a messaging system on top of this API, allowing for dialogs and sidebars 12 | in the same browser to communicate with each other. 13 | 14 | An overview of the process is as follows: 15 | 16 | * The sidebar requests a new dialog to be opened. 17 | * The backend generates a new ID for the dialog, opens the dialog (passing in 18 | that ID as a template parameter), and sends the ID back to the sidebar. 19 | * The sidebar listens for events on the dialog's intercom.js channel. 20 | * The dialog regularly "checks in" with the sidebar, resetting a 21 | [timer](https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Timers). 22 | * When the user completes the dialog (by clicking either the "OK" or "Cancel" 23 | button) it sends this status change to the sidebar. 24 | * If the sidebar's timer actually fires, that means the dialog hasn't checked in 25 | recently, and it is considered "lost". 26 | -------------------------------------------------------------------------------- /docs/quickstart/quickstart.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START docs_quickstart] 17 | /** 18 | * Prints the title of the sample document: 19 | * https://docs.google.com/document/d/195j9eDD3ccgjQRttHhJPymLJUCOUjs-jmwTrekvdjFE/edit 20 | * @see https://developers.google.com/docs/api/reference/rest/v1/documents/get 21 | */ 22 | function printDocTitle() { 23 | const documentId = '195j9eDD3ccgjQRttHhJPymLJUCOUjs-jmwTrekvdjFE'; 24 | const doc = Docs.Documents.get(documentId, {'includeTabsContent': true}); 25 | console.log(`The title of the doc is: ${doc.title}`); 26 | } 27 | // [END docs_quickstart] 28 | -------------------------------------------------------------------------------- /docs/translate/README.md: -------------------------------------------------------------------------------- 1 | # Translate 2 | 3 | Translate is a sample script for Google Docs that allows you to translate 4 | selected text from a set of source languages to a set of destination languages. 5 | The resulting translation can then be inserted back into the Google Document. 6 | This sample was originally designed as a 7 | [quickstart](https://developers.google.com/apps-script/quickstart/docs). 8 | 9 | ![Google Docs Translate Quickstart](https://developers.google.com/apps-script/images/quickstart-translate.png) 10 | -------------------------------------------------------------------------------- /drive/quickstart/quickstart.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START drive_quickstart] 17 | /** 18 | * Lists the names and IDs of up to 10 files. 19 | */ 20 | function listFiles() { 21 | try { 22 | // Files.list method returns the list of files in drive. 23 | const files = Drive.Files.list({ 24 | fields: 'nextPageToken, items(id, title)', 25 | maxResults: 10 26 | }).items; 27 | // Print the title and id of files available in drive 28 | for (const file of files) { 29 | console.log('%s (%s)', file.title, file.id); 30 | } 31 | } catch (err) { 32 | // TODO(developer)-Handle Files.list() exception 33 | console.log('failed with error %s', err.message); 34 | } 35 | } 36 | // [END drive_quickstart] 37 | -------------------------------------------------------------------------------- /forms-api/demos/AppsScriptFormsAPIWebApp/Code.gs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | function doGet() { 16 | return HtmlService.createTemplateFromFile('Main').evaluate(); 17 | } -------------------------------------------------------------------------------- /forms-api/demos/AppsScriptFormsAPIWebApp/README.md: -------------------------------------------------------------------------------- 1 | # Google Forms API Apps Script web app 2 | 3 | This solution demonstrates how to interact with the new Google Forms API directly from Apps Script using REST calls, not the native Apps Script Forms Service. 4 | 5 | ## General setup 6 | 7 | * Enable the Forms API for your Google Cloud project 8 | 9 | ## Web app setup 10 | 11 | 1. Create a new blank Apps Script project. 12 | 13 | 1. Click **Project Settings**, then: 14 | * Check **Show "appsscript.json" manifest file in editor**. 15 | * Enter the project number of the Google Cloud project that has the 16 | Forms API enabled and click **Change project**. 17 | 18 | 1. Copy the contents of the Apps Script, HTML and JSON files into your 19 | Apps Script project. 20 | 21 | 1. Edit the `FormsAPI.gs` file to customize the constants. 22 | * `formId`: Choose a `formId` from an existing form. 23 | * `topicName`: Optional, if using watches (pub/sub). 24 | 25 | Note: Further project setup is required to use the watch features. To 26 | set up pub/sub topics, see 27 | [Google Cloud Pubsub](https://cloud.google.com/pubsub/docs/building-pubsub-messaging-system) 28 | for additional details. 29 | 30 | 1. Deploy the project as a Web app, authorize access and click on the 31 | deployment URL. 32 | 33 | -------------------------------------------------------------------------------- /forms-api/demos/AppsScriptFormsAPIWebApp/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "dependencies": {}, 6 | "webapp": { 7 | "executeAs": "USER_DEPLOYING", 8 | "access": "MYSELF" 9 | }, 10 | "oauthScopes": [ 11 | "https://www.googleapis.com/auth/script.external_request", 12 | "https://www.googleapis.com/auth/drive", 13 | "https://www.googleapis.com/auth/drive.readonly", 14 | "https://www.googleapis.com/auth/forms.body", 15 | "https://www.googleapis.com/auth/forms.body.readonly", 16 | "https://www.googleapis.com/auth/forms.responses.readonly", 17 | "https://www.googleapis.com/auth/userinfo.email" 18 | ] 19 | } -------------------------------------------------------------------------------- /forms-api/snippets/README.md: -------------------------------------------------------------------------------- 1 | # Forms API 2 | 3 | To run, you must set up your GCP project to use the Forms API. 4 | See: [Forms API](https://developers.google.com/forms/api/) 5 | -------------------------------------------------------------------------------- /forms-api/snippets/retrieve_all_responses.gs: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # [START forms_retrieve_all_responses] 16 | function callFormsAPI() { 17 | console.log('Calling the Forms API!'); 18 | var formId = ''; 19 | 20 | // Get OAuth Token 21 | var OAuthToken = ScriptApp.getOAuthToken(); 22 | console.log('OAuth token is: ' + OAuthToken); 23 | var formsAPIUrl = 'https://forms.googleapis.com/v1/forms/' + formId + '/' + 'responses'; 24 | console.log('formsAPIUrl is: ' + formsAPIUrl); 25 | var options = { 26 | 'headers': { 27 | Authorization: 'Bearer ' + OAuthToken, 28 | Accept: 'application/json' 29 | }, 30 | 'method': 'get' 31 | }; 32 | var response = UrlFetchApp.fetch(formsAPIUrl, options); 33 | console.log('Response from forms.responses was: ' + response); 34 | } 35 | # [END forms_retrieve_all_responses] 36 | -------------------------------------------------------------------------------- /forms/README.md: -------------------------------------------------------------------------------- 1 | # Google Forms Add-ons 2 | 3 | ## [Notification Add-on](https://developers.google.com/apps-script/quickstart/forms-add-on) 4 | 5 | This add-on allows Form creators to automatically 6 | send email notifications when a form is submitted. In addition, the 7 | add-on allows form creators to be notified when they have received 8 | responses. 9 | 10 | ![Form Notifications](https://developers.google.com/apps-script/images/quickstart-form-notifications.png) 11 | -------------------------------------------------------------------------------- /forms/notifications/respondentNotification.html: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 |

18 | 19 | 20 |
21 | 22 |

This automatic message was sent to you via the Form 23 | Notifications add-on for Google Forms. 24 |

25 | 26 | -------------------------------------------------------------------------------- /gmail-sentiment-analysis/.clasp.json: -------------------------------------------------------------------------------- 1 | { 2 | "scriptId": "1Z2gfvr0oYn68ppDtQbv0qIuKKVWhvwOTr-gCE0GFKVjNk8NDlpfJAGAr" 3 | } 4 | -------------------------------------------------------------------------------- /gmail-sentiment-analysis/Code.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /** 18 | * Callback for rendering the homepage card. 19 | * @return {CardService.Card} The card to show to the user. 20 | */ 21 | function onHomepageTrigger(e) { 22 | return buildHomepageCard(); 23 | } 24 | -------------------------------------------------------------------------------- /gmail-sentiment-analysis/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Toronto", 3 | "oauthScopes": [ 4 | "https://www.googleapis.com/auth/cloud-platform", 5 | "https://www.googleapis.com/auth/gmail.addons.execute", 6 | "https://www.googleapis.com/auth/gmail.labels", 7 | "https://www.googleapis.com/auth/gmail.modify", 8 | "https://www.googleapis.com/auth/script.external_request", 9 | "https://www.googleapis.com/auth/script.locale", 10 | "https://www.googleapis.com/auth/userinfo.email" 11 | ], 12 | "addOns": { 13 | "common": { 14 | "name": "Sentiment Analysis", 15 | "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/dynamic_feed/v6/black-24dp/1x/gm_dynamic_feed_black_24dp.png", 16 | "useLocaleFromApp": true 17 | }, 18 | "gmail": { 19 | "homepageTrigger": { 20 | "runFunction": "onHomepageTrigger", 21 | "enabled": true 22 | } 23 | } 24 | }, 25 | "exceptionLogging": "STACKDRIVER", 26 | "runtimeVersion": "V8" 27 | } 28 | -------------------------------------------------------------------------------- /gmail/README.md: -------------------------------------------------------------------------------- 1 | # Apps Scripts for Gmail 2 | 3 | Sample Google Apps Script functions for Gmail. 4 | 5 | ## [Mail Merge](https://developers.google.com/apps-script/articles/mail_merge) 6 | 7 | This tutorial shows an easy way to collect information from different users in a spreadsheet using Google Forms, then leverage it to generate and distribute personalized emails. 8 | 9 | ## [Sending Emails](https://developers.google.com/apps-script/articles/sending_emails) 10 | 11 | This tutorial shows how to use Spreadsheet data to send emails to different people. 12 | 13 | ## [Inline Image](inlineimage/inlineimage.gs) 14 | 15 | This example shows how to send an HTML email that includes an inline image attachment. 16 | -------------------------------------------------------------------------------- /gmail/add-ons/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "oauthScopes": [ 3 | "https://www.googleapis.com/auth/gmail.addons.execute", 4 | "https://www.googleapis.com/auth/gmail.addons.current.message.metadata", 5 | "https://www.googleapis.com/auth/gmail.modify" 6 | ], 7 | "gmail": { 8 | "name": "Gmail Add-on Quickstart - QuickLabels", 9 | "logoUrl": "https://www.gstatic.com/images/icons/material/system/1x/label_googblue_24dp.png", 10 | "contextualTriggers": [{ 11 | "unconditional": { 12 | }, 13 | "onTriggerFunction": "buildAddOn" 14 | }], 15 | "openLinkUrlPrefixes": [ 16 | "https://mail.google.com/" 17 | ], 18 | "primaryColor": "#4285F4", 19 | "secondaryColor": "#4285F4" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /gmail/markup/Code.gs: -------------------------------------------------------------------------------- 1 | // [START gmail_send_email_with_markup] 2 | /** 3 | * Send an email with schemas in order to test email markup. 4 | */ 5 | function testSchemas() { 6 | try { 7 | const htmlBody = HtmlService.createHtmlOutputFromFile('mail_template').getContent(); 8 | 9 | MailApp.sendEmail({ 10 | to: Session.getActiveUser().getEmail(), 11 | subject: 'Test Email markup - ' + new Date(), 12 | htmlBody: htmlBody 13 | }); 14 | } catch (err) { 15 | console.log(err.message); 16 | } 17 | } 18 | // [END gmail_send_email_with_markup] 19 | 20 | -------------------------------------------------------------------------------- /gmail/markup/mail_template.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 30 | 31 | 32 |

33 | This a test for a Go-To action in Gmail. 34 |

35 | 36 | 37 | -------------------------------------------------------------------------------- /mashups/sheets2contacts.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a new contact for every row in a spreadsheet. This code assumes that 3 | * the data is in the first sheet (workbook) in the spreadsheet and has the 4 | * columns "First Name", "Last Name", and "Email" in that order. 5 | */ 6 | function createContactsFromSpreadsheet() { 7 | // Open the spreadsheet and get the data. 8 | var ss = SpreadsheetApp.openByUrl('ENTER SPREADSHEET URL HERE'); 9 | var sheet = ss.getSheets()[0]; 10 | var data = sheet.getDataRange().getValues(); 11 | 12 | // Remove any frozen rows from the data, since they contain headers. 13 | data.splice(sheet.getFrozenRows()); 14 | 15 | // Send a contact for each row. 16 | data.forEach(function(row) { 17 | var firstName = row[0]; 18 | var lastName = row[1]; 19 | var email = row[2]; 20 | ContactsApp.createContact(firstName, lastName, email); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /mashups/sheets2docs.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a new document for every row in a spreadsheet. This code assumes that 3 | * the data is in the first sheet (workbook) in the spreadsheet and has the 4 | * columns "Title", "Content", and "Emails" in that order, with multiple email 5 | * addresses separated by a comma. 6 | */ 7 | function createDocsFromSpreadsheet() { 8 | // Open the spreadsheet and get the data. 9 | var ss = SpreadsheetApp.openByUrl('ENTER SPREADSHEET URL HERE'); 10 | var sheet = ss.getSheets()[0]; 11 | var data = sheet.getDataRange().getValues(); 12 | 13 | // Remove any frozen rows from the data, since they contain headers. 14 | data.splice(sheet.getFrozenRows()); 15 | 16 | // Create a document for each row. 17 | data.forEach(function(row) { 18 | var title = row[0]; 19 | var content = row[1]; 20 | var emails = row[2]; 21 | 22 | // Split the emails into an array and remove extra whitespace. 23 | emails = emails.split(',').map(function(email) { 24 | return email.trim(); 25 | }); 26 | 27 | // Create the document, append the content, and share it out. 28 | var doc = DocumentApp.create(title); 29 | doc.getBody().appendParagraph(content); 30 | doc.addEditors(emails); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /mashups/sheets2drive.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a PDF file in Google Drive for every row in a spreadsheet. This 3 | * code assumes that the data is in the first sheet (workbook) in the 4 | * spreadsheet and has the columns "File Name", "HTML Content", and "Emails" in that 5 | * order, with multiple email addresses separated by a comma. 6 | */ 7 | function createDriveFilesFromSpreadsheet() { 8 | // Open the spreadsheet and get the data. 9 | var ss = SpreadsheetApp.openByUrl('ENTER SPREADSHEET URL HERE'); 10 | var sheet = ss.getSheets()[0]; 11 | var data = sheet.getDataRange().getValues(); 12 | 13 | // Remove any frozen rows from the data, since they contain headers. 14 | data.splice(sheet.getFrozenRows()); 15 | 16 | // Create a PDF in Google Drive for each row. 17 | data.forEach(function(row) { 18 | var fileName = row[0]; 19 | var htmlContent = row[1]; 20 | var emails = row[2]; 21 | 22 | // Split the emails into an array and remove extra whitespace. 23 | emails = emails.split(',').map(function(email) { 24 | return email.trim(); 25 | }); 26 | 27 | // Convert the HTML content to PDF. 28 | var html = Utilities.newBlob(htmlContent, 'text/html'); 29 | var pdf = html.getAs('application/pdf'); 30 | 31 | // Create the Drive file and share it out. 32 | var file = DriveApp.createFile(pdf).setName(fileName); 33 | file.addEditors(emails); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /mashups/sheets2forms.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a new form for every row in a spreadsheet. This code assumes that the 3 | * data is in the first sheet (workbook) in the spreadsheet and has the 4 | * columns "Title", "Question", and "Emails" in that order, with multiple email 5 | * addresses separated by a comma. 6 | */ 7 | function createFormsFromSpreadsheet() { 8 | // Open the spreadsheet and get the data. 9 | var ss = SpreadsheetApp.openByUrl('ENTER SPREADSHEET URL HERE'); 10 | var sheet = ss.getSheets()[0]; 11 | var data = sheet.getDataRange().getValues(); 12 | 13 | // Remove any frozen rows from the data, since they contain headers. 14 | data.splice(sheet.getFrozenRows()); 15 | 16 | // Create a form for each row. 17 | data.forEach(function(row) { 18 | var title = row[0]; 19 | var question = row[1]; 20 | var emails = row[2]; 21 | 22 | // Split the emails into an array and remove extra whitespace. 23 | emails = emails.split(',').map(function(email) { 24 | return email.trim(); 25 | }); 26 | 27 | // Create the form, append the question, and share it out. 28 | var form = FormApp.create(title); 29 | form.addTextItem().setTitle(question); 30 | form.addEditors(emails); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /mashups/sheets2gmail.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Sends an email for every row in a spreadsheet. This code assumes that the 3 | * data is in the first sheet (workbook) in the spreadsheet and has the columns 4 | * "Subject", "HTML Message", and "Emails" in that order, with multiple email 5 | * addresses separated by a comma. 6 | */ 7 | function sendEmailsFromSpreadsheet() { 8 | // Open the spreadsheet and get the data. 9 | var ss = SpreadsheetApp.openByUrl('ENTER SPREADSHEET URL HERE'); 10 | var sheet = ss.getSheets()[0]; 11 | var data = sheet.getDataRange().getValues(); 12 | 13 | // Remove any frozen rows from the data, since they contain headers. 14 | data.splice(sheet.getFrozenRows()); 15 | 16 | // Send an email for each row. 17 | data.forEach(function(row) { 18 | var subject = row[0]; 19 | var htmlMessage = row[1]; 20 | var emails = row[2]; 21 | 22 | // Send the email. 23 | GmailApp.sendEmail(emails, subject, null, { 24 | htmlBody: htmlMessage 25 | }); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /mashups/sheets2maps.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * A custom function that gets the county (or equivalent administrative 3 | * district) that an address lies within. Use within a cell like: 4 | * 5 | * =COUNTY("76 9th Ave, New York NY") 6 | * 7 | * This script must be attached to the spreadsheet (created in Google Sheets 8 | * under "Tools > Script editor"). 9 | * 10 | * @param {String} address The address to lookup. 11 | * @return {String} The county (or equivalent) the address is within. 12 | * @customFunction 13 | */ 14 | function COUNTY(address) { 15 | var results = Maps.newGeocoder().geocode(address).results; 16 | if (!results || results.length === 0) { 17 | throw new Error('Unknown address'); 18 | } 19 | var counties = results[0].address_components.filter(function(component) { 20 | return component.types.indexOf('administrative_area_level_2') >= 0; 21 | }); 22 | if (!counties.length) { 23 | throw new Error('Unable to determine county'); 24 | } 25 | return counties[0].long_name; 26 | } 27 | -------------------------------------------------------------------------------- /mashups/sheets2slides.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a new presentation for every row in a spreadsheet. This code assumes 3 | * that the data is in the first sheet (workbook) in the spreadsheet and has the 4 | * columns "Title", "Content", and "Emails" in that order, with multiple email 5 | * addresses separated by a comma. 6 | */ 7 | function createPresentationsFromSpreadsheet() { 8 | // Open the spreadsheet and get the data. 9 | var ss = SpreadsheetApp.openByUrl('ENTER SPREADSHEET URL HERE'); 10 | var sheet = ss.getSheets()[0]; 11 | var data = sheet.getDataRange().getValues(); 12 | 13 | // Remove any frozen rows from the data, since they contain headers. 14 | data.splice(sheet.getFrozenRows()); 15 | 16 | // Create a presentation for each row. 17 | data.forEach(function(row) { 18 | var title = row[0]; 19 | var content = row[1]; 20 | var emails = row[2]; 21 | 22 | // Split the emails into an array and remove extra whitespace. 23 | emails = emails.split(',').map(function(email) { 24 | return email.trim(); 25 | }); 26 | 27 | // Create the presentation, insert a new slide at the start, append the content, 28 | // and share it out. 29 | var presentation = SlidesApp.create(title); 30 | var slide = presentation.insertSlide(0, SlidesApp.PredefinedLayout.MAIN_POINT); 31 | var textBox = slide.getShapes()[0]; 32 | textBox.getText().appendParagraph(content); 33 | presentation.addEditors(emails); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /mashups/sheets2translate.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Whenever a cell is edited and it's value is a string, add a note to the cell 3 | * with the English translation of the cell's content. 4 | * 5 | * For example, type "la gato" into a cell and this script will add a note 6 | * with the text "the cat". 7 | * 8 | * This script must be attached to the spreadsheet (created in Google Sheets 9 | * under "Tools > Script editor"). 10 | */ 11 | function onEdit() { 12 | var range = SpreadsheetApp.getActiveRange(); 13 | var value = range.getValue(); 14 | if (typeof value === 'string') { 15 | var translated = LanguageApp.translate(value, null, 'en'); 16 | range.setNote(translated); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gsuite-apps-script-samples", 3 | "version": "1.0.0", 4 | "description": "Apps Script samples for [G Suite API](https://developers.google.com/gsuite/) docs.", 5 | "license": "MIT", 6 | "private": true, 7 | "author": "Grant Timmerman", 8 | "keywords": [ 9 | "Google Workspace", 10 | "Apps Script", 11 | "Calendar", 12 | "Drive", 13 | "Sheets", 14 | "Slides", 15 | "API" 16 | ], 17 | "devDependencies": { 18 | "eslint": "8.18.0", 19 | "eslint-config-google": "0.14.0", 20 | "eslint-plugin-googleappsscript": "1.0.4" 21 | }, 22 | "scripts": { 23 | "lint": "./node_modules/.bin/eslint **/*.gs", 24 | "fix": "./node_modules/.bin/eslint **/*.gs --fix --quiet" 25 | }, 26 | "eslintIgnore": [ 27 | "**/node_modules/**" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /picker/README.md: -------------------------------------------------------------------------------- 1 | # File Picker Sample 2 | 3 | This sample shows how to create a "file-open" dialog in Google Sheets thatallows the user to select a file from their Drive. It does so by loading [Google Picker](https://developers.google.com/picker/), for this purpose. More information is available in the Apps Script guide [Dialogs and Sidebars in Google Workspace Documents](https://developers.google.com/apps-script/guides/dialogs#file-open_dialogs). 4 | 5 | Note that this sample expects to be [bound](https://developers.google.com/apps-script/guides/bound) to a spreadsheet. 6 | -------------------------------------------------------------------------------- /picker/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "oauthScopes": [ 6 | "https://www.googleapis.com/auth/script.container.ui", 7 | "https://www.googleapis.com/auth/drive.file" 8 | ], 9 | "dependencies": { 10 | "enabledAdvancedServices": [ 11 | { 12 | "userSymbol": "Drive", 13 | "version": "v3", 14 | "serviceId": "drive" 15 | } 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /service/test_propertyServices.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the 'License'); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an 'AS IS' BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Run all tests for propertyService.gs 19 | */ 20 | function RUN_ALL_TESTS() { 21 | console.log('> itShouldSaveSingleProperty'); 22 | saveSingleProperty(); 23 | console.log('> itShouldSaveMultipleProperties'); 24 | saveMultipleProperties(); 25 | console.log('> itShouldReadSingleProperty'); 26 | readSingleProperty(); 27 | console.log('> itShouldReadAllProperties'); 28 | readAllProperties(); 29 | // The tests below are successful if they run without any extra output 30 | console.log('> itShouldUpdateProperty'); 31 | updateProperty(); 32 | console.log('> itShouldDeleteSingleProperty'); 33 | deleteSingleProperty(); 34 | console.log('> itShouldDeleteAllUserProperties'); 35 | deleteAllUserProperties(); 36 | } 37 | -------------------------------------------------------------------------------- /sheets/README.md: -------------------------------------------------------------------------------- 1 | # Quickstart: Apps Scripts for Google Sheets 2 | 3 | Sample Google Apps Script add-ons and menus, and custom functions for Google Sheets. 4 | 5 | ## Date Add and Subtract 6 | 7 | Date Add and Subtract is a sample add-on for Google Sheets that provides custom functions for date manipulation. 8 | 9 | ## [Managing Responses for Google Forms](https://developers.google.com/apps-script/quickstart/forms) 10 | 11 | Create a Google Form based on data in a spreadsheet that emails Google Calendar invites and a personalized Google Doc to everyone who responds. 12 | 13 | ![Quickstart Forms](https://developers.google.com/apps-script/images/quickstart-forms.png) 14 | 15 | ## [Menus and Custom Functions](https://developers.google.com/apps-script/quickstart/custom-functions) 16 | 17 | Create a spreadsheet with custom functions, menu items, and automated procedures. 18 | 19 | ![Quickstart Custom Functions](https://developers.google.com/apps-script/images/quickstart-custom-functions.png) 20 | 21 | ## [Bracket Maker](https://developers.google.com/apps-script/articles/bracket_maker) 22 | 23 | This tutorial shows you how to use the Spreadsheets service to create Tournament Brackets similar to College Basketball's March Madness. You can use this tutorial to easily create your own brackets. 24 | 25 | ## [Removing Duplicates](https://developers.google.com/apps-script/articles/removing_duplicates) 26 | 27 | This tutorial shows how to avoid duplicates when you want to automate the process of copying data in Google Workspace and specifically how to remove duplicate rows in spreadsheet data. 28 | -------------------------------------------------------------------------------- /sheets/api/helpers.gs: -------------------------------------------------------------------------------- 1 | let filesToDelete = []; 2 | /** 3 | * Helper methods for Google Sheets tests. 4 | */ 5 | function Helpers() { 6 | this.filesToDelete = []; 7 | } 8 | 9 | Helpers.prototype.reset = function() { 10 | this.filesToDelete = []; 11 | }; 12 | 13 | Helpers.prototype.deleteFileOnCleanup = function(id) { 14 | this.filesToDelete.push(id); 15 | }; 16 | 17 | Helpers.prototype.cleanup = function() { 18 | filesToDelete.forEach(Drive.Files.remove); 19 | }; 20 | 21 | Helpers.prototype.createTestSpreadsheet = function() { 22 | const spreadsheet = SpreadsheetApp.create('Test Spreadsheet'); 23 | for (let i = 0; i < 3; ++i) { 24 | spreadsheet.appendRow([1, 2, 3]); 25 | } 26 | this.deleteFileOnCleanup(spreadsheet.getId()); 27 | return spreadsheet.getId(); 28 | }; 29 | 30 | Helpers.prototype.populateValues = function(spreadsheetId) { 31 | const batchUpdateRequest = Sheets.newBatchUpdateSpreadsheetRequest(); 32 | const repeatCellRequest = Sheets.newRepeatCellRequest(); 33 | 34 | let values = []; 35 | for (let i = 0; i < 10; ++i) { 36 | values[i] = []; 37 | for (let j = 0; j < 10; ++j) { 38 | values[i].push('Hello'); 39 | } 40 | } 41 | let range = 'A1:J10'; 42 | SpreadsheetApp.openById(spreadsheetId).getRange(range).setValues(values); 43 | SpreadsheetApp.flush(); 44 | }; 45 | -------------------------------------------------------------------------------- /sheets/customFunctions/btc.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // See https://support.coinbase.com/customer/en/portal/articles/1914910-how-can-i-generate-api-keys-within-coinbase-commerce- 18 | var COINBASE_API_TOKEN = ''; // TODO 19 | /** 20 | * Get's the bitcoin price at a date. 21 | * 22 | * @param {string} date The date in yyyy-MM-dd format. Defaults to today. 23 | * @return The value of BTC in USD at the date. From Coinbase's API 24 | * @customfunction 25 | */ 26 | function BTC(date) { 27 | var dateObject = new Date(); 28 | if (date) { 29 | dateObject = new Date(date); 30 | } 31 | var dateString = Utilities.formatDate(dateObject, "GMT", "yyyy-MM-dd"); 32 | var res = UrlFetchApp.fetch("https://api.coinbase.com/v2/prices/BTC-USD/spot?date=" + dateString, { 33 | headers: { 34 | "CB-VERSION": "2016-10-10", 35 | Authorization: "Bearer " + COINBASE_API_TOKEN 36 | } 37 | }); 38 | var json = JSON.parse(res.getContentText()); 39 | return json.data.amount; 40 | } 41 | -------------------------------------------------------------------------------- /sheets/dateAddAndSubtract/README.md: -------------------------------------------------------------------------------- 1 | # Date Add and Subtract 2 | 3 | Date Add and Subtract is a sample 4 | [add-on for Google Sheets](https://developers.google.com/apps-script/add-ons) 5 | that provides custom functions for date manipulation. The script uses the 6 | [Moment.js](http://momentjs.com/) JavaScript library, which is included directly 7 | in the Apps Script project. 8 | 9 | ![Date Add and Subtract screenshot](screenshot.png) 10 | 11 | ## Try it out 12 | 13 | For your convience we have published the script to the Google Sheets 14 | [add-ons store](https://chrome.google.com/webstore/detail/date-add-and-subtract/mhdmhddjinipgjhpicaidhpimlmgnflb). 15 | Install the add-on via the store and follow the instructions to get started. 16 | -------------------------------------------------------------------------------- /sheets/dateAddAndSubtract/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googleworkspace/apps-script-samples/9d4f74231bd86a6c0f12adf81ad7f0352ee11361/sheets/dateAddAndSubtract/screenshot.png -------------------------------------------------------------------------------- /sheets/next18/.claspignore: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /sheets/next18/Constants.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | /* Salesforce config */ 19 | 20 | // Salesforce OAuth configuration, which you get by creating a developer project 21 | // with OAuth authentication on Salesforce. 22 | var SALESFORCE_CLIENT_ID = ''; 23 | var SALESFORCE_CLIENT_SECRET = ''; 24 | 25 | // The Salesforce instance to talk to. 26 | var SALESFORCE_INSTANCE = 'na1'; 27 | 28 | /* Invoice generation config */ 29 | 30 | // The ID of a Google Doc that is used as a template. Defaults to 31 | // https://docs.google.com/document/d/1awKvXXMOQomdD68PGMpP5j1kNZwk_2Z0wBbwUgjKKws/view 32 | var INVOICE_TEMPLATE = '1awKvXXMOQomdD68PGMpP5j1kNZwk_2Z0wBbwUgjKKws'; 33 | 34 | // The ID of a Drive folder that the generated invoices are created in. Create 35 | // a new folder that your Google account has edit access to. 36 | var INVOICES_FOLDER = ''; 37 | -------------------------------------------------------------------------------- /sheets/next18/LinkDialog.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /sheets/next18/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | "libraries": [{ 5 | "userSymbol": "OAuth2", 6 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", 7 | "version": "26" 8 | }] 9 | }, 10 | "exceptionLogging": "STACKDRIVER", 11 | "oauthScopes": [ 12 | "https://www.googleapis.com/auth/script.container.ui", 13 | "https://www.googleapis.com/auth/script.external_request", 14 | "https://www.googleapis.com/auth/spreadsheets.currentonly", 15 | "https://www.googleapis.com/auth/drive", 16 | "https://www.googleapis.com/auth/documents", 17 | "https://www.googleapis.com/auth/presentations" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /sheets/next18/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googleworkspace/apps-script-samples/9d4f74231bd86a6c0f12adf81ad7f0352ee11361/sheets/next18/demo.gif -------------------------------------------------------------------------------- /slides/README.md: -------------------------------------------------------------------------------- 1 | # Quickstarts: Add-ons for Google Slides 2 | 3 | Sample Google Apps Script add-ons for Google Slides. 4 | 5 | ## [Translate](https://developers.google.com/apps-script/guides/slides/samples/translate) 6 | 7 | This add-on translates selected text from one language to another. 8 | 9 | ![Translate](https://user-images.githubusercontent.com/380123/45050204-9f383a00-b04e-11e8-9dc8-30fcc5e9fdd7.png) 10 | 11 | ## [Progress Bars](https://developers.google.com/apps-script/guides/slides/samples/progress-bar) 12 | 13 | This add-on adds a progress bar to your presentation. 14 | 15 | ![Progress Bars](https://user-images.githubusercontent.com/380123/45050203-9f383a00-b04e-11e8-9abf-042ce463a149.png) 16 | 17 | ## Speaker Notes Script 18 | 19 | This add-on extracts all the Speaker Notes from your presentation and creates a Document in your 20 | Drive directory with a formatted "script". 21 | 22 | ![Script](https://user-images.githubusercontent.com/380123/45051769-022bd000-b053-11e8-9700-7a67e89cc4c9.png) 23 | -------------------------------------------------------------------------------- /slides/SpeakerNotesScript/README.md: -------------------------------------------------------------------------------- 1 | # Speaker Notes Script 2 | 3 | This add-on will extract all your Speaker Notes and creates a Google Doc with your 'formatted' script. 4 | To run this add-on, first go to your Google slides with Speaker Notes. 5 | 6 | ![scriptscreenshot](https://user-images.githubusercontent.com/380123/45267455-878bf780-b43a-11e8-9aeb-9c909feb9613.jpg) 7 | 8 | ## Set Up 9 | 10 | 1. From within your new presentation, select the menu item 11 | **Tools > Script editor**. If you are presented with a welcome screen, click **Blank Project**. 12 | 1. Delete any code in the script editor and rename `Code.gs` to `scriptGen.gs`. Copy and paste the contents of `scriptGen.gs` into this file. 13 | 1. Then select the menu item **View > Show manifest file** in your Script Editor screen. Copy and paste the contents of `appsscript.json` in here. You need 2 scopes to run this sample: 14 | * To create and write a document: `https://www.googleapis.com/auth/documents` 15 | * To read the current presentation: `https://www.googleapis.com/auth/presentations.currentonly` 16 | 17 | ## Try It Out 18 | 19 | 1. Switch back to your presentation and reload the page. 20 | 1. After a few seconds, a **Speaker Notes Script** sub-menu appears under the 21 | **Add-ons** menu. Click **Add-ons > Speaker Notes Script > Generate Script Document**. 22 | 1. A dialog box indicates that the script requires authorization. 23 | Click **Continue**. A second dialog box requests authorization for 24 | specific Google services. Click **Allow**. 25 | 1. Check your Drive folder for script! 26 | -------------------------------------------------------------------------------- /slides/SpeakerNotesScript/appscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "oauthScopes": [ 4 | "https://www.googleapis.com/auth/documents", 5 | "https://www.googleapis.com/auth/presentations.currentonly" 6 | ], 7 | "exceptionLogging": "STACKDRIVER" 8 | } 9 | -------------------------------------------------------------------------------- /slides/style/test_style.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * runs all the test 19 | */ 20 | function RUN_ALL_TESTS() { 21 | console.log('> itShouldSetTextHelloWorld'); 22 | setTextHelloWorld(); 23 | console.log('> itShouldInsertText'); 24 | insertText(); 25 | console.log('> itShouldStyleText'); 26 | styleText(); 27 | console.log('> itShouldStyleParagraph'); 28 | paragraphStyling(); 29 | console.log('> itShouldListStyling'); 30 | listStyling(); 31 | } 32 | -------------------------------------------------------------------------------- /solutions/add-on/book-smartchip/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"14tK6PD4C624ivRyGk-S6eYCbYJnDfA24xeP0Jhb1U8sPgAvZXeZm5gpb"} 2 | -------------------------------------------------------------------------------- /solutions/add-on/book-smartchip/README.md: -------------------------------------------------------------------------------- 1 | # Preview links from Google Books with smart chips 2 | 3 | See 4 | https://developers.google.com/workspace/add-ons/samples/preview-links-google-books 5 | for additional details. 6 | -------------------------------------------------------------------------------- /solutions/add-on/book-smartchip/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "oauthScopes": [ 6 | "https://www.googleapis.com/auth/workspace.linkpreview", 7 | "https://www.googleapis.com/auth/script.external_request" 8 | ], 9 | "urlFetchWhitelist": [ 10 | "https://www.googleapis.com/books/v1/volumes/" 11 | ], 12 | "addOns": { 13 | "common": { 14 | "name": "Preview Books Add-on", 15 | "logoUrl": "https://developers.google.com/workspace/add-ons/images/library-icon.png", 16 | "layoutProperties": { 17 | "primaryColor": "#dd4b39" 18 | } 19 | }, 20 | "docs": { 21 | "linkPreviewTriggers": [ 22 | { 23 | "runFunction": "bookLinkPreview", 24 | "patterns": [ 25 | { 26 | "hostPattern": "*.google.*", 27 | "pathPrefix": "books" 28 | }, 29 | { 30 | "hostPattern": "*.google.*", 31 | "pathPrefix": "books/edition" 32 | } 33 | ], 34 | "labelText": "Book", 35 | "logoUrl": "https://developers.google.com/workspace/add-ons/images/book-icon.png", 36 | "localizedLabelText": { 37 | "es": "Libros" 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /solutions/add-on/share-macro/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1BsbWOAbLADGoLtp5P9oqctZMiqT5EFh_R-CufxAV9y1hvVSAMO35Azu9"} 2 | -------------------------------------------------------------------------------- /solutions/add-on/share-macro/README.md: -------------------------------------------------------------------------------- 1 | # Copy macros to other spreadsheets 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/add-ons/share-macro) for additional details. 4 | 5 | -------------------------------------------------------------------------------- /solutions/add-on/share-macro/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "oauthScopes": [ 6 | "https://www.googleapis.com/auth/spreadsheets", 7 | "https://www.googleapis.com/auth/script.external_request", 8 | "https://www.googleapis.com/auth/drive.readonly", 9 | "https://www.googleapis.com/auth/script.projects" 10 | ], 11 | "urlFetchWhitelist": [ 12 | "https://script.googleapis.com/" 13 | ], 14 | "addOns": { 15 | "common": { 16 | "name": "Share Macro", 17 | "logoUrl": "https://www.gstatic.com/images/branding/product/2x/apps_script_48dp.png", 18 | "layoutProperties": { 19 | "primaryColor": "#188038", 20 | "secondaryColor": "#34a853" 21 | }, 22 | "homepageTrigger": { 23 | "runFunction": "onHomepage" 24 | } 25 | }, 26 | "sheets": {} 27 | } 28 | } -------------------------------------------------------------------------------- /solutions/attendance-chat-app/README.md: -------------------------------------------------------------------------------- 1 | # Attendance Chat App 2 | 3 | This code sample shows how to build a Google Chat app using Google 4 | Apps Script. The Chat app responds to messages in a space or direct message (DM) and 5 | allows the user to set a vacation responder in Gmail or add an all-day event to 6 | their Calendar from Google Chat. 7 | 8 | ## Usage 9 | 10 | You can follow [this codelab](https://developers.google.com/codelabs/chat-apps-script) 11 | to build and test this Chat app. 12 | 13 | To use this Chat app, you must enable the Hangouts Chat API in the 14 | [Google API Console](https://console.developers.google.com/). After enabling 15 | the API, configuring the Chat app, and publishing it, you must add the Chat app to a space 16 | or DM to begin a conversation. 17 | 18 | For more information about how to publish a Chat app, see 19 | [Publishing Google Chat apps](https://developers.google.com/workspace/chat/apps-publish). 20 | 21 | ## Disclaimer 22 | 23 | This is not an official product. 24 | -------------------------------------------------------------------------------- /solutions/attendance-chat-app/final/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | "enabledAdvancedServices": [{ 5 | "userSymbol": "Gmail", 6 | "serviceId": "gmail", 7 | "version": "v1" 8 | }] 9 | }, 10 | "chat": { 11 | } 12 | } -------------------------------------------------------------------------------- /solutions/attendance-chat-app/step-3/Code.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Responds to an ADDED_TO_SPACE event 3 | * in Google Chat. 4 | * 5 | * @param event the event object from Google Chat 6 | * @return JSON-formatted response 7 | */ 8 | function onAddToSpace(event) { 9 | console.info(event); 10 | 11 | var message = ""; 12 | 13 | if (event.space.type === "DM") { 14 | message = "Thank you for adding me to a DM, " + 15 | event.user.displayName + "!"; 16 | } else { 17 | message = "Thank you for adding me to " + 18 | event.space.displayName; 19 | } 20 | 21 | return { "text": message }; 22 | } 23 | 24 | /** 25 | * Responds to a REMOVED_FROM_SPACE event 26 | * in Google Chat. 27 | * 28 | * @param event the event object from Google Chat 29 | */ 30 | function onRemoveFromSpace(event) { 31 | console.info(event); 32 | console.info("Chat app removed from ", event.space.name); 33 | } 34 | -------------------------------------------------------------------------------- /solutions/attendance-chat-app/step-3/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | }, 5 | "chat": {} 6 | } -------------------------------------------------------------------------------- /solutions/attendance-chat-app/step-4/Code.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Responds to an ADDED_TO_SPACE event 3 | * in Google Chat. 4 | * 5 | * @param event the event object from Google Chat 6 | * @return JSON-formatted response 7 | */ 8 | function onAddToSpace(event) { 9 | console.info(event); 10 | 11 | var message = ""; 12 | 13 | if (event.space.type === "DM") { 14 | message = "Thank you for adding me to a DM, " + 15 | event.user.displayName + "!"; 16 | } else { 17 | message = "Thank you for adding me to " + 18 | event.space.displayName; 19 | } 20 | 21 | return { "text": message }; 22 | } 23 | 24 | /** 25 | * Responds to a REMOVED_FROM_SPACE event 26 | * in Google Chat. 27 | * 28 | * @param event the event object from Google Chat 29 | */ 30 | function onRemoveFromSpace(event) { 31 | console.info(event); 32 | console.info("Chat app removed from ", event.space.name); 33 | } 34 | -------------------------------------------------------------------------------- /solutions/attendance-chat-app/step-4/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | }, 5 | "chat": {} 6 | } -------------------------------------------------------------------------------- /solutions/attendance-chat-app/step-5/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | }, 5 | "chat": {} 6 | } -------------------------------------------------------------------------------- /solutions/attendance-chat-app/step-6/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | "enabledAdvancedServices": [{ 5 | "userSymbol": "Gmail", 6 | "serviceId": "gmail", 7 | "version": "v1" 8 | }] 9 | }, 10 | "chat": { 11 | } 12 | } -------------------------------------------------------------------------------- /solutions/automations/agenda-maker/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "147xVWUWmw8b010zbiDMIa3eeKATo3P2q5rJCZmY3meirC-yA_XucdZlp"} 2 | -------------------------------------------------------------------------------- /solutions/automations/agenda-maker/README.md: -------------------------------------------------------------------------------- 1 | # Make an agenda for meetings 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/agenda-maker) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/agenda-maker/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/aggregate-document-content/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1YGstQLxmTcAQlSHfm0yke12Y2UgT8eVfCxrG_jGpG1dHDmFdOaHQfQZJ"} 2 | -------------------------------------------------------------------------------- /solutions/automations/aggregate-document-content/README.md: -------------------------------------------------------------------------------- 1 | # Aggregate content from multiple documents 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/aggregate-document-content) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/aggregate-document-content/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/bracket-maker/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1LkY5nKFdBg2Q9-oIUcZsxRuESvgIcFHGobveNeQ5CpTgV6GgpTUQeOIB"} 2 | -------------------------------------------------------------------------------- /solutions/automations/bracket-maker/README.md: -------------------------------------------------------------------------------- 1 | # Create a tournament bracket 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/bracket-maker) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/bracket-maker/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/calendar-timesheet/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1WL3-mzC219UHqy_vqI1gEeoFy5Y8eeiKCZjiiPsWmVmQfVVedN5Vt7rK"} 2 | -------------------------------------------------------------------------------- /solutions/automations/calendar-timesheet/README.md: -------------------------------------------------------------------------------- 1 | # Record time and activities in Calendar and Sheets 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/calendar-timesheet) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/calendar-timesheet/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/content-signup/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1G8TfU6Rfcl76Uo4gKig7jFMYKai-V_fiUNbO12pAb25pA4_uyxN5PSvd"} 2 | -------------------------------------------------------------------------------- /solutions/automations/content-signup/README.md: -------------------------------------------------------------------------------- 1 | # Send curated content 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/content-signup) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/content-signup/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": {}, 4 | "exceptionLogging": "STACKDRIVER", 5 | "oauthScopes": [ 6 | "https://www.googleapis.com/auth/documents", 7 | "https://www.googleapis.com/auth/drive.readonly", 8 | "https://www.googleapis.com/auth/script.external_request", 9 | "https://www.googleapis.com/auth/script.scriptapp", 10 | "https://www.googleapis.com/auth/script.send_mail", 11 | "https://www.googleapis.com/auth/spreadsheets.currentonly" 12 | ], 13 | "runtimeVersion": "V8" 14 | } -------------------------------------------------------------------------------- /solutions/automations/course-feedback-response/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1k75E4EdC3TcJEGGIupBANjm5duvs35ORAU1Mg2_6DNXENo827dFzmFeC"} 2 | -------------------------------------------------------------------------------- /solutions/automations/course-feedback-response/README.md: -------------------------------------------------------------------------------- 1 | # Respond to feedback 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/course-feedback-response) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/course-feedback-response/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/employee-certificate/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1f0EhMh_a2Jtq3DS96ZWeG2XviJ-XHSStB2B3mVXODPz3KyojS7nFRzV-"} 2 | -------------------------------------------------------------------------------- /solutions/automations/employee-certificate/README.md: -------------------------------------------------------------------------------- 1 | # Send personalized appreciation certificates to employees 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/employee-certificate) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/employee-certificate/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/equipment-requests/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1T0G2Qr0QkHfqOK8dqjdiMRGuX2UVzkQU3BGfl2lC3wsNwkSmISbp2q6t"} 2 | -------------------------------------------------------------------------------- /solutions/automations/equipment-requests/README.md: -------------------------------------------------------------------------------- 1 | # Manage new employee equipment requests 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/equipment-requests) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/equipment-requests/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/equipment-requests/new-equipment-request.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 |

21 | A new equipment request has been made by . 22 |

23 | 24 |

25 | Employee name:
26 | Desk location name:
27 | Due date:
28 | Laptop model:
29 | Desktop model:
30 | Monitor(s):
31 |

32 | 33 | See the spreadsheet to take or assign this item. 34 | 35 | 36 | -------------------------------------------------------------------------------- /solutions/automations/equipment-requests/request-complete.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 |

21 | An equipment request has been completed. 22 |

23 | 24 |

25 | Employee name:
26 | Desk location name:
27 |

28 | 29 | 30 | -------------------------------------------------------------------------------- /solutions/automations/event-session-signup/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1RTfpaBw-RYW8PTJsidiqXHRrqaKnwMWAK_nq4LnWk9xXKGJWi_bhexRj"} 2 | -------------------------------------------------------------------------------- /solutions/automations/event-session-signup/README.md: -------------------------------------------------------------------------------- 1 | # Create a sign-up for sessions at a conference 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/event-session-signup) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/event-session-signup/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/feedback-sentiment-analysis/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"1LOheMLQDlSkvmlt8EQOGGETewdt8tKWyzxspCwqzfianqxTXjBGpAc8c"} -------------------------------------------------------------------------------- /solutions/automations/feedback-sentiment-analysis/README.md: -------------------------------------------------------------------------------- 1 | # Analyze sentiment of open-ended feedback 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/feedback-sentiment-analysis) for additional details. -------------------------------------------------------------------------------- /solutions/automations/feedback-sentiment-analysis/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | "libraries": [{ 5 | "userSymbol": "OAuth2", 6 | "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", 7 | "version": "24" 8 | }] 9 | }, 10 | "exceptionLogging": "STACKDRIVER", 11 | "runtimeVersion": "V8" 12 | } -------------------------------------------------------------------------------- /solutions/automations/folder-creation/Code.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Google LLC 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | https://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | /* 15 | This function will create a new folder in the defined Shard Drive. 16 | You define the Shared Drive by adding its ID on line number 26. 17 | The parameter 'project' is passed in from the AppSheet app. 18 | Please watch this video tutorial to see how to use this script: https://youtu.be/Utl57R7I2Cs 19 | */ 20 | 21 | function createNewFolder(project) { 22 | const folder = Drive.Files.insert( 23 | { 24 | parents: [{ id: 'ADD YOUR SHARED DRIVE FOLDER ID HERE' }], 25 | title: project, 26 | mimeType: "application/vnd.google-apps.folder", 27 | }, 28 | null, 29 | { supportsAllDrives: true } 30 | ); 31 | 32 | return folder.alternateLink; 33 | } 34 | -------------------------------------------------------------------------------- /solutions/automations/folder-creation/README.md: -------------------------------------------------------------------------------- 1 | # Folder creation 2 | 3 | This code sample is part of a video tutorial on how to combine AppSheet and Apps Script. 4 | 5 | You can watch the video tutorial to find out how to use the sample. 6 | 7 |

8 | 9 |

10 | 11 | See the [Google Apps Script Documentation](https://developers.google.com/apps-script/advanced/drive) for additional information about the advanced Google Drive services. 12 | -------------------------------------------------------------------------------- /solutions/automations/folder-creation/appscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "Europe/Madrid", 3 | "dependencies": { 4 | "enabledAdvancedServices": [ 5 | { 6 | "userSymbol": "Drive", 7 | "version": "v2", 8 | "serviceId": "drive" 9 | } 10 | ] 11 | }, 12 | "exceptionLogging": "STACKDRIVER", 13 | "runtimeVersion": "V8" 14 | } -------------------------------------------------------------------------------- /solutions/automations/generate-pdfs/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1k9PjGdQ_G0HKEoS3np_Szfe-flmLw9gUvblQIxOfvTmS-NLeLgVUzvOa"} 2 | -------------------------------------------------------------------------------- /solutions/automations/generate-pdfs/Menu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * @OnlyCurrentDoc 19 | * 20 | * The above comment specifies that this automation will only 21 | * attempt to read or modify the spreadsheet this script is bound to. 22 | * The authorization request message presented to users reflects the 23 | * limited scope. 24 | */ 25 | 26 | /** 27 | * Creates a custom menu in the Google Sheets UI when the document is opened. 28 | * 29 | * @param {object} e The event parameter for a simple onOpen trigger. 30 | */ 31 | function onOpen(e) { 32 | 33 | const menu = SpreadsheetApp.getUi().createMenu(APP_TITLE) 34 | menu 35 | .addItem('Process invoices', 'processDocuments') 36 | .addItem('Send emails', 'sendEmails') 37 | .addSeparator() 38 | .addItem('Reset template', 'clearTemplateSheet') 39 | .addToUi(); 40 | } -------------------------------------------------------------------------------- /solutions/automations/generate-pdfs/README.md: -------------------------------------------------------------------------------- 1 | # Generate and send PDFs from Google Sheets 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/generate-pdfs) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/generate-pdfs/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/import-csv-sheets/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1ANsCqbcTeepCzPpAKRUSxavm-2bTtKhp6I-G530ddH315H-59LGofc6m"} 2 | -------------------------------------------------------------------------------- /solutions/automations/import-csv-sheets/README.md: -------------------------------------------------------------------------------- 1 | # Import CSV data to a spreadsheet 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/import-csv-sheets) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/import-csv-sheets/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/mail-merge/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1evL25lW9fLN43j6gGBJWtLq4GncLkdgoxxSVCawc8dWNoLoravNebAih"} 2 | -------------------------------------------------------------------------------- /solutions/automations/mail-merge/README.md: -------------------------------------------------------------------------------- 1 | # Create a mail merge with Gmail & Google Sheets 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/mail-merge) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/mail-merge/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/news-sentiment/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"1KHPvTOwE2pd2myZmvX0mbsp8SPlhJBFotNCwflZiP01xmTasNfibG4zl"} -------------------------------------------------------------------------------- /solutions/automations/news-sentiment/README.md: -------------------------------------------------------------------------------- 1 | # Connect to an external API: Analyze news headlines 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/news-sentiment) for additional details. -------------------------------------------------------------------------------- /solutions/automations/news-sentiment/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/offsite-activity-signup/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "10clpAH4ojSXvTlZaE74rhJ6dDwwkfvi24L_AilGROca5Nds2Jy2oZmvY"} 2 | -------------------------------------------------------------------------------- /solutions/automations/offsite-activity-signup/README.md: -------------------------------------------------------------------------------- 1 | # Create a sign-up for an offsite 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/offsite-activity-signup) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/offsite-activity-signup/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/tax-loss-harvest-alerts/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"1SVf_XAGJiwksNTMnAwtlIvkKaDou4RLsmwGTa9ipVHKgwITgwXWqMixB"} -------------------------------------------------------------------------------- /solutions/automations/tax-loss-harvest-alerts/README.md: -------------------------------------------------------------------------------- 1 | # Get stock price drop alerts 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/tax-loss-harvest-alerts) for additional details. -------------------------------------------------------------------------------- /solutions/automations/tax-loss-harvest-alerts/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/timesheets/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1uzOldn2RjqdrbDJwxuPlcsb7twKLdW59YPS02rbEg_ajAG9XzrYF1-fH"} 2 | -------------------------------------------------------------------------------- /solutions/automations/timesheets/README.md: -------------------------------------------------------------------------------- 1 | # Collect and review timesheets from employees 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/timesheets) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/timesheets/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/upload-files/README.md: -------------------------------------------------------------------------------- 1 | # Upload files to Google Drive from Google Forms 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/upload-files) for additional details. 4 | -------------------------------------------------------------------------------- /solutions/automations/upload-files/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/vacation-calendar/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"1jvPSSwJcuLzlDLDy2dr-qorjihiTNAW2H6B5k-dJxHjEPX6hMcNghzSh"} 2 | -------------------------------------------------------------------------------- /solutions/automations/vacation-calendar/README.md: -------------------------------------------------------------------------------- 1 | # Populate a team vacation calendar 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/vacation-calendar) for additional details. -------------------------------------------------------------------------------- /solutions/automations/vacation-calendar/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/youtube-tracker/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"15WP4FukVYk_4zy21j0_13GftPH7J8lpdtemYcy_168TYKsAQ4x-pAeQz"} -------------------------------------------------------------------------------- /solutions/automations/youtube-tracker/README.md: -------------------------------------------------------------------------------- 1 | # Track YouTube video views and comments 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/automations/youtube-tracker) for additional details. -------------------------------------------------------------------------------- /solutions/automations/youtube-tracker/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/automations/youtube-tracker/email.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | Hello,

You have new comments and/or replies on videos:

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Video TitleLinkNumber of new replies and comments
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /solutions/custom-functions/calculate-driving-distance/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1_cfhZv-VJBekzu1V4mFD1C5ggRaUumWw9rUz0NaLED6XD4_yHB-eJ01a"} 2 | -------------------------------------------------------------------------------- /solutions/custom-functions/calculate-driving-distance/README.md: -------------------------------------------------------------------------------- 1 | # Calculate driving distance & convert meters to miles 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/custom-functions/calculate-driving-distance) for additional details. 4 | 5 | -------------------------------------------------------------------------------- /solutions/custom-functions/calculate-driving-distance/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/custom-functions/summarize-sheets-data/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1NN-ROSZO3ZsfiVUlCdmNqggpCQuGNtgO_r0nehV0s5mkZJN2bcMTri-7"} 2 | -------------------------------------------------------------------------------- /solutions/custom-functions/summarize-sheets-data/README.md: -------------------------------------------------------------------------------- 1 | # Summarize data from multiple sheets 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/custom-functions/summarize-sheets-data) for additional details. 4 | 5 | -------------------------------------------------------------------------------- /solutions/custom-functions/summarize-sheets-data/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/custom-functions/tier-pricing/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1-ql7ECe91XZgWu-hW_UZBx8mhuTtQQj0yNITYh8yQCOuHxLEjxtTngGB"} 2 | -------------------------------------------------------------------------------- /solutions/custom-functions/tier-pricing/README.md: -------------------------------------------------------------------------------- 1 | # Calculate a tiered pricing discount 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/custom-functions/tier-pricing) for additional details. 4 | 5 | -------------------------------------------------------------------------------- /solutions/custom-functions/tier-pricing/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/editor-add-on/clean-sheet/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "10bxhn6eGypm20dgRcTbUCbzP4Bz0dyYR6IZTNEA2gIXXxwoy8Zqs06yr"} 2 | -------------------------------------------------------------------------------- /solutions/editor-add-on/clean-sheet/README.md: -------------------------------------------------------------------------------- 1 | # Clean up data in a spreadsheet 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/add-ons/clean-sheet) for additional details. 4 | 5 | -------------------------------------------------------------------------------- /solutions/editor-add-on/clean-sheet/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER", 6 | "runtimeVersion": "V8" 7 | } -------------------------------------------------------------------------------- /solutions/ooo-assistant/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "16L_UmGrkrDKYWrfw9YlnUnnnWOMBEWywyPrZDZIQqKF17Q97RtZeinqn"} 2 | -------------------------------------------------------------------------------- /solutions/ooo-assistant/README.md: -------------------------------------------------------------------------------- 1 | # Build a Google Workspace add-on extending all UIs 2 | 3 | **Warning:** This sample builds a Chat app as a Google Workspace add-on. It's only available in the [Developer Preview Program](https://developers.google.com/workspace/preview). 4 | 5 | The add-on extends the following Google Workspace UIs: Chat, Calendar, Gmail, Drive, Docs, Sheets, and Slides. 6 | 7 | It relies on app commands in Chat, and homepage and universal actions in the others. 8 | -------------------------------------------------------------------------------- /solutions/ooo-assistant/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "dependencies": { 6 | "enabledAdvancedServices": [{ 7 | "userSymbol": "Gmail", 8 | "version": "v1", 9 | "serviceId": "gmail" 10 | }, 11 | { 12 | "userSymbol": "Calendar", 13 | "version": "v3", 14 | "serviceId": "calendar" 15 | }] 16 | }, 17 | "addOns": { 18 | "common": { 19 | "name": "OOO Assistant", 20 | "logoUrl": "https://goo.gle/3SfMkjb", 21 | "homepageTrigger": { 22 | "runFunction": "onHomepage" 23 | }, 24 | "universalActions": [{ 25 | "label": "Block day out", 26 | "runFunction": "blockDayOut" 27 | }, { 28 | "label": "Set auto reply", 29 | "runFunction": "setAutoReply" 30 | }] 31 | }, 32 | "chat": {}, 33 | "calendar": {}, 34 | "gmail": {}, 35 | "drive": {}, 36 | "docs": {}, 37 | "sheets": {}, 38 | "slides": {} 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /solutions/ooo-chat-app/README.md: -------------------------------------------------------------------------------- 1 | # OOO Chat App 2 | 3 | Sample code for a custom Google Chat app that manages your out of office tasks. 4 | 5 | Learn more about [Chat apps](https://developers.google.com/chat). 6 | -------------------------------------------------------------------------------- /solutions/ooo-chat-app/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "Europe/Madrid", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "dependencies": { 6 | "enabledAdvancedServices": [ 7 | { 8 | "userSymbol": "Gmail", 9 | "version": "v1", 10 | "serviceId": "gmail" 11 | }, 12 | { 13 | "userSymbol": "Calendar", 14 | "version": "v3", 15 | "serviceId": "calendar" 16 | } 17 | ] 18 | }, 19 | "chat": {} 20 | } -------------------------------------------------------------------------------- /solutions/schedule-meetings/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId": "1NdhQ_nXfEUUhWcWKiY6WJjeunY70a1W9vnFdS7BCLPMFreSaHaOS3ucM"} 2 | -------------------------------------------------------------------------------- /solutions/schedule-meetings/README.md: -------------------------------------------------------------------------------- 1 | # Schedule meetings from Google Chat 2 | 3 | See [developers.google.com](https://developers.google.com/apps-script/samples/chat-apps/schedule-meetings) for additional details. 4 | 5 | -------------------------------------------------------------------------------- /solutions/schedule-meetings/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "exceptionLogging": "STACKDRIVER", 4 | "runtimeVersion": "V8", 5 | "chat": { 6 | "addToSpaceFallbackMessage": "Thank you for adding this Chat App!" 7 | } 8 | } -------------------------------------------------------------------------------- /tasks/quickstart/quickstart.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // [START tasks_quickstart] 17 | /** 18 | * Lists the user's tasks. 19 | * @see https://developers.google.com/tasks/reference/rest/v1/tasklists/list 20 | */ 21 | function listTaskLists() { 22 | const optionalArgs = { 23 | maxResults: 10 24 | }; 25 | try { 26 | // Returns all the authenticated user's task lists. 27 | const response = Tasks.Tasklists.list(optionalArgs); 28 | const taskLists = response.items; 29 | // Print task list of user if available. 30 | if (!taskLists || taskLists.length === 0) { 31 | console.log('No task lists found.'); 32 | return; 33 | } 34 | for (const taskList of taskLists) { 35 | console.log('%s (%s)', taskList.title, taskList.id); 36 | } 37 | } catch (err) { 38 | // TODO (developer) - Handle exception from Task API 39 | console.log('Failed with error %s', err.message); 40 | } 41 | } 42 | // [END tasks_quickstart] 43 | -------------------------------------------------------------------------------- /tasks/simpleTasks/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Los_Angeles", 3 | "dependencies": { 4 | "enabledAdvancedServices": [{ 5 | "userSymbol": "Tasks", 6 | "serviceId": "tasks", 7 | "version": "v1" 8 | }] 9 | }, 10 | "exceptionLogging": "STACKDRIVER" 11 | } 12 | -------------------------------------------------------------------------------- /tasks/simpleTasks/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googleworkspace/apps-script-samples/9d4f74231bd86a6c0f12adf81ad7f0352ee11361/tasks/simpleTasks/screenshot.png -------------------------------------------------------------------------------- /tasks/simpleTasks/stylesheet.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 39 | -------------------------------------------------------------------------------- /templates/custom-functions/README.md: -------------------------------------------------------------------------------- 1 | Template: Custom Functions for Sheets 2 | ===================================== 3 | 4 | This template provides a framework for creating custom functions 5 | in Google Sheets. It shows the structure needed to define a 6 | custom function and its autocomplete documentation, and provides 7 | a few examples. 8 | 9 | The examples provided here demonstrate: 10 | 11 | * How to create custom functions that accept arguments of different types 12 | * How to document a custom function to generate correct autocomplete 13 | information in Sheets 14 | 15 | Note that this template must be added to a container-bound script 16 | attached to a Google Sheet in order to function. 17 | 18 | 19 | For more information, see [Custom Functions in Google Sheets](https://developers.google.com/apps-script/guides/sheets/functions). 20 | 21 | In addition, developers of Sheets custom functions should be aware of 22 | the [known issues specific to Google Sheets](https://developers.google.com/apps-script/migration/sheets). 23 | 24 | -------------------------------------------------------------------------------- /templates/docs-addon/README.md: -------------------------------------------------------------------------------- 1 | Template: Google Docs Add-on 2 | ============================ 3 | 4 | This template provides a framework for creating a 5 | [Google Docs add-on](https://developers.google.com/apps-script/add-ons/). 6 | It shows the structure needed to define a UI (including 7 | menus, a sidebar and dialog) and how to coordinate communication 8 | between the UI client and the server where the Doc resides. This 9 | template also covers some basic uses of Apps Script with Google 10 | Docs, including: 11 | 12 | * Reading and writing text to and from a Google Doc 13 | * Getting and modifying basic file information, such as the file title 14 | 15 | Note that add-ons that work with Google Docs will usually need to read 16 | and manipulate the (sometimes complex) 17 | [Doc structure](https://developers.google.com/apps-script/guides/docs#structure_of_a_document). 18 | 19 | Finally, note that this template must be added to a container-bound 20 | script attached to a Google Doc in order to function. Developed 21 | add-ons must go through a 22 | [publishing process](https://developers.google.com/apps-script/add-ons/publish) 23 | before they can be made available publicly. 24 | -------------------------------------------------------------------------------- /templates/forms-addon/README.md: -------------------------------------------------------------------------------- 1 | Template: Google Forms Add-on 2 | ============================= 3 | 4 | This template provides a framework for creating a 5 | [Google Forms add-on](https://developers.google.com/apps-script/add-ons/). 6 | It shows the structure needed to define a UI (including 7 | menus, a sidebar and dialog) and how to coordinate communication 8 | between the UI client and the server where the Form resides. This 9 | template also covers some basic uses of Apps Script with Google 10 | Forms, including: 11 | 12 | * Creating new form items programmatically 13 | * Setting, removing and responding to form submit triggers 14 | 15 | Note that this template must be added to a container-bound script 16 | attached to a Google Form in order to function. Also note that 17 | developed add-ons must go through a 18 | [publishing process](https://developers.google.com/apps-script/add-ons/publish) 19 | before they can be made available publicly. 20 | -------------------------------------------------------------------------------- /templates/forms-addon/Stylesheet.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 58 | -------------------------------------------------------------------------------- /templates/sheets-addon/README.md: -------------------------------------------------------------------------------- 1 | Template: Google Sheets Add-on 2 | ============================== 3 | 4 | This template provides a framework for creating a 5 | [Google Sheets add-on](https://developers.google.com/apps-script/add-ons/). 6 | It shows the structure needed to define a UI (including menus, a sidebar and 7 | dialog) and how to coordinate communication between the UI client and the server 8 | where the Sheet resides. This template also covers some basic uses of Apps 9 | Script with Google Sheets, including: 10 | 11 | * Reading and writing data to a Sheet 12 | * Creating, copying and clearing a sheet 13 | 14 | Note that add-ons that work with Google Sheets will usually need to 15 | read and manipulate the Sheet data, formatting, validation, etc. For 16 | more information, see 17 | [Extending Google Sheets](https://developers.google.com/apps-script/guides/sheets). 18 | 19 | In addition, developers of Sheets add-ons should be aware of the 20 | [Known Issues specific to Google Sheets](https://developers.google.com/apps-script/migration/sheets). 21 | 22 | Finally, note that this template must be added to a container-bound 23 | script attached to a Google Sheet in order to function. Developed 24 | add-ons must go through a 25 | [publishing process](https://developers.google.com/apps-script/add-ons/publish) 26 | before they can be made available publicly. 27 | 28 | -------------------------------------------------------------------------------- /templates/sheets-addon/Stylesheet.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 60 | -------------------------------------------------------------------------------- /templates/sheets-import/AuthorizationEmail.html: -------------------------------------------------------------------------------- 1 | 16 | 17 |

The Google Sheets add-on was recently updated 18 | and it needs you to re-authorize.

19 | 20 |

The add-on's automatic report updates are temporarily disabled until you 21 | re-authorize. You can accomplish this by opening one of the sheets 22 | using the add-on and running the add-on through the menu. Alternatively, you can 23 | click this link to approve authorization directly:

24 | 25 |

Click here to re-authorize the add-on.

26 | 27 |

This notification email will be sent to you at most once per day until the 28 | add-on is re-authorized.

29 | 30 |
31 | 32 |

This automatic message was sent to you via 33 | the add-on for Google Sheets. 34 |

35 | -------------------------------------------------------------------------------- /templates/sheets-import/Stylesheet.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 66 | -------------------------------------------------------------------------------- /templates/web-app/README.md: -------------------------------------------------------------------------------- 1 | Template: Script as Web App 2 | =========================== 3 | 4 | This template provides a framework for creating a [web app](https://developers.google.com/apps-script/guides/web). 5 | 6 | It shows the basic structure needed to define a UI and how to coordinate 7 | communication between the client and server. This template also includes some 8 | useful aspects of Apps Script, including: 9 | 10 | * Using [Templated HTML](https://developers.google.com/apps-script/guides/html/templates) 11 | * Responding to HTTP GET requests with doGet(e) 12 | * Using IFRAME sandbox mode 13 | -------------------------------------------------------------------------------- /templates/web-app/Stylesheet.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 35 | -------------------------------------------------------------------------------- /triggers/form/AuthorizationEmail.html: -------------------------------------------------------------------------------- 1 | 13 | 14 |

The Google Sheets add-on is set to run automatically 15 | whenever a form is submitted. The add-on was recently updated and it needs you 16 | to re-authorize it to run on your behalf.

17 | 18 |

The add-on's automatic functions are temporarily disabled until you 19 | re-authorize it. To do so, open Google Sheets and run the add-on from the 20 | Add-ons menu. Alternatively, you can click this link to authorize it:

21 | 22 |

Re-authorize the add-on.

23 | 24 |

This notification email will be sent to you at most once per day until the 25 | add-on is re-authorized.

26 | 27 | -------------------------------------------------------------------------------- /triggers/test_triggers.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Tests createTimeDrivenTrigger function of trigger.gs 19 | */ 20 | function itShouldCreateTimeDrivenTriggers() { 21 | console.log('> itShouldCreateTimeDrivenTriggers'); 22 | createTimeDrivenTriggers(); 23 | } 24 | 25 | /** 26 | * Tests createSpreadsheetOpenTrigger function of triggers.gs 27 | */ 28 | function itShouldCreateSpreadsheetOpenTrigger() { 29 | console.log('> itShouldCreateSpreadsheetOpenTrigger'); 30 | createSpreadsheetOpenTrigger(); 31 | } 32 | 33 | /** 34 | * Tests deleteTrigger function of triggers.gs 35 | */ 36 | function itShouldDeleteTrigger() { 37 | console.log('> itShouldDeleteTrigger'); 38 | deleteTrigger(); 39 | } 40 | 41 | /** 42 | * Run all the tests for triggers.gs 43 | */ 44 | function RUN_ALL_TESTS() { 45 | itShouldCreateSpreadsheetOpenTrigger(); 46 | itShouldCreateTimeDrivenTriggers(); 47 | itShouldDeleteTrigger(); 48 | } 49 | -------------------------------------------------------------------------------- /ui/communication/basic/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } 4 | 5 | function doSomething() { 6 | console.log('I was called!'); 7 | } 8 | -------------------------------------------------------------------------------- /ui/communication/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | -------------------------------------------------------------------------------- /ui/communication/failure/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } 4 | 5 | function getUnreadEmails() { 6 | // 'got' instead of 'get' will throw an error. 7 | return GmailApp.gotInboxUnreadCount(); 8 | } -------------------------------------------------------------------------------- /ui/communication/failure/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 30 | 31 | 32 |
33 | 34 | -------------------------------------------------------------------------------- /ui/communication/private/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } 4 | 5 | function getBankBalance() { 6 | var email = Session.getActiveUser().getEmail() 7 | return deepSecret_(email); 8 | } 9 | 10 | function deepSecret_(email) { 11 | // Do some secret calculations 12 | return email + ' has $1,000,000 in the bank.'; 13 | } -------------------------------------------------------------------------------- /ui/communication/private/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 30 | 31 | 32 |
No result yet...
33 | 34 | -------------------------------------------------------------------------------- /ui/communication/runner.gs: -------------------------------------------------------------------------------- 1 | var myRunner = google.script.run.withFailureHandler(onFailure); 2 | var myRunner1 = myRunner.withSuccessHandler(onSuccess); 3 | var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess); 4 | 5 | myRunner1.doSomething(); 6 | myRunner1.doSomethingElse(); 7 | myRunner2.doSomething(); 8 | -------------------------------------------------------------------------------- /ui/communication/success/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } 4 | 5 | function getUnreadEmails() { 6 | return GmailApp.getInboxUnreadCount(); 7 | } -------------------------------------------------------------------------------- /ui/communication/success/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 31 | 32 | 33 |
34 | 35 | -------------------------------------------------------------------------------- /ui/dialogs/page.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | Hello, world! 15 | -------------------------------------------------------------------------------- /ui/forms/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } 4 | 5 | function processForm(formObject) { 6 | var formBlob = formObject.myFile; 7 | var driveFile = DriveApp.createFile(formBlob); 8 | return driveFile.getUrl(); 9 | } -------------------------------------------------------------------------------- /ui/html/printing_scriptlet.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ui/html/scriptlet.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Hello, World! The time is . 24 | 25 | -------------------------------------------------------------------------------- /ui/html/standard_scriptlet.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |

This will always be served!

25 | 26 |

This will never be served.

27 | 28 | 29 | -------------------------------------------------------------------------------- /ui/sidebar/code.gs: -------------------------------------------------------------------------------- 1 | // Use this code for Google Docs, Slides, Forms, or Sheets. 2 | function onOpen() { 3 | SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp. 4 | .createMenu('Dialog') 5 | .addItem('Open', 'openDialog') 6 | .addToUi(); 7 | } 8 | 9 | function openDialog() { 10 | var html = HtmlService.createHtmlOutputFromFile('Index'); 11 | SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp. 12 | .showModalDialog(html, 'Dialog title'); 13 | } -------------------------------------------------------------------------------- /ui/sidebar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Hello, World! 24 | 26 | 27 | -------------------------------------------------------------------------------- /ui/user/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } 4 | 5 | function getEmail() { 6 | return Session.getActiveUser().getEmail(); 7 | } -------------------------------------------------------------------------------- /ui/user/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 33 | 38 | 39 | -------------------------------------------------------------------------------- /ui/webapp/code.gs: -------------------------------------------------------------------------------- 1 | function doGet() { 2 | return HtmlService.createHtmlOutputFromFile('Index'); 3 | } -------------------------------------------------------------------------------- /ui/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Hello, World! 24 | 25 | -------------------------------------------------------------------------------- /wasm/README.md: -------------------------------------------------------------------------------- 1 | # Unleashing the power of Rust, Python, and WebAssembly in Apps Script 2 | 3 | This folder is the companion to the talk "Unleashing the power of Rust, Python, and WebAssembly in Apps Script" at Google Cloud Next '24. 4 | 5 | ## Development 6 | 7 | The development of this proof of concept requires a deep understanding of the Apps Script runtime, JavaScript bundlers, the Rust programming language, and the WebAssembly ecosystem. Please note that this is a quickly evolving space, and the tools and techniques used in this project may become outdated quickly. 8 | 9 | ### Prerequisites 10 | 11 | - Node.js - https://nodejs.org/en/download 12 | - Rust - https://www.rust-lang.org/tools/install 13 | - Binaryen (for wasm-opt) - https://github.com/WebAssembly/binaryen 14 | 15 | -------------------------------------------------------------------------------- /wasm/hello-world/.clasp.json: -------------------------------------------------------------------------------- 1 | { 2 | "scriptId": "1xt1CvoUyFAzfoCdkwCHXBXzu3oaNz2a6iNsPW2GA6rOAsyBv66r4TarA", 3 | "rootDir": "./dist" 4 | } 5 | -------------------------------------------------------------------------------- /wasm/hello-world/.gitattributes: -------------------------------------------------------------------------------- 1 | package-lock.json merge=binary -diff 2 | Cargo.lock merge=binary -diff 3 | -------------------------------------------------------------------------------- /wasm/hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /node_modules 3 | /dist 4 | /src/pkg 5 | .wireit -------------------------------------------------------------------------------- /wasm/hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | rust-version = "1.57" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | wasm-bindgen = { version = "0.2.91", features = [] } 12 | 13 | [dev-dependencies] 14 | wasm-bindgen-cli = "0.2.91" 15 | 16 | [profile.release] 17 | opt-level = 's' 18 | -------------------------------------------------------------------------------- /wasm/hello-world/README.md: -------------------------------------------------------------------------------- 1 | # Unleashing the power of Rust, Python, and WebAssembly in Apps Script 2 | 3 | This folder is the companion to the talk "Unleashing the power of Rust, Python, and WebAssembly in Apps Script" at Google Cloud Next '24. 4 | 5 | ## Development 6 | 7 | The development of this proof of concept requires a deep understanding of the Apps Script runtime, JavaScript bundlers, the Rust programming language, and the WebAssembly ecosystem. Please note that this is a quickly evolving space, and the tools and techniques used in this project may become outdated quickly. 8 | 9 | ### Prerequisites 10 | 11 | - Node.js - https://nodejs.org/en/download 12 | - Rust - https://www.rust-lang.org/tools/install 13 | - Binaryen (for wasm-opt) - https://github.com/WebAssembly/binaryen 14 | 15 | ### Build 16 | 17 | 1. `npm i` 18 | 1. `npm run build` 19 | -------------------------------------------------------------------------------- /wasm/hello-world/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "formatter": { 4 | "indentStyle": "space" 5 | }, 6 | "files": { 7 | "ignore": ["node_modules", "dist", "target", "pkg"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /wasm/hello-world/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import fs from "fs"; 18 | import esbuild from "esbuild"; 19 | import { wasmLoader } from "esbuild-plugin-wasm"; 20 | import path from "path"; 21 | 22 | const outdir = "dist"; 23 | const sourceRoot = "src"; 24 | 25 | await esbuild.build({ 26 | entryPoints: ["./src/wasm.js"], 27 | bundle: true, 28 | outdir, 29 | sourceRoot, 30 | platform: "neutral", 31 | format: "esm", 32 | plugins: [wasmLoader({ mode: "embedded" })], 33 | inject: ["polyfill.js"], 34 | minify: true, 35 | banner: { js: "// Generated code DO NOT EDIT\n" }, 36 | }); 37 | 38 | const passThroughFiles = [ 39 | "main.js", 40 | "test.js", 41 | "appsscript.json", 42 | ]; 43 | 44 | await Promise.all( 45 | passThroughFiles.map(async (file) => 46 | fs.promises.copyFile( 47 | path.join(sourceRoot, file), 48 | path.join(outdir, file) 49 | ) 50 | ) 51 | ); 52 | -------------------------------------------------------------------------------- /wasm/hello-world/polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export { 18 | TextEncoder, 19 | TextDecoder, 20 | } from "fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js"; 21 | -------------------------------------------------------------------------------- /wasm/hello-world/src/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Denver", 3 | "dependencies": {}, 4 | "exceptionLogging": "STACKDRIVER", 5 | "runtimeVersion": "V8" 6 | } 7 | -------------------------------------------------------------------------------- /wasm/hello-world/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use wasm_bindgen::prelude::*; 16 | 17 | #[wasm_bindgen] 18 | pub fn hello(name: &str) -> JsValue { 19 | format!("Hello, {} from Rust!", name).into() 20 | } 21 | -------------------------------------------------------------------------------- /wasm/hello-world/src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | async function main() { 18 | const name = "world"; 19 | console.log(await hello_(name)); 20 | } 21 | -------------------------------------------------------------------------------- /wasm/hello-world/src/wasm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Wrapper function for hello 19 | * @param {string} name 20 | * @returns 21 | */ 22 | async function hello_(name) { 23 | const wasm = await import("./pkg/example_bg.wasm"); 24 | const { __wbg_set_wasm, hello } = await import("./pkg/example_bg.js"); 25 | 26 | __wbg_set_wasm(wasm); 27 | 28 | return hello(name); 29 | } 30 | 31 | globalThis.hello_ = hello_; 32 | -------------------------------------------------------------------------------- /wasm/image-add-on/.clasp.json: -------------------------------------------------------------------------------- 1 | { 2 | "scriptId": "1gP1tiV1KkhVbMADIA_M-d4IJP1GNXwU7-7MundfqlESmSAdo0sC_Nml4", 3 | "rootDir": "./dist" 4 | } 5 | -------------------------------------------------------------------------------- /wasm/image-add-on/.gitattributes: -------------------------------------------------------------------------------- 1 | package-lock.json merge=binary -diff 2 | Cargo.lock merge=binary -diff 3 | -------------------------------------------------------------------------------- /wasm/image-add-on/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /node_modules 3 | /dist 4 | /src/pkg 5 | .wireit -------------------------------------------------------------------------------- /wasm/image-add-on/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | rust-version = "1.57" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | base64 = "0.22.0" 12 | console_error_panic_hook = "0.1.7" 13 | image = {version = "0.24.9", features = ["jpeg"]} 14 | js-sys = "0.3.69" 15 | wasm-bindgen = { version = "0.2.91", features = [] } 16 | 17 | [dev-dependencies] 18 | wasm-bindgen-cli = "0.2.91" 19 | 20 | [profile.release] 21 | opt-level = 's' 22 | -------------------------------------------------------------------------------- /wasm/image-add-on/README.md: -------------------------------------------------------------------------------- 1 | # Unleashing the power of Rust, Python, and WebAssembly in Apps Script 2 | 3 | This folder is the companion to the talk "Unleashing the power of Rust, Python, and WebAssembly in Apps Script" at Google Cloud Next '24. 4 | 5 | ## Development 6 | 7 | The development of this proof of concept requires a deep understanding of the Apps Script runtime, JavaScript bundlers, the Rust programming language, and the WebAssembly ecosystem. Please note that this is a quickly evolving space, and the tools and techniques used in this project may become outdated quickly. 8 | 9 | ### Prerequisites 10 | 11 | - Node.js - https://nodejs.org/en/download 12 | - Rust - https://www.rust-lang.org/tools/install 13 | - Binaryen (for wasm-opt) - https://github.com/WebAssembly/binaryen 14 | 15 | ### Build 16 | 17 | 1. `npm i` 18 | 1. `npm run build` 19 | -------------------------------------------------------------------------------- /wasm/image-add-on/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "formatter": { 4 | "indentStyle": "space" 5 | }, 6 | "files": { 7 | "ignore": ["node_modules", "dist", "target", "pkg"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /wasm/image-add-on/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import fs from "fs"; 18 | import path from "path"; 19 | import esbuild from "esbuild"; 20 | import { wasmLoader } from "esbuild-plugin-wasm"; 21 | 22 | const outdir = "dist"; 23 | const sourceRoot = "src"; 24 | 25 | await esbuild.build({ 26 | entryPoints: ["./src/wasm.js"], 27 | bundle: true, 28 | outdir, 29 | sourceRoot, 30 | platform: "neutral", 31 | format: "esm", 32 | plugins: [wasmLoader({ mode: "embedded" })], 33 | inject: ["polyfill.js"], 34 | minify: true, 35 | banner: { js: "// Generated code DO NOT EDIT\n" }, 36 | }); 37 | 38 | const passThroughFiles = ["main.js", "test.js", "appsscript.json", "add-on.js"]; 39 | 40 | await Promise.all( 41 | passThroughFiles.map(async (file) => 42 | fs.promises.copyFile(path.join(sourceRoot, file), path.join(outdir, file)), 43 | ), 44 | ); 45 | -------------------------------------------------------------------------------- /wasm/image-add-on/polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export { 18 | TextEncoder, 19 | TextDecoder, 20 | } from "fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js"; 21 | -------------------------------------------------------------------------------- /wasm/image-add-on/src/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Denver", 3 | "dependencies": { 4 | "enabledAdvancedServices": [ 5 | { 6 | "userSymbol": "Drive", 7 | "version": "v3", 8 | "serviceId": "drive" 9 | } 10 | ] 11 | }, 12 | "exceptionLogging": "STACKDRIVER", 13 | "runtimeVersion": "V8", 14 | "addOns": { 15 | "common": { 16 | "logoUrl": "https://ssl.gstatic.com/docs/script/images/logo/script-64.png", 17 | "name": "Drive Image Compress Add-on", 18 | "universalActions": [] 19 | }, 20 | "drive": { 21 | "homepageTrigger": { 22 | "runFunction": "onHomePageTrigger", 23 | "enabled": true 24 | }, 25 | "onItemsSelectedTrigger": { 26 | "runFunction": "onItemsSelectedTrigger" 27 | } 28 | } 29 | }, 30 | "oauthScopes": [ 31 | "https://www.googleapis.com/auth/script.locale", 32 | "https://www.googleapis.com/auth/drive.addons.metadata.readonly", 33 | "https://www.googleapis.com/auth/drive" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /wasm/image-add-on/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use wasm_bindgen::prelude::*; 16 | 17 | #[wasm_bindgen] 18 | pub fn compress(data: &[u8], quality: u8, width: u32, height: u32) -> JsValue { 19 | console_error_panic_hook::set_once(); 20 | 21 | let img = match image::load_from_memory_with_format(data, image::ImageFormat::Jpeg) { 22 | Ok(img) => img, 23 | Err(_) => return JsValue::from_str("something went wrong"), 24 | }; 25 | 26 | let img = match width == 0 || height == 0 { 27 | true => img, 28 | false => img.resize(width, height, image::imageops::FilterType::Lanczos3), 29 | }; 30 | 31 | let mut data = Vec::new(); 32 | 33 | let _ = img.write_with_encoder(image::codecs::jpeg::JpegEncoder::new_with_quality( 34 | &mut data, quality, 35 | )); 36 | 37 | js_sys::Uint8Array::from(&data[..]).into() 38 | } 39 | -------------------------------------------------------------------------------- /wasm/image-add-on/src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const QUALITY = 80; 18 | 19 | async function main() { 20 | const iterator = DriveApp.getFilesByType("image/jpeg"); 21 | 22 | while (iterator.hasNext()) { 23 | const file = iterator.next(); 24 | const bytes = file.getBlob().getBytes(); 25 | 26 | const dataUrl = await compress_(bytes, QUALITY); 27 | 28 | if (dataUrl) { 29 | console.log(dataUrl); 30 | } else { 31 | console.warn("failed to decode image"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /wasm/image-add-on/src/wasm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | async function compress_(bytes, { quality, format, width, height }) { 18 | const wasm = await import("./pkg/example_bg.wasm"); 19 | const { __wbg_set_wasm, compress } = await import("./pkg/example_bg.js"); 20 | 21 | __wbg_set_wasm(wasm); 22 | 23 | width = width || 0; 24 | height = height || 0; 25 | 26 | console.log({ quality, format, width, height }); 27 | 28 | const result = compress(bytes, quality, format, width, height); 29 | 30 | if (typeof result === "string") { 31 | throw new Error(result); 32 | } 33 | 34 | return result; 35 | } 36 | 37 | globalThis.compress_ = compress_; 38 | -------------------------------------------------------------------------------- /wasm/python/.clasp.json: -------------------------------------------------------------------------------- 1 | { 2 | "scriptId": "1_tU8IFkT1ZZ-b08YFeC8umntrH92WVQ27jvUmsCo1W4ZqKKqcytBLdcn", 3 | "rootDir": "./dist" 4 | } 5 | -------------------------------------------------------------------------------- /wasm/python/.gitattributes: -------------------------------------------------------------------------------- 1 | package-lock.json merge=binary -diff 2 | Cargo.lock merge=binary -diff 3 | -------------------------------------------------------------------------------- /wasm/python/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /node_modules 3 | /dist 4 | /src/pkg 5 | .wireit -------------------------------------------------------------------------------- /wasm/python/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | rust-version = "1.57" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | console_error_panic_hook = "0.1.7" 12 | getrandom = { version = "0.2", features = ["js"] } 13 | rustpython-vm = { version = "0.3.0", features = ["compiler", "serde"] } 14 | serde-wasm-bindgen = "0.6.5" 15 | wasm-bindgen = { version = "0.2.91", features = [] } 16 | web-sys = { version = "0.3.69", features = ["console"] } 17 | 18 | [dev-dependencies] 19 | wasm-bindgen-cli = "0.2.91" 20 | 21 | [profile.release] 22 | opt-level = 's' 23 | -------------------------------------------------------------------------------- /wasm/python/README.md: -------------------------------------------------------------------------------- 1 | # Unleashing the power of Rust, Python, and WebAssembly in Apps Script 2 | 3 | This folder is the companion to the talk "Unleashing the power of Rust, Python, and WebAssembly in Apps Script" at Google Cloud Next '24. 4 | 5 | ## Development 6 | 7 | The development of this proof of concept requires a deep understanding of the Apps Script runtime, JavaScript bundlers, the Rust programming language, and the WebAssembly ecosystem. Please note that this is a quickly evolving space, and the tools and techniques used in this project may become outdated quickly. 8 | 9 | ### Prerequisites 10 | 11 | - Node.js - https://nodejs.org/en/download 12 | - Rust - https://www.rust-lang.org/tools/install 13 | - Binaryen (for wasm-opt) - https://github.com/WebAssembly/binaryen 14 | 15 | ### Build 16 | 17 | 1. `npm i` 18 | 1. `npm run build` 19 | -------------------------------------------------------------------------------- /wasm/python/biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "formatter": { 4 | "indentStyle": "space" 5 | }, 6 | "files": { 7 | "ignore": ["node_modules", "dist", "target", "pkg"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /wasm/python/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import fs from "fs"; 18 | import path from "path"; 19 | import esbuild from "esbuild"; 20 | import { wasmLoader } from "esbuild-plugin-wasm"; 21 | 22 | const outdir = "dist"; 23 | const sourceRoot = "src"; 24 | 25 | await esbuild.build({ 26 | entryPoints: ["./src/wasm.js"], 27 | bundle: true, 28 | outdir, 29 | sourceRoot, 30 | platform: "neutral", 31 | format: "esm", 32 | plugins: [wasmLoader({ mode: "embedded" })], 33 | inject: ["polyfill.js"], 34 | minify: true, 35 | banner: { js: "// Generated code DO NOT EDIT\n" }, 36 | }); 37 | 38 | const passThroughFiles = ["main.js", "test.js", "appsscript.json"]; 39 | 40 | await Promise.all( 41 | passThroughFiles.map(async (file) => 42 | fs.promises.copyFile(path.join(sourceRoot, file), path.join(outdir, file)), 43 | ), 44 | ); 45 | -------------------------------------------------------------------------------- /wasm/python/polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | export { 18 | TextEncoder, 19 | TextDecoder, 20 | } from "fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js"; 21 | -------------------------------------------------------------------------------- /wasm/python/src/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/Denver", 3 | "dependencies": { 4 | "enabledAdvancedServices": [ 5 | { 6 | "userSymbol": "Drive", 7 | "version": "v3", 8 | "serviceId": "drive" 9 | } 10 | ] 11 | }, 12 | "exceptionLogging": "STACKDRIVER", 13 | "runtimeVersion": "V8", 14 | "oauthScopes": [] 15 | } 16 | -------------------------------------------------------------------------------- /wasm/python/src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Execute Python code and return the result. 19 | * @param {string} code 20 | * @param {...*} args - Arguments to pass to the Python code. Accessible as 21 | * `args` in the Python code. 22 | * 23 | * @customfunction 24 | */ 25 | async function PYTHON(code = "args", ...args) { 26 | const result = await python_(`${code}`, ...args); 27 | 28 | if (result instanceof Error) { 29 | throw result; 30 | } 31 | 32 | return result; 33 | } 34 | -------------------------------------------------------------------------------- /wasm/python/src/test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | async function test() {} 18 | 19 | async function assert(a, b, message) { 20 | const aVal = await a; 21 | const bVal = await b; 22 | 23 | if (aVal !== bVal) { 24 | throw message ?? `'${aVal}' !== '${bVal}'`; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /wasm/python/src/wasm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2024 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | globalThis.crypto = { 18 | getRandomValues: (array) => array.map(() => Math.floor(Math.random() * 256)), 19 | }; 20 | 21 | /** 22 | * Wrapper function for hello 23 | * @param {string} name 24 | * @returns 25 | */ 26 | async function python_(source, ...args) { 27 | const wasm = await import("./pkg/example_bg.wasm"); 28 | const { __wbg_set_wasm, python } = await import("./pkg/example_bg.js"); 29 | 30 | __wbg_set_wasm(wasm); 31 | 32 | return await python(source, args); 33 | } 34 | 35 | globalThis.python_ = python_; 36 | --------------------------------------------------------------------------------