mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 12:44:07 -08:00
feat(Google Calendar Node): Use resource locator component for calendar parameters (#4410)
* use calendar RLC for event resource * use calendar RLC for calendar resource * listSearch getCalendars support query filter * improve RLC parameter descriptions to match standards * stricter google calendar id email regex with optional trailing whitespace * calendarId RLC for Google Calendar Trigger node * Event -> Get : Timezone RLC option * Event -> Get Many : Timezone RLC option * Calendar -> Availability : Timezone RLC option * Removed unused loadOptions getTimezones; Removed unused imports * fix prettier linting errors
This commit is contained in:
parent
47b9d22ed5
commit
b319671fd0
|
@ -1,4 +1,5 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
import { TIMEZONE_VALIDATION_REGEX } from './GenericFunctions';
|
||||
|
||||
export const calendarOperations: INodeProperties[] = [
|
||||
{
|
||||
|
@ -28,21 +29,50 @@ export const calendarFields: INodeProperties[] = [
|
|||
/* calendar:availability */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Calendar Name or ID',
|
||||
displayName: 'Calendar',
|
||||
name: 'calendar',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCalendars',
|
||||
},
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
required: true,
|
||||
description: 'Google Calendar to operate on',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'Calendar',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a Calendar...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getCalendars',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
// calendar ids are emails. W3C email regex with optional trailing whitespace.
|
||||
regex:
|
||||
'(^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*(?:[ \t]+)*$)',
|
||||
errorMessage: 'Not a valid Google Calendar ID',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex: '(^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)',
|
||||
},
|
||||
placeholder: 'name@google.com',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['calendar'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Start Time',
|
||||
|
@ -110,15 +140,42 @@ export const calendarFields: INodeProperties[] = [
|
|||
description: 'The format to return the data in',
|
||||
},
|
||||
{
|
||||
displayName: 'Timezone Name or ID',
|
||||
displayName: 'Timezone',
|
||||
name: 'timezone',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTimezones',
|
||||
},
|
||||
default: '',
|
||||
description:
|
||||
'Time zone used in the response. By default n8n timezone is used. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
description: 'Time zone used in the response. By default n8n timezone is used.',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'Timezone',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a Timezone...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getTimezones',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
regex: TIMEZONE_VALIDATION_REGEX,
|
||||
errorMessage: 'Not a valid Timezone',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex: '([-+/_a-zA-Z0-9]*)',
|
||||
},
|
||||
placeholder: 'Europe/Berlin',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import { TIMEZONE_VALIDATION_REGEX } from './GenericFunctions';
|
||||
|
||||
export const eventOperations: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
|
@ -52,21 +54,50 @@ export const eventFields: INodeProperties[] = [
|
|||
/* event:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Calendar Name or ID',
|
||||
displayName: 'Calendar',
|
||||
name: 'calendar',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCalendars',
|
||||
},
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
required: true,
|
||||
description: 'Google Calendar to operate on',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'Calendar',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a Calendar...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getCalendars',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
// calendar ids are emails. W3C email regex with optional trailing whitespace.
|
||||
regex:
|
||||
'(^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*(?:[ \t]+)*$)',
|
||||
errorMessage: 'Not a valid Google Calendar ID',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex: '(^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)',
|
||||
},
|
||||
placeholder: 'name@google.com',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['event'],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -526,15 +557,43 @@ export const eventFields: INodeProperties[] = [
|
|||
'The maximum number of attendees to include in the response. If there are more than the specified number of attendees, only the participant is returned.',
|
||||
},
|
||||
{
|
||||
displayName: 'Timezone Name or ID',
|
||||
displayName: 'Timezone',
|
||||
name: 'timeZone',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTimezones',
|
||||
},
|
||||
default: '',
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
description:
|
||||
'Time zone used in the response. The default is the time zone of the calendar. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
|
||||
'Time zone used in the response. The default is the time zone of the calendar.',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'Timezone',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a Timezone...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getTimezones',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
regex: TIMEZONE_VALIDATION_REGEX,
|
||||
errorMessage: 'Not a valid Timezone',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex: '([-+/_a-zA-Z0-9]*)',
|
||||
},
|
||||
placeholder: 'Europe/Berlin',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -667,15 +726,43 @@ export const eventFields: INodeProperties[] = [
|
|||
description: "Lower bound (exclusive) for an event's end time to filter by",
|
||||
},
|
||||
{
|
||||
displayName: 'Timezone Name or ID',
|
||||
displayName: 'Timezone',
|
||||
name: 'timeZone',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTimezones',
|
||||
},
|
||||
default: '',
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
description:
|
||||
'Time zone used in the response. The default is the time zone of the calendar. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
|
||||
'Time zone used in the response. The default is the time zone of the calendar.',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'Timezone',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a Timezone...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getTimezones',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
regex: TIMEZONE_VALIDATION_REGEX,
|
||||
errorMessage: 'Not a valid Timezone',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex: '([-+/_a-zA-Z0-9]*)',
|
||||
},
|
||||
placeholder: 'Europe/Berlin',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Updated Min',
|
||||
|
|
|
@ -2,7 +2,15 @@ import { OptionsWithUri } from 'request';
|
|||
|
||||
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
|
||||
|
||||
import { IDataObject, IPollFunctions, NodeApiError } from 'n8n-workflow';
|
||||
import {
|
||||
IDataObject,
|
||||
INodeListSearchItems,
|
||||
INodeListSearchResult,
|
||||
IPollFunctions,
|
||||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
export async function googleApiRequest(
|
||||
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions,
|
||||
|
@ -62,3 +70,62 @@ export async function googleApiRequestAllItems(
|
|||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export function encodeURIComponentOnce(uri: string) {
|
||||
// load options used to save encoded uri strings
|
||||
return encodeURIComponent(decodeURIComponent(uri));
|
||||
}
|
||||
|
||||
export async function getCalendars(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const calendars = (await googleApiRequestAllItems.call(
|
||||
this,
|
||||
'items',
|
||||
'GET',
|
||||
'/calendar/v3/users/me/calendarList',
|
||||
)) as Array<{ id: string; summary: string }>;
|
||||
|
||||
const results: INodeListSearchItems[] = calendars
|
||||
.map((c) => ({
|
||||
name: c.summary,
|
||||
value: c.id,
|
||||
}))
|
||||
.filter(
|
||||
(c) =>
|
||||
!filter ||
|
||||
c.name.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
c.value?.toString() === filter,
|
||||
)
|
||||
.sort((a, b) => {
|
||||
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
|
||||
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
|
||||
return 0;
|
||||
});
|
||||
return { results };
|
||||
}
|
||||
|
||||
export const TIMEZONE_VALIDATION_REGEX = `(${moment.tz
|
||||
.names()
|
||||
.map((t) => t.replace('+', '\\+'))
|
||||
.join('|')})[ \t]*`;
|
||||
|
||||
export async function getTimezones(
|
||||
this: ILoadOptionsFunctions,
|
||||
filter?: string,
|
||||
): Promise<INodeListSearchResult> {
|
||||
const results: INodeListSearchItems[] = moment.tz
|
||||
.names()
|
||||
.map((timezone) => ({
|
||||
name: timezone,
|
||||
value: timezone,
|
||||
}))
|
||||
.filter(
|
||||
(c) =>
|
||||
!filter ||
|
||||
c.name.toLowerCase().includes(filter.toLowerCase()) ||
|
||||
c.value?.toString() === filter,
|
||||
);
|
||||
return { results };
|
||||
}
|
||||
|
|
|
@ -11,7 +11,13 @@ import {
|
|||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
|
||||
import {
|
||||
encodeURIComponentOnce,
|
||||
getCalendars,
|
||||
getTimezones,
|
||||
googleApiRequest,
|
||||
googleApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import { eventFields, eventOperations } from './EventDescription';
|
||||
|
||||
|
@ -69,6 +75,10 @@ export class GoogleCalendar implements INodeType {
|
|||
};
|
||||
|
||||
methods = {
|
||||
listSearch: {
|
||||
getCalendars,
|
||||
getTimezones,
|
||||
},
|
||||
loadOptions: {
|
||||
// Get all the calendars to display them to user so that he can
|
||||
// select them easily
|
||||
|
@ -95,26 +105,6 @@ export class GoogleCalendar implements INodeType {
|
|||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the calendars to display them to user so that he can
|
||||
// select them easily
|
||||
async getCalendars(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const calendars = await googleApiRequestAllItems.call(
|
||||
this,
|
||||
'items',
|
||||
'GET',
|
||||
'/calendar/v3/users/me/calendarList',
|
||||
);
|
||||
for (const calendar of calendars) {
|
||||
const calendarName = calendar.summary;
|
||||
const calendarId = encodeURIComponent(calendar.id);
|
||||
returnData.push({
|
||||
name: calendarName,
|
||||
value: calendarId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the colors to display them to user so that he can
|
||||
// select them easily
|
||||
async getColors(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
|
@ -130,20 +120,6 @@ export class GoogleCalendar implements INodeType {
|
|||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the timezones to display them to user so that he can
|
||||
// select them easily
|
||||
async getTimezones(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
for (const timezone of moment.tz.names()) {
|
||||
const timezoneName = timezone;
|
||||
const timezoneId = timezone;
|
||||
returnData.push({
|
||||
name: timezoneName,
|
||||
value: timezoneId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -161,11 +137,17 @@ export class GoogleCalendar implements INodeType {
|
|||
if (resource === 'calendar') {
|
||||
//https://developers.google.com/calendar/v3/reference/freebusy/query
|
||||
if (operation === 'availability') {
|
||||
const calendarId = this.getNodeParameter('calendar', i) as string;
|
||||
// we need to decode once because calendar used to be saved encoded
|
||||
const calendarId = decodeURIComponent(
|
||||
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
|
||||
);
|
||||
const timeMin = this.getNodeParameter('timeMin', i) as string;
|
||||
const timeMax = this.getNodeParameter('timeMax', i) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
const outputFormat = options.outputFormat || 'availability';
|
||||
const tz = this.getNodeParameter('options.timezone', i, '', {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const body: IDataObject = {
|
||||
timeMin: moment(timeMin).utc().format(),
|
||||
|
@ -175,7 +157,7 @@ export class GoogleCalendar implements INodeType {
|
|||
id: calendarId,
|
||||
},
|
||||
],
|
||||
timeZone: options.timezone || timezone,
|
||||
timeZone: tz || timezone,
|
||||
};
|
||||
|
||||
responseData = await googleApiRequest.call(
|
||||
|
@ -204,7 +186,9 @@ export class GoogleCalendar implements INodeType {
|
|||
if (resource === 'event') {
|
||||
//https://developers.google.com/calendar/v3/reference/events/insert
|
||||
if (operation === 'create') {
|
||||
const calendarId = this.getNodeParameter('calendar', i) as string;
|
||||
const calendarId = encodeURIComponentOnce(
|
||||
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
|
||||
);
|
||||
const start = this.getNodeParameter('start', i) as string;
|
||||
const end = this.getNodeParameter('end', i) as string;
|
||||
const useDefaultReminders = this.getNodeParameter('useDefaultReminders', i) as boolean;
|
||||
|
@ -351,7 +335,9 @@ export class GoogleCalendar implements INodeType {
|
|||
}
|
||||
//https://developers.google.com/calendar/v3/reference/events/delete
|
||||
if (operation === 'delete') {
|
||||
const calendarId = this.getNodeParameter('calendar', i) as string;
|
||||
const calendarId = encodeURIComponentOnce(
|
||||
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
|
||||
);
|
||||
const eventId = this.getNodeParameter('eventId', i) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
if (options.sendUpdates) {
|
||||
|
@ -367,14 +353,19 @@ export class GoogleCalendar implements INodeType {
|
|||
}
|
||||
//https://developers.google.com/calendar/v3/reference/events/get
|
||||
if (operation === 'get') {
|
||||
const calendarId = this.getNodeParameter('calendar', i) as string;
|
||||
const calendarId = encodeURIComponentOnce(
|
||||
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
|
||||
);
|
||||
const eventId = this.getNodeParameter('eventId', i) as string;
|
||||
const options = this.getNodeParameter('options', i);
|
||||
const tz = this.getNodeParameter('options.timeZone', i, '', {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
if (options.maxAttendees) {
|
||||
qs.maxAttendees = options.maxAttendees as number;
|
||||
}
|
||||
if (options.timeZone) {
|
||||
qs.timeZone = options.timeZone as string;
|
||||
if (tz) {
|
||||
qs.timeZone = tz;
|
||||
}
|
||||
responseData = await googleApiRequest.call(
|
||||
this,
|
||||
|
@ -387,8 +378,13 @@ export class GoogleCalendar implements INodeType {
|
|||
//https://developers.google.com/calendar/v3/reference/events/list
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i);
|
||||
const calendarId = this.getNodeParameter('calendar', i) as string;
|
||||
const calendarId = encodeURIComponentOnce(
|
||||
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
|
||||
);
|
||||
const options = this.getNodeParameter('options', i);
|
||||
const tz = this.getNodeParameter('options.timeZone', i, '', {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
if (options.iCalUID) {
|
||||
qs.iCalUID = options.iCalUID as string;
|
||||
}
|
||||
|
@ -416,8 +412,8 @@ export class GoogleCalendar implements INodeType {
|
|||
if (options.timeMin) {
|
||||
qs.timeMin = options.timeMin as string;
|
||||
}
|
||||
if (options.timeZone) {
|
||||
qs.timeZone = options.timeZone as string;
|
||||
if (tz) {
|
||||
qs.timeZone = tz;
|
||||
}
|
||||
if (options.updatedMin) {
|
||||
qs.updatedMin = options.updatedMin as string;
|
||||
|
@ -445,7 +441,9 @@ export class GoogleCalendar implements INodeType {
|
|||
}
|
||||
//https://developers.google.com/calendar/v3/reference/events/patch
|
||||
if (operation === 'update') {
|
||||
const calendarId = this.getNodeParameter('calendar', i) as string;
|
||||
const calendarId = encodeURIComponentOnce(
|
||||
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
|
||||
);
|
||||
const eventId = this.getNodeParameter('eventId', i) as string;
|
||||
const useDefaultReminders = this.getNodeParameter('useDefaultReminders', i) as boolean;
|
||||
const updateFields = this.getNodeParameter('updateFields', i);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import {
|
||||
IDataObject,
|
||||
ILoadOptionsFunctions,
|
||||
INodeExecutionData,
|
||||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IPollFunctions,
|
||||
|
@ -10,7 +8,7 @@ import {
|
|||
NodeOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
|
||||
import { getCalendars, googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
|
@ -37,16 +35,45 @@ export class GoogleCalendarTrigger implements INodeType {
|
|||
polling: true,
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Calendar Name or ID',
|
||||
displayName: 'Calendar',
|
||||
name: 'calendarId',
|
||||
type: 'options',
|
||||
description:
|
||||
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
|
||||
type: 'resourceLocator',
|
||||
default: { mode: 'list', value: '' },
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCalendars',
|
||||
},
|
||||
default: '',
|
||||
description: 'Google Calendar to operate on',
|
||||
modes: [
|
||||
{
|
||||
displayName: 'Calendar',
|
||||
name: 'list',
|
||||
type: 'list',
|
||||
placeholder: 'Select a Calendar...',
|
||||
typeOptions: {
|
||||
searchListMethod: 'getCalendars',
|
||||
searchable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
validation: [
|
||||
{
|
||||
type: 'regex',
|
||||
properties: {
|
||||
// calendar ids are emails. W3C email regex with optional trailing whitespace.
|
||||
regex:
|
||||
'(^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*(?:[ \t]+)*$)',
|
||||
errorMessage: 'Not a valid Google Calendar ID',
|
||||
},
|
||||
},
|
||||
],
|
||||
extractValue: {
|
||||
type: 'regex',
|
||||
regex: '(^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)',
|
||||
},
|
||||
placeholder: 'name@google.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Trigger On',
|
||||
|
@ -94,32 +121,15 @@ export class GoogleCalendarTrigger implements INodeType {
|
|||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
// Get all the calendars to display them to user so that he can
|
||||
// select them easily
|
||||
async getCalendars(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const calendars = await googleApiRequestAllItems.call(
|
||||
this,
|
||||
'items',
|
||||
'GET',
|
||||
'/calendar/v3/users/me/calendarList',
|
||||
);
|
||||
for (const calendar of calendars) {
|
||||
returnData.push({
|
||||
name: calendar.summary,
|
||||
value: calendar.id,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
listSearch: {
|
||||
getCalendars,
|
||||
},
|
||||
};
|
||||
|
||||
async poll(this: IPollFunctions): Promise<INodeExecutionData[][] | null> {
|
||||
const poolTimes = this.getNodeParameter('pollTimes.item', []) as IDataObject[];
|
||||
const triggerOn = this.getNodeParameter('triggerOn', '') as string;
|
||||
const calendarId = this.getNodeParameter('calendarId') as string;
|
||||
const calendarId = this.getNodeParameter('calendarId', '', { extractValue: true }) as string;
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const matchTerm = this.getNodeParameter('options.matchTerm', '') as string;
|
||||
|
||||
|
|
Loading…
Reference in a new issue