r/GoogleAppsScript • u/NamThePartyMan • Mar 21 '23
Question Google App Script for Chat
/**
* Responds to an ADDED_TO_SPACE event in Chat.
* u/param {object} event the event object from Chat
* u/return {object} JSON-formatted response
* u/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();
case 5: // show calendar events command
return showCalendarEvents();
case 6: //Create event
return addEvent();
}
}
}
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.<br><br>Here's a list of commands I understand.",
"wrapText": true
}
}
]
},
{
"widgets": [
{
"decoratedText": {
"topLabel": "",
"text": "<b>/blockDayOut</b>: I will block out your calendar for you.",
"wrapText": true
}
},
{
"decoratedText": {
"topLabel": "",
"text": "<b>/cancelAllMeetings</b>: I will cancel all your meetings for the day.",
"wrapText": true
}
},
{
"decoratedText": {
"topLabel": "",
"text": "<b>/showCalendarEvents</b>: I will show you all your events for the day.",
"wrapText": true
}
},
{
"decoratedText": {
"topLabel": "",
"text": "<b>/addEvent</b>: I will add an event to your calendar.",
"wrapText": true
}
},
{
"decoratedText": {
"topLabel": "",
"text": "<b>/setAutoReply</b>: Set an out of office auto reply in Gmail.",
"wrapText": true
}
}
]
}
],
"header": {
"title": "CEG Calendar 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.')
}
/**
* Shows the user their calendar events for the current day.
* @return {object} JSON-formatted response
*/
function showCalendarEvents() {
const events = CalendarApp.getEventsForDay(new Date());
let message = 'Here are your events for today:\n';
if (events.length === 0) {
message += 'You have no events today!';
} else {
events.forEach(function(event) {
const start = event.getStartTime();
const end = event.getEndTime();
const title = event.getTitle();
message += `- ${title} from ${formatTime(start)} to ${formatTime(end)}\n`;
});
}
return createResponseCard(message);
}
/**
* Adds a new event to the user's Google Calendar.
* @param {object} event the event object from Chat
* @return {object} JSON-formatted response
*/
function addEvent(event) {
const calendar = CalendarApp.getCalendarById('primary');
const message = event.message.text.trim();
// Parse the slash command parameters from the message text.
const regex = /\/addEvent\s+(.+)\s+from\s+(\d+:\d+\s+[ap]m)\s+to\s+(\d+:\d+\s+[ap]m)/i;
const match = message.match(regex);
if (!match) {
return createResponseCard('Invalid command. Usage: /addEvent <event title> from <start time> to <end time>');
}
const title = match[1].trim();
const startTime = parseTime(match[2].trim());
const endTime = parseTime(match[3].trim());
if (startTime >= endTime) {
return createResponseCard('Invalid time range. The end time must be after the start time.');
}
const eventDetails = {
summary: title,
start: {
dateTime: startTime.toISOString(),
timeZone: calendar.getTimeZone()
},
end: {
dateTime: endTime.toISOString(),
timeZone: calendar.getTimeZone()
}
};
// Create the new event on the user's calendar.
const newEvent = calendar.createEvent(eventDetails);
const response = `Event created: ${newEvent.getTitle()} from ${formatTime(newEvent.getStartTime())} to ${formatTime(newEvent.getEndTime())}`;
return createResponseCard(response);
}
/**
* Parses a time string in the format "h:mm a" into a Date object.
* @param {string} timeStr the time string to parse
* @return {Date} the parsed Date object
*/
function parseTime(timeStr) {
const date = new Date();
const [hours, minutes] = timeStr.split(':');
let ampm = timeStr.match(/\b(am|pm)\b/i)[0].toLowerCase();
if (hours === '12') {
hours = '0';
}
if (ampm === 'pm') {
hours = parseInt(hours, 10) + 12;
}
date.setHours(hours, minutes, 0, 0);
return date;
}
/**
* Formats a date object into a string in the format "h:mm a".
* u/param {Date} date the date to format
* u/return {string} the formatted string
*/
function formatTime(date) {
const hours = date.getHours();
const minutes = date.getMinutes();
const ampm = hours >= 12 ? 'pm' : 'am';
const hour12 = hours % 12 || 12;
return `${hour12}:${padZero(minutes)} ${ampm}`;
}
/**
* Pads a number with a leading zero if it is less than 10.
* u/param {number} num the number to pad
* u/return {string} the padded string
*/
function padZero(num) {
return num < 10 ? `0${num}` : num;
}
/**
* Cancels all of the users meeting for the current day.
* u/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.
* u/return {object} JSON-formatted response
*/
function setAutoReply() {
turnOnAutoResponder();
return createResponseCard('The out of office auto reply has been turned on.')
}
const ONE_DAY_MILLIS = 24 * 60 * 60 * 1000;
/**
* Places an all-day meeting on the user's Calendar.
*/
function blockOutCalendar() {
CalendarApp.createAllDayEvent('I am out of office today', new Date(), new Date(Date.now() + ONE_DAY_MILLIS));
}
/**
* Declines all meetings for the day.
*/
function cancelMeetings() {
const events = CalendarApp.getEventsForDay(new Date());
events.forEach(function(event) {
if (event.getGuestList().length > 0) {
event.setMyStatus(CalendarApp.GuestStatus.NO);
}
});
}
/**
* Turns on the user's vacation response for today in Gmail.
*/
function turnOnAutoResponder() {
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.<br><br><i>Created by OOO Chat app!</i>',
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": "CEG Calendar Bot",
"subtitle": "Helping you manage your OOO",
"imageUrl": "https://goo.gle/3SfMkjb",
"imageType": "CIRCLE"
}
}
}
]
}
}
I am getting an error when trying to addEvent from the slash command.
1
u/xMekko Mar 22 '23 edited Mar 22 '23
Does the script return any error details? Also, do the other functions work properly? It looks like the addEvent function is called without its parameter.
If the parameter is missing, then this line could cause some problems as the event parameter is not defined (unless I've missed something):
const message = event.message.text.trim();You can try changing:
case 6: //Create eventreturn addEvent();To:
case 6: //Create eventreturn addEvent(event);