diff --git a/solutions/ooo-chat-app/Code.js b/solutions/ooo-chat-app/Code.js deleted file mode 100644 index 3aae1a695..000000000 --- a/solutions/ooo-chat-app/Code.js +++ /dev/null @@ -1,247 +0,0 @@ -/* -Copyright 2022 Google LLC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * Responds to an ADDED_TO_SPACE event in Chat. - * @param {object} event the event object from Chat - * @return {object} JSON-formatted response - * @see https://developers.google.com/hangouts/chat/reference/message-formats/events - */ -function onAddToSpace(event) { - let message = "Thank you for adding me to "; - if (event.space.type === "DM") { - message += `a DM, ${event.user.displayName}!`; - } else { - message += event.space.displayName; - } - return { text: message }; -} - -/** - * Responds to a REMOVED_FROM_SPACE event in Chat. - * @param {object} event the event object from Chat - * @param {object} event the event object from Chat - * @see https://developers.google.com/hangouts/chat/reference/message-formats/events - */ -function onRemoveFromSpace(event) { - console.log("App removed from ", event.space.name); -} - -/** - * Responds to a MESSAGE event triggered in Chat. - * @param {object} event the event object from Chat - * @return {function} call the respective function - */ -function onMessage(event) { - const message = event.message; - - if (message.slashCommand) { - switch (message.slashCommand.commandId) { - case 1: // Help command - return createHelpCard(); - case 2: // Block out day command - return blockDayOut(); - case 3: // Cancel all meetings command - return cancelAllMeetings(); - case 4: // Set auto reply command - return setAutoReply(); - } - } -} - -function createHelpCard() { - return { - cardsV2: [ - { - cardId: "2", - card: { - sections: [ - { - header: "", - widgets: [ - { - decoratedText: { - topLabel: "", - text: "Hi! 👋 I'm here to help you with your out of office tasks.

Here's a list of commands I understand.", - wrapText: true, - }, - }, - ], - }, - { - widgets: [ - { - decoratedText: { - topLabel: "", - text: "/blockDayOut: I will block out your calendar for you.", - wrapText: true, - }, - }, - { - decoratedText: { - topLabel: "", - text: "/cancelAllMeetings: I will cancel all your meetings for the day.", - wrapText: true, - }, - }, - { - decoratedText: { - topLabel: "", - text: "/setAutoReply: Set an out of office auto reply in Gmail.", - wrapText: true, - }, - }, - ], - }, - ], - header: { - title: "OOO app", - subtitle: "Helping you manage your OOO", - imageUrl: "https://goo.gle/3SfMkjb", - imageType: "SQUARE", - }, - }, - }, - ], - }; -} - -/** - * Adds an all day event to the users Google Calendar. - * @return {object} JSON-formatted response - */ -function blockDayOut() { - blockOutCalendar(); - return createResponseCard("Your calendar has been blocked out for you."); -} - -/** - * Cancels all of the users meeting for the current day. - * @return {object} JSON-formatted response - */ -function cancelAllMeetings() { - cancelMeetings(); - return createResponseCard("All your meetings have been canceled."); -} - -/** - * Sets an out of office auto reply in the users Gmail account. - * @return {object} JSON-formatted response - */ -function setAutoReply() { - turnOnAutoResponder(); - return createResponseCard("The out of office auto reply has been turned on."); -} - -/** - * Creates an out of office event in the user's Calendar. - */ -function blockOutCalendar() { - /** - * Helper function to get a the current date and set the time for the start and end of the event. - * @param {number} hour The hour of the day for the new date. - * @param {number} minutes The minutes of the day for the new date. - * @return {Date} The new date. - */ - function getDateAndHours(hour, minutes) { - const date = new Date(); - date.setHours(hour); - date.setMinutes(minutes); - date.setSeconds(0); - date.setMilliseconds(0); - return date.toISOString(); - } - - const event = { - start: { dateTime: getDateAndHours(9, 0) }, - end: { dateTime: getDateAndHours(17, 0) }, - eventType: "outOfOffice", - summary: "Out of office", - outOfOfficeProperties: { - autoDeclineMode: "declineOnlyNewConflictingInvitations", - declineMessage: "Declined because I am taking a day of.", - }, - }; - Calendar.Events.insert(event, "primary"); -} - -/** - * Declines all meetings for the day. - */ -function cancelMeetings() { - const events = CalendarApp.getEventsForDay(new Date()); - - for (const event of events) { - if (event.getGuestList().length > 0) { - event.setMyStatus(CalendarApp.GuestStatus.NO); - } - } -} - -/** - * Turns on the user's vacation response for today in Gmail. - */ -function turnOnAutoResponder() { - const ONE_DAY_MILLIS = 24 * 60 * 60 * 1000; - const currentTime = new Date().getTime(); - Gmail.Users.Settings.updateVacation( - { - enableAutoReply: true, - responseSubject: "I am out of the office today", - responseBodyHtml: - "I am out of the office today; will be back on the next business day.

Created by OOO Chat app!", - restrictToContacts: true, - restrictToDomain: true, - startTime: currentTime, - endTime: currentTime + ONE_DAY_MILLIS, - }, - "me", - ); -} - -function createResponseCard(responseText) { - return { - cardsV2: [ - { - cardId: "1", - card: { - sections: [ - { - widgets: [ - { - decoratedText: { - topLabel: "", - text: responseText, - startIcon: { - knownIcon: "NONE", - altText: "Task done", - iconUrl: - "https://fonts.gstatic.com/s/i/short-term/web/system/1x/task_alt_gm_grey_48dp.png", - }, - wrapText: true, - }, - }, - ], - }, - ], - header: { - title: "OOO app", - subtitle: "Helping you manage your OOO", - imageUrl: "https://goo.gle/3SfMkjb", - imageType: "CIRCLE", - }, - }, - }, - ], - }; -} diff --git a/solutions/ooo-chat-app/README.md b/solutions/ooo-chat-app/README.md deleted file mode 100644 index 4d72f861a..000000000 --- a/solutions/ooo-chat-app/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# OOO Chat App - -Sample code for a custom Google Chat app that manages your out of office tasks. - -Learn more about [Chat apps](https://developers.google.com/chat). diff --git a/solutions/ooo-chat-app/appsscript.json b/solutions/ooo-chat-app/appsscript.json deleted file mode 100644 index 2d1fa08f5..000000000 --- a/solutions/ooo-chat-app/appsscript.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "timeZone": "Europe/Madrid", - "exceptionLogging": "STACKDRIVER", - "runtimeVersion": "V8", - "dependencies": { - "enabledAdvancedServices": [ - { - "userSymbol": "Gmail", - "version": "v1", - "serviceId": "gmail" - }, - { - "userSymbol": "Calendar", - "version": "v3", - "serviceId": "calendar" - } - ] - }, - "chat": {} -} diff --git a/solutions/schedule-meetings/.clasp.json b/solutions/schedule-meetings/.clasp.json deleted file mode 100644 index d07e68bf6..000000000 --- a/solutions/schedule-meetings/.clasp.json +++ /dev/null @@ -1 +0,0 @@ -{ "scriptId": "1NdhQ_nXfEUUhWcWKiY6WJjeunY70a1W9vnFdS7BCLPMFreSaHaOS3ucM" } diff --git a/solutions/schedule-meetings/Code.js b/solutions/schedule-meetings/Code.js deleted file mode 100644 index ae81986aa..000000000 --- a/solutions/schedule-meetings/Code.js +++ /dev/null @@ -1,182 +0,0 @@ -// To learn how to use this script, refer to the documentation: -// https://developers.google.com/apps-script/samples/chat-apps/schedule-meetings - -/* -Copyright 2022 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Application constants -const APPNAME = "Chat Meeting Scheduler"; -const SLASHCOMMAND = { - HELP: 1, // /help - DIALOG: 2, // /schedule_Meeting -}; - -/** - * Responds to an ADDED_TO_SPACE event in Google Chat. - * Called when the Chat app is added to a space. The Chat app can either be directly added to the space - * or added by a @mention. If the Chat app is added by a @mention, the event object includes a message property. - * Returns a Message object, which is usually a welcome message informing users about the Chat app. - * - * @param {Object} event The event object from Google Chat - */ -function onAddToSpace(event) { - let message = ""; - - // Personalizes the message depending on how the Chat app is called. - if (event.space.singleUserBotDm) { - message = `Hi ${event.user.displayName}!`; - } else { - const spaceName = event.space.displayName - ? event.space.displayName - : "this chat"; - message = `Hi! Thank you for adding me to ${spaceName}`; - } - - // Lets users know what they can do and how they can get help. - message = `${message}/nI can quickly schedule a meeting for you with just a few clicks.Try me out by typing */schedule_Meeting*. /nTo learn what else I can do, type */help*.`; - - return { text: message }; -} - -/** - * Responds to a MESSAGE event triggered in Chat. - * Called when the Chat app is already in the space and the user invokes it via @mention or / command. - * Returns a message object containing the Chat app's response. For this Chat app, the response is either the - * help text or the dialog to schedule a meeting. - * - * @param {object} event The event object from Google Chat - * @return {object} JSON-formatted response as text or Card message - */ -function onMessage(event) { - // Handles regular onMessage logic. - // Evaluates if and handles for all slash commands. - if (event.message.slashCommand) { - switch (event.message.slashCommand.commandId) { - case SLASHCOMMAND.DIALOG: // Displays meeting dialog for /schedule_Meeting. - // TODO update this with your own logic to set meeting recipients, subjects, etc (e.g. a group email). - return getInputFormAsDialog_({ - invitee: "", - startTime: getTopOfHourDateString_(), - duration: 30, - subject: "Status Stand-up", - body: "Scheduling a quick status stand-up meeting.", - }); - - case SLASHCOMMAND.HELP: // Responds with help text for /help. - return getHelpTextResponse_(); - - /* TODO Add other use cases here. E.g: - case SLASHCOMMAND.NEW_FEATURE: // Your Feature Here - getDialogForAddContact(message); - */ - } - } - // Returns text if users didn't invoke a slash command. - return { text: "No action taken - use Slash Commands." }; -} - -/** - * Responds to a CARD_CLICKED event triggered in Chat. - * @param {object} event the event object from Chat - * @return {object} JSON-formatted response - * @see https://developers.google.com/chat/api/guides/message-formats/events - */ -function onCardClick(event) { - if (event.action.actionMethodName === "handleFormSubmit") { - const recipients = getFieldValue_(event.common.formInputs, "email"); - const subject = getFieldValue_(event.common.formInputs, "subject"); - const body = getFieldValue_(event.common.formInputs, "body"); - - // Assumes dialog card inputs for date and times are in the correct format. mm/dd/yyy HH:MM - const dateTimeInput = getFieldValue_(event.common.formInputs, "date"); - const startTime = getStartTimeAsDateObject_(dateTimeInput); - const duration = Number( - getFieldValue_(event.common.formInputs, "duration"), - ); - - // Handles instances of missing or invalid input parameters. - const errors = []; - - if (!recipients) { - errors.push("Missing or invalid recipient email address."); - } - if (!subject) { - errors.push("Missing subject line."); - } - if (!body) { - errors.push("Missing event description."); - } - if (!startTime) { - errors.push("Missing or invalid start time."); - } - if (!duration || Number.isNaN(duration)) { - errors.push("Missing or invalid duration"); - } - if (errors.length) { - // Redisplays the form if missing or invalid inputs exist. - return getInputFormAsDialog_({ - errors, - invitee: recipients, - startTime: dateTimeInput, - duration, - subject, - body, - }); - } - - // Calculates the end time via duration. - const endTime = new Date(startTime.valueOf()); - endTime.setMinutes(endTime.getMinutes() + duration); - - // Creates calendar event with notification. - const calendar = CalendarApp.getDefaultCalendar(); - const scheduledEvent = calendar.createEvent(subject, startTime, endTime, { - guests: recipients, - sendInvites: true, - description: `${body}\nThis meeting scheduled by a Google Chat App!`, - }); - - // Gets a link to the Calendar event. - const url = getCalendarEventURL_(scheduledEvent, calendar); - - return getConfirmationDialog_(url); - } - if (event.action.actionMethodName === "closeDialog") { - // Returns this dialog as success. - return { - actionResponse: { - type: "DIALOG", - dialog_action: { - actionStatus: "OK", - }, - }, - }; - } -} - -/** - * Responds with help text about this Chat app. - * @return {string} The help text as seen below - */ -function getHelpTextResponse_() { - const help = `*${APPNAME}* lets you quickly create meetings from Google Chat. Here\'s a list of all its commands: - \`/schedule_Meeting\` Opens a dialog with editable, preset parameters to create a meeting event - \`/help\` Displays this help message - - Learn more about creating Google Chat apps at https://developers.google.com/chat.`; - - return { text: help }; -} diff --git a/solutions/schedule-meetings/Dialog.js b/solutions/schedule-meetings/Dialog.js deleted file mode 100644 index b0f018723..000000000 --- a/solutions/schedule-meetings/Dialog.js +++ /dev/null @@ -1,209 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Form input dialog as JSON. - * @return {object} JSON-formatted cards for the dialog. - */ -function getInputFormAsDialog_(options) { - const form = getForm_(options); - return { - actionResponse: { - type: "DIALOG", - dialogAction: { - dialog: { - body: form, - }, - }, - }, - }; -} - -/** - * Form JSON to collect inputs regarding the meeting. - * @return {object} JSON-formatted cards. - */ -function getForm_(options) { - const sections = []; - - // If errors present, display additional section with validation messages. - if (options.errors?.length) { - let errors = options.errors.reduce((str, err) => `${str}• ${err}
`, ""); - errors = `Errors:
${errors}`; - const errorSection = { - widgets: [ - { - textParagraph: { - text: errors, - }, - }, - ], - }; - sections.push(errorSection); - } - const formSection = { - header: "Schedule meeting and send email to invited participants", - widgets: [ - { - textInput: { - label: "Event Title", - type: "SINGLE_LINE", - name: "subject", - value: options.subject, - }, - }, - { - textInput: { - label: "Invitee Email Address", - type: "SINGLE_LINE", - name: "email", - value: options.invitee, - hintText: "Add team group email", - }, - }, - { - textInput: { - label: "Description", - type: "MULTIPLE_LINE", - name: "body", - value: options.body, - }, - }, - { - textInput: { - label: "Meeting start date & time", - type: "SINGLE_LINE", - name: "date", - value: options.startTime, - hintText: "mm/dd/yyyy H:MM", - }, - }, - { - selectionInput: { - type: "DROPDOWN", - label: "Meeting Duration", - name: "duration", - items: [ - { - text: "15 minutes", - value: "15", - selected: options.duration === 15, - }, - { - text: "30 minutes", - value: "30", - selected: options.duration === 30, - }, - { - text: "45 minutes", - value: "45", - selected: options.duration === 45, - }, - { - text: "1 Hour", - value: "60", - selected: options.duration === 60, - }, - { - text: "1.5 Hours", - value: "90", - selected: options.duration === 90, - }, - { - text: "2 Hours", - value: "120", - selected: options.duration === 120, - }, - ], - }, - }, - ], - collapsible: false, - }; - sections.push(formSection); - const card = { - sections: sections, - name: "Google Chat Scheduled Meeting", - fixedFooter: { - primaryButton: { - text: "Submit", - onClick: { - action: { - function: "handleFormSubmit", - }, - }, - altText: "Submit", - }, - }, - }; - return card; -} - -/** - * Confirmation dialog after a calendar event is created successfully. - * @param {string} url The Google Calendar Event url for link button - * @return {object} JSON-formatted cards for the dialog - */ -function getConfirmationDialog_(url) { - return { - actionResponse: { - type: "DIALOG", - dialogAction: { - dialog: { - body: { - sections: [ - { - widgets: [ - { - textParagraph: { - text: "Meeting created successfully!", - }, - horizontalAlignment: "CENTER", - }, - { - buttonList: { - buttons: [ - { - text: "Open Calendar Event", - onClick: { - openLink: { - url: url, - }, - }, - }, - ], - }, - horizontalAlignment: "CENTER", - }, - ], - }, - ], - fixedFooter: { - primaryButton: { - text: "OK", - onClick: { - action: { - function: "closeDialog", - }, - }, - }, - }, - }, - }, - }, - }, - }; -} diff --git a/solutions/schedule-meetings/README.md b/solutions/schedule-meetings/README.md deleted file mode 100644 index 000aed7af..000000000 --- a/solutions/schedule-meetings/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Schedule meetings from Google Chat - -See [developers.google.com](https://developers.google.com/apps-script/samples/chat-apps/schedule-meetings) for additional details. - diff --git a/solutions/schedule-meetings/Utilities.js b/solutions/schedule-meetings/Utilities.js deleted file mode 100644 index 6ecef73aa..000000000 --- a/solutions/schedule-meetings/Utilities.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helper function that gets the field value from the given form input. - * @return {string} - */ -function getFieldValue_(formInputs, fieldName) { - return formInputs[fieldName][""].stringInputs.value[0]; -} - -// Regular expression to validate the date/time input. -const DATE_TIME_PATTERN = /\d{1,2}\/\d{1,2}\/\d{4}\s+\d{1,2}:\d\d/; - -/** - * Casts date and time from string to Date object. - * @return {date} - */ -function getStartTimeAsDateObject_(dateTimeStr) { - if (!dateTimeStr || !dateTimeStr.match(DATE_TIME_PATTERN)) { - return null; - } - - const parts = dateTimeStr.split(" "); - const [month, day, year] = parts[0].split("/").map(Number); - const [hour, minute] = parts[1].split(":").map(Number); - - Session.getScriptTimeZone(); - - return new Date(year, month - 1, day, hour, minute); -} - -/** - * Gets the current date and time for the upcoming top of the hour (e.g. 01/25/2022 18:00). - * @return {string} date/time in mm/dd/yyy HH:MM format needed for use by Calendar - */ -function getTopOfHourDateString_() { - const date = new Date(); - date.setHours(date.getHours() + 1); - date.setMinutes(0, 0, 0); - // Adding the date as string might lead to an incorrect response due to time zone adjustments. - return Utilities.formatDate( - date, - Session.getScriptTimeZone(), - "MM/dd/yyyy H:mm", - ); -} - -/** - * Creates the URL for the Google Calendar event. - * - * @param {object} event The Google Calendar Event instance - * @param {object} cal The associated Google Calendar - * @return {string} URL in the form of 'https://www.google.com/calendar/event?eid={event-id}' - */ -function getCalendarEventURL_(event, cal) { - const baseCalUrl = "https://www.google.com/calendar"; - // Joins Calendar Event Id with Calendar Id, then base64 encode to derive the event URL. - let encodedId = Utilities.base64Encode( - `${event.getId().split("@")[0]} ${cal.getId()}`, - ).replace(/\=/g, ""); - encodedId = `/event?eid=${encodedId}`; - return baseCalUrl + encodedId; -} diff --git a/solutions/schedule-meetings/appsscript.json b/solutions/schedule-meetings/appsscript.json deleted file mode 100644 index cf76895c9..000000000 --- a/solutions/schedule-meetings/appsscript.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "timeZone": "America/Los_Angeles", - "exceptionLogging": "STACKDRIVER", - "runtimeVersion": "V8", - "chat": { - "addToSpaceFallbackMessage": "Thank you for adding this Chat App!" - } -}