From 2202224c9430a79bde75840370ed21f6850e1181 Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Fri, 30 Oct 2020 04:31:27 -0400 Subject: [PATCH] :zap: Add Google Calendar availability (#1105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ⚡ Add Feebusy resource to the Google Calendar node * :zap: Improvements Co-authored-by: Harshil --- .../nodes/Google/Calendar/EventDescription.ts | 10 +- .../Google/Calendar/FreebusyDescription.ts | 132 ++++++++++++++++++ .../Google/Calendar/GoogleCalendar.node.ts | 52 +++++++ 3 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 packages/nodes-base/nodes/Google/Calendar/FreebusyDescription.ts diff --git a/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts b/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts index 5e178f143b..67e1314ca5 100644 --- a/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts +++ b/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts @@ -51,7 +51,7 @@ export const eventFields = [ /* event:create */ /* -------------------------------------------------------------------------- */ { - displayName: 'Calendar', + displayName: 'Calendar ID', name: 'calendar', type: 'options', typeOptions: { @@ -453,7 +453,7 @@ export const eventFields = [ /* event:delete */ /* -------------------------------------------------------------------------- */ { - displayName: 'Calendar', + displayName: 'Calendar ID', name: 'calendar', type: 'options', typeOptions: { @@ -536,7 +536,7 @@ export const eventFields = [ /* event:get */ /* -------------------------------------------------------------------------- */ { - displayName: 'Calendar', + displayName: 'Calendar ID', name: 'calendar', type: 'options', typeOptions: { @@ -613,7 +613,7 @@ export const eventFields = [ /* event:getAll */ /* -------------------------------------------------------------------------- */ { - displayName: 'Calendar', + displayName: 'Calendar ID', name: 'calendar', type: 'options', typeOptions: { @@ -791,7 +791,7 @@ export const eventFields = [ /* event:update */ /* -------------------------------------------------------------------------- */ { - displayName: 'Calendar', + displayName: 'Calendar ID', name: 'calendar', type: 'options', typeOptions: { diff --git a/packages/nodes-base/nodes/Google/Calendar/FreebusyDescription.ts b/packages/nodes-base/nodes/Google/Calendar/FreebusyDescription.ts new file mode 100644 index 0000000000..3afdbcc6d2 --- /dev/null +++ b/packages/nodes-base/nodes/Google/Calendar/FreebusyDescription.ts @@ -0,0 +1,132 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const freeBusyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'freeBusy', + ], + }, + }, + options: [ + { + name: 'Get', + value: 'get', + description: 'Returns free/busy information for a calendar', + }, + ], + default: 'get', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const freeBusyFields = [ + { + displayName: 'Calendar ID', + name: 'calendarId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCalendars', + }, + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'freeBusy', + ], + }, + }, + default: '', + }, + { + displayName: 'Time Min.', + name: 'timeMin', + type: 'dateTime', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'freeBusy', + ], + }, + }, + default: '', + description: 'Start of the interval', + }, + { + displayName: 'Time Max.', + name: 'timeMax', + type: 'dateTime', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'freeBusy', + ], + }, + }, + default: '', + description: 'End of the interval', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'freeBusy', + ], + operation: [ + 'get', + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'freeBusy', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Timezone', + name: 'timezone', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getTimezones', + }, + default: '', + description: 'Time zone used in the response. By default n8n timezone is used.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts b/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts index 65000abc48..42b3a6943a 100644 --- a/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts +++ b/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts @@ -21,6 +21,11 @@ import { eventOperations, } from './EventDescription'; +import { + freeBusyFields, + freeBusyOperations, +} from './freeBusyDescription'; + import { IEvent, } from './EventInterface'; @@ -60,12 +65,18 @@ export class GoogleCalendar implements INodeType { name: 'Event', value: 'event', }, + { + name: 'Freebusy', + value: 'freeBusy', + }, ], default: 'event', description: 'The resource to operate on.', }, ...eventOperations, ...eventFields, + ...freeBusyOperations, + ...freeBusyFields, ], }; @@ -543,6 +554,47 @@ export class GoogleCalendar implements INodeType { ); } } + if (resource === 'freeBusy') { + //https://developers.google.com/calendar/v3/reference/freebusy/query + if (operation === 'get') { + const timezone = this.getTimezone(); + const calendarId = this.getNodeParameter('calendarId', i) as string; + const timeMin = this.getNodeParameter('timeMin', i) as string; + const timeMax = this.getNodeParameter('timeMax', i) as string; + const simple = this.getNodeParameter('simple', i) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + const body: IDataObject = { + timeMin: moment.tz(timeMin, timezone).utc().format(), + timeMax: moment.tz(timeMax, timezone).utc().format(), + items: [ + { + id: calendarId, + }, + ], + timeZone: additionalFields.timezone || timezone, + }; + + responseData = await googleApiRequest.call( + this, + 'POST', + `/calendar/v3/freeBusy`, + body, + {}, + ); + + if (responseData.calendars[calendarId].errors) { + let errors = responseData.calendars[calendarId].errors; + errors = errors.map((e: IDataObject) => e.reason); + throw new Error( + `Google Calendar error response: ${errors.join('|')}`, + ); + } + + if (simple) { + responseData = responseData.calendars[calendarId].busy; + } + } + } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else if (responseData !== undefined) {