n8n-3867-progressively-apply-prettier-to-all (#3873)

* 🔨 formatting nodes with prettier
This commit is contained in:
Michael Kret 2022-08-17 18:50:24 +03:00 committed by GitHub
parent f2d326c7f0
commit 91d7e16c81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1072 changed files with 42357 additions and 59109 deletions

View file

@ -7,194 +7,4 @@ packages/design-system
!packages/nodes-base/test
!packages/nodes-base/nodes
packages/nodes-base/nodes/GetResponse
packages/nodes-base/nodes/Ghost
packages/nodes-base/nodes/Git
packages/nodes-base/nodes/Github
packages/nodes-base/nodes/Gitlab
packages/nodes-base/nodes/Google
packages/nodes-base/nodes/Gotify
packages/nodes-base/nodes/GoToWebinar
packages/nodes-base/nodes/Grafana
packages/nodes-base/nodes/GraphQL
packages/nodes-base/nodes/Grist
packages/nodes-base/nodes/Gumroad
packages/nodes-base/nodes/HackerNews
packages/nodes-base/nodes/HaloPSA
packages/nodes-base/nodes/Harvest
packages/nodes-base/nodes/HelpScout
packages/nodes-base/nodes/HomeAssistant
packages/nodes-base/nodes/HtmlExtract
packages/nodes-base/nodes/HttpRequest
packages/nodes-base/nodes/Hubspot
packages/nodes-base/nodes/HumanticAI
packages/nodes-base/nodes/Hunter
packages/nodes-base/nodes/ICalendar
packages/nodes-base/nodes/If
packages/nodes-base/nodes/Intercom
packages/nodes-base/nodes/Interval
packages/nodes-base/nodes/InvoiceNinja
packages/nodes-base/nodes/ItemLists
packages/nodes-base/nodes/Iterable
packages/nodes-base/nodes/Jenkins
packages/nodes-base/nodes/Jira
packages/nodes-base/nodes/JotForm
packages/nodes-base/nodes/Kafka
packages/nodes-base/nodes/Keap
packages/nodes-base/nodes/Kitemaker
packages/nodes-base/nodes/KoBoToolbox
packages/nodes-base/nodes/Lemlist
packages/nodes-base/nodes/Line
packages/nodes-base/nodes/Linear
packages/nodes-base/nodes/LingvaNex
packages/nodes-base/nodes/LinkedIn
packages/nodes-base/nodes/LocalFileTrigger
packages/nodes-base/nodes/Magento
packages/nodes-base/nodes/Mailcheck
packages/nodes-base/nodes/Mailchimp
packages/nodes-base/nodes/MailerLite
packages/nodes-base/nodes/Mailgun
packages/nodes-base/nodes/Mailjet
packages/nodes-base/nodes/Mandrill
packages/nodes-base/nodes/Markdown
packages/nodes-base/nodes/Marketstack
packages/nodes-base/nodes/Matrix
packages/nodes-base/nodes/Mattermost
packages/nodes-base/nodes/Mautic
packages/nodes-base/nodes/Medium
packages/nodes-base/nodes/Merge
packages/nodes-base/nodes/MessageBird
packages/nodes-base/nodes/Microsoft
packages/nodes-base/nodes/Mindee
packages/nodes-base/nodes/Misp
packages/nodes-base/nodes/Mocean
packages/nodes-base/nodes/MondayCom
packages/nodes-base/nodes/MongoDb
packages/nodes-base/nodes/MonicaCrm
packages/nodes-base/nodes/MoveBinaryData
packages/nodes-base/nodes/MQTT
packages/nodes-base/nodes/Msg91
packages/nodes-base/nodes/MySql
packages/nodes-base/nodes/N8nTrainingCustomerDatastore
packages/nodes-base/nodes/N8nTrainingCustomerMessenger
packages/nodes-base/nodes/N8nTrigger
packages/nodes-base/nodes/Nasa
packages/nodes-base/nodes/Netlify
packages/nodes-base/nodes/NextCloud
packages/nodes-base/nodes/NocoDB
packages/nodes-base/nodes/NoOp
packages/nodes-base/nodes/Notion
packages/nodes-base/nodes/Odoo
packages/nodes-base/nodes/OneSimpleApi
packages/nodes-base/nodes/Onfleet
packages/nodes-base/nodes/OpenThesaurus
packages/nodes-base/nodes/OpenWeatherMap
packages/nodes-base/nodes/Orbit
packages/nodes-base/nodes/Oura
packages/nodes-base/nodes/Paddle
packages/nodes-base/nodes/PagerDuty
packages/nodes-base/nodes/PayPal
packages/nodes-base/nodes/Peekalink
packages/nodes-base/nodes/Phantombuster
packages/nodes-base/nodes/PhilipsHue
packages/nodes-base/nodes/Pipedrive
packages/nodes-base/nodes/Plivo
packages/nodes-base/nodes/PostBin
packages/nodes-base/nodes/Postgres
packages/nodes-base/nodes/PostHog
packages/nodes-base/nodes/Postmark
packages/nodes-base/nodes/ProfitWell
packages/nodes-base/nodes/Pushbullet
packages/nodes-base/nodes/Pushcut
packages/nodes-base/nodes/Pushover
packages/nodes-base/nodes/QuestDb
packages/nodes-base/nodes/QuickBase
packages/nodes-base/nodes/QuickBooks
packages/nodes-base/nodes/RabbitMQ
packages/nodes-base/nodes/Raindrop
packages/nodes-base/nodes/ReadBinaryFile
packages/nodes-base/nodes/ReadBinaryFiles
packages/nodes-base/nodes/ReadPdf
packages/nodes-base/nodes/Reddit
packages/nodes-base/nodes/Redis
packages/nodes-base/nodes/RenameKeys
packages/nodes-base/nodes/RespondToWebhook
packages/nodes-base/nodes/Rocketchat
packages/nodes-base/nodes/RssFeedRead
packages/nodes-base/nodes/Rundeck
packages/nodes-base/nodes/S3
packages/nodes-base/nodes/Salesforce
packages/nodes-base/nodes/Salesmate
packages/nodes-base/nodes/SeaTable
packages/nodes-base/nodes/SecurityScorecard
packages/nodes-base/nodes/Segment
packages/nodes-base/nodes/SendGrid
packages/nodes-base/nodes/Sendy
packages/nodes-base/nodes/SentryIo
packages/nodes-base/nodes/ServiceNow
packages/nodes-base/nodes/Set
packages/nodes-base/nodes/Shopify
packages/nodes-base/nodes/Signl4
packages/nodes-base/nodes/Slack
packages/nodes-base/nodes/Sms77
packages/nodes-base/nodes/Snowflake
packages/nodes-base/nodes/SplitInBatches
packages/nodes-base/nodes/Splunk
packages/nodes-base/nodes/Spontit
packages/nodes-base/nodes/Spotify
packages/nodes-base/nodes/SpreadsheetFile
packages/nodes-base/nodes/SseTrigger
packages/nodes-base/nodes/Ssh
packages/nodes-base/nodes/Stackby
packages/nodes-base/nodes/Start
packages/nodes-base/nodes/StickyNote
packages/nodes-base/nodes/StopAndError
packages/nodes-base/nodes/Storyblok
packages/nodes-base/nodes/Strapi
packages/nodes-base/nodes/Strava
packages/nodes-base/nodes/Stripe
packages/nodes-base/nodes/Supabase
packages/nodes-base/nodes/SurveyMonkey
packages/nodes-base/nodes/Switch
packages/nodes-base/nodes/SyncroMSP
packages/nodes-base/nodes/Taiga
packages/nodes-base/nodes/Tapfiliate
packages/nodes-base/nodes/Telegram
packages/nodes-base/nodes/TheHive
packages/nodes-base/nodes/TimescaleDb
packages/nodes-base/nodes/Todoist
packages/nodes-base/nodes/Toggl
packages/nodes-base/nodes/TravisCi
packages/nodes-base/nodes/Trello
packages/nodes-base/nodes/Twake
packages/nodes-base/nodes/Twilio
packages/nodes-base/nodes/Twist
packages/nodes-base/nodes/Twitter
packages/nodes-base/nodes/Typeform
packages/nodes-base/nodes/UnleashedSoftware
packages/nodes-base/nodes/Uplead
packages/nodes-base/nodes/UProc
packages/nodes-base/nodes/UptimeRobot
packages/nodes-base/nodes/UrlScanIo
packages/nodes-base/nodes/utils
packages/nodes-base/nodes/Vero
packages/nodes-base/nodes/Vonage
packages/nodes-base/nodes/Wait
packages/nodes-base/nodes/Webflow
packages/nodes-base/nodes/Webhook
packages/nodes-base/nodes/Wekan
packages/nodes-base/nodes/Wise
packages/nodes-base/nodes/WooCommerce
packages/nodes-base/nodes/Wordpress
packages/nodes-base/nodes/Workable
packages/nodes-base/nodes/WorkflowTrigger
packages/nodes-base/nodes/WriteBinaryFile
packages/nodes-base/nodes/Wufoo
packages/nodes-base/nodes/Xero
packages/nodes-base/nodes/Xml
packages/nodes-base/nodes/Yourls
packages/nodes-base/nodes/Zammad
packages/nodes-base/nodes/Zendesk
packages/nodes-base/nodes/Zoho
packages/nodes-base/nodes/Zoom
packages/nodes-base/nodes/Zulip
packages/nodes-base/nodes/UProc/Json/Tools.ts

View file

@ -537,9 +537,8 @@ function digestAuthAxiosConfig(
async function proxyRequestToAxios(
uriOrObject: string | IDataObject,
options?: IDataObject,
// tslint:disable-next-line:no-any
): Promise<any> {
// tslint:disable-line:no-any
// Check if there's a better way of getting this config here
if (process.env.N8N_USE_DEPRECATED_REQUEST_LIB) {
// @ts-ignore

View file

@ -5,7 +5,6 @@ import {
INodeProperties,
} from 'n8n-workflow';
export class NocoDbApiToken implements ICredentialType {
name = 'nocoDbApiToken';
displayName = 'NocoDB API Token';

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const contactOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const contactOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'contact',
],
resource: ['contact'],
},
},
options: [
@ -62,12 +58,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'name@email.com',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
resource: ['contact'],
operation: ['create'],
},
},
default: '',
@ -81,16 +73,13 @@ export const contactFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
resource: ['contact'],
operation: ['create'],
},
},
default: '',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
},
{
displayName: 'Additional Fields',
@ -100,12 +89,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
resource: ['contact'],
operation: ['create'],
},
},
options: [
@ -130,7 +115,8 @@ export const contactFields: INodeProperties[] = [
typeOptions: {
loadOptionsMethod: 'getCustomFields',
},
description: 'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
default: '',
},
{
@ -148,14 +134,15 @@ export const contactFields: INodeProperties[] = [
displayName: 'Day Of Cycle',
name: 'dayOfCycle',
type: 'string',
description: 'The day on which the contact is in the Autoresponder cycle. null indicates the contacts is not in the cycle.',
description:
'The day on which the contact is in the Autoresponder cycle. null indicates the contacts is not in the cycle.',
default: '',
},
{
displayName: 'IP Address',
name: 'ipAddress',
type: 'string',
description: 'The contact\'s IP address. IPv4 and IPv6 formats are accepted.',
description: "The contact's IP address. IPv4 and IPv6 formats are accepted.",
default: '',
},
{
@ -184,7 +171,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Tag Names or IDs',
name: 'tags',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTags',
},
@ -203,12 +191,8 @@ export const contactFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'delete',
],
resource: ['contact'],
operation: ['delete'],
},
},
default: '',
@ -222,12 +206,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'delete',
],
resource: ['contact'],
operation: ['delete'],
},
},
options: [
@ -235,14 +215,16 @@ export const contactFields: INodeProperties[] = [
displayName: 'IP Address',
name: 'ipAddress',
type: 'string',
description: 'This makes it possible to pass the IP from which the contact unsubscribed. Used only if the messageId was send.',
description:
'This makes it possible to pass the IP from which the contact unsubscribed. Used only if the messageId was send.',
default: '',
},
{
displayName: 'Message ID',
name: 'messageId',
type: 'string',
description: 'The ID of a message (such as a newsletter, an autoresponder, or an RSS-newsletter). When passed, this method will simulate the unsubscribe process, as if the contact clicked the unsubscribe link in a given message.',
description:
'The ID of a message (such as a newsletter, an autoresponder, or an RSS-newsletter). When passed, this method will simulate the unsubscribe process, as if the contact clicked the unsubscribe link in a given message.',
default: '',
},
],
@ -258,12 +240,8 @@ export const contactFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'get',
],
resource: ['contact'],
operation: ['get'],
},
},
default: '',
@ -277,12 +255,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'get',
],
resource: ['contact'],
operation: ['get'],
},
},
options: [
@ -290,7 +264,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Fields',
name: 'fields',
type: 'string',
description: 'List of fields that should be returned. ID is always returned. Fields should be separated by comma',
description:
'List of fields that should be returned. ID is always returned. Fields should be separated by comma',
default: '',
},
],
@ -305,12 +280,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
resource: ['contact'],
operation: ['getAll'],
},
},
default: false,
@ -327,15 +298,9 @@ export const contactFields: INodeProperties[] = [
default: 20,
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['contact'],
operation: ['getAll'],
returnAll: [false],
},
},
},
@ -347,12 +312,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
resource: ['contact'],
operation: ['getAll'],
},
},
options: [
@ -396,13 +357,15 @@ export const contactFields: INodeProperties[] = [
name: 'exactMatch',
type: 'boolean',
default: false,
description: 'Whether to search for contacts with the exact value of the email and name provided in the query string. Without this flag, matching is done via a standard \'like\' comparison, which may sometimes be slow.',
description:
"Whether to search for contacts with the exact value of the email and name provided in the query string. Without this flag, matching is done via a standard 'like' comparison, which may sometimes be slow.",
},
{
displayName: 'Fields',
name: 'fields',
type: 'string',
description: 'List of fields that should be returned. ID is always returned. Fields should be separated by comma',
description:
'List of fields that should be returned. ID is always returned. Fields should be separated by comma',
default: '',
},
{
@ -526,12 +489,8 @@ export const contactFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'update',
],
resource: ['contact'],
operation: ['update'],
},
},
default: '',
@ -545,12 +504,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'update',
],
resource: ['contact'],
operation: ['update'],
},
},
options: [
@ -558,7 +513,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
@ -585,7 +541,8 @@ export const contactFields: INodeProperties[] = [
typeOptions: {
loadOptionsMethod: 'getCustomFields',
},
description: 'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
default: '',
},
{
@ -603,7 +560,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Day Of Cycle',
name: 'dayOfCycle',
type: 'string',
description: 'The day on which the contact is in the Autoresponder cycle. null indicates the contacts is not in the cycle.',
description:
'The day on which the contact is in the Autoresponder cycle. null indicates the contacts is not in the cycle.',
default: '',
},
{
@ -617,7 +575,7 @@ export const contactFields: INodeProperties[] = [
displayName: 'IP Address',
name: 'ipAddress',
type: 'string',
description: 'The contact\'s IP address. IPv4 and IPv6 formats are accepted.',
description: "The contact's IP address. IPv4 and IPv6 formats are accepted.",
default: '',
},
{
@ -646,7 +604,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Tag Names or IDs',
name: 'tags',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTags',
},
@ -654,5 +613,4 @@ export const contactFields: INodeProperties[] = [
},
],
},
];

View file

@ -1,6 +1,4 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
@ -9,12 +7,19 @@ import {
IWebhookFunctions,
} from 'n8n-core';
import {
IDataObject, NodeApiError
} from 'n8n-workflow';
export async function getresponseApiRequest(this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function getresponseApiRequest(
this: IWebhookFunctions | IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authentication = this.getNodeParameter('authentication', 0, 'apiKey') as string;
let options: OptionsWithUri = {
@ -44,20 +49,33 @@ export async function getresponseApiRequest(this: IWebhookFunctions | IHookFunct
}
}
export async function getResponseApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function getResponseApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
query.page = 1;
do {
responseData = await getresponseApiRequest.call(this, method, endpoint, body, query, undefined, { resolveWithFullResponse: true });
responseData = await getresponseApiRequest.call(
this,
method,
endpoint,
body,
query,
undefined,
{ resolveWithFullResponse: true },
);
query.page++;
returnData.push.apply(returnData, responseData.body);
} while (
responseData.headers.TotalPages !== responseData.headers.CurrentPage
);
} while (responseData.headers.TotalPages !== responseData.headers.CurrentPage);
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -11,15 +9,9 @@ import {
INodeTypeDescription,
} from 'n8n-workflow';
import {
getresponseApiRequest,
getResponseApiRequestAllItems,
} from './GenericFunctions';
import { getresponseApiRequest, getResponseApiRequestAllItems } from './GenericFunctions';
import {
contactFields,
contactOperations,
} from './ContactDescription';
import { contactFields, contactOperations } from './ContactDescription';
import moment from 'moment-timezone';
@ -44,9 +36,7 @@ export class GetResponse implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'apiKey',
],
authentication: ['apiKey'],
},
},
},
@ -55,9 +45,7 @@ export class GetResponse implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -101,15 +89,9 @@ export class GetResponse implements INodeType {
loadOptions: {
// Get all the campaigns to display them to user so that he can
// select them easily
async getCampaigns(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getCampaigns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const campaigns = await getresponseApiRequest.call(
this,
'GET',
`/campaigns`,
);
const campaigns = await getresponseApiRequest.call(this, 'GET', `/campaigns`);
for (const campaign of campaigns) {
returnData.push({
name: campaign.name as string,
@ -120,15 +102,9 @@ export class GetResponse implements INodeType {
},
// Get all the tagd to display them to user so that he can
// select them easily
async getTags(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const tags = await getresponseApiRequest.call(
this,
'GET',
`/tags`,
);
const tags = await getresponseApiRequest.call(this, 'GET', `/tags`);
for (const tag of tags) {
returnData.push({
name: tag.name as string,
@ -139,15 +115,9 @@ export class GetResponse implements INodeType {
},
// Get all the custom fields to display them to user so that he can
// select them easily
async getCustomFields(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const customFields = await getresponseApiRequest.call(
this,
'GET',
`/custom-fields`,
);
const customFields = await getresponseApiRequest.call(this, 'GET', `/custom-fields`);
for (const customField of customFields) {
returnData.push({
name: customField.name as string,
@ -188,7 +158,8 @@ export class GetResponse implements INodeType {
Object.assign(body, additionalFields);
if (additionalFields.customFieldsUi) {
const customFieldValues = (additionalFields.customFieldsUi as IDataObject).customFieldValues as IDataObject[];
const customFieldValues = (additionalFields.customFieldsUi as IDataObject)
.customFieldValues as IDataObject[];
if (customFieldValues) {
body.customFieldValues = customFieldValues;
for (let i = 0; i < customFieldValues.length; i++) {
@ -212,7 +183,13 @@ export class GetResponse implements INodeType {
Object.assign(qs, options);
responseData = await getresponseApiRequest.call(this, 'DELETE', `/contacts/${contactId}`, {}, qs);
responseData = await getresponseApiRequest.call(
this,
'DELETE',
`/contacts/${contactId}`,
{},
qs,
);
responseData = { success: true };
}
@ -224,7 +201,13 @@ export class GetResponse implements INodeType {
Object.assign(qs, options);
responseData = await getresponseApiRequest.call(this, 'GET', `/contacts/${contactId}`, {}, qs);
responseData = await getresponseApiRequest.call(
this,
'GET',
`/contacts/${contactId}`,
{},
qs,
);
}
//https://apireference.getresponse.com/?_ga=2.160836350.2102802044.1604719933-1897033509.1604598019#operation/getContactList
if (operation === 'getAll') {
@ -236,32 +219,23 @@ export class GetResponse implements INodeType {
Object.assign(qs, options);
const isNotQuery = [
'sortBy',
'sortOrder',
'additionalFlags',
'fields',
'exactMatch',
];
const isNotQuery = ['sortBy', 'sortOrder', 'additionalFlags', 'fields', 'exactMatch'];
const isDate = [
'createdOnFrom',
'createdOnTo',
'changeOnFrom',
'changeOnTo',
];
const isDate = ['createdOnFrom', 'createdOnTo', 'changeOnFrom', 'changeOnTo'];
const dateMapToKey: { [key: string]: string; } = {
'createdOnFrom': '[createdOn][from]',
'createdOnTo': '[createdOn][to]',
'changeOnFrom': '[changeOn][from]',
'changeOnTo': '[changeOn][to]',
const dateMapToKey: { [key: string]: string } = {
createdOnFrom: '[createdOn][from]',
createdOnTo: '[createdOn][to]',
changeOnFrom: '[changeOn][from]',
changeOnTo: '[changeOn][to]',
};
for (const key of Object.keys(qs)) {
if (!isNotQuery.includes(key)) {
if (isDate.includes(key)) {
qs[`query${dateMapToKey[key]}`] = moment.tz(qs[key], timezone).format('YYYY-MM-DDTHH:mm:ssZZ');
qs[`query${dateMapToKey[key]}`] = moment
.tz(qs[key], timezone)
.format('YYYY-MM-DDTHH:mm:ssZZ');
} else {
qs[`query[${key}]`] = qs[key];
}
@ -279,7 +253,13 @@ export class GetResponse implements INodeType {
}
if (returnAll) {
responseData = await getResponseApiRequestAllItems.call(this, 'GET', `/contacts`, {}, qs);
responseData = await getResponseApiRequestAllItems.call(
this,
'GET',
`/contacts`,
{},
qs,
);
} else {
qs.perPage = this.getNodeParameter('limit', i) as number;
responseData = await getresponseApiRequest.call(this, 'GET', `/contacts`, {}, qs);
@ -287,7 +267,6 @@ export class GetResponse implements INodeType {
}
//https://apireference.getresponse.com/?_ga=2.160836350.2102802044.1604719933-1897033509.1604598019#operation/updateContact
if (operation === 'update') {
const contactId = this.getNodeParameter('contactId', i) as string;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
@ -297,19 +276,24 @@ export class GetResponse implements INodeType {
Object.assign(body, updateFields);
if (updateFields.customFieldsUi) {
const customFieldValues = (updateFields.customFieldsUi as IDataObject).customFieldValues as IDataObject[];
const customFieldValues = (updateFields.customFieldsUi as IDataObject)
.customFieldValues as IDataObject[];
if (customFieldValues) {
body.customFieldValues = customFieldValues;
delete body.customFieldsUi;
}
}
responseData = await getresponseApiRequest.call(this, 'POST', `/contacts/${contactId}`, body);
responseData = await getresponseApiRequest.call(
this,
'POST',
`/contacts/${contactId}`,
body,
);
}
}
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (responseData !== undefined) {
returnData.push(responseData as IDataObject);
}

View file

@ -1,7 +1,4 @@
import {
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
import {
IDataObject,
@ -14,10 +11,7 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
getresponseApiRequest,
getResponseApiRequestAllItems,
} from './GenericFunctions';
import { getresponseApiRequest, getResponseApiRequestAllItems } from './GenericFunctions';
export class GetResponseTrigger implements INodeType {
description: INodeTypeDescription = {
@ -39,9 +33,7 @@ export class GetResponseTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'apiKey',
],
authentication: ['apiKey'],
},
},
},
@ -50,9 +42,7 @@ export class GetResponseTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -120,7 +110,8 @@ export class GetResponseTrigger implements INodeType {
displayName: 'List Names or IDs',
name: 'listIds',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getLists',
},
@ -176,7 +167,9 @@ export class GetResponseTrigger implements INodeType {
if (data.url !== webhookUrl) {
if (deleteCurrentSubscription === false) {
throw new NodeApiError(this.getNode(), data, { message: `The webhook (${data.url}) is active in the account. Delete it manually or set the parameter "Delete Current Subscription" to true, and the node will delete it for you.` });
throw new NodeApiError(this.getNode(), data, {
message: `The webhook (${data.url}) is active in the account. Delete it manually or set the parameter "Delete Current Subscription" to true, and the node will delete it for you.`,
});
}
}
} catch (error) {
@ -195,10 +188,13 @@ export class GetResponseTrigger implements INodeType {
const body = {
url: webhookUrl,
actions: events.reduce((accumulator: { [key: string]: boolean }, currentValue: string) => {
accumulator[currentValue] = true;
return accumulator;
}, {}),
actions: events.reduce(
(accumulator: { [key: string]: boolean }, currentValue: string) => {
accumulator[currentValue] = true;
return accumulator;
},
{},
),
};
await getresponseApiRequest.call(this, 'POST', '/accounts/callbacks', body);
@ -226,9 +222,7 @@ export class GetResponseTrigger implements INodeType {
}
return {
workflowData: [
this.helpers.returnJsonArray(query),
],
workflowData: [this.helpers.returnJsonArray(query)],
};
}
}

View file

@ -1,6 +1,4 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
@ -9,14 +7,18 @@ import {
ILoadOptionsFunctions,
} from 'n8n-core';
import {
IDataObject,
JsonObject,
NodeApiError,
} from 'n8n-workflow';
export async function ghostApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise<any> { // tslint:disable-line:no-any
import { IDataObject, JsonObject, NodeApiError } from 'n8n-workflow';
export async function ghostApiRequest(
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const source = this.getNodeParameter('source', 0) as string;
let credentials;
@ -44,13 +46,21 @@ export async function ghostApiRequest(this: IHookFunctions | IExecuteFunctions |
try {
return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch(error) {
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
export async function ghostApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function ghostApiRequestAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -62,13 +72,12 @@ export async function ghostApiRequestAllItems(this: IHookFunctions | IExecuteFun
responseData = await ghostApiRequest.call(this, method, endpoint, body, query);
query.page = responseData.meta.pagination.next;
returnData.push.apply(returnData, responseData[propertyName]);
} while (
query.page !== null
);
} while (query.page !== null);
return returnData;
}
export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any
// tslint:disable-next-line:no-any
export function validateJSON(json: string | undefined): any {
let result;
try {
result = JSON.parse(json!);

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,16 +10,9 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
ghostApiRequest,
ghostApiRequestAllItems,
validateJSON,
} from './GenericFunctions';
import { ghostApiRequest, ghostApiRequestAllItems, validateJSON } from './GenericFunctions';
import {
postFields,
postOperations,
} from './PostDescription';
import { postFields, postOperations } from './PostDescription';
import moment from 'moment-timezone';
@ -45,9 +36,7 @@ export class Ghost implements INodeType {
required: true,
displayOptions: {
show: {
source: [
'adminApi',
],
source: ['adminApi'],
},
},
},
@ -56,9 +45,7 @@ export class Ghost implements INodeType {
required: true,
displayOptions: {
show: {
source: [
'contentApi',
],
source: ['contentApi'],
},
},
},
@ -99,21 +86,13 @@ export class Ghost implements INodeType {
],
};
methods = {
loadOptions: {
// Get all the authors to display them to user so that he can
// select them easily
async getAuthors(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getAuthors(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const users = await ghostApiRequestAllItems.call(
this,
'users',
'GET',
`/admin/users`,
);
const users = await ghostApiRequestAllItems.call(this, 'users', 'GET', `/admin/users`);
for (const user of users) {
returnData.push({
name: user.name,
@ -124,16 +103,9 @@ export class Ghost implements INodeType {
},
// Get all the tags to display them to user so that he can
// select them easily
async getTags(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const tags = await ghostApiRequestAllItems.call(
this,
'tags',
'GET',
`/admin/tags`,
);
const tags = await ghostApiRequestAllItems.call(this, 'tags', 'GET', `/admin/tags`);
for (const tag of tags) {
returnData.push({
name: tag.name,
@ -160,7 +132,6 @@ export class Ghost implements INodeType {
if (source === 'contentApi') {
if (resource === 'post') {
if (operation === 'get') {
const by = this.getNodeParameter('by', i) as string;
const identifier = this.getNodeParameter('identifier', i) as string;
@ -179,11 +150,9 @@ export class Ghost implements INodeType {
responseData = await ghostApiRequest.call(this, 'GET', endpoint, {}, qs);
returnData.push.apply(returnData, responseData.posts);
}
if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const options = this.getNodeParameter('options', i) as IDataObject;
@ -191,7 +160,14 @@ export class Ghost implements INodeType {
Object.assign(qs, options);
if (returnAll) {
responseData = await ghostApiRequestAllItems.call(this, 'posts', 'GET', '/content/posts', {} ,qs);
responseData = await ghostApiRequestAllItems.call(
this,
'posts',
'GET',
'/content/posts',
{},
qs,
);
} else {
qs.limit = this.getNodeParameter('limit', 0);
responseData = await ghostApiRequest.call(this, 'GET', '/content/posts', {}, qs);
@ -199,7 +175,6 @@ export class Ghost implements INodeType {
}
returnData.push.apply(returnData, responseData);
}
}
}
@ -207,7 +182,6 @@ export class Ghost implements INodeType {
if (source === 'adminApi') {
if (resource === 'post') {
if (operation === 'create') {
const title = this.getNodeParameter('title', i) as string;
const contentFormat = this.getNodeParameter('contentFormat', i) as string;
@ -226,7 +200,9 @@ export class Ghost implements INodeType {
} else {
const mobileDoc = validateJSON(content);
if (mobileDoc === undefined) {
throw new NodeOperationError(this.getNode(), 'Content must be a valid JSON', { itemIndex: i });
throw new NodeOperationError(this.getNode(), 'Content must be a valid JSON', {
itemIndex: i,
});
}
post.mobiledoc = content;
}
@ -240,27 +216,33 @@ export class Ghost implements INodeType {
}
if (post.status === 'scheduled' && post.published_at === undefined) {
throw new NodeOperationError(this.getNode(), 'Published at must be define when status is scheduled', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'Published at must be define when status is scheduled',
{ itemIndex: i },
);
}
responseData = await ghostApiRequest.call(this, 'POST', '/admin/posts', { posts: [post] }, qs);
responseData = await ghostApiRequest.call(
this,
'POST',
'/admin/posts',
{ posts: [post] },
qs,
);
returnData.push.apply(returnData, responseData.posts);
}
if (operation === 'delete') {
const postId = this.getNodeParameter('postId', i) as string;
responseData = await ghostApiRequest.call(this, 'DELETE', `/admin/posts/${postId}`);
returnData.push({ success: true });
}
if (operation === 'get') {
const by = this.getNodeParameter('by', i) as string;
const identifier = this.getNodeParameter('identifier', i) as string;
@ -279,12 +261,9 @@ export class Ghost implements INodeType {
responseData = await ghostApiRequest.call(this, 'GET', endpoint, {}, qs);
returnData.push.apply(returnData, responseData.posts);
}
if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const options = this.getNodeParameter('options', i) as IDataObject;
@ -292,7 +271,14 @@ export class Ghost implements INodeType {
Object.assign(qs, options);
if (returnAll) {
responseData = await ghostApiRequestAllItems.call(this, 'posts', 'GET', '/admin/posts', {} ,qs);
responseData = await ghostApiRequestAllItems.call(
this,
'posts',
'GET',
'/admin/posts',
{},
qs,
);
} else {
qs.limit = this.getNodeParameter('limit', 0);
responseData = await ghostApiRequest.call(this, 'GET', '/admin/posts', {}, qs);
@ -300,11 +286,9 @@ export class Ghost implements INodeType {
}
returnData.push.apply(returnData, responseData);
}
if (operation === 'update') {
const postId = this.getNodeParameter('postId', i) as string;
const contentFormat = this.getNodeParameter('contentFormat', i) as string;
@ -318,9 +302,11 @@ export class Ghost implements INodeType {
qs.source = 'html';
delete updateFields.content;
} else {
const mobileDoc = validateJSON(updateFields.contentJson as string || undefined);
const mobileDoc = validateJSON((updateFields.contentJson as string) || undefined);
if (mobileDoc === undefined) {
throw new NodeOperationError(this.getNode(), 'Content must be a valid JSON', { itemIndex: i });
throw new NodeOperationError(this.getNode(), 'Content must be a valid JSON', {
itemIndex: i,
});
}
post.mobiledoc = updateFields.contentJson;
delete updateFields.contentJson;
@ -328,22 +314,37 @@ export class Ghost implements INodeType {
Object.assign(post, updateFields);
const { posts } = await ghostApiRequest.call(this, 'GET', `/admin/posts/${postId}`, {}, { fields: 'id, updated_at' });
const { posts } = await ghostApiRequest.call(
this,
'GET',
`/admin/posts/${postId}`,
{},
{ fields: 'id, updated_at' },
);
if (post.published_at) {
post.published_at = moment.tz(post.published_at, timezone).utc().format();
}
if (post.status === 'scheduled' && post.published_at === undefined) {
throw new NodeOperationError(this.getNode(), 'Published at must be define when status is scheduled', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'Published at must be define when status is scheduled',
{ itemIndex: i },
);
}
post.updated_at = posts[0].updated_at;
responseData = await ghostApiRequest.call(this, 'PUT', `/admin/posts/${postId}`, { posts: [post] }, qs);
responseData = await ghostApiRequest.call(
this,
'PUT',
`/admin/posts/${postId}`,
{ posts: [post] },
qs,
);
returnData.push.apply(returnData, responseData.posts);
}
}
}

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const postOperations: INodeProperties[] = [
{
@ -10,12 +8,8 @@ export const postOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
source: [
'contentApi',
],
resource: [
'post',
],
source: ['contentApi'],
resource: ['post'],
},
},
options: [
@ -41,12 +35,8 @@ export const postOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
source: ['adminApi'],
resource: ['post'],
},
},
options: [
@ -97,18 +87,12 @@ export const postFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'create',
],
source: ['adminApi'],
resource: ['post'],
operation: ['create'],
},
},
description: 'Post\'s title',
description: "Post's title",
},
{
displayName: 'Content Format',
@ -116,15 +100,9 @@ export const postFields: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'create',
],
source: ['adminApi'],
resource: ['post'],
operation: ['create'],
},
},
options: [
@ -149,18 +127,10 @@ export const postFields: INodeProperties[] = [
},
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'create',
],
contentFormat: [
'html',
],
source: ['adminApi'],
resource: ['post'],
operation: ['create'],
contentFormat: ['html'],
},
},
default: '',
@ -172,23 +142,16 @@ export const postFields: INodeProperties[] = [
type: 'json',
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'create',
],
contentFormat: [
'mobileDoc',
],
source: ['adminApi'],
resource: ['post'],
operation: ['create'],
contentFormat: ['mobileDoc'],
},
},
default: '',
description: 'Mobiledoc is the raw JSON format that Ghost uses to store post contents. <a href="https://ghost.org/docs/concepts/posts/#document-storage">Info</a>.',
description:
'Mobiledoc is the raw JSON format that Ghost uses to store post contents. <a href="https://ghost.org/docs/concepts/posts/#document-storage">Info</a>.',
},
{
displayName: 'Additional Fields',
@ -198,15 +161,9 @@ export const postFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'create',
],
source: ['adminApi'],
resource: ['post'],
operation: ['create'],
},
},
options: [
@ -214,7 +171,8 @@ export const postFields: INodeProperties[] = [
displayName: 'Author Names or IDs',
name: 'authors',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getAuthors',
},
@ -270,7 +228,6 @@ export const postFields: INodeProperties[] = [
type: 'string',
default: '',
description: 'URL of the image',
},
{
displayName: 'Open Graph Title',
@ -314,7 +271,8 @@ export const postFields: INodeProperties[] = [
displayName: 'Tag Names or IDs',
name: 'tags',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTags',
},
@ -353,15 +311,9 @@ export const postFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'delete',
],
source: ['adminApi'],
resource: ['post'],
operation: ['delete'],
},
},
description: 'The ID of the post to delete',
@ -388,16 +340,9 @@ export const postFields: INodeProperties[] = [
],
displayOptions: {
show: {
source: [
'contentApi',
'adminApi',
],
resource: [
'post',
],
operation: [
'get',
],
source: ['contentApi', 'adminApi'],
resource: ['post'],
operation: ['get'],
},
},
description: 'Get the post either by slug or ID',
@ -410,16 +355,9 @@ export const postFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
source: [
'contentApi',
'adminApi',
],
resource: [
'post',
],
operation: [
'get',
],
source: ['contentApi', 'adminApi'],
resource: ['post'],
operation: ['get'],
},
},
description: 'The ID or slug of the post to get',
@ -432,15 +370,9 @@ export const postFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'get',
],
source: ['adminApi'],
resource: ['post'],
operation: ['get'],
},
},
options: [
@ -450,7 +382,8 @@ export const postFields: INodeProperties[] = [
type: 'string',
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-url
description: 'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
description:
'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
},
{
displayName: 'Formats',
@ -466,9 +399,7 @@ export const postFields: INodeProperties[] = [
value: 'mobiledoc',
},
],
default: [
'mobiledoc',
],
default: ['mobiledoc'],
},
],
},
@ -480,15 +411,9 @@ export const postFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
source: [
'contentApi',
],
resource: [
'post',
],
operation: [
'get',
],
source: ['contentApi'],
resource: ['post'],
operation: ['get'],
},
},
options: [
@ -498,7 +423,8 @@ export const postFields: INodeProperties[] = [
type: 'string',
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-url
description: 'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
description:
'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
},
{
displayName: 'Formats',
@ -514,9 +440,7 @@ export const postFields: INodeProperties[] = [
value: 'plaintext',
},
],
default: [
'html',
],
default: ['html'],
},
],
},
@ -530,16 +454,9 @@ export const postFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
source: [
'contentApi',
'adminApi',
],
resource: [
'post',
],
operation: [
'getAll',
],
source: ['contentApi', 'adminApi'],
resource: ['post'],
operation: ['getAll'],
},
},
default: false,
@ -551,19 +468,10 @@ export const postFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
source: [
'adminApi',
'contentApi',
],
resource: [
'post',
],
operation: [
'getAll',
],
returnAll: [
false,
],
source: ['adminApi', 'contentApi'],
resource: ['post'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
@ -581,15 +489,9 @@ export const postFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
source: [
'contentApi',
],
resource: [
'post',
],
operation: [
'getAll',
],
source: ['contentApi'],
resource: ['post'],
operation: ['getAll'],
},
},
options: [
@ -608,7 +510,8 @@ export const postFields: INodeProperties[] = [
},
],
default: [],
description: 'Tells the API to return additional data related to the resource you have requested',
description:
'Tells the API to return additional data related to the resource you have requested',
},
{
displayName: 'Fields',
@ -616,7 +519,8 @@ export const postFields: INodeProperties[] = [
type: 'string',
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-url
description: 'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
description:
'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
},
{
displayName: 'Formats',
@ -632,10 +536,9 @@ export const postFields: INodeProperties[] = [
value: 'plaintext',
},
],
default: [
'html',
],
description: 'By default, only html is returned, however each post and page in Ghost has 2 available formats: html and plaintext',
default: ['html'],
description:
'By default, only html is returned, however each post and page in Ghost has 2 available formats: html and plaintext',
},
],
},
@ -647,15 +550,9 @@ export const postFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'getAll',
],
source: ['adminApi'],
resource: ['post'],
operation: ['getAll'],
},
},
options: [
@ -674,7 +571,8 @@ export const postFields: INodeProperties[] = [
},
],
default: [],
description: 'Tells the API to return additional data related to the resource you have requested',
description:
'Tells the API to return additional data related to the resource you have requested',
},
{
displayName: 'Fields',
@ -682,7 +580,8 @@ export const postFields: INodeProperties[] = [
type: 'string',
default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-url
description: 'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
description:
'Limit the fields returned in the response object. E.g. for posts fields=title,url.',
},
{
displayName: 'Formats',
@ -698,9 +597,7 @@ export const postFields: INodeProperties[] = [
value: 'mobiledoc',
},
],
default: [
'mobiledoc',
],
default: ['mobiledoc'],
},
],
},
@ -714,15 +611,9 @@ export const postFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'update',
],
source: ['adminApi'],
resource: ['post'],
operation: ['update'],
},
},
default: '',
@ -734,15 +625,9 @@ export const postFields: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'update',
],
source: ['adminApi'],
resource: ['post'],
operation: ['update'],
},
},
options: [
@ -766,15 +651,9 @@ export const postFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
source: [
'adminApi',
],
resource: [
'post',
],
operation: [
'update',
],
source: ['adminApi'],
resource: ['post'],
operation: ['update'],
},
},
options: [
@ -782,7 +661,8 @@ export const postFields: INodeProperties[] = [
displayName: 'Author Names or IDs',
name: 'authors',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getAuthors',
},
@ -812,9 +692,7 @@ export const postFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
'/contentFormat': [
'html',
],
'/contentFormat': ['html'],
},
},
typeOptions: {
@ -828,13 +706,12 @@ export const postFields: INodeProperties[] = [
type: 'json',
displayOptions: {
show: {
'/contentFormat': [
'mobileDoc',
],
'/contentFormat': ['mobileDoc'],
},
},
default: '',
description: 'Mobiledoc is the raw JSON format that Ghost uses to store post contents. <a href="https://ghost.org/docs/concepts/posts/#document-storage">Info.</a>.',
description:
'Mobiledoc is the raw JSON format that Ghost uses to store post contents. <a href="https://ghost.org/docs/concepts/posts/#document-storage">Info.</a>.',
},
{
displayName: 'Featured',
@ -909,7 +786,8 @@ export const postFields: INodeProperties[] = [
displayName: 'Tag Names or IDs',
name: 'tags',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTags',
},
@ -920,7 +798,7 @@ export const postFields: INodeProperties[] = [
name: 'title',
type: 'string',
default: '',
description: 'Post\'s title',
description: "Post's title",
},
{
displayName: 'Twitter Description',

View file

@ -1,10 +1,5 @@
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
import {
addConfigFields,
@ -16,16 +11,9 @@ import {
tagFields,
} from './descriptions';
import simpleGit, {
LogOptions,
SimpleGit,
SimpleGitOptions,
} from 'simple-git';
import simpleGit, { LogOptions, SimpleGit, SimpleGitOptions } from 'simple-git';
import {
access,
mkdir,
} from 'fs/promises';
import { access, mkdir } from 'fs/promises';
import { URL } from 'url';
@ -48,9 +36,7 @@ export class Git implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'gitPassword',
],
authentication: ['gitPassword'],
},
},
},
@ -72,10 +58,7 @@ export class Git implements INodeType {
],
displayOptions: {
show: {
operation: [
'clone',
'push',
],
operation: ['clone', 'push'],
},
},
default: 'none',
@ -175,9 +158,7 @@ export class Git implements INodeType {
type: 'string',
displayOptions: {
hide: {
operation: [
'clone',
],
operation: ['clone'],
},
},
default: '',
@ -191,9 +172,7 @@ export class Git implements INodeType {
type: 'string',
displayOptions: {
show: {
operation: [
'clone',
],
operation: ['clone'],
},
},
default: '',
@ -213,11 +192,9 @@ export class Git implements INodeType {
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const prepareRepository = async (repositoryPath: string): Promise<string> => {
const authentication = this.getNodeParameter('authentication', 0) as string;
@ -280,7 +257,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'addConfig') {
// ----------------------------------
// addConfig
@ -303,7 +279,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'clone') {
// ----------------------------------
// clone
@ -322,7 +297,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'commit') {
// ----------------------------------
// commit
@ -345,7 +319,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'fetch') {
// ----------------------------------
// fetch
@ -360,7 +333,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'log') {
// ----------------------------------
// log
@ -378,14 +350,15 @@ export class Git implements INodeType {
const log = await git.log(logOptions);
// @ts-ignore
returnItems.push(...this.helpers.returnJsonArray(log.all).map(item => {
return {
...item,
pairedItem: { item: itemIndex },
};
}));
returnItems.push(
// @ts-ignore
...this.helpers.returnJsonArray(log.all).map((item) => {
return {
...item,
pairedItem: { item: itemIndex },
};
}),
);
} else if (operation === 'pull') {
// ----------------------------------
// pull
@ -400,7 +373,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'push') {
// ----------------------------------
// push
@ -438,7 +410,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'pushTags') {
// ----------------------------------
// pushTags
@ -453,7 +424,6 @@ export class Git implements INodeType {
item: itemIndex,
},
});
} else if (operation === 'listConfig') {
// ----------------------------------
// listConfig
@ -470,13 +440,14 @@ export class Git implements INodeType {
}
// @ts-ignore
returnItems.push(...this.helpers.returnJsonArray(data).map(item => {
return {
...item,
pairedItem: { item: itemIndex },
};
}));
returnItems.push(
...this.helpers.returnJsonArray(data).map((item) => {
return {
...item,
pairedItem: { item: itemIndex },
};
}),
);
} else if (operation === 'status') {
// ----------------------------------
// status
@ -484,14 +455,15 @@ export class Git implements INodeType {
const status = await git.status();
// @ts-ignore
returnItems.push(...this.helpers.returnJsonArray([status]).map(item => {
return {
...item,
pairedItem: { item: itemIndex },
};
}));
returnItems.push(
// @ts-ignore
...this.helpers.returnJsonArray([status]).map((item) => {
return {
...item,
pairedItem: { item: itemIndex },
};
}),
);
} else if (operation === 'tag') {
// ----------------------------------
// tag
@ -509,9 +481,7 @@ export class Git implements INodeType {
},
});
}
} catch (error) {
if (this.continueOnFail()) {
returnItems.push({
json: {

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const addConfigFields: INodeProperties[] = [
{
@ -9,9 +7,7 @@ export const addConfigFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'addConfig',
],
operation: ['addConfig'],
},
},
default: '',
@ -25,9 +21,7 @@ export const addConfigFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'addConfig',
],
operation: ['addConfig'],
},
},
default: '',
@ -41,9 +35,7 @@ export const addConfigFields: INodeProperties[] = [
type: 'collection',
displayOptions: {
show: {
operation: [
'addConfig',
],
operation: ['addConfig'],
},
},
placeholder: 'Add Option',

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const addFields: INodeProperties[] = [
{
@ -9,14 +7,13 @@ export const addFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'add',
],
operation: ['add'],
},
},
default: '',
placeholder: 'README.md',
description: 'Comma-separated list of paths (absolute or relative to Repository Path) of files or folders to add',
description:
'Comma-separated list of paths (absolute or relative to Repository Path) of files or folders to add',
required: true,
},
];

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const cloneFields: INodeProperties[] = [
{
@ -9,9 +7,7 @@ export const cloneFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'clone',
],
operation: ['clone'],
},
},
default: '',

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const commitFields: INodeProperties[] = [
{
@ -9,9 +7,7 @@ export const commitFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'commit',
],
operation: ['commit'],
},
},
default: '',
@ -23,9 +19,7 @@ export const commitFields: INodeProperties[] = [
type: 'collection',
displayOptions: {
show: {
operation: [
'commit',
],
operation: ['commit'],
},
},
placeholder: 'Add Option',
@ -37,7 +31,8 @@ export const commitFields: INodeProperties[] = [
type: 'string',
default: '',
placeholder: '/data/file1.json',
description: 'Comma-separated list of paths (absolute or relative to Repository Path) of files or folders to commit. If not set will all "added" files and folders be committed.',
description:
'Comma-separated list of paths (absolute or relative to Repository Path) of files or folders to commit. If not set will all "added" files and folders be committed.',
},
],
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const logFields: INodeProperties[] = [
{
@ -9,9 +7,7 @@ export const logFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'log',
],
operation: ['log'],
},
},
default: false,
@ -23,12 +19,8 @@ export const logFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'log',
],
returnAll: [
false,
],
operation: ['log'],
returnAll: [false],
},
},
typeOptions: {
@ -44,9 +36,7 @@ export const logFields: INodeProperties[] = [
type: 'collection',
displayOptions: {
show: {
operation: [
'log',
],
operation: ['log'],
},
},
placeholder: 'Add Option',
@ -57,7 +47,8 @@ export const logFields: INodeProperties[] = [
name: 'file',
type: 'string',
default: 'README.md',
description: 'The path (absolute or relative to Repository Path) of file or folder to get the history of',
description:
'The path (absolute or relative to Repository Path) of file or folder to get the history of',
},
],
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const pushFields: INodeProperties[] = [
{
@ -9,9 +7,7 @@ export const pushFields: INodeProperties[] = [
type: 'collection',
displayOptions: {
show: {
operation: [
'push',
],
operation: ['push'],
},
},
placeholder: 'Add Option',

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const tagFields: INodeProperties[] = [
{
@ -9,9 +7,7 @@ export const tagFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'tag',
],
operation: ['tag'],
},
},
default: '',

View file

@ -1,13 +1,8 @@
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IHookFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IHookFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
/**
* Make an API request to Github
@ -18,8 +13,15 @@ import {
* @param {object} body
* @returns {Promise<any>}
*/
export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: object, query?: object, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function githubApiRequest(
this: IHookFunctions | IExecuteFunctions,
method: string,
endpoint: string,
body: object,
query?: object,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
method,
headers: {
@ -36,7 +38,11 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions,
}
try {
const authenticationMethod = this.getNodeParameter('authentication', 0, 'accessToken') as string;
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'accessToken',
) as string;
let credentialType = '';
if (authenticationMethod === 'accessToken') {
@ -59,8 +65,6 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions,
}
}
/**
* Returns the SHA of the given file
*
@ -72,7 +76,14 @@ export async function githubApiRequest(this: IHookFunctions | IExecuteFunctions,
* @param {string} [branch]
* @returns {Promise<any>}
*/
export async function getFileSha(this: IHookFunctions | IExecuteFunctions, owner: string, repository: string, filePath: string, branch?: string): Promise<any> { // tslint:disable-line:no-any
export async function getFileSha(
this: IHookFunctions | IExecuteFunctions,
owner: string,
repository: string,
filePath: string,
branch?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const getBody: IDataObject = {};
if (branch !== undefined) {
getBody.branch = branch;
@ -86,8 +97,15 @@ export async function getFileSha(this: IHookFunctions | IExecuteFunctions, owner
return responseData.sha;
}
export async function githubApiRequestAllItems(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function githubApiRequestAllItems(
this: IHookFunctions | IExecuteFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -96,11 +114,11 @@ export async function githubApiRequestAllItems(this: IHookFunctions | IExecuteFu
query.page = 1;
do {
responseData = await githubApiRequest.call(this, method, endpoint, body, query, { resolveWithFullResponse: true });
responseData = await githubApiRequest.call(this, method, endpoint, body, query, {
resolveWithFullResponse: true,
});
query.page++;
returnData.push.apply(returnData, responseData.body);
} while (
responseData.headers.link && responseData.headers.link.includes('next')
);
} while (responseData.headers.link && responseData.headers.link.includes('next'));
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -10,15 +8,9 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
getFileSha,
githubApiRequest,
githubApiRequestAllItems,
} from './GenericFunctions';
import { getFileSha, githubApiRequest, githubApiRequestAllItems } from './GenericFunctions';
import {
snakeCase,
} from 'change-case';
import { snakeCase } from 'change-case';
export class Github implements INodeType {
description: INodeTypeDescription = {
@ -249,7 +241,8 @@ export class Github implements INodeType {
{
name: 'Get License',
value: 'getLicense',
description: 'Returns the contents of the repository\'s license file, if one is detected',
description:
"Returns the contents of the repository's license file, if one is detected",
action: 'Get the license of a repository',
},
{
@ -290,7 +283,7 @@ export class Github implements INodeType {
name: 'Get Repositories',
value: 'getRepositories',
description: 'Returns the repositories of a user',
action: 'Get a user\'s repositories',
action: "Get a user's repositories",
},
{
name: 'Invite',
@ -1026,8 +1019,7 @@ export class Github implements INodeType {
name: 'prerelease',
type: 'boolean',
default: false,
description:
'Whether to point out that the release is non-production ready',
description: 'Whether to point out that the release is non-production ready',
},
{
displayName: 'Target Commitish',
@ -1035,7 +1027,7 @@ export class Github implements INodeType {
type: 'string',
default: '',
description:
'Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository\'s default branch(usually master).',
"Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository's default branch(usually master).",
},
],
},
@ -1105,8 +1097,7 @@ export class Github implements INodeType {
name: 'prerelease',
type: 'boolean',
default: false,
description:
'Whether to point out that the release is non-production ready',
description: 'Whether to point out that the release is non-production ready',
},
{
displayName: 'Tag Name',
@ -1121,7 +1112,7 @@ export class Github implements INodeType {
type: 'string',
default: '',
description:
'Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository\'s default branch(usually master).',
"Specifies the commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Unused if the Git tag already exists. Default: the repository's default branch(usually master).",
},
],
},
@ -1741,7 +1732,9 @@ export class Github implements INodeType {
const item = items[i];
if (item.binary === undefined) {
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', { itemIndex: i });
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', {
itemIndex: i,
});
}
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i) as string;
@ -2104,7 +2097,9 @@ export class Github implements INodeType {
}
}
} else {
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`, { itemIndex: i });
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`, {
itemIndex: i,
});
}
if (returnAll === true) {
@ -2124,7 +2119,9 @@ export class Github implements INodeType {
if (asBinaryProperty === true) {
if (Array.isArray(responseData)) {
throw new NodeOperationError(this.getNode(), 'File Path is a folder, not a file.', { itemIndex: i });
throw new NodeOperationError(this.getNode(), 'File Path is a folder, not a file.', {
itemIndex: i,
});
}
// Add the returned data to the item as binary property
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i) as string;

View file

@ -1,7 +1,4 @@
import {
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,10 +9,7 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
githubApiRequest,
} from './GenericFunctions';
import { githubApiRequest } from './GenericFunctions';
export class GithubTrigger implements INodeType {
description: INodeTypeDescription = {
@ -24,7 +18,8 @@ export class GithubTrigger implements INodeType {
icon: 'file:github.svg',
group: ['trigger'],
version: 1,
subtitle: '={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}',
subtitle:
'={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}',
description: 'Starts the workflow when Github events occur',
defaults: {
name: 'Github Trigger',
@ -37,9 +32,7 @@ export class GithubTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'accessToken',
],
authentication: ['accessToken'],
},
},
},
@ -48,9 +41,7 @@ export class GithubTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -111,7 +102,8 @@ export class GithubTrigger implements INodeType {
{
name: 'Check Run',
value: 'check_run',
description: 'Triggered when a check run is created, rerequested, completed, or has a requested_action',
description:
'Triggered when a check run is created, rerequested, completed, or has a requested_action',
},
{
name: 'Check Suite',
@ -126,7 +118,8 @@ export class GithubTrigger implements INodeType {
{
name: 'Content Reference',
value: 'content_reference',
description: 'Triggered when the body or comment of an issue or pull request includes a URL that matches a configured content reference domain. Only GitHub Apps can receive this event.',
description:
'Triggered when the body or comment of an issue or pull request includes a URL that matches a configured content reference domain. Only GitHub Apps can receive this event.',
},
{
name: 'Create',
@ -171,7 +164,8 @@ export class GithubTrigger implements INodeType {
{
name: 'Installation',
value: 'installation',
description: 'Triggered when someone installs (created), uninstalls (deleted), or accepts new permissions (new_permissions_accepted) for a GitHub App. When a GitHub App owner requests new permissions, the person who installed the GitHub App must accept the new permissions request.',
description:
'Triggered when someone installs (created), uninstalls (deleted), or accepts new permissions (new_permissions_accepted) for a GitHub App. When a GitHub App owner requests new permissions, the person who installed the GitHub App must accept the new permissions request.',
},
{
name: 'Installation Repositories',
@ -186,27 +180,31 @@ export class GithubTrigger implements INodeType {
{
name: 'Issues',
value: 'issues',
description: 'Triggered when an issue is opened, edited, deleted, transferred, pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, locked, unlocked, milestoned, or demilestoned',
description:
'Triggered when an issue is opened, edited, deleted, transferred, pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, locked, unlocked, milestoned, or demilestoned',
},
{
name: 'Label',
value: 'label',
description: 'Triggered when a repository\'s label is created, edited, or deleted',
description: "Triggered when a repository's label is created, edited, or deleted",
},
{
name: 'Marketplace Purchase',
value: 'marketplace_purchase',
description: 'Triggered when someone purchases a GitHub Marketplace plan, cancels their plan, upgrades their plan (effective immediately), downgrades a plan that remains pending until the end of the billing cycle, or cancels a pending plan change',
description:
'Triggered when someone purchases a GitHub Marketplace plan, cancels their plan, upgrades their plan (effective immediately), downgrades a plan that remains pending until the end of the billing cycle, or cancels a pending plan change',
},
{
name: 'Member',
value: 'member',
description: 'Triggered when a user accepts an invitation or is removed as a collaborator to a repository, or has their permissions changed',
description:
'Triggered when a user accepts an invitation or is removed as a collaborator to a repository, or has their permissions changed',
},
{
name: 'Membership',
value: 'membership',
description: 'Triggered when a user is added or removed from a team. Organization hooks only.',
description:
'Triggered when a user is added or removed from a team. Organization hooks only.',
},
{
name: 'Meta',
@ -216,32 +214,38 @@ export class GithubTrigger implements INodeType {
{
name: 'Milestone',
value: 'milestone',
description: 'Triggered when a milestone is created, closed, opened, edited, or deleted',
description:
'Triggered when a milestone is created, closed, opened, edited, or deleted',
},
{
name: 'Org Block',
value: 'org_block',
description: 'Triggered when an organization blocks or unblocks a user. Organization hooks only.',
description:
'Triggered when an organization blocks or unblocks a user. Organization hooks only.',
},
{
name: 'Organization',
value: 'organization',
description: 'Triggered when an organization is deleted and renamed, and when a user is added, removed, or invited to an organization. Organization hooks only.',
description:
'Triggered when an organization is deleted and renamed, and when a user is added, removed, or invited to an organization. Organization hooks only.',
},
{
name: 'Page Build',
value: 'page_build',
description: 'Triggered on push to a GitHub Pages enabled branch (gh-pages for project pages, master for user and organization pages)',
description:
'Triggered on push to a GitHub Pages enabled branch (gh-pages for project pages, master for user and organization pages)',
},
{
name: 'Project',
value: 'project',
description: 'Triggered when a project is created, updated, closed, reopened, or deleted',
description:
'Triggered when a project is created, updated, closed, reopened, or deleted',
},
{
name: 'Project Card',
value: 'project_card',
description: 'Triggered when a project card is created, edited, moved, converted to an issue, or deleted',
description:
'Triggered when a project card is created, edited, moved, converted to an issue, or deleted',
},
{
name: 'Project Column',
@ -256,37 +260,44 @@ export class GithubTrigger implements INodeType {
{
name: 'Pull Request',
value: 'pull_request',
description: 'Triggered when a pull request is assigned, unassigned, labeled, unlabeled, opened, edited, closed, reopened, synchronize, ready_for_review, locked, unlocked, a pull request review is requested, or a review request is removed',
description:
'Triggered when a pull request is assigned, unassigned, labeled, unlabeled, opened, edited, closed, reopened, synchronize, ready_for_review, locked, unlocked, a pull request review is requested, or a review request is removed',
},
{
name: 'Pull Request Review',
value: 'pull_request_review',
description: 'Triggered when a pull request review is submitted into a non-pending state, the body is edited, or the review is dismissed',
description:
'Triggered when a pull request review is submitted into a non-pending state, the body is edited, or the review is dismissed',
},
{
name: 'Pull Request Review Comment',
value: 'pull_request_review_comment',
description: 'Triggered when a comment on a pull request\'s unified diff is created, edited, or deleted (in the Files Changed tab)',
description:
"Triggered when a comment on a pull request's unified diff is created, edited, or deleted (in the Files Changed tab)",
},
{
name: 'Push',
value: 'push',
description: 'Triggered on a push to a repository branch. Branch pushes and repository tag pushes also trigger webhook push events. This is the default event.',
description:
'Triggered on a push to a repository branch. Branch pushes and repository tag pushes also trigger webhook push events. This is the default event.',
},
{
name: 'Release',
value: 'release',
description: 'Triggered when a release is published, unpublished, created, edited, deleted, or prereleased',
description:
'Triggered when a release is published, unpublished, created, edited, deleted, or prereleased',
},
{
name: 'Repository',
value: 'repository',
description: 'Triggered when a repository is created, archived, unarchived, renamed, edited, transferred, made public, or made private. Organization hooks are also triggered when a repository is deleted.',
description:
'Triggered when a repository is created, archived, unarchived, renamed, edited, transferred, made public, or made private. Organization hooks are also triggered when a repository is deleted.',
},
{
name: 'Repository Import',
value: 'repository_import',
description: 'Triggered when a successful, cancelled, or failed repository import finishes for a GitHub organization or a personal repository',
description:
'Triggered when a successful, cancelled, or failed repository import finishes for a GitHub organization or a personal repository',
},
{
name: 'Repository Vulnerability Alert',
@ -296,7 +307,8 @@ export class GithubTrigger implements INodeType {
{
name: 'Security Advisory',
value: 'security_advisory',
description: 'Triggered when a new security advisory is published, updated, or withdrawn',
description:
'Triggered when a new security advisory is published, updated, or withdrawn',
},
{
name: 'Star',
@ -311,7 +323,8 @@ export class GithubTrigger implements INodeType {
{
name: 'Team',
value: 'team',
description: 'Triggered when an organization\'s team is created, deleted, edited, added_to_repository, or removed_from_repository. Organization hooks only.',
description:
"Triggered when an organization's team is created, deleted, edited, added_to_repository, or removed_from_repository. Organization hooks only.",
},
{
name: 'Team Add',
@ -369,7 +382,10 @@ export class GithubTrigger implements INodeType {
const webhookUrl = this.getNodeWebhookUrl('default') as string;
if (webhookUrl.includes('//localhost')) {
throw new NodeOperationError(this.getNode(), 'The Webhook can not work on "localhost". Please, either setup n8n on a custom domain or start with "--tunnel"!');
throw new NodeOperationError(
this.getNode(),
'The Webhook can not work on "localhost". Please, either setup n8n on a custom domain or start with "--tunnel"!',
);
}
const owner = this.getNodeParameter('owner') as string;
@ -415,7 +431,10 @@ export class GithubTrigger implements INodeType {
}
}
throw new NodeOperationError(this.getNode(), 'A webhook with the identical URL probably exists already. Please delete it manually on Github!');
throw new NodeOperationError(
this.getNode(),
'A webhook with the identical URL probably exists already. Please delete it manually on Github!',
);
}
throw error;
@ -423,7 +442,9 @@ export class GithubTrigger implements INodeType {
if (responseData.id === undefined || responseData.active !== true) {
// Required data is missing so was not successful
throw new NodeApiError(this.getNode(), responseData, { message: 'Github webhook creation response did not contain the expected data.' });
throw new NodeApiError(this.getNode(), responseData, {
message: 'Github webhook creation response did not contain the expected data.',
});
}
webhookData.webhookId = responseData.id as string;
@ -457,8 +478,6 @@ export class GithubTrigger implements INodeType {
},
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
@ -477,18 +496,14 @@ export class GithubTrigger implements INodeType {
// TODO: Add headers & requestPath
const returnData: IDataObject[] = [];
returnData.push(
{
body: bodyData,
headers: this.getHeaderData(),
query: this.getQueryData(),
},
);
returnData.push({
body: bodyData,
headers: this.getHeaderData(),
query: this.getQueryData(),
});
return {
workflowData: [
this.helpers.returnJsonArray(returnData),
],
workflowData: [this.helpers.returnJsonArray(returnData)],
};
}
}

View file

@ -1,11 +1,6 @@
import {
IExecuteFunctions,
IHookFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IHookFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import { OptionsWithUri } from 'request';
/**
@ -17,7 +12,15 @@ import { OptionsWithUri } from 'request';
* @param {object} body
* @returns {Promise<any>}
*/
export async function gitlabApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: object, query?: object, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function gitlabApiRequest(
this: IHookFunctions | IExecuteFunctions,
method: string,
endpoint: string,
body: object,
query?: object,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
method,
headers: {},
@ -53,8 +56,15 @@ export async function gitlabApiRequest(this: IHookFunctions | IExecuteFunctions,
}
}
export async function gitlabApiRequestAllItems(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function gitlabApiRequestAllItems(
this: IHookFunctions | IExecuteFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -63,11 +73,11 @@ export async function gitlabApiRequestAllItems(this: IHookFunctions | IExecuteFu
query.page = 1;
do {
responseData = await gitlabApiRequest.call(this, method, endpoint, body, query, { resolveWithFullResponse: true });
responseData = await gitlabApiRequest.call(this, method, endpoint, body, query, {
resolveWithFullResponse: true,
});
query.page++;
returnData.push.apply(returnData, responseData.body);
} while (
responseData.headers.link && responseData.headers.link.includes('next')
);
} while (responseData.headers.link && responseData.headers.link.includes('next'));
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -10,10 +8,7 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
gitlabApiRequest,
gitlabApiRequestAllItems,
} from './GenericFunctions';
import { gitlabApiRequest, gitlabApiRequestAllItems } from './GenericFunctions';
export class Gitlab implements INodeType {
description: INodeTypeDescription = {
@ -35,9 +30,7 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'accessToken',
],
authentication: ['accessToken'],
},
},
},
@ -46,9 +39,7 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -96,8 +87,6 @@ export class Gitlab implements INodeType {
default: 'issue',
},
// ----------------------------------
// operations
// ----------------------------------
@ -108,9 +97,7 @@ export class Gitlab implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'issue',
],
resource: ['issue'],
},
},
options: [
@ -155,9 +142,7 @@ export class Gitlab implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'repository',
],
resource: ['repository'],
},
},
options: [
@ -184,9 +169,7 @@ export class Gitlab implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'user',
],
resource: ['user'],
},
},
options: [
@ -194,7 +177,7 @@ export class Gitlab implements INodeType {
name: 'Get Repositories',
value: 'getRepositories',
description: 'Returns the repositories of a user',
action: 'Get a user\'s repositories',
action: "Get a user's repositories",
},
],
default: 'getRepositories',
@ -207,9 +190,7 @@ export class Gitlab implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'release',
],
resource: ['release'],
},
},
options: [
@ -247,8 +228,6 @@ export class Gitlab implements INodeType {
default: 'create',
},
// ----------------------------------
// shared
// ----------------------------------
@ -269,12 +248,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
hide: {
resource: [
'user',
],
operation: [
'getRepositories',
],
resource: ['user'],
operation: ['getRepositories'],
},
},
placeholder: 'n8n',
@ -296,12 +271,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'issue',
],
operation: ['create'],
resource: ['issue'],
},
},
description: 'The title of the issue',
@ -316,12 +287,8 @@ export class Gitlab implements INodeType {
default: '',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'issue',
],
operation: ['create'],
resource: ['issue'],
},
},
description: 'The body of the issue',
@ -332,12 +299,8 @@ export class Gitlab implements INodeType {
type: 'dateTime',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'issue',
],
operation: ['create'],
resource: ['issue'],
},
},
default: '',
@ -353,15 +316,11 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'issue',
],
operation: ['create'],
resource: ['issue'],
},
},
default: { 'label': '' },
default: { label: '' },
options: [
{
displayName: 'Label',
@ -382,15 +341,11 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'issue',
],
operation: ['create'],
resource: ['issue'],
},
},
default: { 'assignee': '' },
default: { assignee: '' },
options: [
{
displayName: 'Assignee',
@ -402,7 +357,6 @@ export class Gitlab implements INodeType {
],
},
// ----------------------------------
// issue:createComment
// ----------------------------------
@ -414,12 +368,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'createComment',
],
resource: [
'issue',
],
operation: ['createComment'],
resource: ['issue'],
},
},
description: 'The number of the issue on which to create the comment on',
@ -433,12 +383,8 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'createComment',
],
resource: [
'issue',
],
operation: ['createComment'],
resource: ['issue'],
},
},
default: '',
@ -456,12 +402,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'edit',
],
resource: [
'issue',
],
operation: ['edit'],
resource: ['issue'],
},
},
description: 'The number of the issue edit',
@ -475,12 +417,8 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'edit',
],
resource: [
'issue',
],
operation: ['edit'],
resource: ['issue'],
},
},
default: {},
@ -529,7 +467,7 @@ export class Gitlab implements INodeType {
multipleValues: true,
multipleValueButtonText: 'Add Label',
},
default: { 'label': '' },
default: { label: '' },
options: [
{
displayName: 'Label',
@ -548,7 +486,7 @@ export class Gitlab implements INodeType {
multipleValues: true,
multipleValueButtonText: 'Add Assignee',
},
default: { 'assignee': '' },
default: { assignee: '' },
options: [
{
displayName: 'Assignees',
@ -580,12 +518,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'issue',
],
operation: ['get'],
resource: ['issue'],
},
},
description: 'The number of the issue get data of',
@ -602,12 +536,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'lock',
],
resource: [
'issue',
],
operation: ['lock'],
resource: ['issue'],
},
},
description: 'The number of the issue to lock',
@ -618,12 +548,8 @@ export class Gitlab implements INodeType {
type: 'options',
displayOptions: {
show: {
operation: [
'lock',
],
resource: [
'issue',
],
operation: ['lock'],
resource: ['issue'],
},
},
options: [
@ -652,8 +578,6 @@ export class Gitlab implements INodeType {
description: 'The reason to lock the issue',
},
// ----------------------------------
// release
// ----------------------------------
@ -669,12 +593,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'release',
],
operation: ['create'],
resource: ['release'],
},
},
description: 'The tag of the release',
@ -688,12 +608,8 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'release',
],
operation: ['create'],
resource: ['release'],
},
},
default: {},
@ -720,7 +636,8 @@ export class Gitlab implements INodeType {
name: 'ref',
type: 'string',
default: '',
description: 'If Tag doesnt exist, the release will be created from Ref. It can be a commit SHA, another tag name, or a branch name.',
description:
'If Tag doesnt exist, the release will be created from Ref. It can be a commit SHA, another tag name, or a branch name.',
},
],
},
@ -736,13 +653,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'delete',
'get',
],
resource: [
'release',
],
operation: ['delete', 'get'],
resource: ['release'],
},
},
description: 'The ID or URL-encoded path of the project',
@ -755,13 +667,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'delete',
'get',
],
resource: [
'release',
],
operation: ['delete', 'get'],
resource: ['release'],
},
},
description: 'The Git tag the release is associated with',
@ -778,12 +685,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'release',
],
operation: ['getAll'],
resource: ['release'],
},
},
description: 'The ID or URL-encoded path of the project',
@ -794,12 +697,8 @@ export class Gitlab implements INodeType {
type: 'boolean',
displayOptions: {
show: {
resource: [
'release',
],
operation: [
'getAll',
],
resource: ['release'],
operation: ['getAll'],
},
},
default: false,
@ -811,15 +710,9 @@ export class Gitlab implements INodeType {
type: 'number',
displayOptions: {
show: {
resource: [
'release',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['release'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
@ -838,12 +731,8 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'release',
],
operation: ['getAll'],
resource: ['release'],
},
},
default: {},
@ -896,12 +785,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'release',
],
operation: ['update'],
resource: ['release'],
},
},
description: 'The ID or URL-encoded path of the project',
@ -914,12 +799,8 @@ export class Gitlab implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'release',
],
operation: ['update'],
resource: ['release'],
},
},
description: 'The Git tag the release is associated with',
@ -933,12 +814,8 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'release',
],
operation: ['update'],
resource: ['release'],
},
},
default: {},
@ -962,7 +839,8 @@ export class Gitlab implements INodeType {
name: 'milestones',
type: 'string',
default: '',
description: 'The title of each milestone to associate with the release (provide a titles list spearated with comma)',
description:
'The title of each milestone to associate with the release (provide a titles list spearated with comma)',
},
{
displayName: 'Released At',
@ -989,12 +867,8 @@ export class Gitlab implements INodeType {
},
displayOptions: {
show: {
operation: [
'getIssues',
],
resource: [
'repository',
],
operation: ['getIssues'],
resource: ['repository'],
},
},
default: {},
@ -1018,7 +892,8 @@ export class Gitlab implements INodeType {
name: 'labels',
type: 'string',
default: '',
description: 'Return only issues with the given labels. Multiple lables can be separated by comma.',
description:
'Return only issues with the given labels. Multiple lables can be separated by comma.',
},
{
displayName: 'Updated After',
@ -1094,14 +969,11 @@ export class Gitlab implements INodeType {
default: 'desc',
description: 'The sort order',
},
],
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
@ -1223,7 +1095,9 @@ export class Gitlab implements INodeType {
body.labels = (body.labels as IDataObject[]).map((data) => data['label']).join(',');
}
if (body.assignee_ids !== undefined) {
body.assignee_ids = (body.assignee_ids as IDataObject[]).map((data) => data['assignee']);
body.assignee_ids = (body.assignee_ids as IDataObject[]).map(
(data) => data['assignee'],
);
}
endpoint = `${baseEndpoint}/issues/${issueNumber}`;
@ -1321,7 +1195,7 @@ export class Gitlab implements INodeType {
const tagName = this.getNodeParameter('tag_name', i) as string;
body = this.getNodeParameter('additionalFields', i, {}) as IDataObject;
if(body.milestones){
if (body.milestones) {
body.milestones = (body.milestones as string).split(',');
}
@ -1362,7 +1236,13 @@ export class Gitlab implements INodeType {
}
if (returnAll === true) {
responseData = await gitlabApiRequestAllItems.call(this, requestMethod, endpoint, body, qs);
responseData = await gitlabApiRequestAllItems.call(
this,
requestMethod,
endpoint,
body,
qs,
);
} else {
responseData = await gitlabApiRequest.call(this, requestMethod, endpoint, body, qs);
}
@ -1374,7 +1254,10 @@ export class Gitlab implements INodeType {
}
} catch (error) {
if (this.continueOnFail()) {
if (overwriteDataOperations.includes(fullOperation) || overwriteDataOperationsArray.includes(fullOperation)) {
if (
overwriteDataOperations.includes(fullOperation) ||
overwriteDataOperationsArray.includes(fullOperation)
) {
returnData.push({ error: error.message });
} else {
items[i].json = { error: error.message };
@ -1385,13 +1268,15 @@ export class Gitlab implements INodeType {
}
}
if (overwriteDataOperations.includes(fullOperation) || overwriteDataOperationsArray.includes(fullOperation)) {
if (
overwriteDataOperations.includes(fullOperation) ||
overwriteDataOperationsArray.includes(fullOperation)
) {
// Return data gets replaced
return [this.helpers.returnJsonArray(returnData)];
} else {
// For all other ones simply return the unchanged items
return this.prepareOutputData(items);
}
}
}

View file

@ -1,7 +1,4 @@
import {
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,20 +9,19 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
gitlabApiRequest,
} from './GenericFunctions';
import { gitlabApiRequest } from './GenericFunctions';
const GITLAB_EVENTS = [
{
name: 'Comment',
value: 'note',
description: 'Triggered when a new comment is made on commits, merge requests, issues, and code snippets',
description:
'Triggered when a new comment is made on commits, merge requests, issues, and code snippets',
},
{
name: 'Confidential Issues',
value: 'confidential_issues',
description: 'Triggered on confidential issues\' events',
description: "Triggered on confidential issues' events",
},
{
name: 'Confidential Comments',
@ -40,7 +36,8 @@ const GITLAB_EVENTS = [
{
name: 'Issue',
value: 'issues',
description: 'Triggered when a new issue is created or an existing issue was updated/closed/reopened',
description:
'Triggered when a new issue is created or an existing issue was updated/closed/reopened',
},
{
name: 'Job',
@ -50,7 +47,8 @@ const GITLAB_EVENTS = [
{
name: 'Merge Request',
value: 'merge_requests',
description: 'Triggered when a new merge request is created, an existing merge request was updated/merged/closed or a commit is added in the source branch',
description:
'Triggered when a new merge request is created, an existing merge request was updated/merged/closed or a commit is added in the source branch',
},
{
name: 'Pipeline',
@ -86,7 +84,8 @@ export class GitlabTrigger implements INodeType {
icon: 'file:gitlab.svg',
group: ['trigger'],
version: 1,
subtitle: '={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}',
subtitle:
'={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}',
description: 'Starts the workflow when GitLab events occur',
defaults: {
name: 'Gitlab Trigger',
@ -99,9 +98,7 @@ export class GitlabTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'accessToken',
],
authentication: ['accessToken'],
},
},
},
@ -110,9 +107,7 @@ export class GitlabTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -194,7 +189,7 @@ export class GitlabTrigger implements INodeType {
const owner = this.getNodeParameter('owner') as string;
const repository = this.getNodeParameter('repository') as string;
const path = (`${owner}/${repository}`).replace(/\//g, '%2F');
const path = `${owner}/${repository}`.replace(/\//g, '%2F');
const endpoint = `/projects/${path}/hooks/${webhookData.webhookId}`;
@ -228,7 +223,7 @@ export class GitlabTrigger implements INodeType {
let eventsArray = this.getNodeParameter('events', []) as string[];
if (eventsArray.includes('*')) {
eventsArray = GITLAB_EVENTS.map(e => e.value);
eventsArray = GITLAB_EVENTS.map((e) => e.value);
}
const events: { [key: string]: boolean } = {};
@ -242,7 +237,7 @@ export class GitlabTrigger implements INodeType {
events['push_events'] = false;
}
const path = (`${owner}/${repository}`).replace(/\//g, '%2F');
const path = `${owner}/${repository}`.replace(/\//g, '%2F');
const endpoint = `/projects/${path}/hooks`;
@ -261,7 +256,9 @@ export class GitlabTrigger implements INodeType {
if (responseData.id === undefined) {
// Required data is missing so was not successful
throw new NodeApiError(this.getNode(), responseData, { message: 'GitLab webhook creation response did not contain the expected data.' });
throw new NodeApiError(this.getNode(), responseData, {
message: 'GitLab webhook creation response did not contain the expected data.',
});
}
const webhookData = this.getWorkflowStaticData('node');
@ -277,7 +274,7 @@ export class GitlabTrigger implements INodeType {
const owner = this.getNodeParameter('owner') as string;
const repository = this.getNodeParameter('repository') as string;
const path = (`${owner}/${repository}`).replace(/\//g, '%2F');
const path = `${owner}/${repository}`.replace(/\//g, '%2F');
const endpoint = `/projects/${path}/hooks/${webhookData.webhookId}`;
const body = {};
@ -299,25 +296,19 @@ export class GitlabTrigger implements INodeType {
},
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
const returnData: IDataObject[] = [];
returnData.push(
{
body: bodyData,
headers: this.getHeaderData(),
query: this.getQueryData(),
},
);
returnData.push({
body: bodyData,
headers: this.getHeaderData(),
query: this.getQueryData(),
});
return {
workflowData: [
this.helpers.returnJsonArray(returnData),
],
workflowData: [this.helpers.returnJsonArray(returnData)],
};
}
}

View file

@ -1,7 +1,4 @@
import {
IExecuteFunctions,
IHookFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IHookFunctions } from 'n8n-core';
import {
IDataObject,
@ -10,9 +7,7 @@ import {
NodeApiError,
} from 'n8n-workflow';
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import moment from 'moment';
@ -29,14 +24,13 @@ export async function goToWebinarApiRequest(
body: IDataObject | IDataObject[],
option: IDataObject = {},
) {
const operation = this.getNodeParameter('operation', 0) as string;
const resource = this.getNodeParameter('resource', 0) as string;
const options: OptionsWithUri = {
headers: {
'user-agent': 'n8n',
'Accept': 'application/json',
Accept: 'application/json',
'Content-Type': 'application/json',
},
method,
@ -63,7 +57,9 @@ export async function goToWebinarApiRequest(
}
try {
const response = await this.helpers.requestOAuth2!.call(this, 'goToWebinarOAuth2Api', options, { tokenExpiredStatusCode: 403 });
const response = await this.helpers.requestOAuth2!.call(this, 'goToWebinarOAuth2Api', options, {
tokenExpiredStatusCode: 403,
});
if (response === '') {
return {};
@ -87,7 +83,6 @@ export async function goToWebinarApiRequestAllItems(
body: IDataObject,
resource: string,
) {
const resourceToResponseKey: { [key: string]: string } = {
session: 'sessionInfoResources',
webinar: 'webinars',
@ -113,9 +108,9 @@ export async function goToWebinarApiRequestAllItems(
returnData = returnData.splice(0, qs.limit as number);
return returnData;
}
} while (
responseData.totalElements && parseInt(responseData.totalElements, 10) > returnData.length
responseData.totalElements &&
parseInt(responseData.totalElements, 10) > returnData.length
);
return returnData;
@ -126,7 +121,8 @@ export async function handleGetAll(
endpoint: string,
qs: IDataObject,
body: IDataObject,
resource: string) {
resource: string,
) {
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
if (!returnAll) {
@ -137,8 +133,8 @@ export async function handleGetAll(
}
export async function loadWebinars(this: ILoadOptionsFunctions) {
const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { account_key: string }
const { oauthTokenData } = (await this.getCredentials('goToWebinarOAuth2Api')) as {
oauthTokenData: { account_key: string };
};
const endpoint = `accounts/${oauthTokenData.account_key}/webinars`;
@ -148,7 +144,14 @@ export async function loadWebinars(this: ILoadOptionsFunctions) {
toTime: moment().add(1, 'years').format(),
};
const resourceItems = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, 'webinar');
const resourceItems = await goToWebinarApiRequestAllItems.call(
this,
'GET',
endpoint,
qs,
{},
'webinar',
);
const returnData: INodePropertyOptions[] = [];
@ -163,21 +166,30 @@ export async function loadWebinars(this: ILoadOptionsFunctions) {
}
export async function loadWebinarSessions(this: ILoadOptionsFunctions) {
const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { organizer_key: string }
const { oauthTokenData } = (await this.getCredentials('goToWebinarOAuth2Api')) as {
oauthTokenData: { organizer_key: string };
};
const webinarKey = this.getCurrentNodeParameter('webinarKey') as string;
const endpoint = `organizers/${oauthTokenData.organizer_key}/webinars/${webinarKey}/sessions`;
const resourceItems = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, {}, {}, 'session');
const resourceItems = await goToWebinarApiRequestAllItems.call(
this,
'GET',
endpoint,
{},
{},
'session',
);
const returnData: INodePropertyOptions[] = [];
resourceItems.forEach((item) => {
returnData.push({
name: `Date: ${moment(item.startTime as string).format('MM-DD-YYYY')} | From: ${moment(item.startTime as string).format('LT')} - To: ${moment(item.endTime as string).format('LT')}`,
name: `Date: ${moment(item.startTime as string).format('MM-DD-YYYY')} | From: ${moment(
item.startTime as string,
).format('LT')} - To: ${moment(item.endTime as string).format('LT')}`,
value: item.sessionKey as string,
});
});
@ -186,8 +198,8 @@ export async function loadWebinarSessions(this: ILoadOptionsFunctions) {
}
export async function loadRegistranSimpleQuestions(this: ILoadOptionsFunctions) {
const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { organizer_key: string }
const { oauthTokenData } = (await this.getCredentials('goToWebinarOAuth2Api')) as {
oauthTokenData: { organizer_key: string };
};
const webinarkey = this.getNodeParameter('webinarKey') as string;
@ -211,8 +223,8 @@ export async function loadRegistranSimpleQuestions(this: ILoadOptionsFunctions)
}
export async function loadAnswers(this: ILoadOptionsFunctions) {
const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { organizer_key: string }
const { oauthTokenData } = (await this.getCredentials('goToWebinarOAuth2Api')) as {
oauthTokenData: { organizer_key: string };
};
const webinarKey = this.getCurrentNodeParameter('webinarKey') as string;
@ -240,8 +252,8 @@ export async function loadAnswers(this: ILoadOptionsFunctions) {
}
export async function loadRegistranMultiChoiceQuestions(this: ILoadOptionsFunctions) {
const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { organizer_key: string }
const { oauthTokenData } = (await this.getCredentials('goToWebinarOAuth2Api')) as {
oauthTokenData: { organizer_key: string };
};
const webinarkey = this.getNodeParameter('webinarKey') as string;
@ -268,8 +280,7 @@ export async function loadRegistranMultiChoiceQuestions(this: ILoadOptionsFuncti
function convertLosslessNumber(key: any, value: any) {
if (value && value.isLosslessNumber) {
return value.toString();
}
else {
} else {
return value;
}
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -38,10 +36,7 @@ import {
loadWebinarSessions,
} from './GenericFunctions';
import {
isEmpty,
omit,
} from 'lodash';
import { isEmpty, omit } from 'lodash';
import moment from 'moment-timezone';
@ -139,10 +134,14 @@ export class GoToWebinar implements INodeType {
}
return returnData;
},
async getRegistranSimpleQuestions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
async getRegistranSimpleQuestions(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
return await loadRegistranSimpleQuestions.call(this);
},
async getRegistranMultiChoiceQuestions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
async getRegistranMultiChoiceQuestions(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
return await loadRegistranMultiChoiceQuestions.call(this);
},
},
@ -157,19 +156,16 @@ export class GoToWebinar implements INodeType {
let responseData;
const returnData: IDataObject[] = [];
const { oauthTokenData } = await this.getCredentials('goToWebinarOAuth2Api') as {
oauthTokenData: { account_key: string, organizer_key: string }
const { oauthTokenData } = (await this.getCredentials('goToWebinarOAuth2Api')) as {
oauthTokenData: { account_key: string; organizer_key: string };
};
const accountKey = oauthTokenData.account_key;
const organizerKey = oauthTokenData.organizer_key;
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'attendee') {
// *********************************************************************
// attendee
// *********************************************************************
@ -177,7 +173,6 @@ export class GoToWebinar implements INodeType {
// https://developer.goto.com/GoToWebinarV2/#tag/Attendees
if (operation === 'get') {
// ----------------------------------
// attendee: get
// ----------------------------------
@ -188,9 +183,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees/${registrantKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// attendee: getAll
// ----------------------------------
@ -200,9 +193,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
} else if (operation === 'getDetails') {
// ----------------------------------
// attendee: getDetails
// ----------------------------------
@ -214,11 +205,8 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees/${registrantKey}/${details}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
}
} else if (resource === 'coorganizer') {
// *********************************************************************
// coorganizer
// *********************************************************************
@ -226,7 +214,6 @@ export class GoToWebinar implements INodeType {
// https://developer.goto.com/GoToWebinarV2/#tag/Co-organizers
if (operation === 'create') {
// ----------------------------------
// coorganizer: create
// ----------------------------------
@ -248,9 +235,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, [body]);
} else if (operation === 'delete') {
// ----------------------------------
// coorganizer: delete
// ----------------------------------
@ -265,9 +250,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers/${coorganizerKey}`;
responseData = await goToWebinarApiRequest.call(this, 'DELETE', endpoint, qs, {});
responseData = { success: true };
} else if (operation === 'getAll') {
// ----------------------------------
// coorganizer: getAll
// ----------------------------------
@ -276,9 +259,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
} else if (operation === 'reinvite') {
// ----------------------------------
// coorganizer: reinvite
// ----------------------------------
@ -294,11 +275,8 @@ export class GoToWebinar implements INodeType {
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, qs, {});
responseData = { success: true };
}
} else if (resource === 'panelist') {
// *********************************************************************
// panelist
// *********************************************************************
@ -306,7 +284,6 @@ export class GoToWebinar implements INodeType {
// https://developer.goto.com/GoToWebinarV2/#tag/Panelists
if (operation === 'create') {
// ----------------------------------
// panelist: create
// ----------------------------------
@ -322,9 +299,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, body);
} else if (operation === 'delete') {
// ----------------------------------
// panelist: delete
// ----------------------------------
@ -335,9 +310,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists/${panelistKey}`;
responseData = await goToWebinarApiRequest.call(this, 'DELETE', endpoint, {}, {});
responseData = { success: true };
} else if (operation === 'getAll') {
// ----------------------------------
// panelist: getAll
// ----------------------------------
@ -346,9 +319,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
} else if (operation === 'reinvite') {
// ----------------------------------
// panelist: reinvite
// ----------------------------------
@ -359,11 +330,8 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/panelists/${panelistKey}/resendInvitation`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, {});
responseData = { success: true };
}
} else if (resource === 'registrant') {
// *********************************************************************
// registrant
// *********************************************************************
@ -371,7 +339,6 @@ export class GoToWebinar implements INodeType {
// https://developer.goto.com/GoToWebinarV2/#tag/Registrants
if (operation === 'create') {
// ----------------------------------
// registrant: create
// ----------------------------------
@ -387,16 +354,12 @@ export class GoToWebinar implements INodeType {
} as IDataObject;
let additionalFields = this.getNodeParameter('additionalFields', i) as Partial<{
resendConfirmation: boolean,
resendConfirmation: boolean;
fullAddress: {
details: { [key: string]: string }
}
simpleResponses: [
{ [key: string]: string }
],
multiChoiceResponses: [
{ [key: string]: string }
],
details: { [key: string]: string };
};
simpleResponses: [{ [key: string]: string }];
multiChoiceResponses: [{ [key: string]: string }];
}>;
if (additionalFields.resendConfirmation) {
@ -425,9 +388,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, qs, body);
} else if (operation === 'delete') {
// ----------------------------------
// registrant: delete
// ----------------------------------
@ -438,9 +399,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants/${registrantKey}`;
responseData = await goToWebinarApiRequest.call(this, 'DELETE', endpoint, {}, {});
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------
// registrant: get
// ----------------------------------
@ -450,9 +409,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants/${registrantKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// registrant: getAll
// ----------------------------------
@ -462,9 +419,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/registrants`;
responseData = await handleGetAll.call(this, endpoint, {}, {}, resource);
}
} else if (resource === 'session') {
// *********************************************************************
// session
// *********************************************************************
@ -472,7 +427,6 @@ export class GoToWebinar implements INodeType {
// https://developer.goto.com/GoToWebinarV2/#tag/Sessions
if (operation === 'get') {
// ----------------------------------
// session: get
// ----------------------------------
@ -482,9 +436,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// session: getAll
// ----------------------------------
@ -497,15 +449,12 @@ export class GoToWebinar implements INodeType {
qs.limit = this.getNodeParameter('limit', 0) as number;
}
const {
webinarKey,
times,
} = this.getNodeParameter('additionalFields', i) as {
filterByWebinar: boolean,
webinarKey: string,
const { webinarKey, times } = this.getNodeParameter('additionalFields', i) as {
filterByWebinar: boolean;
webinarKey: string;
times: {
timesProperties: { [key: string]: string }
}
timesProperties: { [key: string]: string };
};
};
if (times) {
@ -517,18 +466,27 @@ export class GoToWebinar implements INodeType {
}
if (webinarKey !== undefined) {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions`;
responseData = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource);
responseData = await goToWebinarApiRequestAllItems.call(
this,
'GET',
endpoint,
qs,
{},
resource,
);
} else {
const endpoint = `organizers/${organizerKey}/sessions`;
responseData = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource);
responseData = await goToWebinarApiRequestAllItems.call(
this,
'GET',
endpoint,
qs,
{},
resource,
);
}
} else if (operation === 'getDetails') {
// ----------------------------------
// session: getDetails
// ----------------------------------
@ -539,11 +497,8 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/${details}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
}
} else if (resource === 'webinar') {
// *********************************************************************
// webinar
// *********************************************************************
@ -551,12 +506,15 @@ export class GoToWebinar implements INodeType {
// https://developer.goto.com/GoToWebinarV2/#tag/Webinars
if (operation === 'create') {
// ----------------------------------
// webinar: create
// ----------------------------------
const timesProperties = this.getNodeParameter('times.timesProperties', i, []) as IDataObject;
const timesProperties = this.getNodeParameter(
'times.timesProperties',
i,
[],
) as IDataObject;
const body = {
subject: this.getNodeParameter('subject', i) as string,
@ -568,16 +526,17 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars`;
responseData = await goToWebinarApiRequest.call(this, 'POST', endpoint, {}, body);
} else if (operation === 'delete') {
// ----------------------------------
// webinar: delete
// ----------------------------------
const webinarKey = this.getNodeParameter('webinarKey', i) as string;
const { sendCancellationEmails } = this.getNodeParameter('additionalFields', i) as IDataObject;
const { sendCancellationEmails } = this.getNodeParameter(
'additionalFields',
i,
) as IDataObject;
const qs = {} as IDataObject;
@ -588,9 +547,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}`;
await goToWebinarApiRequest.call(this, 'DELETE', endpoint, qs, {});
responseData = { success: true };
} else if (operation === 'get') {
// ----------------------------------
// webinar: get
// ----------------------------------
@ -599,9 +556,7 @@ export class GoToWebinar implements INodeType {
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}`;
responseData = await goToWebinarApiRequest.call(this, 'GET', endpoint, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// webinar: getAll
// ----------------------------------
@ -616,8 +571,8 @@ export class GoToWebinar implements INodeType {
const { times } = this.getNodeParameter('additionalFields', i) as {
times: {
timesProperties: { [key: string]: string }
}
timesProperties: { [key: string]: string };
};
};
if (times) {
@ -629,10 +584,15 @@ export class GoToWebinar implements INodeType {
}
const endpoint = `accounts/${accountKey}/webinars`;
responseData = await goToWebinarApiRequestAllItems.call(this, 'GET', endpoint, qs, {}, resource);
responseData = await goToWebinarApiRequestAllItems.call(
this,
'GET',
endpoint,
qs,
{},
resource,
);
} else if (operation === 'update') {
// ----------------------------------
// webinar: update
// ----------------------------------
@ -649,7 +609,7 @@ export class GoToWebinar implements INodeType {
if (updateFields.times) {
const { times } = updateFields as {
times: { timesProperties: Array<{ startTime: string, endTime: string }> }
times: { timesProperties: Array<{ startTime: string; endTime: string }> };
};
body = {
@ -662,7 +622,11 @@ export class GoToWebinar implements INodeType {
Object.assign(body, updateFields);
if (isEmpty(updateFields)) {
throw new NodeOperationError(this.getNode(), `Please enter at least one field to update for the ${resource}.`, { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
`Please enter at least one field to update for the ${resource}.`,
{ itemIndex: i },
);
}
const endpoint = `organizers/${organizerKey}/webinars/${webinarKey}`;
@ -670,7 +634,6 @@ export class GoToWebinar implements INodeType {
responseData = { success: true };
}
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const attendeeOperations: INodeProperties[] = [
{
@ -28,9 +26,7 @@ export const attendeeOperations: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'attendee',
],
resource: ['attendee'],
},
},
},
@ -49,12 +45,11 @@ export const attendeeFields: INodeProperties[] = [
},
required: true,
default: '',
description: 'Key of the webinar that the attendee attended. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar that the attendee attended. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'attendee',
],
resource: ['attendee'],
},
},
},
@ -65,17 +60,14 @@ export const attendeeFields: INodeProperties[] = [
required: true,
typeOptions: {
loadOptionsMethod: 'getWebinarSessions',
loadOptionsDependsOn: [
'webinarKey',
],
loadOptionsDependsOn: ['webinarKey'],
},
default: '',
description: 'Key of the session that the attendee attended. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the session that the attendee attended. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'attendee',
],
resource: ['attendee'],
},
},
},
@ -92,12 +84,8 @@ export const attendeeFields: INodeProperties[] = [
description: 'Registrant key of the attendee at the webinar session',
displayOptions: {
show: {
resource: [
'attendee',
],
operation: [
'get',
],
resource: ['attendee'],
operation: ['get'],
},
},
},
@ -114,12 +102,8 @@ export const attendeeFields: INodeProperties[] = [
description: 'Registrant key of the attendee at the webinar session',
displayOptions: {
show: {
resource: [
'attendee',
],
operation: [
'getDetails',
],
resource: ['attendee'],
operation: ['getDetails'],
},
},
},
@ -149,12 +133,8 @@ export const attendeeFields: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'attendee',
],
operation: [
'getDetails',
],
resource: ['attendee'],
operation: ['getDetails'],
},
},
},
@ -170,12 +150,8 @@ export const attendeeFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'attendee',
],
operation: [
'getAll',
],
resource: ['attendee'],
operation: ['getAll'],
},
},
},
@ -191,15 +167,9 @@ export const attendeeFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'attendee',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['attendee'],
operation: ['getAll'],
returnAll: [false],
},
},
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const coorganizerOperations: INodeProperties[] = [
{
@ -33,9 +31,7 @@ export const coorganizerOperations: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'coorganizer',
],
resource: ['coorganizer'],
},
},
},
@ -54,15 +50,12 @@ export const coorganizerFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar that the co-organizer is hosting. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar that the co-organizer is hosting. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'create',
],
resource: ['coorganizer'],
operation: ['create'],
},
},
},
@ -75,12 +68,8 @@ export const coorganizerFields: INodeProperties[] = [
description: 'Whether the co-organizer has no GoToWebinar account',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'create',
],
resource: ['coorganizer'],
operation: ['create'],
},
},
},
@ -89,18 +78,12 @@ export const coorganizerFields: INodeProperties[] = [
name: 'organizerKey',
type: 'string',
default: '',
description: 'The co-organizer\'s organizer key for the webinar',
description: "The co-organizer's organizer key for the webinar",
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'create',
],
isExternal: [
false,
],
resource: ['coorganizer'],
operation: ['create'],
isExternal: [false],
},
},
},
@ -109,18 +92,12 @@ export const coorganizerFields: INodeProperties[] = [
name: 'givenName',
type: 'string',
default: '',
description: 'The co-organizer\'s given name',
description: "The co-organizer's given name",
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'create',
],
isExternal: [
true,
],
resource: ['coorganizer'],
operation: ['create'],
isExternal: [true],
},
},
},
@ -130,18 +107,12 @@ export const coorganizerFields: INodeProperties[] = [
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'The co-organizer\'s email address',
description: "The co-organizer's email address",
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'create',
],
isExternal: [
true,
],
resource: ['coorganizer'],
operation: ['create'],
isExternal: [true],
},
},
},
@ -158,15 +129,12 @@ export const coorganizerFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'delete',
],
resource: ['coorganizer'],
operation: ['delete'],
},
},
},
@ -178,12 +146,8 @@ export const coorganizerFields: INodeProperties[] = [
description: 'Key of the co-organizer to delete',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'delete',
],
resource: ['coorganizer'],
operation: ['delete'],
},
},
},
@ -195,16 +159,13 @@ export const coorganizerFields: INodeProperties[] = [
default: false,
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'delete',
],
resource: ['coorganizer'],
operation: ['delete'],
},
},
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'By default only internal co-organizers (with a GoToWebinar account) can be deleted. If you want to use this call for external co-organizers you have to set this parameter to \'true\'.',
description:
"By default only internal co-organizers (with a GoToWebinar account) can be deleted. If you want to use this call for external co-organizers you have to set this parameter to 'true'.",
},
// ----------------------------------
@ -219,15 +180,12 @@ export const coorganizerFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar to retrieve all co-organizers from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar to retrieve all co-organizers from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'getAll',
],
resource: ['coorganizer'],
operation: ['getAll'],
},
},
},
@ -239,12 +197,8 @@ export const coorganizerFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'getAll',
],
resource: ['coorganizer'],
operation: ['getAll'],
},
},
},
@ -260,15 +214,9 @@ export const coorganizerFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['coorganizer'],
operation: ['getAll'],
returnAll: [false],
},
},
},
@ -282,15 +230,12 @@ export const coorganizerFields: INodeProperties[] = [
type: 'string',
required: true,
default: '',
description: 'By default only internal co-organizers (with a GoToWebinar account) can be deleted. If you want to use this call for external co-organizers you have to set this parameter to \'true\'.',
description:
"By default only internal co-organizers (with a GoToWebinar account) can be deleted. If you want to use this call for external co-organizers you have to set this parameter to 'true'.",
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'reinvite',
],
resource: ['coorganizer'],
operation: ['reinvite'],
},
},
},
@ -302,12 +247,8 @@ export const coorganizerFields: INodeProperties[] = [
description: 'Key of the co-organizer to reinvite',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'reinvite',
],
resource: ['coorganizer'],
operation: ['reinvite'],
},
},
},
@ -320,12 +261,8 @@ export const coorganizerFields: INodeProperties[] = [
description: 'Whether the co-organizer has no GoToWebinar account',
displayOptions: {
show: {
resource: [
'coorganizer',
],
operation: [
'reinvite',
],
resource: ['coorganizer'],
operation: ['reinvite'],
},
},
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const panelistOperations: INodeProperties[] = [
{
@ -33,9 +31,7 @@ export const panelistOperations: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'panelist',
],
resource: ['panelist'],
},
},
},
@ -54,12 +50,8 @@ export const panelistFields: INodeProperties[] = [
description: 'Name of the panelist to create',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'create',
],
resource: ['panelist'],
operation: ['create'],
},
},
},
@ -73,12 +65,8 @@ export const panelistFields: INodeProperties[] = [
description: 'Email address of the panelist to create',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'create',
],
resource: ['panelist'],
operation: ['create'],
},
},
},
@ -91,15 +79,12 @@ export const panelistFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar that the panelist will present at. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar that the panelist will present at. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'create',
],
resource: ['panelist'],
operation: ['create'],
},
},
},
@ -116,15 +101,12 @@ export const panelistFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar to retrieve all panelists from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar to retrieve all panelists from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'getAll',
],
resource: ['panelist'],
operation: ['getAll'],
},
},
},
@ -136,12 +118,8 @@ export const panelistFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'getAll',
],
resource: ['panelist'],
operation: ['getAll'],
},
},
},
@ -157,15 +135,9 @@ export const panelistFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['panelist'],
operation: ['getAll'],
returnAll: [false],
},
},
},
@ -182,15 +154,12 @@ export const panelistFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar to delete the panelist from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar to delete the panelist from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'delete',
],
resource: ['panelist'],
operation: ['delete'],
},
},
},
@ -203,12 +172,8 @@ export const panelistFields: INodeProperties[] = [
description: 'Key of the panelist to delete',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'delete',
],
resource: ['panelist'],
operation: ['delete'],
},
},
},
@ -225,15 +190,12 @@ export const panelistFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar to reinvite the panelist to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar to reinvite the panelist to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'reinvite',
],
resource: ['panelist'],
operation: ['reinvite'],
},
},
},
@ -246,12 +208,8 @@ export const panelistFields: INodeProperties[] = [
description: 'Key of the panelist to reinvite',
displayOptions: {
show: {
resource: [
'panelist',
],
operation: [
'reinvite',
],
resource: ['panelist'],
operation: ['reinvite'],
},
},
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const registrantOperations: INodeProperties[] = [
{
@ -33,9 +31,7 @@ export const registrantOperations: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'registrant',
],
resource: ['registrant'],
},
},
},
@ -54,15 +50,12 @@ export const registrantFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar of the registrant to create. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar of the registrant to create. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'create',
],
resource: ['registrant'],
operation: ['create'],
},
},
},
@ -74,12 +67,8 @@ export const registrantFields: INodeProperties[] = [
description: 'First name of the registrant to create',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'create',
],
resource: ['registrant'],
operation: ['create'],
},
},
},
@ -91,12 +80,8 @@ export const registrantFields: INodeProperties[] = [
description: 'Last name of the registrant to create',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'create',
],
resource: ['registrant'],
operation: ['create'],
},
},
},
@ -109,12 +94,8 @@ export const registrantFields: INodeProperties[] = [
description: 'Email address of the registrant to create',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'create',
],
resource: ['registrant'],
operation: ['create'],
},
},
},
@ -125,12 +106,8 @@ export const registrantFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'create',
],
resource: ['registrant'],
operation: ['create'],
},
},
default: {},
@ -186,7 +163,7 @@ export const registrantFields: INodeProperties[] = [
name: 'industry',
type: 'string',
default: '',
description: 'The type of industry the registrant\'s organization belongs to',
description: "The type of industry the registrant's organization belongs to",
},
{
displayName: 'Job Title',
@ -213,12 +190,11 @@ export const registrantFields: INodeProperties[] = [
displayName: 'Question Key Name or ID',
name: 'questionKey',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getRegistranMultiChoiceQuestions',
loadOptionsDependsOn: [
'webinarKey',
],
loadOptionsDependsOn: ['webinarKey'],
},
default: '',
},
@ -238,7 +214,7 @@ export const registrantFields: INodeProperties[] = [
name: 'numberOfEmployees',
type: 'string',
default: '',
description: 'The size in employees of the registrant\'s organization',
description: "The size in employees of the registrant's organization",
},
{
displayName: 'Organization',
@ -257,7 +233,7 @@ export const registrantFields: INodeProperties[] = [
name: 'purchasingRole',
type: 'string',
default: '',
description: 'Registrant\'s role in purchasing the product',
description: "Registrant's role in purchasing the product",
},
{
displayName: 'Purchasing Time Frame',
@ -298,12 +274,11 @@ export const registrantFields: INodeProperties[] = [
displayName: 'Question Key Name or ID',
name: 'questionKey',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getRegistranSimpleQuestions',
loadOptionsDependsOn: [
'webinarKey',
],
loadOptionsDependsOn: ['webinarKey'],
},
default: '',
},
@ -340,15 +315,12 @@ export const registrantFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'The key of the webinar to retrieve registrants from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The key of the webinar to retrieve registrants from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'getAll',
],
resource: ['registrant'],
operation: ['getAll'],
},
},
},
@ -360,12 +332,8 @@ export const registrantFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'getAll',
],
resource: ['registrant'],
operation: ['getAll'],
},
},
},
@ -381,15 +349,9 @@ export const registrantFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['registrant'],
operation: ['getAll'],
returnAll: [false],
},
},
},
@ -406,15 +368,12 @@ export const registrantFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar of the registrant to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar of the registrant to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'delete',
],
resource: ['registrant'],
operation: ['delete'],
},
},
},
@ -427,12 +386,8 @@ export const registrantFields: INodeProperties[] = [
description: 'Key of the registrant to delete',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'delete',
],
resource: ['registrant'],
operation: ['delete'],
},
},
},
@ -449,15 +404,12 @@ export const registrantFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar of the registrant to retrieve. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar of the registrant to retrieve. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'get',
],
resource: ['registrant'],
operation: ['get'],
},
},
},
@ -470,12 +422,8 @@ export const registrantFields: INodeProperties[] = [
description: 'Key of the registrant to retrieve',
displayOptions: {
show: {
resource: [
'registrant',
],
operation: [
'get',
],
resource: ['registrant'],
operation: ['get'],
},
},
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const sessionOperations: INodeProperties[] = [
{
@ -28,9 +26,7 @@ export const sessionOperations: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'session',
],
resource: ['session'],
},
},
},
@ -48,12 +44,8 @@ export const sessionFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'session',
],
operation: [
'getAll',
],
resource: ['session'],
operation: ['getAll'],
},
},
},
@ -69,15 +61,9 @@ export const sessionFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'session',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['session'],
operation: ['getAll'],
returnAll: [false],
},
},
},
@ -88,12 +74,8 @@ export const sessionFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'session',
],
operation: [
'getAll',
],
resource: ['session'],
operation: ['getAll'],
},
},
default: {},
@ -136,7 +118,8 @@ export const sessionFields: INodeProperties[] = [
loadOptionsMethod: 'getWebinars',
},
default: {},
description: 'Webinar by which to filter the sessions to retrieve. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Webinar by which to filter the sessions to retrieve. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
],
},
@ -153,16 +136,12 @@ export const sessionFields: INodeProperties[] = [
},
required: true,
default: [],
description: 'Key of the webinar to which the session belongs. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Key of the webinar to which the session belongs. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
displayOptions: {
show: {
resource: [
'session',
],
operation: [
'get',
'getDetails',
],
resource: ['session'],
operation: ['get', 'getDetails'],
},
},
},
@ -174,13 +153,8 @@ export const sessionFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'session',
],
operation: [
'get',
'getDetails',
],
resource: ['session'],
operation: ['get', 'getDetails'],
},
},
},
@ -217,12 +191,8 @@ export const sessionFields: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'session',
],
operation: [
'getDetails',
],
resource: ['session'],
operation: ['getDetails'],
},
},
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const webinarOperations: INodeProperties[] = [
{
@ -37,9 +35,7 @@ export const webinarOperations: INodeProperties[] = [
],
displayOptions: {
show: {
resource: [
'webinar',
],
resource: ['webinar'],
},
},
},
@ -57,12 +53,8 @@ export const webinarFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'create',
],
resource: ['webinar'],
operation: ['create'],
},
},
},
@ -78,12 +70,8 @@ export const webinarFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'create',
],
resource: ['webinar'],
operation: ['create'],
},
},
options: [
@ -116,12 +104,8 @@ export const webinarFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'create',
],
resource: ['webinar'],
operation: ['create'],
},
},
default: {},
@ -171,7 +155,8 @@ export const webinarFields: INodeProperties[] = [
displayName: 'Timezone Name or ID',
name: 'timezone',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true,
default: '',
placeholder: '2020-12-11T09:00:00Z',
@ -194,12 +179,14 @@ export const webinarFields: INodeProperties[] = [
{
name: 'Series',
value: 'series',
description: 'Webinar with multiple meetings times where attendees choose only one to attend',
description:
'Webinar with multiple meetings times where attendees choose only one to attend',
},
{
name: 'Sequence',
value: 'sequence',
description: 'Webinar with multiple meeting times where attendees are expected to be the same for all sessions',
description:
'Webinar with multiple meeting times where attendees are expected to be the same for all sessions',
},
],
},
@ -218,12 +205,8 @@ export const webinarFields: INodeProperties[] = [
description: 'Key of the webinar to delete',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'delete',
],
resource: ['webinar'],
operation: ['delete'],
},
},
},
@ -234,12 +217,8 @@ export const webinarFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'delete',
],
resource: ['webinar'],
operation: ['delete'],
},
},
default: {},
@ -265,12 +244,8 @@ export const webinarFields: INodeProperties[] = [
description: 'Key of the webinar to retrieve',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'get',
],
resource: ['webinar'],
operation: ['get'],
},
},
},
@ -286,12 +261,8 @@ export const webinarFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'getAll',
],
resource: ['webinar'],
operation: ['getAll'],
},
},
},
@ -307,15 +278,9 @@ export const webinarFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['webinar'],
operation: ['getAll'],
returnAll: [false],
},
},
},
@ -326,12 +291,8 @@ export const webinarFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'getAll',
],
resource: ['webinar'],
operation: ['getAll'],
},
},
default: {},
@ -381,12 +342,8 @@ export const webinarFields: INodeProperties[] = [
description: 'Key of the webinar to update',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'update',
],
resource: ['webinar'],
operation: ['update'],
},
},
},
@ -398,12 +355,8 @@ export const webinarFields: INodeProperties[] = [
default: false,
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'update',
],
resource: ['webinar'],
operation: ['update'],
},
},
},
@ -414,12 +367,8 @@ export const webinarFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'webinar',
],
operation: [
'update',
],
resource: ['webinar'],
operation: ['update'],
},
},
default: {},
@ -514,7 +463,8 @@ export const webinarFields: INodeProperties[] = [
type: 'options',
default: '',
placeholder: '2020-12-11T09:00:00Z',
description: 'Timezone where the webinar is to take place. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Timezone where the webinar is to take place. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
typeOptions: {
alwaysOpenEditWindow: true,
loadOptionsMethod: 'getTimezones',
@ -534,12 +484,14 @@ export const webinarFields: INodeProperties[] = [
{
name: 'Series',
value: 'series',
description: 'Webinar with multiple meetings times where attendees choose only one to attend',
description:
'Webinar with multiple meetings times where attendees choose only one to attend',
},
{
name: 'Sequence',
value: 'sequence',
description: 'Webinar with multiple meeting times where attendees are expected to be the same for all sessions',
description:
'Webinar with multiple meeting times where attendees are expected to be the same for all sessions',
},
],
},

View file

@ -14,9 +14,7 @@ export const campaignOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'campaign',
],
resource: ['campaign'],
},
},
options: [
@ -29,41 +27,41 @@ export const campaignOperations: INodeProperties[] = [
method: 'POST',
url: '={{"/v9/customers/" + $parameter["clientCustomerId"].toString().replace(/-/g, "") + "/googleAds:search"}}',
body: {
query: '={{ "' +
'select ' +
'campaign.id, ' +
'campaign.name, ' +
'campaign_budget.amount_micros, ' +
'campaign_budget.period,' +
'campaign.status,' +
'campaign.optimization_score,' +
'campaign.advertising_channel_type,' +
'campaign.advertising_channel_sub_type,' +
'metrics.impressions,' +
'metrics.interactions,' +
'metrics.interaction_rate,' +
'metrics.average_cost,' +
'metrics.cost_micros,' +
'metrics.conversions,' +
'metrics.cost_per_conversion,' +
'metrics.conversions_from_interactions_rate,' +
'metrics.video_views,' +
'metrics.average_cpm,' +
'metrics.ctr ' +
'from campaign ' +
'where campaign.id > 0 ' + // create a dummy where clause so we can append more conditions
'" + (["allTime", undefined, ""].includes($parameter.additionalOptions?.dateRange) ? "" : " and segments.date DURING " + $parameter.additionalOptions.dateRange) + " ' +
'" + (["all", undefined, ""].includes($parameter.additionalOptions?.campaignStatus) ? "" : " and campaign.status = \'" + $parameter.additionalOptions.campaignStatus + "\'") + "' +
'" }}',
query:
'={{ "' +
'select ' +
'campaign.id, ' +
'campaign.name, ' +
'campaign_budget.amount_micros, ' +
'campaign_budget.period,' +
'campaign.status,' +
'campaign.optimization_score,' +
'campaign.advertising_channel_type,' +
'campaign.advertising_channel_sub_type,' +
'metrics.impressions,' +
'metrics.interactions,' +
'metrics.interaction_rate,' +
'metrics.average_cost,' +
'metrics.cost_micros,' +
'metrics.conversions,' +
'metrics.cost_per_conversion,' +
'metrics.conversions_from_interactions_rate,' +
'metrics.video_views,' +
'metrics.average_cpm,' +
'metrics.ctr ' +
'from campaign ' +
'where campaign.id > 0 ' + // create a dummy where clause so we can append more conditions
'" + (["allTime", undefined, ""].includes($parameter.additionalOptions?.dateRange) ? "" : " and segments.date DURING " + $parameter.additionalOptions.dateRange) + " ' +
'" + (["all", undefined, ""].includes($parameter.additionalOptions?.campaignStatus) ? "" : " and campaign.status = \'" + $parameter.additionalOptions.campaignStatus + "\'") + "' +
'" }}',
},
headers: {
'login-customer-id': '={{$parameter["managerCustomerId"].toString().replace(/-/g, "")}}',
'login-customer-id':
'={{$parameter["managerCustomerId"].toString().replace(/-/g, "")}}',
},
},
output: {
postReceive: [
processCampaignSearchResponse,
],
postReceive: [processCampaignSearchResponse],
},
},
action: 'Get all campaigns',
@ -105,14 +103,13 @@ export const campaignOperations: INodeProperties[] = [
'}}',
},
headers: {
'login-customer-id': '={{$parameter["managerCustomerId"].toString().replace(/-/g, "")}}',
'login-customer-id':
'={{$parameter["managerCustomerId"].toString().replace(/-/g, "")}}',
'content-type': 'application/x-www-form-urlencoded',
},
},
output: {
postReceive: [
processCampaignSearchResponse,
],
postReceive: [processCampaignSearchResponse],
},
},
action: 'Get a campaign',
@ -131,9 +128,7 @@ export const campaignFields: INodeProperties[] = [
placeholder: '9998887777',
displayOptions: {
show: {
resource: [
'campaign',
],
resource: ['campaign'],
},
},
default: '',
@ -146,9 +141,7 @@ export const campaignFields: INodeProperties[] = [
placeholder: '6665554444',
displayOptions: {
show: {
resource: [
'campaign',
],
resource: ['campaign'],
},
},
default: '',
@ -160,12 +153,8 @@ export const campaignFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'campaign',
],
operation: ['get'],
resource: ['campaign'],
},
},
default: '',
@ -177,12 +166,8 @@ export const campaignFields: INodeProperties[] = [
type: 'collection',
displayOptions: {
show: {
resource: [
'campaign',
],
operation: [
'getAll',
],
resource: ['campaign'],
operation: ['getAll'],
},
},
default: {},
@ -219,7 +204,8 @@ export const campaignFields: INodeProperties[] = [
{
name: 'Last Business Week',
value: 'LAST_BUSINESS_WEEK',
description: 'The 5 day business week, Monday through Friday, of the previous business week',
description:
'The 5 day business week, Monday through Friday, of the previous business week',
},
{
name: 'This Month',
@ -277,24 +263,30 @@ export const campaignFields: INodeProperties[] = [
},
];
function processCampaignSearchResponse(this: IExecuteSingleFunctions, _inputData: INodeExecutionData[], responseData: IN8nHttpFullResponse): Promise<INodeExecutionData[]> {
function processCampaignSearchResponse(
this: IExecuteSingleFunctions,
_inputData: INodeExecutionData[],
responseData: IN8nHttpFullResponse,
): Promise<INodeExecutionData[]> {
const results = (responseData.body as IDataObject).results as GoogleAdsCampaignElement;
return Promise.resolve(results.map((result) => {
return {
json: {
...result.campaign,
...result.metrics,
...result.campaignBudget,
},
};
}));
return Promise.resolve(
results.map((result) => {
return {
json: {
...result.campaign,
...result.metrics,
...result.campaignBudget,
},
};
}),
);
}
type GoogleAdsCampaignElement = [
{
campaign: object,
metrics: object,
campaignBudget: object,
}
campaign: object;
metrics: object;
campaignBudget: object;
},
];

View file

@ -1,12 +1,6 @@
import {
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { INodeType, INodeTypeDescription } from 'n8n-workflow';
import {
campaignFields,
campaignOperations,
} from './CampaignDescription';
import { campaignFields, campaignOperations } from './CampaignDescription';
export class GoogleAds implements INodeType {
description: INodeTypeDescription = {
@ -61,15 +55,14 @@ export class GoogleAds implements INodeType {
//-------------------------------
...campaignOperations,
{
displayName: 'Divide field names expressed with <i>micros</i> by 1,000,000 to get the actual value',
displayName:
'Divide field names expressed with <i>micros</i> by 1,000,000 to get the actual value',
name: 'campaigsNotice',
type: 'notice',
default: '',
displayOptions: {
show: {
resource: [
'campaign',
],
resource: ['campaign'],
},
},
},

View file

@ -1,22 +1,23 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string,
endpoint: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
let options: OptionsWithUri = {
headers: {
'Accept': 'application/json',
Accept: 'application/json',
'Content-Type': 'application/json',
},
method,
@ -36,14 +37,22 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
//@ts-ignore
return await this.helpers.requestOAuth2.call(this, 'googleAnalyticsOAuth2', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -57,8 +66,7 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
}
returnData.push.apply(returnData, responseData[propertyName]);
} while (
(responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== '') ||
(responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '') ||
(responseData[propertyName] &&
responseData[propertyName][0].nextPageToken &&
responseData[propertyName][0].nextPageToken !== undefined)
@ -67,9 +75,13 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
return returnData;
}
export function simplify(responseData: any | [any]) { // tslint:disable-line:no-any
// tslint:disable-next-line:no-any
export function simplify(responseData: any | [any]) {
const response = [];
for (const { columnHeader: { dimensions }, data: { rows } } of responseData) {
for (const {
columnHeader: { dimensions },
data: { rows },
} of responseData) {
if (rows === undefined) {
// Do not error if there is no data
continue;
@ -90,13 +102,16 @@ export function simplify(responseData: any | [any]) { // tslint:disable-line:no-
return response;
}
export function merge(responseData: [any]) { // tslint:disable-line:no-any
const response: { columnHeader: IDataObject, data: { rows: [] } } = {
// tslint:disable-next-line:no-any
export function merge(responseData: [any]) {
const response: { columnHeader: IDataObject; data: { rows: [] } } = {
columnHeader: responseData[0].columnHeader,
data: responseData[0].data,
};
const allRows = [];
for (const { data: { rows } } of responseData) {
for (const {
data: { rows },
} of responseData) {
allRows.push(...rows);
}
response.data.rows = allRows as [];

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -11,28 +9,15 @@ import {
INodeTypeDescription,
} from 'n8n-workflow';
import {
reportFields,
reportOperations,
} from './ReportDescription';
import { reportFields, reportOperations } from './ReportDescription';
import {
userActivityFields,
userActivityOperations,
} from './UserActivityDescription';
import { userActivityFields, userActivityOperations } from './UserActivityDescription';
import {
googleApiRequest,
googleApiRequestAllItems,
merge,
simplify,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems, merge, simplify } from './GenericFunctions';
import moment from 'moment-timezone';
import {
IData,
} from './Interfaces';
import { IData } from './Interfaces';
export class GoogleAnalytics implements INodeType {
description: INodeTypeDescription = {
@ -90,9 +75,7 @@ export class GoogleAnalytics implements INodeType {
loadOptions: {
// Get all the dimensions to display them to user so that he can
// select them easily
async getDimensions(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getDimensions(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { items: dimensions } = await googleApiRequest.call(
this,
@ -104,7 +87,10 @@ export class GoogleAnalytics implements INodeType {
);
for (const dimesion of dimensions) {
if (dimesion.attributes.type === 'DIMENSION' && dimesion.attributes.status !== 'DEPRECATED') {
if (
dimesion.attributes.type === 'DIMENSION' &&
dimesion.attributes.status !== 'DEPRECATED'
) {
returnData.push({
name: dimesion.attributes.uiName,
value: dimesion.id,
@ -114,10 +100,14 @@ export class GoogleAnalytics implements INodeType {
}
returnData.sort((a, b) => {
const aName= a.name.toLowerCase();
const bName= b.name.toLowerCase();
if (aName < bName) { return -1; }
if (aName > bName) { return 1; }
const aName = a.name.toLowerCase();
const bName = b.name.toLowerCase();
if (aName < bName) {
return -1;
}
if (aName > bName) {
return 1;
}
return 0;
});
@ -125,9 +115,7 @@ export class GoogleAnalytics implements INodeType {
},
// Get all the views to display them to user so that he can
// select them easily
async getViews(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getViews(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { items } = await googleApiRequest.call(
this,
@ -151,7 +139,6 @@ export class GoogleAnalytics implements INodeType {
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
const resource = this.getNodeParameter('resource', 0) as string;
@ -163,17 +150,14 @@ export class GoogleAnalytics implements INodeType {
let responseData;
for (let i = 0; i < items.length; i++) {
try {
if(resource === 'report') {
if(operation === 'get') {
if (resource === 'report') {
if (operation === 'get') {
//https://developers.google.com/analytics/devguides/reporting/core/v4/rest/v4/reports/batchGet
method = 'POST';
endpoint = '/v4/reports:batchGet';
const viewId = this.getNodeParameter('viewId', i) as string;
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const additionalFields = this.getNodeParameter(
'additionalFields',
i,
) as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const simple = this.getNodeParameter('simple', i) as boolean;
const body: IData = {
@ -184,39 +168,39 @@ export class GoogleAnalytics implements INodeType {
qs.useResourceQuotas = additionalFields.useResourceQuotas;
}
if (additionalFields.dateRangesUi) {
const dateValues = (additionalFields.dateRangesUi as IDataObject).dateRanges as IDataObject;
const dateValues = (additionalFields.dateRangesUi as IDataObject)
.dateRanges as IDataObject;
if (dateValues) {
const start = dateValues.startDate as string;
const end = dateValues.endDate as string;
Object.assign(
body,
{
dateRanges:
[
{
startDate: moment(start).utc().format('YYYY-MM-DD'),
endDate: moment(end).utc().format('YYYY-MM-DD'),
},
],
},
);
Object.assign(body, {
dateRanges: [
{
startDate: moment(start).utc().format('YYYY-MM-DD'),
endDate: moment(end).utc().format('YYYY-MM-DD'),
},
],
});
}
}
if (additionalFields.metricsUi) {
const metrics = (additionalFields.metricsUi as IDataObject).metricValues as IDataObject[];
const metrics = (additionalFields.metricsUi as IDataObject)
.metricValues as IDataObject[];
body.metrics = metrics;
}
if (additionalFields.dimensionUi) {
const dimensions = (additionalFields.dimensionUi as IDataObject).dimensionValues as IDataObject[];
const dimensions = (additionalFields.dimensionUi as IDataObject)
.dimensionValues as IDataObject[];
if (dimensions) {
body.dimensions = dimensions;
}
}
if (additionalFields.dimensionFiltersUi) {
const dimensionFilters = (additionalFields.dimensionFiltersUi as IDataObject).filterValues as IDataObject[];
const dimensionFilters = (additionalFields.dimensionFiltersUi as IDataObject)
.filterValues as IDataObject[];
if (dimensionFilters) {
dimensionFilters.forEach(filter => filter.expressions = [filter.expressions]);
dimensionFilters.forEach((filter) => (filter.expressions = [filter.expressions]));
body.dimensionFilterClauses = { filters: dimensionFilters };
}
}
@ -232,9 +216,22 @@ export class GoogleAnalytics implements INodeType {
}
if (returnAll === true) {
responseData = await googleApiRequestAllItems.call(this, 'reports', method, endpoint, { reportRequests: [body] }, qs);
responseData = await googleApiRequestAllItems.call(
this,
'reports',
method,
endpoint,
{ reportRequests: [body] },
qs,
);
} else {
responseData = await googleApiRequest.call(this, method, endpoint, { reportRequests: [body] }, qs);
responseData = await googleApiRequest.call(
this,
method,
endpoint,
{ reportRequests: [body] },
qs,
);
responseData = responseData.reports;
}
@ -253,10 +250,7 @@ export class GoogleAnalytics implements INodeType {
const viewId = this.getNodeParameter('viewId', i);
const userId = this.getNodeParameter('userId', i);
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const additionalFields = this.getNodeParameter(
'additionalFields',
i,
) as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const body: IDataObject = {
viewId,
user: {
@ -268,7 +262,13 @@ export class GoogleAnalytics implements INodeType {
}
if (returnAll) {
responseData = await googleApiRequestAllItems.call(this, 'sessions', method, endpoint, body);
responseData = await googleApiRequestAllItems.call(
this,
'sessions',
method,
endpoint,
body,
);
} else {
body.pageSize = this.getNodeParameter('limit', 0) as number;
responseData = await googleApiRequest.call(this, method, endpoint, body);

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const reportOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const reportOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'report',
],
resource: ['report'],
},
},
options: [
@ -39,16 +35,13 @@ export const reportFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'report',
],
operation: [
'get',
],
resource: ['report'],
operation: ['get'],
},
},
placeholder: '123456',
description: 'The View ID of Google Analytics. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The View ID of Google Analytics. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Return All',
@ -56,12 +49,8 @@ export const reportFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'report',
],
operation: ['get'],
resource: ['report'],
},
},
default: false,
@ -73,15 +62,9 @@ export const reportFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'report',
],
returnAll: [
false,
],
operation: ['get'],
resource: ['report'],
returnAll: [false],
},
},
typeOptions: {
@ -97,12 +80,8 @@ export const reportFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'report',
],
operation: ['get'],
resource: ['report'],
},
},
default: true,
@ -116,12 +95,8 @@ export const reportFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'report',
],
operation: [
'get',
],
resource: ['report'],
operation: ['get'],
},
},
options: [
@ -162,7 +137,8 @@ export const reportFields: INodeProperties[] = [
multipleValues: true,
},
placeholder: 'Add Dimension',
description: 'Dimensions are attributes of your data. For example, the dimension ga:city indicates the city, for example, "Paris" or "New York", from which a session originates.',
description:
'Dimensions are attributes of your data. For example, the dimension ga:city indicates the city, for example, "Paris" or "New York", from which a session originates.',
options: [
{
displayName: 'Dimension',
@ -176,7 +152,8 @@ export const reportFields: INodeProperties[] = [
loadOptionsMethod: 'getDimensions',
},
default: '',
description: 'Name of the dimension to fetch, for example ga:browser. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Name of the dimension to fetch, for example ga:browser. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
],
},
@ -205,7 +182,8 @@ export const reportFields: INodeProperties[] = [
loadOptionsMethod: 'getDimensions',
},
default: '',
description: 'Name of the dimension to filter by. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Name of the dimension to filter by. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
// https://developers.google.com/analytics/devguides/reporting/core/v4/rest/v4/reports/batchGet#Operator
{
@ -255,7 +233,8 @@ export const reportFields: INodeProperties[] = [
type: 'string',
default: '',
placeholder: 'ga:newUsers',
description: 'String or <a href="https://support.google.com/analytics/answer/1034324?hl=en">regular expression</a> to match against',
description:
'String or <a href="https://support.google.com/analytics/answer/1034324?hl=en">regular expression</a> to match against',
},
],
},
@ -266,7 +245,8 @@ export const reportFields: INodeProperties[] = [
name: 'hideTotals',
type: 'boolean',
default: false,
description: 'Whether to hide the total of all metrics for all the matching rows, for every date range',
description:
'Whether to hide the total of all metrics for all the matching rows, for every date range',
},
{
displayName: 'Hide Value Ranges',
@ -280,7 +260,8 @@ export const reportFields: INodeProperties[] = [
name: 'includeEmptyRows',
type: 'boolean',
default: false,
description: 'Whether the response exclude rows if all the retrieved metrics are equal to zero',
description:
'Whether the response exclude rows if all the retrieved metrics are equal to zero',
},
{
displayName: 'Metrics',
@ -302,14 +283,16 @@ export const reportFields: INodeProperties[] = [
name: 'alias',
type: 'string',
default: '',
description: 'An alias for the metric expression is an alternate name for the expression. The alias can be used for filtering and sorting.',
description:
'An alias for the metric expression is an alternate name for the expression. The alias can be used for filtering and sorting.',
},
{
displayName: 'Expression',
name: 'expression',
type: 'string',
default: 'ga:newUsers',
description: '<p>A metric expression in the request. An expression is constructed from one or more metrics and numbers.</p><p>Accepted operators include: Plus (+), Minus (-), Negation (Unary -), Divided by (/), Multiplied by (*), Parenthesis, Positive cardinal numbers (0-9), can include decimals and is limited to 1024 characters.</p><p>Example ga:totalRefunds/ga:users, in most cases the metric expression is just a single metric name like ga:users.</p><p>Adding mixed MetricType (E.g., CURRENCY + PERCENTAGE) metrics will result in unexpected results.</p>.',
description:
'<p>A metric expression in the request. An expression is constructed from one or more metrics and numbers.</p><p>Accepted operators include: Plus (+), Minus (-), Negation (Unary -), Divided by (/), Multiplied by (*), Parenthesis, Positive cardinal numbers (0-9), can include decimals and is limited to 1024 characters.</p><p>Example ga:totalRefunds/ga:users, in most cases the metric expression is just a single metric name like ga:users.</p><p>Adding mixed MetricType (E.g., CURRENCY + PERCENTAGE) metrics will result in unexpected results.</p>.',
},
{
displayName: 'Formatting Type',

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const userActivityOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const userActivityOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'userActivity',
],
resource: ['userActivity'],
},
},
options: [
@ -39,16 +35,13 @@ export const userActivityFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'userActivity',
],
operation: [
'search',
],
resource: ['userActivity'],
operation: ['search'],
},
},
placeholder: '123456',
description: 'The View ID of Google Analytics. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The View ID of Google Analytics. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'User ID',
@ -58,12 +51,8 @@ export const userActivityFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'userActivity',
],
operation: [
'search',
],
resource: ['userActivity'],
operation: ['search'],
},
},
placeholder: '123456',
@ -75,12 +64,8 @@ export const userActivityFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'search',
],
resource: [
'userActivity',
],
operation: ['search'],
resource: ['userActivity'],
},
},
default: false,
@ -92,15 +77,9 @@ export const userActivityFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'search',
],
resource: [
'userActivity',
],
returnAll: [
false,
],
operation: ['search'],
resource: ['userActivity'],
returnAll: [false],
},
},
typeOptions: {
@ -118,12 +97,8 @@ export const userActivityFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'search',
],
resource: [
'userActivity',
],
operation: ['search'],
resource: ['userActivity'],
},
},
options: [

View file

@ -1,26 +1,29 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject,
JsonObject,
NodeApiError,
NodeOperationError
} from 'n8n-workflow';
import { IDataObject, JsonObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import moment from 'moment-timezone';
import * as jwt from 'jsonwebtoken';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
const options: OptionsWithUri = {
headers: {
@ -64,8 +67,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -75,41 +86,39 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['pageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['pageToken'] !== undefined &&
responseData['pageToken'] !== ''
);
} while (responseData['pageToken'] !== undefined && responseData['pageToken'] !== '');
return returnData;
}
function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, credentials: IDataObject): Promise<IDataObject> {
function getAccessToken(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
credentials: IDataObject,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const privateKey = (credentials.privateKey as string).replace(/\\n/g, '\n').trim();
const scopes = [
'https://www.googleapis.com/auth/bigquery',
];
const scopes = ['https://www.googleapis.com/auth/bigquery'];
const now = moment().unix();
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey,
{
algorithm: 'RS256',
header: {
'kid': privateKey,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey,
typ: 'JWT',
alg: 'RS256',
},
},
);

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,16 +10,9 @@ import {
NodeApiError,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
simplify,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems, simplify } from './GenericFunctions';
import {
recordFields,
recordOperations,
} from './RecordDescription';
import { recordFields, recordOperations } from './RecordDescription';
import { v4 as uuid } from 'uuid';
@ -45,9 +36,7 @@ export class GoogleBigQuery implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -56,9 +45,7 @@ export class GoogleBigQuery implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -101,15 +88,9 @@ export class GoogleBigQuery implements INodeType {
methods = {
loadOptions: {
async getProjects(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getProjects(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { projects } = await googleApiRequest.call(
this,
'GET',
'/v2/projects',
);
const { projects } = await googleApiRequest.call(this, 'GET', '/v2/projects');
for (const project of projects) {
returnData.push({
name: project.friendlyName as string,
@ -118,9 +99,7 @@ export class GoogleBigQuery implements INodeType {
}
return returnData;
},
async getDatasets(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getDatasets(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const projectId = this.getCurrentNodeParameter('projectId');
const returnData: INodePropertyOptions[] = [];
const { datasets } = await googleApiRequest.call(
@ -136,9 +115,7 @@ export class GoogleBigQuery implements INodeType {
}
return returnData;
},
async getTables(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getTables(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const projectId = this.getCurrentNodeParameter('projectId');
const datasetId = this.getCurrentNodeParameter('datasetId');
const returnData: INodePropertyOptions[] = [];
@ -168,13 +145,11 @@ export class GoogleBigQuery implements INodeType {
const operation = this.getNodeParameter('operation', 0) as string;
if (resource === 'record') {
// *********************************************************************
// record
// *********************************************************************
if (operation === 'create') {
// ----------------------------------
// record: create
// ----------------------------------
@ -188,14 +163,13 @@ export class GoogleBigQuery implements INodeType {
const body: IDataObject = {};
for (let i = 0; i < length; i++) {
const options = this.getNodeParameter('options', i) as IDataObject;
Object.assign(body, options);
if (body.traceId === undefined) {
body.traceId = uuid();
}
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map(column => column.trim());
const columnList = columns.split(',').map((column) => column.trim());
const record: IDataObject = {};
for (const key of Object.keys(items[i].json)) {
@ -224,7 +198,6 @@ export class GoogleBigQuery implements INodeType {
}
}
} else if (operation === 'getAll') {
// ----------------------------------
// record: getAll
// ----------------------------------
@ -273,7 +246,10 @@ export class GoogleBigQuery implements INodeType {
{},
qs,
);
returnData.push.apply(returnData, (simple) ? simplify(responseData, fields) : responseData);
returnData.push.apply(
returnData,
simple ? simplify(responseData, fields) : responseData,
);
} else {
qs.maxResults = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(
@ -283,7 +259,10 @@ export class GoogleBigQuery implements INodeType {
{},
qs,
);
returnData.push.apply(returnData, (simple) ? simplify(responseData.rows, fields) : responseData.rows);
returnData.push.apply(
returnData,
simple ? simplify(responseData.rows, fields) : responseData.rows,
);
}
} catch (error) {
if (this.continueOnFail()) {

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const recordOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const recordOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'record',
],
resource: ['record'],
},
},
options: [
@ -47,16 +43,13 @@ export const recordFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'record',
],
operation: ['create'],
resource: ['record'],
},
},
default: '',
description: 'ID of the project to create the record in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'ID of the project to create the record in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Dataset Name or ID',
@ -64,23 +57,18 @@ export const recordFields: INodeProperties[] = [
type: 'options',
typeOptions: {
loadOptionsMethod: 'getDatasets',
loadOptionsDependsOn: [
'projectId',
],
loadOptionsDependsOn: ['projectId'],
},
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'record',
],
operation: ['create'],
resource: ['record'],
},
},
default: '',
description: 'ID of the dataset to create the record in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'ID of the dataset to create the record in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Table Name or ID',
@ -88,24 +76,18 @@ export const recordFields: INodeProperties[] = [
type: 'options',
typeOptions: {
loadOptionsMethod: 'getTables',
loadOptionsDependsOn: [
'projectId',
'datasetId',
],
loadOptionsDependsOn: ['projectId', 'datasetId'],
},
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'record',
],
operation: ['create'],
resource: ['record'],
},
},
default: '',
description: 'ID of the table to create the record in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'ID of the table to create the record in. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Columns',
@ -113,12 +95,8 @@ export const recordFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
resource: [
'record',
],
operation: [
'create',
],
resource: ['record'],
operation: ['create'],
},
},
default: '',
@ -134,12 +112,8 @@ export const recordFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'record',
],
operation: ['create'],
resource: ['record'],
},
},
options: [
@ -162,14 +136,16 @@ export const recordFields: INodeProperties[] = [
name: 'templateSuffix',
type: 'string',
default: '',
description: 'Create a new table based on the destination table and insert rows into the new table. The new table will be named <code>{destinationTable}{templateSuffix}</code>',
description:
'Create a new table based on the destination table and insert rows into the new table. The new table will be named <code>{destinationTable}{templateSuffix}</code>',
},
{
displayName: 'Trace ID',
name: 'traceId',
type: 'string',
default: '',
description: 'Unique ID for the request, for debugging only. It is case-sensitive, limited to up to 36 ASCII characters. A UUID is recommended.',
description:
'Unique ID for the request, for debugging only. It is case-sensitive, limited to up to 36 ASCII characters. A UUID is recommended.',
},
],
},
@ -187,16 +163,13 @@ export const recordFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'record',
],
operation: ['getAll'],
resource: ['record'],
},
},
default: '',
description: 'ID of the project to retrieve all rows from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'ID of the project to retrieve all rows from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Dataset Name or ID',
@ -204,23 +177,18 @@ export const recordFields: INodeProperties[] = [
type: 'options',
typeOptions: {
loadOptionsMethod: 'getDatasets',
loadOptionsDependsOn: [
'projectId',
],
loadOptionsDependsOn: ['projectId'],
},
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'record',
],
operation: ['getAll'],
resource: ['record'],
},
},
default: '',
description: 'ID of the dataset to retrieve all rows from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'ID of the dataset to retrieve all rows from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Table Name or ID',
@ -228,24 +196,18 @@ export const recordFields: INodeProperties[] = [
type: 'options',
typeOptions: {
loadOptionsMethod: 'getTables',
loadOptionsDependsOn: [
'projectId',
'datasetId',
],
loadOptionsDependsOn: ['projectId', 'datasetId'],
},
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'record',
],
operation: ['getAll'],
resource: ['record'],
},
},
default: '',
description: 'ID of the table to retrieve all rows from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'ID of the table to retrieve all rows from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Return All',
@ -253,12 +215,8 @@ export const recordFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'record',
],
operation: ['getAll'],
resource: ['record'],
},
},
default: false,
@ -270,15 +228,9 @@ export const recordFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'record',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['record'],
returnAll: [false],
},
},
typeOptions: {
@ -294,12 +246,8 @@ export const recordFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'record',
],
operation: [
'getAll',
],
resource: ['record'],
operation: ['getAll'],
},
},
default: true,
@ -313,12 +261,8 @@ export const recordFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'record',
],
operation: ['getAll'],
resource: ['record'],
},
},
options: [
@ -327,7 +271,8 @@ export const recordFields: INodeProperties[] = [
name: 'selectedFields',
type: 'string',
default: '',
description: 'Subset of fields to return, supports select into sub fields. Example: <code>selectedFields = "a,e.d.f"</code>',
description:
'Subset of fields to return, supports select into sub fields. Example: <code>selectedFields = "a,e.d.f"</code>',
},
// {
// displayName: 'Use Int64 Timestamp',

View file

@ -1,16 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import moment from 'moment-timezone';
@ -23,8 +15,22 @@ interface IGoogleAuthCredentials {
privateKey: string;
}
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -44,12 +50,15 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi') as {
const credentials = (await this.getCredentials('googleApi')) as {
email: string;
privateKey: string;
};
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
//@ts-ignore
@ -67,8 +76,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -77,19 +94,18 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
do {
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
returnData.push.apply(returnData, responseData[propertyName] || []);
} while (
returnData.length < responseData.totalItems
);
} while (returnData.length < responseData.totalItems);
return returnData;
}
function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
function getAccessToken(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
'https://www.googleapis.com/auth/books',
];
const scopes = ['https://www.googleapis.com/auth/books'];
const now = moment().unix();
@ -98,20 +114,20 @@ function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoa
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey as string,
{
algorithm: 'RS256',
header: {
'kid': privateKey as string,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey as string,
typ: 'JWT',
alg: 'RS256',
},
},
);

View file

@ -1,19 +1,8 @@
import { IExecuteFunctions } from 'n8n-core';
import {
IExecuteFunctions,
} from 'n8n-core';
import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
export interface IGoogleAuthCredentials {
email: string;
@ -40,9 +29,7 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -51,9 +38,7 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -76,9 +61,7 @@ export class GoogleBooks implements INodeType {
default: 'serviceAccount',
displayOptions: {
show: {
'@version': [
1,
],
'@version': [1],
},
},
},
@ -99,9 +82,7 @@ export class GoogleBooks implements INodeType {
default: 'oAuth2',
displayOptions: {
show: {
'@version': [
2,
],
'@version': [2],
},
},
},
@ -147,9 +128,7 @@ export class GoogleBooks implements INodeType {
],
displayOptions: {
show: {
resource: [
'bookshelf',
],
resource: ['bookshelf'],
},
},
default: 'get',
@ -193,9 +172,7 @@ export class GoogleBooks implements INodeType {
],
displayOptions: {
show: {
resource: [
'bookshelfVolume',
],
resource: ['bookshelfVolume'],
},
},
default: 'getAll',
@ -221,9 +198,7 @@ export class GoogleBooks implements INodeType {
],
displayOptions: {
show: {
resource: [
'volume',
],
resource: ['volume'],
},
},
default: 'get',
@ -236,14 +211,8 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'get',
'getAll',
],
resource: [
'bookshelf',
'bookshelfVolume',
],
operation: ['get', 'getAll'],
resource: ['bookshelf', 'bookshelfVolume'],
},
},
},
@ -260,12 +229,8 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'volume',
],
operation: ['getAll'],
resource: ['volume'],
},
},
},
@ -278,19 +243,11 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'get',
'getAll',
],
resource: [
'bookshelf',
'bookshelfVolume',
],
operation: ['get', 'getAll'],
resource: ['bookshelf', 'bookshelfVolume'],
},
hide: {
myLibrary: [
true,
],
myLibrary: [true],
},
},
},
@ -303,17 +260,8 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'get',
'add',
'clear',
'move',
'remove',
],
resource: [
'bookshelf',
'bookshelfVolume',
],
operation: ['get', 'add', 'clear', 'move', 'remove'],
resource: ['bookshelf', 'bookshelfVolume'],
},
},
},
@ -326,12 +274,8 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'bookshelfVolume',
],
operation: ['getAll'],
resource: ['bookshelfVolume'],
},
},
},
@ -344,16 +288,8 @@ export class GoogleBooks implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'add',
'move',
'remove',
'get',
],
resource: [
'bookshelfVolume',
'volume',
],
operation: ['add', 'move', 'remove', 'get'],
resource: ['bookshelfVolume', 'volume'],
},
},
},
@ -361,17 +297,14 @@ export class GoogleBooks implements INodeType {
displayName: 'Volume Position',
name: 'volumePosition',
type: 'string',
description: 'Position on shelf to move the item (0 puts the item before the current first item, 1 puts it between the first and the second and so on)',
description:
'Position on shelf to move the item (0 puts the item before the current first item, 1 puts it between the first and the second and so on)',
default: '',
required: true,
displayOptions: {
show: {
operation: [
'move',
],
resource: [
'bookshelfVolume',
],
operation: ['move'],
resource: ['bookshelfVolume'],
},
},
},
@ -381,9 +314,7 @@ export class GoogleBooks implements INodeType {
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
operation: ['getAll'],
},
},
default: false,
@ -395,12 +326,8 @@ export class GoogleBooks implements INodeType {
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
returnAll: [
false,
],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
@ -424,7 +351,6 @@ export class GoogleBooks implements INodeType {
for (let i = 0; i < length; i++) {
try {
if (resource === 'volume') {
if (operation === 'get') {
const volumeId = this.getNodeParameter('volumeId', i) as string;
@ -433,10 +359,22 @@ export class GoogleBooks implements INodeType {
const searchQuery = this.getNodeParameter('searchQuery', i) as string;
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
if (returnAll) {
responseData = await googleApiRequestAllItems.call(this, 'items', 'GET', `v1/volumes?q=${searchQuery}`, {});
responseData = await googleApiRequestAllItems.call(
this,
'items',
'GET',
`v1/volumes?q=${searchQuery}`,
{},
);
} else {
qs.maxResults = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(this, 'GET', `v1/volumes?q=${searchQuery}`, {}, qs);
responseData = await googleApiRequest.call(
this,
'GET',
`v1/volumes?q=${searchQuery}`,
{},
qs,
);
responseData = responseData.items || [];
}
}
@ -466,7 +404,13 @@ export class GoogleBooks implements INodeType {
endpoint = `v1/mylibrary/bookshelves`;
}
if (returnAll) {
responseData = await googleApiRequestAllItems.call(this, 'items', 'GET', endpoint, {});
responseData = await googleApiRequestAllItems.call(
this,
'items',
'GET',
endpoint,
{},
);
} else {
qs.maxResults = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(this, 'GET', endpoint, {}, qs);
@ -482,12 +426,21 @@ export class GoogleBooks implements INodeType {
const body: IDataObject = {
volumeId,
};
responseData = await googleApiRequest.call(this, 'POST', `v1/mylibrary/bookshelves/${shelfId}/addVolume`, body);
responseData = await googleApiRequest.call(
this,
'POST',
`v1/mylibrary/bookshelves/${shelfId}/addVolume`,
body,
);
}
if (operation === 'clear') {
const shelfId = this.getNodeParameter('shelfId', i) as string;
responseData = await googleApiRequest.call(this, 'POST', `v1/mylibrary/bookshelves/${shelfId}/clearVolumes`);
responseData = await googleApiRequest.call(
this,
'POST',
`v1/mylibrary/bookshelves/${shelfId}/clearVolumes`,
);
}
if (operation === 'getAll') {
@ -502,7 +455,13 @@ export class GoogleBooks implements INodeType {
endpoint = `v1/mylibrary/bookshelves/${shelfId}/volumes`;
}
if (returnAll) {
responseData = await googleApiRequestAllItems.call(this, 'items', 'GET', endpoint, {});
responseData = await googleApiRequestAllItems.call(
this,
'items',
'GET',
endpoint,
{},
);
} else {
qs.maxResults = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(this, 'GET', endpoint, {}, qs);
@ -518,7 +477,12 @@ export class GoogleBooks implements INodeType {
volumeId,
volumePosition,
};
responseData = await googleApiRequest.call(this, 'POST', `v1/mylibrary/bookshelves/${shelfId}/moveVolume`, body);
responseData = await googleApiRequest.call(
this,
'POST',
`v1/mylibrary/bookshelves/${shelfId}/moveVolume`,
body,
);
}
if (operation === 'remove') {
@ -527,7 +491,12 @@ export class GoogleBooks implements INodeType {
const body: IDataObject = {
volumeId,
};
responseData = await googleApiRequest.call(this, 'POST', `v1/mylibrary/bookshelves/${shelfId}/removeVolume`, body);
responseData = await googleApiRequest.call(
this,
'POST',
`v1/mylibrary/bookshelves/${shelfId}/removeVolume`,
body,
);
}
}
if (Array.isArray(responseData)) {
@ -535,7 +504,6 @@ export class GoogleBooks implements INodeType {
} else {
returnData.push(responseData as IDataObject);
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const calendarOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const calendarOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'calendar',
],
resource: ['calendar'],
},
},
options: [
@ -35,16 +31,15 @@ export const calendarFields: INodeProperties[] = [
displayName: 'Calendar Name or ID',
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>',
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',
},
required: true,
displayOptions: {
show: {
resource: [
'calendar',
],
resource: ['calendar'],
},
},
default: '',
@ -56,12 +51,8 @@ export const calendarFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'availability',
],
resource: [
'calendar',
],
operation: ['availability'],
resource: ['calendar'],
},
},
default: '',
@ -74,12 +65,8 @@ export const calendarFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'availability',
],
resource: [
'calendar',
],
operation: ['availability'],
resource: ['calendar'],
},
},
default: '',
@ -92,12 +79,8 @@ export const calendarFields: INodeProperties[] = [
placeholder: 'Add Options',
displayOptions: {
show: {
operation: [
'availability',
],
resource: [
'calendar',
],
operation: ['availability'],
resource: ['calendar'],
},
},
default: {},
@ -134,7 +117,8 @@ export const calendarFields: INodeProperties[] = [
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>.',
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>.',
},
],
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const eventOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const eventOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'event',
],
resource: ['event'],
},
},
options: [
@ -59,16 +55,15 @@ export const eventFields: INodeProperties[] = [
displayName: 'Calendar Name or ID',
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>',
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',
},
required: true,
displayOptions: {
show: {
resource: [
'event',
],
resource: ['event'],
},
},
default: '',
@ -84,12 +79,8 @@ export const eventFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'event',
],
operation: ['create'],
resource: ['event'],
},
},
default: '',
@ -102,12 +93,8 @@ export const eventFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'event',
],
operation: ['create'],
resource: ['event'],
},
},
default: '',
@ -119,12 +106,8 @@ export const eventFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'event',
],
operation: ['create'],
resource: ['event'],
},
},
default: true,
@ -137,12 +120,8 @@ export const eventFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'event',
],
operation: ['create'],
resource: ['event'],
},
},
options: [
@ -182,7 +161,8 @@ export const eventFields: INodeProperties[] = [
loadOptionsMethod: 'getColors',
},
default: '',
description: 'The color of the event. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The color of the event. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Conference Data',
@ -202,12 +182,11 @@ export const eventFields: INodeProperties[] = [
displayName: 'Type Name or ID',
name: 'conferenceSolution',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getConferenceSolutations',
loadOptionsDependsOn: [
'calendar',
],
loadOptionsDependsOn: ['calendar'],
},
default: '',
},
@ -244,7 +223,8 @@ export const eventFields: INodeProperties[] = [
name: 'guestsCanSeeOtherGuests',
type: 'boolean',
default: true,
description: 'Whether attendees other than the organizer can see who the event\'s attendees are',
description:
"Whether attendees other than the organizer can see who the event's attendees are",
},
{
displayName: 'ID',
@ -265,7 +245,8 @@ export const eventFields: INodeProperties[] = [
name: 'maxAttendees',
type: 'number',
default: 0,
description: '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.',
description:
'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: 'Repeat Frequency',
@ -311,7 +292,8 @@ export const eventFields: INodeProperties[] = [
name: 'rrule',
type: 'string',
default: '',
description: 'Recurrence rule. When set, the parameters Repeat Frequency, Repeat How Many Times and Repeat Until are ignored.',
description:
'Recurrence rule. When set, the parameters Repeat Frequency, Repeat How Many Times and Repeat Until are ignored.',
},
{
displayName: 'Send Updates',
@ -331,7 +313,8 @@ export const eventFields: INodeProperties[] = [
{
name: 'None',
value: 'none',
description: 'No notifications are sent. This value should only be used for migration use case.',
description:
'No notifications are sent. This value should only be used for migration use case.',
},
],
description: 'Whether to send notifications about the creation of the new event',
@ -386,7 +369,8 @@ export const eventFields: INodeProperties[] = [
{
name: 'Public',
value: 'public',
description: 'The event is public and event details are visible to all readers of the calendar',
description:
'The event is public and event details are visible to all readers of the calendar',
},
],
default: 'default',
@ -405,15 +389,9 @@ export const eventFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'event',
],
operation: [
'create',
],
useDefaultReminders: [
false,
],
resource: ['event'],
operation: ['create'],
useDefaultReminders: [false],
},
},
options: [
@ -450,7 +428,8 @@ export const eventFields: INodeProperties[] = [
],
},
],
description: 'If the event doesn\'t use the default reminders, this lists the reminders specific to the event',
description:
"If the event doesn't use the default reminders, this lists the reminders specific to the event",
},
/* -------------------------------------------------------------------------- */
@ -463,12 +442,8 @@ export const eventFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'event',
],
operation: ['delete'],
resource: ['event'],
},
},
default: '',
@ -481,12 +456,8 @@ export const eventFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'event',
],
operation: ['delete'],
resource: ['event'],
},
},
options: [
@ -508,7 +479,8 @@ export const eventFields: INodeProperties[] = [
{
name: 'None',
value: 'none',
description: 'No notifications are sent. This value should only be used for migration use case.',
description:
'No notifications are sent. This value should only be used for migration use case.',
},
],
description: 'Whether to send notifications about the creation of the new event',
@ -526,12 +498,8 @@ export const eventFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'event',
],
operation: ['get'],
resource: ['event'],
},
},
default: '',
@ -544,12 +512,8 @@ export const eventFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'event',
],
operation: ['get'],
resource: ['event'],
},
},
options: [
@ -558,7 +522,8 @@ export const eventFields: INodeProperties[] = [
name: 'maxAttendees',
type: 'number',
default: 0,
description: '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.',
description:
'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',
@ -568,7 +533,8 @@ export const eventFields: INodeProperties[] = [
loadOptionsMethod: 'getTimezones',
},
default: '',
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>.',
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>.',
},
],
},
@ -582,12 +548,8 @@ export const eventFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'event',
],
operation: ['getAll'],
resource: ['event'],
},
},
default: false,
@ -599,15 +561,9 @@ export const eventFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'event',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['event'],
returnAll: [false],
},
},
typeOptions: {
@ -625,12 +581,8 @@ export const eventFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'event',
],
operation: ['getAll'],
resource: ['event'],
},
},
options: [
@ -646,7 +598,8 @@ export const eventFields: INodeProperties[] = [
name: 'maxAttendees',
type: 'number',
default: 0,
description: '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.',
description:
'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: 'Order By',
@ -656,7 +609,8 @@ export const eventFields: INodeProperties[] = [
{
name: 'Start Time',
value: 'startTime',
description: 'Order by the start date/time (ascending). This is only available when querying single events (i.e. the parameter singleEvents is True).',
description:
'Order by the start date/time (ascending). This is only available when querying single events (i.e. the parameter singleEvents is True).',
},
{
name: 'Updated',
@ -672,14 +626,16 @@ export const eventFields: INodeProperties[] = [
name: 'query',
type: 'string',
default: '',
description: 'Free text search terms to find events that match these terms in any field, except for extended properties',
description:
'Free text search terms to find events that match these terms in any field, except for extended properties',
},
{
displayName: 'Show Deleted',
name: 'showDeleted',
type: 'boolean',
default: false,
description: 'Whether to include deleted events (with status equals "cancelled") in the result',
description:
'Whether to include deleted events (with status equals "cancelled") in the result',
},
{
displayName: 'Show Hidden Invitations',
@ -693,21 +649,22 @@ export const eventFields: INodeProperties[] = [
name: 'singleEvents',
type: 'boolean',
default: false,
description: 'Whether to expand recurring events into instances and only return single one-off events and instances of recurring events, but not the underlying recurring events themselves',
description:
'Whether to expand recurring events into instances and only return single one-off events and instances of recurring events, but not the underlying recurring events themselves',
},
{
displayName: 'Start Time',
name: 'timeMax',
type: 'dateTime',
default: '',
description: 'Upper bound (exclusive) for an event\'s start time to filter by',
description: "Upper bound (exclusive) for an event's start time to filter by",
},
{
displayName: 'End Time',
name: 'timeMin',
type: 'dateTime',
default: '',
description: 'Lower bound (exclusive) for an event\'s end time to filter by',
description: "Lower bound (exclusive) for an event's end time to filter by",
},
{
displayName: 'Timezone Name or ID',
@ -717,14 +674,16 @@ export const eventFields: INodeProperties[] = [
loadOptionsMethod: 'getTimezones',
},
default: '',
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>.',
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>.',
},
{
displayName: 'Updated Min',
name: 'updatedMin',
type: 'dateTime',
default: '',
description: 'Lower bound for an event\'s last modification time (as a RFC3339 timestamp) to filter by. When specified, entries deleted since this time will always be included regardless of showDeleted.',
description:
"Lower bound for an event's last modification time (as a RFC3339 timestamp) to filter by. When specified, entries deleted since this time will always be included regardless of showDeleted.",
},
],
},
@ -739,12 +698,8 @@ export const eventFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'event',
],
operation: ['update'],
resource: ['event'],
},
},
default: '',
@ -755,12 +710,8 @@ export const eventFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'event',
],
operation: ['update'],
resource: ['event'],
},
},
default: true,
@ -773,12 +724,8 @@ export const eventFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'event',
],
operation: ['update'],
resource: ['event'],
},
},
options: [
@ -818,7 +765,8 @@ export const eventFields: INodeProperties[] = [
loadOptionsMethod: 'getColors',
},
default: '',
description: 'The color of the event. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The color of the event. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Description',
@ -855,7 +803,8 @@ export const eventFields: INodeProperties[] = [
name: 'guestsCanSeeOtherGuests',
type: 'boolean',
default: true,
description: 'Whether attendees other than the organizer can see who the event\'s attendees are',
description:
"Whether attendees other than the organizer can see who the event's attendees are",
},
{
displayName: 'ID',
@ -876,7 +825,8 @@ export const eventFields: INodeProperties[] = [
name: 'maxAttendees',
type: 'number',
default: 0,
description: '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.',
description:
'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: 'Repeat Frequency',
@ -922,7 +872,8 @@ export const eventFields: INodeProperties[] = [
name: 'rrule',
type: 'string',
default: '',
description: 'Recurrence rule. When set, the parameters Repeat Frequency, Repeat How Many Times and Repeat Until are ignored.',
description:
'Recurrence rule. When set, the parameters Repeat Frequency, Repeat How Many Times and Repeat Until are ignored.',
},
{
displayName: 'Send Updates',
@ -942,7 +893,8 @@ export const eventFields: INodeProperties[] = [
{
name: 'None',
value: 'none',
description: 'No notifications are sent. This value should only be used for migration use case.',
description:
'No notifications are sent. This value should only be used for migration use case.',
},
],
description: 'Whether to send notifications about the creation of the new event',
@ -999,7 +951,8 @@ export const eventFields: INodeProperties[] = [
{
name: 'Public',
value: 'public',
description: 'The event is public and event details are visible to all readers of the calendar',
description:
'The event is public and event details are visible to all readers of the calendar',
},
{
name: 'Private',
@ -1023,15 +976,9 @@ export const eventFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'event',
],
operation: [
'update',
],
useDefaultReminders: [
false,
],
resource: ['event'],
operation: ['update'],
useDefaultReminders: [false],
},
},
options: [
@ -1068,6 +1015,7 @@ export const eventFields: INodeProperties[] = [
],
},
],
description: 'If the event doesn\'t use the default reminders, this lists the reminders specific to the event',
description:
"If the event doesn't use the default reminders, this lists the reminders specific to the event",
},
];

View file

@ -1,6 +1,4 @@
import {
IDataObject,
} from 'n8n-workflow';
import { IDataObject } from 'n8n-workflow';
export interface IReminder {
useDefault?: boolean;
@ -9,10 +7,10 @@ export interface IReminder {
export interface IConferenceData {
createRequest?: {
requestId: string,
requestId: string;
conferenceSolution: {
type: string,
}
type: string;
};
};
}

View file

@ -1,20 +1,20 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject,
IPollFunctions,
NodeApiError,
} from 'n8n-workflow';
import { IDataObject, IPollFunctions, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -39,8 +39,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -50,10 +58,7 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -14,24 +12,13 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
import {
eventFields,
eventOperations,
} from './EventDescription';
import { eventFields, eventOperations } from './EventDescription';
import {
calendarFields,
calendarOperations,
} from './CalendarDescription';
import { calendarFields, calendarOperations } from './CalendarDescription';
import {
IEvent,
} from './EventInterface';
import { IEvent } from './EventInterface';
import moment from 'moment-timezone';
@ -86,17 +73,17 @@ export class GoogleCalendar implements INodeType {
loadOptions: {
// Get all the calendars to display them to user so that he can
// select them easily
async getConferenceSolutations(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getConferenceSolutations(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const calendar = this.getCurrentNodeParameter('calendar') as string;
const posibleSolutions: IDataObject = {
'eventHangout': 'Google Hangout',
'eventNamedHangout': 'Google Hangout Classic',
'hangoutsMeet': 'Google Meet',
eventHangout: 'Google Hangout',
eventNamedHangout: 'Google Hangout Classic',
hangoutsMeet: 'Google Meet',
};
const { conferenceProperties: { allowedConferenceSolutionTypes } } = await googleApiRequest.call(
const {
conferenceProperties: { allowedConferenceSolutionTypes },
} = await googleApiRequest.call(
this,
'GET',
`/calendar/v3/users/me/calendarList/${calendar}`,
@ -111,9 +98,7 @@ export class GoogleCalendar implements INodeType {
},
// Get all the calendars to display them to user so that he can
// select them easily
async getCalendars(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getCalendars(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const calendars = await googleApiRequestAllItems.call(
this,
@ -133,15 +118,9 @@ export class GoogleCalendar implements INodeType {
},
// Get all the colors to display them to user so that he can
// select them easily
async getColors(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getColors(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { event } = await googleApiRequest.call(
this,
'GET',
'/calendar/v3/colors',
);
const { event } = await googleApiRequest.call(this, 'GET', '/calendar/v3/colors');
for (const key of Object.keys(event)) {
const colorName = `Background: ${event[key].background} - Foreground: ${event[key].foreground}`;
const colorId = key;
@ -154,9 +133,7 @@ export class GoogleCalendar implements INodeType {
},
// Get all the timezones to display them to user so that he can
// select them easily
async getTimezones(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getTimezones(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
for (const timezone of moment.tz.names()) {
const timezoneName = timezone;
@ -218,7 +195,6 @@ export class GoogleCalendar implements INodeType {
responseData = {
available: !responseData.calendars[calendarId].busy.length,
};
} else if (outputFormat === 'bookedSlots') {
responseData = responseData.calendars[calendarId].busy;
}
@ -230,14 +206,8 @@ export class GoogleCalendar implements INodeType {
const calendarId = this.getNodeParameter('calendar', i) 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;
const additionalFields = this.getNodeParameter(
'additionalFields',
i,
) as IDataObject;
const useDefaultReminders = this.getNodeParameter('useDefaultReminders', i) as boolean;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (additionalFields.maxAttendees) {
qs.maxAttendees = additionalFields.maxAttendees as number;
@ -260,8 +230,14 @@ export class GoogleCalendar implements INodeType {
};
if (additionalFields.attendees) {
body.attendees = [];
(additionalFields.attendees as string[]).forEach(attendee => {
body.attendees!.push.apply(body.attendees, attendee.split(',').map(a => a.trim()).map(email => ({ email })));
(additionalFields.attendees as string[]).forEach((attendee) => {
body.attendees!.push.apply(
body.attendees,
attendee
.split(',')
.map((a) => a.trim())
.map((email) => ({ email })),
);
});
}
if (additionalFields.color) {
@ -295,10 +271,8 @@ export class GoogleCalendar implements INodeType {
body.visibility = additionalFields.visibility as string;
}
if (!useDefaultReminders) {
const reminders = (this.getNodeParameter(
'remindersUi',
i,
) as IDataObject).remindersValues as IDataObject[];
const reminders = (this.getNodeParameter('remindersUi', i) as IDataObject)
.remindersValues as IDataObject[];
body.reminders = {
useDefault: false,
};
@ -309,14 +283,14 @@ export class GoogleCalendar implements INodeType {
if (additionalFields.allday) {
body.start = {
date: timezone ?
moment.tz(start, timezone).utc(true).format('YYYY-MM-DD') :
moment.tz(start, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
date: timezone
? moment.tz(start, timezone).utc(true).format('YYYY-MM-DD')
: moment.tz(start, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
};
body.end = {
date: timezone ?
moment.tz(end, timezone).utc(true).format('YYYY-MM-DD') :
moment.tz(end, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
date: timezone
? moment.tz(end, timezone).utc(true).format('YYYY-MM-DD')
: moment.tz(end, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
};
}
//exampel: RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10;UNTIL=20110701T170000Z
@ -325,12 +299,11 @@ export class GoogleCalendar implements INodeType {
if (additionalFields.rrule) {
body.recurrence = [`RRULE:${additionalFields.rrule}`];
} else {
if (
additionalFields.repeatHowManyTimes &&
additionalFields.repeatUntil
) {
throw new NodeOperationError(this.getNode(),
`You can set either 'Repeat How Many Times' or 'Repeat Until' but not both`, { itemIndex: i },
if (additionalFields.repeatHowManyTimes && additionalFields.repeatUntil) {
throw new NodeOperationError(
this.getNode(),
`You can set either 'Repeat How Many Times' or 'Repeat Until' but not both`,
{ itemIndex: i },
);
}
if (additionalFields.repeatFrecuency) {
@ -339,17 +312,13 @@ export class GoogleCalendar implements INodeType {
);
}
if (additionalFields.repeatHowManyTimes) {
body.recurrence?.push(
`COUNT=${additionalFields.repeatHowManyTimes};`,
);
body.recurrence?.push(`COUNT=${additionalFields.repeatHowManyTimes};`);
}
if (additionalFields.repeatUntil) {
const repeatUntil = moment(additionalFields.repeatUntil as string)
.utc()
.format('YYYYMMDDTHHmmss');
body.recurrence?.push(
`UNTIL=${repeatUntil}Z`,
);
body.recurrence?.push(`UNTIL=${repeatUntil}Z`);
}
if (body.recurrence.length !== 0) {
body.recurrence = [`RRULE:${body.recurrence.join('')}`];
@ -357,9 +326,9 @@ export class GoogleCalendar implements INodeType {
}
if (additionalFields.conferenceDataUi) {
const conferenceData = (additionalFields.conferenceDataUi as IDataObject).conferenceDataValues as IDataObject;
const conferenceData = (additionalFields.conferenceDataUi as IDataObject)
.conferenceDataValues as IDataObject;
if (conferenceData) {
qs.conferenceDataVersion = 1;
body.conferenceData = {
createRequest: {
@ -477,15 +446,9 @@ export class GoogleCalendar implements INodeType {
if (operation === 'update') {
const calendarId = this.getNodeParameter('calendar', i) as string;
const eventId = this.getNodeParameter('eventId', i) as string;
const useDefaultReminders = this.getNodeParameter(
'useDefaultReminders',
i,
) as boolean;
const updateFields = this.getNodeParameter(
'updateFields',
i,
) as IDataObject;
const timezone = (updateFields.timezone as string);
const useDefaultReminders = this.getNodeParameter('useDefaultReminders', i) as boolean;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
const timezone = updateFields.timezone as string;
if (updateFields.maxAttendees) {
qs.maxAttendees = updateFields.maxAttendees as number;
@ -511,8 +474,14 @@ export class GoogleCalendar implements INodeType {
}
if (updateFields.attendees) {
body.attendees = [];
(updateFields.attendees as string[]).forEach(attendee => {
body.attendees!.push.apply(body.attendees, attendee.split(',').map(a => a.trim()).map(email => ({ email })));
(updateFields.attendees as string[]).forEach((attendee) => {
body.attendees!.push.apply(
body.attendees,
attendee
.split(',')
.map((a) => a.trim())
.map((email) => ({ email })),
);
});
}
if (updateFields.color) {
@ -546,10 +515,8 @@ export class GoogleCalendar implements INodeType {
body.visibility = updateFields.visibility as string;
}
if (!useDefaultReminders) {
const reminders = (this.getNodeParameter(
'remindersUi',
i,
) as IDataObject).remindersValues as IDataObject[];
const reminders = (this.getNodeParameter('remindersUi', i) as IDataObject)
.remindersValues as IDataObject[];
body.reminders = {
useDefault: false,
};
@ -559,14 +526,14 @@ export class GoogleCalendar implements INodeType {
}
if (updateFields.allday && updateFields.start && updateFields.end) {
body.start = {
date: timezone ?
moment.tz(updateFields.start, timezone).utc(true).format('YYYY-MM-DD') :
moment.tz(updateFields.start, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
date: timezone
? moment.tz(updateFields.start, timezone).utc(true).format('YYYY-MM-DD')
: moment.tz(updateFields.start, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
};
body.end = {
date: timezone ?
moment.tz(updateFields.end, timezone).utc(true).format('YYYY-MM-DD') :
moment.tz(updateFields.end, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
date: timezone
? moment.tz(updateFields.end, timezone).utc(true).format('YYYY-MM-DD')
: moment.tz(updateFields.end, moment.tz.guess()).utc(true).format('YYYY-MM-DD'),
};
}
//exampel: RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10;UNTIL=20110701T170000Z
@ -576,8 +543,10 @@ export class GoogleCalendar implements INodeType {
body.recurrence = [`RRULE:${updateFields.rrule}`];
} else {
if (updateFields.repeatHowManyTimes && updateFields.repeatUntil) {
throw new NodeOperationError(this.getNode(),
`You can set either 'Repeat How Many Times' or 'Repeat Until' but not both`, { itemIndex: i },
throw new NodeOperationError(
this.getNode(),
`You can set either 'Repeat How Many Times' or 'Repeat Until' but not both`,
{ itemIndex: i },
);
}
if (updateFields.repeatFrecuency) {
@ -593,9 +562,7 @@ export class GoogleCalendar implements INodeType {
.utc()
.format('YYYYMMDDTHHmmss');
body.recurrence?.push(
`UNTIL=${repeatUntil}Z`,
);
body.recurrence?.push(`UNTIL=${repeatUntil}Z`);
}
if (body.recurrence.length !== 0) {
body.recurrence = [`RRULE:${body.recurrence.join('')}`];
@ -623,11 +590,9 @@ export class GoogleCalendar implements INodeType {
throw error;
} else {
// Return the actual reason as error
returnData.push(
{
error: (error as JsonObject).message,
},
);
returnData.push({
error: (error as JsonObject).message,
});
continue;
}
}

View file

@ -1,4 +1,3 @@
import {
IDataObject,
ILoadOptionsFunctions,
@ -11,10 +10,7 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
import moment from 'moment';
@ -44,7 +40,8 @@ export class GoogleCalendarTrigger implements INodeType {
displayName: 'Calendar Name or ID',
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>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true,
typeOptions: {
loadOptionsMethod: 'getCalendars',
@ -88,7 +85,8 @@ export class GoogleCalendarTrigger implements INodeType {
name: 'matchTerm',
type: 'string',
default: '',
description: 'Free text search terms to filter events that match these terms in any field, except for extended properties',
description:
'Free text search terms to filter events that match these terms in any field, except for extended properties',
},
],
},
@ -99,9 +97,7 @@ export class GoogleCalendarTrigger implements INodeType {
loadOptions: {
// Get all the calendars to display them to user so that he can
// select them easily
async getCalendars(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getCalendars(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const calendars = await googleApiRequestAllItems.call(
this,
@ -128,29 +124,20 @@ export class GoogleCalendarTrigger implements INodeType {
const matchTerm = this.getNodeParameter('options.matchTerm', '') as string;
if (poolTimes.length === 0) {
throw new NodeOperationError(
this.getNode(),
'Please set a poll time',
);
throw new NodeOperationError(this.getNode(), 'Please set a poll time');
}
if (triggerOn === '') {
throw new NodeOperationError(
this.getNode(),
'Please select an event',
);
throw new NodeOperationError(this.getNode(), 'Please select an event');
}
if (calendarId === '') {
throw new NodeOperationError(
this.getNode(),
'Please select a calendar',
);
throw new NodeOperationError(this.getNode(), 'Please select a calendar');
}
const now = moment().utc().format();
const startDate = webhookData.lastTimeChecked as string || now;
const startDate = (webhookData.lastTimeChecked as string) || now;
const endDate = now;
@ -184,18 +171,42 @@ export class GoogleCalendarTrigger implements INodeType {
delete qs.timeMax;
qs.maxResults = 1;
events = await googleApiRequest.call(this, 'GET', `/calendar/v3/calendars/${calendarId}/events`, {}, qs);
events = await googleApiRequest.call(
this,
'GET',
`/calendar/v3/calendars/${calendarId}/events`,
{},
qs,
);
events = events.items;
} else {
events = await googleApiRequestAllItems.call(this, 'items', 'GET', `/calendar/v3/calendars/${calendarId}/events`, {}, qs);
events = await googleApiRequestAllItems.call(
this,
'items',
'GET',
`/calendar/v3/calendars/${calendarId}/events`,
{},
qs,
);
if (triggerOn === 'eventCreated') {
events = events.filter((event: { created: string }) => moment(event.created).isBetween(startDate, endDate));
events = events.filter((event: { created: string }) =>
moment(event.created).isBetween(startDate, endDate),
);
} else if (triggerOn === 'eventUpdated') {
events = events.filter((event: { created: string, updated: string }) => !moment(moment(event.created).format('YYYY-MM-DDTHH:mm:ss')).isSame(moment(event.updated).format('YYYY-MM-DDTHH:mm:ss')));
events = events.filter(
(event: { created: string; updated: string }) =>
!moment(moment(event.created).format('YYYY-MM-DDTHH:mm:ss')).isSame(
moment(event.updated).format('YYYY-MM-DDTHH:mm:ss'),
),
);
} else if (triggerOn === 'eventStarted') {
events = events.filter((event: { start: { dateTime: string } }) => moment(event.start.dateTime).isBetween(startDate, endDate, null, '[]'));
events = events.filter((event: { start: { dateTime: string } }) =>
moment(event.start.dateTime).isBetween(startDate, endDate, null, '[]'),
);
} else if (triggerOn === 'eventEnded') {
events = events.filter((event: { end: { dateTime: string } }) => moment(event.end.dateTime).isBetween(startDate, endDate, null, '[]'));
events = events.filter((event: { end: { dateTime: string } }) =>
moment(event.end.dateTime).isBetween(startDate, endDate, null, '[]'),
);
}
}
@ -206,7 +217,9 @@ export class GoogleCalendarTrigger implements INodeType {
}
if (this.getMode() === 'manual') {
throw new NodeApiError(this.getNode(), { message: 'No data with the current filter could be found' });
throw new NodeApiError(this.getNode(), {
message: 'No data with the current filter could be found',
});
}
return null;

View file

@ -1,12 +1,6 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
// ICredentialDataDecryptedObject,
@ -28,8 +22,18 @@ interface IGoogleAuthCredentials {
privateKey: string;
}
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, noCredentials = false, encoding?: null | undefined): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
noCredentials = false,
encoding?: null | undefined,
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -54,10 +58,13 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
if (noCredentials) {
//@ts-ignore
responseData = await this.helpers.request(options);
} else{
} else {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
//@ts-ignore
responseData = await this.helpers.request(options);
@ -69,16 +76,23 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
throw new NodeApiError(this.getNode(), error);
}
if(Object.keys(responseData as IDataObject).length !== 0) {
if (Object.keys(responseData as IDataObject).length !== 0) {
return responseData;
}
else {
return { 'success': true };
} else {
return { success: true };
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -88,20 +102,22 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
export function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | ICredentialTestFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
export function getAccessToken(
this:
| IExecuteFunctions
| IExecuteSingleFunctions
| ILoadOptionsFunctions
| ICredentialTestFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
'https://www.googleapis.com/auth/chat.bot',
];
const scopes = ['https://www.googleapis.com/auth/chat.bot'];
const now = moment().unix();
@ -110,20 +126,20 @@ export function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey,
{
algorithm: 'RS256',
header: {
'kid': privateKey,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey,
typ: 'JWT',
alg: 'RS256',
},
},
);
@ -145,7 +161,8 @@ export function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions
return this.helpers.request(options);
}
export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any
// tslint:disable-next-line:no-any
export function validateJSON(json: string | undefined): any {
let result;
try {
result = JSON.parse(json!);
@ -156,19 +173,15 @@ export function validateJSON(json: string | undefined): any { // tslint:disable-
}
export function getPagingParameters(resource: string, operation = 'getAll') {
const pagingParameters: INodeProperties [] = [
const pagingParameters: INodeProperties[] = [
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: [
resource,
],
operation: [
operation,
],
resource: [resource],
operation: [operation],
},
},
default: false,
@ -183,15 +196,9 @@ export function getPagingParameters(resource: string, operation = 'getAll') {
},
displayOptions: {
show: {
resource: [
resource,
],
operation: [
operation,
],
returnAll: [
false,
],
resource: [resource],
operation: [operation],
returnAll: [false],
},
},
default: 100,

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
ICredentialsDecrypted,
@ -15,14 +13,9 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
IMessage,
IMessageUi,
} from './MessageInterface';
import { IMessage, IMessageUi } from './MessageInterface';
import {
OptionsWithUri
} from 'request';
import { OptionsWithUri } from 'request';
import {
// attachmentFields,
@ -36,14 +29,10 @@ import {
messageFields,
messageOperations,
spaceFields,
spaceOperations
spaceOperations,
} from './descriptions';
import {
googleApiRequest,
googleApiRequestAllItems,
validateJSON,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems, validateJSON } from './GenericFunctions';
import moment from 'moment-timezone';
@ -124,16 +113,9 @@ export class GoogleChat implements INodeType {
loadOptions: {
// Get all the spaces to display them to user so that he can
// select them easily
async getSpaces(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getSpaces(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const spaces = await googleApiRequestAllItems.call(
this,
'spaces',
'GET',
`/v1/spaces`,
);
const spaces = await googleApiRequestAllItems.call(this, 'spaces', 'GET', `/v1/spaces`);
for (const space of spaces) {
returnData.push({
name: space.displayName,
@ -144,11 +126,11 @@ export class GoogleChat implements INodeType {
},
},
credentialTest: {
async testGoogleTokenAuth(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult> {
const scopes = [
'https://www.googleapis.com/auth/chat.bot',
];
async testGoogleTokenAuth(
this: ICredentialTestFunctions,
credential: ICredentialsDecrypted,
): Promise<INodeCredentialTestResult> {
const scopes = ['https://www.googleapis.com/auth/chat.bot'];
const now = moment().unix();
@ -158,20 +140,20 @@ export class GoogleChat implements INodeType {
try {
const signature = jwt.sign(
{
'iss': email,
'sub': credential.data!.delegatedEmail || email,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now,
iss: email,
sub: credential.data!.delegatedEmail || email,
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now,
},
privateKey,
{
algorithm: 'RS256',
header: {
'kid': privateKey,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey,
typ: 'JWT',
alg: 'RS256',
},
},
);
@ -264,13 +246,13 @@ export class GoogleChat implements INodeType {
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i) as string;
items[i].binary![binaryPropertyName] = await this.helpers.prepareBinaryData(responseData, endpoint);
items[i].binary![binaryPropertyName] = await this.helpers.prepareBinaryData(
responseData,
endpoint,
);
}
} else if (resource === 'space') {
if (operation === 'get') {
// ----------------------------------------
// space: get
// ----------------------------------------
@ -279,14 +261,8 @@ export class GoogleChat implements INodeType {
const spaceId = this.getNodeParameter('spaceId', i) as string;
responseData = await googleApiRequest.call(
this,
'GET',
`/v1/${spaceId}`,
);
responseData = await googleApiRequest.call(this, 'GET', `/v1/${spaceId}`);
} else if (operation === 'getAll') {
// ----------------------------------------
// space: getAll
// ----------------------------------------
@ -305,19 +281,12 @@ export class GoogleChat implements INodeType {
const limit = this.getNodeParameter('limit', i) as number;
qs.pageSize = limit;
responseData = await googleApiRequest.call(
this,
'GET',
`/v1/spaces`,
undefined,
qs,
);
responseData = await googleApiRequest.call(this, 'GET', `/v1/spaces`, undefined, qs);
responseData = responseData.spaces;
}
}
} else if (resource === 'member') {
if (operation === 'get') {
// ----------------------------------------
// member: get
// ----------------------------------------
@ -326,14 +295,8 @@ export class GoogleChat implements INodeType {
const memberId = this.getNodeParameter('memberId', i) as string;
responseData = await googleApiRequest.call(
this,
'GET',
`/v1/${memberId}`,
);
responseData = await googleApiRequest.call(this, 'GET', `/v1/${memberId}`);
} else if (operation === 'getAll') {
// ----------------------------------------
// member: getAll
// ----------------------------------------
@ -352,7 +315,6 @@ export class GoogleChat implements INodeType {
undefined,
qs,
);
} else {
const limit = this.getNodeParameter('limit', i) as number;
qs.pageSize = limit;
@ -366,11 +328,9 @@ export class GoogleChat implements INodeType {
);
responseData = responseData.memberships;
}
}
} else if (resource === 'message') {
if (operation === 'create') {
// ----------------------------------------
// message: create
// ----------------------------------------
@ -401,16 +361,21 @@ export class GoogleChat implements INodeType {
if (validateJSON(messageJson as string) !== undefined) {
message = JSON.parse(messageJson as string) as IMessage;
} else {
throw new NodeOperationError(this.getNode(), 'Message (JSON) must be a valid json', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'Message (JSON) must be a valid json',
{ itemIndex: i },
);
}
}
} else {
const messageUi = this.getNodeParameter('messageUi', i) as IMessageUi;
if (messageUi.text && messageUi.text !== '') {
message.text = messageUi.text;
} else {
throw new NodeOperationError(this.getNode(), 'Message Text must be provided.', { itemIndex: i });
throw new NodeOperationError(this.getNode(), 'Message Text must be provided.', {
itemIndex: i,
});
}
// // TODO: get cards from the UI
// if (messageUi?.cards?.metadataValues && messageUi?.cards?.metadataValues.length !== 0) {
@ -429,9 +394,7 @@ export class GoogleChat implements INodeType {
body,
qs,
);
} else if (operation === 'delete') {
// ----------------------------------------
// message: delete
// ----------------------------------------
@ -440,14 +403,8 @@ export class GoogleChat implements INodeType {
const messageId = this.getNodeParameter('messageId', i) as string;
responseData = await googleApiRequest.call(
this,
'DELETE',
`/v1/${messageId}`,
);
responseData = await googleApiRequest.call(this, 'DELETE', `/v1/${messageId}`);
} else if (operation === 'get') {
// ----------------------------------------
// message: get
// ----------------------------------------
@ -456,14 +413,8 @@ export class GoogleChat implements INodeType {
const messageId = this.getNodeParameter('messageId', i) as string;
responseData = await googleApiRequest.call(
this,
'GET',
`/v1/${messageId}`,
);
responseData = await googleApiRequest.call(this, 'GET', `/v1/${messageId}`);
} else if (operation === 'update') {
// ----------------------------------------
// message: update
// ----------------------------------------
@ -485,10 +436,13 @@ export class GoogleChat implements INodeType {
if (validateJSON(updateFieldsJson as string) !== undefined) {
message = JSON.parse(updateFieldsJson as string) as IMessage;
} else {
throw new NodeOperationError(this.getNode(), 'Update Fields (JSON) must be a valid json', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'Update Fields (JSON) must be a valid json',
{ itemIndex: i },
);
}
}
} else {
const updateFieldsUi = this.getNodeParameter('updateFieldsUi', i) as IDataObject;
if (updateFieldsUi.text) {
@ -514,17 +468,9 @@ export class GoogleChat implements INodeType {
updateMask = updateMask.slice(0, -1); // remove trailing comma
qs.updateMask = updateMask;
responseData = await googleApiRequest.call(
this,
'PUT',
`/v1/${messageId}`,
body,
qs,
);
responseData = await googleApiRequest.call(this, 'PUT', `/v1/${messageId}`, body, qs);
}
} else if (resource === 'attachment') {
if (operation === 'get') {
// ----------------------------------------
// attachment: get
@ -534,15 +480,10 @@ export class GoogleChat implements INodeType {
const attachmentName = this.getNodeParameter('attachmentName', i) as string;
responseData = await googleApiRequest.call(
this,
'GET',
`/v1/${attachmentName}`,
);
responseData = await googleApiRequest.call(this, 'GET', `/v1/${attachmentName}`);
}
} else if (resource === 'incomingWebhook') {
if (operation === 'create') {
// ----------------------------------------
// incomingWebhook: create
// ----------------------------------------
@ -570,33 +511,29 @@ export class GoogleChat implements INodeType {
if (validateJSON(messageJson as string) !== undefined) {
message = JSON.parse(messageJson as string) as IMessage;
} else {
throw new NodeOperationError(this.getNode(), 'Message (JSON) must be a valid json', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'Message (JSON) must be a valid json',
{ itemIndex: i },
);
}
}
} else {
const messageUi = this.getNodeParameter('messageUi', i) as IMessageUi;
if (messageUi.text && messageUi.text !== '') {
message.text = messageUi.text;
} else {
throw new NodeOperationError(this.getNode(), 'Message Text must be provided.', { itemIndex: i });
throw new NodeOperationError(this.getNode(), 'Message Text must be provided.', {
itemIndex: i,
});
}
}
const body: IDataObject = {};
Object.assign(body, message);
responseData = await googleApiRequest.call(
this,
'POST',
'',
body,
qs,
uri,
true,
);
responseData = await googleApiRequest.call(this, 'POST', '', body, qs, uri, true);
}
}
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const attachmentOperations: INodeProperties[] = [
{
@ -10,16 +8,15 @@ export const attachmentOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
resource: [
'attachment',
],
resource: ['attachment'],
},
},
options: [
{
name: 'Get',
value: 'get',
description: 'Gets the metadata of a message attachment. The attachment data is fetched using the media API.',
description:
'Gets the metadata of a message attachment. The attachment data is fetched using the media API.',
action: 'Get an attachment',
},
],
@ -27,7 +24,7 @@ export const attachmentOperations: INodeProperties[] = [
},
];
export const attachmentFields: INodeProperties[] = [
export const attachmentFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* attachments:get */
/* -------------------------------------------------------------------------- */
@ -38,12 +35,8 @@ export const attachmentFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'attachment',
],
operation: [
'get',
],
resource: ['attachment'],
operation: ['get'],
},
},
default: '',

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const incomingWebhookOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const incomingWebhookOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
resource: ['incomingWebhook'],
},
},
options: [
@ -27,24 +23,19 @@ export const incomingWebhookOperations: INodeProperties[] = [
},
];
export const incomingWebhookFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* incomingWebhook:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'See <a href="https://developers.google.com/chat/how-tos/webhooks" target="_blank">Google Chat Guide</a> To Webhooks',
displayName:
'See <a href="https://developers.google.com/chat/how-tos/webhooks" target="_blank">Google Chat Guide</a> To Webhooks',
name: 'jsonNotice',
type: 'notice',
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
resource: ['incomingWebhook'],
operation: ['create'],
},
},
default: '',
@ -56,12 +47,8 @@ export const incomingWebhookFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
resource: ['incomingWebhook'],
operation: ['create'],
},
},
default: '',
@ -73,12 +60,8 @@ export const incomingWebhookFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
resource: ['incomingWebhook'],
operation: ['create'],
},
},
default: false,
@ -92,18 +75,12 @@ export const incomingWebhookFields: INodeProperties[] = [
placeholder: 'Add Options',
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
jsonParameters: [
false,
],
resource: ['incomingWebhook'],
operation: ['create'],
jsonParameters: [false],
},
},
default: {'text': ''},
default: { text: '' },
description: 'The message object',
options: [
{
@ -116,20 +93,15 @@ export const incomingWebhookFields: INodeProperties[] = [
],
},
{
displayName: 'See <a href="https://developers.google.com/chat/reference/rest/v1/spaces.messages#Message" target="_blank">Google Chat Guide</a> To Creating Messages',
displayName:
'See <a href="https://developers.google.com/chat/reference/rest/v1/spaces.messages#Message" target="_blank">Google Chat Guide</a> To Creating Messages',
name: 'jsonNotice',
type: 'notice',
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
jsonParameters: [
true,
],
resource: ['incomingWebhook'],
operation: ['create'],
jsonParameters: [true],
},
},
default: '',
@ -144,15 +116,9 @@ export const incomingWebhookFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
jsonParameters: [
true,
],
resource: ['incomingWebhook'],
operation: ['create'],
jsonParameters: [true],
},
},
default: '',
@ -166,12 +132,8 @@ export const incomingWebhookFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'incomingWebhook',
],
operation: [
'create',
],
resource: ['incomingWebhook'],
operation: ['create'],
},
},
options: [
@ -180,7 +142,8 @@ export const incomingWebhookFields: INodeProperties[] = [
name: 'threadKey',
type: 'string',
default: '',
description: 'Thread identifier which groups messages into a single thread. Has no effect if thread field, corresponding to an existing thread, is set in message. Example: spaces/AAAAMpdlehY/threads/MZ8fXhZXGkk.',
description:
'Thread identifier which groups messages into a single thread. Has no effect if thread field, corresponding to an existing thread, is set in message. Example: spaces/AAAAMpdlehY/threads/MZ8fXhZXGkk.',
},
],
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const mediaOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const mediaOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
resource: [
'media',
],
resource: ['media'],
},
},
options: [
@ -27,7 +23,7 @@ export const mediaOperations: INodeProperties[] = [
},
];
export const mediaFields: INodeProperties[] = [
export const mediaFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* media:download */
/* -------------------------------------------------------------------------- */
@ -38,12 +34,8 @@ export const mediaFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'media',
],
operation: [
'download',
],
resource: ['media'],
operation: ['download'],
},
},
default: '',
@ -57,12 +49,8 @@ export const mediaFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'media',
],
operation: [
'download',
],
resource: ['media'],
operation: ['download'],
},
},
description: 'Name of the binary property to which to write the data of the read file',

View file

@ -1,10 +1,6 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
import {
getPagingParameters
} from '../GenericFunctions';
import { getPagingParameters } from '../GenericFunctions';
export const memberOperations: INodeProperties[] = [
{
@ -14,9 +10,7 @@ export const memberOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
resource: [
'member',
],
resource: ['member'],
},
},
options: [
@ -37,7 +31,6 @@ export const memberOperations: INodeProperties[] = [
},
];
export const memberFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* member:get */
@ -49,12 +42,8 @@ export const memberFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'member',
],
operation: [
'get',
],
resource: ['member'],
operation: ['get'],
},
},
default: '',
@ -74,18 +63,14 @@ export const memberFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'member',
],
operation: [
'getAll',
],
resource: ['member'],
operation: ['getAll'],
},
},
default: [],
description: 'The name of the space for which to retrieve members, in the form "spaces/*". Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The name of the space for which to retrieve members, in the form "spaces/*". Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
...getPagingParameters('member'),
];

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const messageOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const messageOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
resource: [
'message',
],
resource: ['message'],
},
},
options: [
@ -46,7 +42,6 @@ export const messageOperations: INodeProperties[] = [
];
export const messageFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* message:create */
/* -------------------------------------------------------------------------- */
@ -60,16 +55,13 @@ export const messageFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'create',
],
resource: ['message'],
operation: ['create'],
},
},
default: '',
description: 'Space resource name, in the form "spaces/*". Example: spaces/AAAAMpdlehY. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Space resource name, in the form "spaces/*". Example: spaces/AAAAMpdlehY. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'JSON Parameters',
@ -77,12 +69,8 @@ export const messageFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'create',
],
resource: ['message'],
operation: ['create'],
},
},
default: false,
@ -96,15 +84,9 @@ export const messageFields: INodeProperties[] = [
placeholder: 'Add Message',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'create',
],
jsonParameters: [
false,
],
resource: ['message'],
operation: ['create'],
jsonParameters: [false],
},
},
default: {},
@ -165,20 +147,15 @@ export const messageFields: INodeProperties[] = [
],
},
{
displayName: 'See <a href="https://developers.google.com/chat/reference/rest/v1/spaces.messages#Message" target="_blank">Google Chat Guide</a> To Creating Messages',
displayName:
'See <a href="https://developers.google.com/chat/reference/rest/v1/spaces.messages#Message" target="_blank">Google Chat Guide</a> To Creating Messages',
name: 'jsonNotice',
type: 'notice',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'create',
],
jsonParameters: [
true,
],
resource: ['message'],
operation: ['create'],
jsonParameters: [true],
},
},
default: '',
@ -193,15 +170,9 @@ export const messageFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'create',
],
jsonParameters: [
true,
],
resource: ['message'],
operation: ['create'],
jsonParameters: [true],
},
},
default: '',
@ -215,12 +186,8 @@ export const messageFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'create',
],
resource: ['message'],
operation: ['create'],
},
},
options: [
@ -236,7 +203,8 @@ export const messageFields: INodeProperties[] = [
name: 'requestId',
type: 'string',
default: '',
description: 'A unique request ID for this message. If a message has already been created in the space with this request ID, the subsequent request will return the existing message and no new message will be created.',
description:
'A unique request ID for this message. If a message has already been created in the space with this request ID, the subsequent request will return the existing message and no new message will be created.',
},
],
},
@ -251,12 +219,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'delete',
],
resource: ['message'],
operation: ['delete'],
},
},
default: '',
@ -273,12 +237,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'get',
],
resource: ['message'],
operation: ['get'],
},
},
default: '',
@ -295,12 +255,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'update',
],
resource: ['message'],
operation: ['update'],
},
},
default: '',
@ -312,12 +268,8 @@ export const messageFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'update',
],
resource: ['message'],
operation: ['update'],
},
},
default: false,
@ -331,15 +283,9 @@ export const messageFields: INodeProperties[] = [
placeholder: 'Add Options',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'update',
],
jsonParameters: [
false,
],
resource: ['message'],
operation: ['update'],
jsonParameters: [false],
},
},
default: {},
@ -400,20 +346,15 @@ export const messageFields: INodeProperties[] = [
],
},
{
displayName: 'See <a href="https://developers.google.com/chat/reference/rest/v1/spaces.messages#Message" target="_blank">Google Chat Guide</a> To Creating Messages',
displayName:
'See <a href="https://developers.google.com/chat/reference/rest/v1/spaces.messages#Message" target="_blank">Google Chat Guide</a> To Creating Messages',
name: 'jsonNotice',
type: 'notice',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'update',
],
jsonParameters: [
true,
],
resource: ['message'],
operation: ['update'],
jsonParameters: [true],
},
},
default: '',
@ -428,15 +369,9 @@ export const messageFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'update',
],
jsonParameters: [
true,
],
resource: ['message'],
operation: ['update'],
jsonParameters: [true],
},
},
default: '',

View file

@ -1,10 +1,6 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
import {
getPagingParameters
} from '../GenericFunctions';
import { getPagingParameters } from '../GenericFunctions';
export const spaceOperations: INodeProperties[] = [
{
@ -14,9 +10,7 @@ export const spaceOperations: INodeProperties[] = [
type: 'options',
displayOptions: {
show: {
resource: [
'space',
],
resource: ['space'],
},
},
options: [
@ -48,12 +42,8 @@ export const spaceFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'space',
],
operation: [
'get',
],
resource: ['space'],
operation: ['get'],
},
},
default: '',

View file

@ -1,22 +1,23 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string,
endpoint: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
let options: OptionsWithUri = {
headers: {
'Accept': 'application/json',
Accept: 'application/json',
'Content-Type': 'application/json',
},
method,
@ -33,8 +34,11 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
delete options.body;
}
//@ts-ignore
return await this.helpers.requestOAuth2.call(this, 'googleCloudNaturalLanguageOAuth2Api', options);
return await this.helpers.requestOAuth2.call(
this,
'googleCloudNaturalLanguageOAuth2Api',
options,
);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}

View file

@ -1,22 +1,10 @@
import { IExecuteFunctions } from 'n8n-core';
import {
IExecuteFunctions,
} from 'n8n-core';
import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { IData } from './Interface';
import {
IData,
} from './Interface';
import {
googleApiRequest,
} from './GenericFunctions';
import { googleApiRequest } from './GenericFunctions';
export class GoogleCloudNaturalLanguage implements INodeType {
description: INodeTypeDescription = {
@ -60,9 +48,7 @@ export class GoogleCloudNaturalLanguage implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'document',
],
resource: ['document'],
},
},
options: [
@ -92,13 +78,12 @@ export class GoogleCloudNaturalLanguage implements INodeType {
},
],
default: 'content',
description: 'The source of the document: a string containing the content or a Google Cloud Storage URI',
description:
'The source of the document: a string containing the content or a Google Cloud Storage URI',
required: true,
displayOptions: {
show: {
operation: [
'analyzeSentiment',
],
operation: ['analyzeSentiment'],
},
},
},
@ -107,16 +92,13 @@ export class GoogleCloudNaturalLanguage implements INodeType {
name: 'content',
type: 'string',
default: '',
description: 'The content of the input in string format. Cloud audit logging exempt since it is based on user data.',
description:
'The content of the input in string format. Cloud audit logging exempt since it is based on user data.',
required: true,
displayOptions: {
show: {
operation: [
'analyzeSentiment',
],
source: [
'content',
],
operation: ['analyzeSentiment'],
source: ['content'],
},
},
},
@ -125,16 +107,13 @@ export class GoogleCloudNaturalLanguage implements INodeType {
name: 'gcsContentUri',
type: 'string',
default: '',
description: 'The Google Cloud Storage URI where the file content is located. This URI must be of the form: <code>gs://bucket_name/object_name</code>. For more details, see <a href="https://cloud.google.com/storage/docs/reference-uris.">reference</a>.',
description:
'The Google Cloud Storage URI where the file content is located. This URI must be of the form: <code>gs://bucket_name/object_name</code>. For more details, see <a href="https://cloud.google.com/storage/docs/reference-uris.">reference</a>.',
required: true,
displayOptions: {
show: {
operation: [
'analyzeSentiment',
],
source: [
'gcsContentUri',
],
operation: ['analyzeSentiment'],
source: ['gcsContentUri'],
},
},
},
@ -144,9 +123,7 @@ export class GoogleCloudNaturalLanguage implements INodeType {
type: 'collection',
displayOptions: {
show: {
operation: [
'analyzeSentiment',
],
operation: ['analyzeSentiment'],
},
},
default: {},
@ -266,7 +243,8 @@ export class GoogleCloudNaturalLanguage implements INodeType {
],
default: 'en',
placeholder: '',
description: 'The language of the document (if not specified, the language is automatically detected). Both ISO and BCP-47 language codes are accepted.',
description:
'The language of the document (if not specified, the language is automatically detected). Both ISO and BCP-47 language codes are accepted.',
},
],
},
@ -306,7 +284,12 @@ export class GoogleCloudNaturalLanguage implements INodeType {
body.document.language = options.language as string;
}
const response = await googleApiRequest.call(this, 'POST', `/v1/documents:analyzeSentiment`, body);
const response = await googleApiRequest.call(
this,
'POST',
`/v1/documents:analyzeSentiment`,
body,
);
responseData.push(response);
}
}

View file

@ -8,4 +8,4 @@ export interface IDocument {
language?: string;
content?: string;
gcsContentUri?: string;
}
}

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const contactOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const contactOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'contact',
],
resource: ['contact'],
},
},
options: [
@ -61,12 +57,8 @@ export const contactFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'contact',
],
operation: ['create'],
resource: ['contact'],
},
},
default: '',
@ -77,12 +69,8 @@ export const contactFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'contact',
],
operation: ['create'],
resource: ['contact'],
},
},
default: '',
@ -95,12 +83,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'contact',
],
operation: ['create'],
resource: ['contact'],
},
},
options: [
@ -282,7 +266,8 @@ export const contactFields: INodeProperties[] = [
},
],
default: '',
description: 'The type of the email address. The type can be custom or one of these predefined values.',
description:
'The type of the email address. The type can be custom or one of these predefined values.',
},
{
displayName: 'Value',
@ -332,7 +317,8 @@ export const contactFields: INodeProperties[] = [
},
],
default: '',
description: 'The type of the event. The type can be custom or one of these predefined values.',
description:
'The type of the event. The type can be custom or one of these predefined values.',
},
],
},
@ -349,7 +335,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Group Names or IDs',
name: 'group',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getGroups',
},
@ -543,7 +530,8 @@ export const contactFields: INodeProperties[] = [
},
],
default: '',
description: 'The person\'s relation to the other person. The type can be custom or one of these predefined values.',
description:
"The person's relation to the other person. The type can be custom or one of these predefined values.",
},
],
},
@ -561,12 +549,8 @@ export const contactFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'contact',
],
operation: ['delete'],
resource: ['contact'],
},
},
default: '',
@ -581,12 +565,8 @@ export const contactFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'contact',
],
operation: ['get'],
resource: ['contact'],
},
},
default: '',
@ -699,16 +679,13 @@ export const contactFields: INodeProperties[] = [
],
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'contact',
],
operation: ['get'],
resource: ['contact'],
},
},
default: [],
description: 'A field mask to restrict which fields on each person are returned. Multiple fields can be specified by separating them with commas.',
description:
'A field mask to restrict which fields on each person are returned. Multiple fields can be specified by separating them with commas.',
},
{
displayName: 'RAW Data',
@ -716,12 +693,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'contact',
],
operation: ['get'],
resource: ['contact'],
},
},
default: false,
@ -736,12 +709,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
operation: ['getAll'],
resource: ['contact'],
},
},
default: false,
@ -753,15 +722,9 @@ export const contactFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['contact'],
returnAll: [false],
},
},
typeOptions: {
@ -879,16 +842,13 @@ export const contactFields: INodeProperties[] = [
],
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
operation: ['getAll'],
resource: ['contact'],
},
},
default: [],
description: 'A field mask to restrict which fields on each person are returned. Multiple fields can be specified by separating them with commas.',
description:
'A field mask to restrict which fields on each person are returned. Multiple fields can be specified by separating them with commas.',
},
{
displayName: 'Use Query',
@ -896,12 +856,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
operation: ['getAll'],
resource: ['contact'],
},
},
default: false,
@ -913,19 +869,14 @@ export const contactFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
useQuery: [
true,
],
operation: ['getAll'],
resource: ['contact'],
useQuery: [true],
},
},
default: '',
description: 'The plain-text query for the request. The query is used to match prefix phrases of the fields on a person. For example, a person with name "foo name" matches queries such as "f", "fo", "foo", "foo n", "nam", etc., but not "oo n".',
description:
'The plain-text query for the request. The query is used to match prefix phrases of the fields on a person. For example, a person with name "foo name" matches queries such as "f", "fo", "foo", "foo n", "nam", etc., but not "oo n".',
},
{
displayName: 'RAW Data',
@ -933,12 +884,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
operation: ['getAll'],
resource: ['contact'],
},
},
default: false,
@ -952,15 +899,9 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'contact',
],
useQuery: [
false,
],
operation: ['getAll'],
resource: ['contact'],
useQuery: [false],
},
},
options: [
@ -1005,12 +946,8 @@ export const contactFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'contact',
],
operation: ['update'],
resource: ['contact'],
},
},
default: '',
@ -1123,16 +1060,13 @@ export const contactFields: INodeProperties[] = [
],
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'contact',
],
operation: ['update'],
resource: ['contact'],
},
},
default: [],
description: 'A field mask to restrict which fields on each person are returned. Multiple fields can be specified by separating them with commas.',
description:
'A field mask to restrict which fields on each person are returned. Multiple fields can be specified by separating them with commas.',
},
{
displayName: 'Update Fields',
@ -1142,12 +1076,8 @@ export const contactFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'contact',
],
operation: ['update'],
resource: ['contact'],
},
},
options: [
@ -1156,7 +1086,8 @@ export const contactFields: INodeProperties[] = [
name: 'etag',
type: 'string',
default: '',
description: 'The etag field in the person is nedded to make sure the contact has not changed since your last read',
description:
'The etag field in the person is nedded to make sure the contact has not changed since your last read',
},
{
displayName: 'Family Name',
@ -1348,7 +1279,8 @@ export const contactFields: INodeProperties[] = [
},
],
default: '',
description: 'The type of the email address. The type can be custom or one of these predefined values.',
description:
'The type of the email address. The type can be custom or one of these predefined values.',
},
{
displayName: 'Value',
@ -1398,7 +1330,8 @@ export const contactFields: INodeProperties[] = [
},
],
default: '',
description: 'The type of the event. The type can be custom or one of these predefined values.',
description:
'The type of the event. The type can be custom or one of these predefined values.',
},
],
},
@ -1415,7 +1348,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Group Names or IDs',
name: 'group',
type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getGroups',
},
@ -1609,7 +1543,8 @@ export const contactFields: INodeProperties[] = [
},
],
default: '',
description: 'The person\'s relation to the other person. The type can be custom or one of these predefined values.',
description:
"The person's relation to the other person. The type can be custom or one of these predefined values.",
},
],
},

View file

@ -1,18 +1,20 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -38,8 +40,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -49,10 +59,7 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
@ -84,7 +91,8 @@ export const allFields = [
'userDefined',
];
export function cleanData(responseData: any) { // tslint:disable-line:no-any
// tslint:disable-next-line:no-any
export function cleanData(responseData: any) {
const fields = ['emailAddresses', 'phoneNumbers', 'relations', 'events', 'addresses'];
const newResponseData = [];
if (!Array.isArray(responseData)) {
@ -97,7 +105,7 @@ export function cleanData(responseData: any) { // tslint:disable-line:no-any
continue;
}
if (key === 'photos') {
responseData[y][key] = responseData[y][key].map(((photo: IDataObject) => photo.url));
responseData[y][key] = responseData[y][key].map((photo: IDataObject) => photo.url);
}
if (key === 'names') {
delete responseData[y][key][0].metadata;

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -18,10 +16,7 @@ import {
googleApiRequestAllItems,
} from './GenericFunctions';
import {
contactFields,
contactOperations,
} from './ContactDescription';
import { contactFields, contactOperations } from './ContactDescription';
import moment from 'moment';
import { IData } from '../Analytics/Interfaces';
@ -70,9 +65,7 @@ export class GoogleContacts implements INodeType {
loadOptions: {
// Get all the calendars to display them to user so that he can
// select them easily
async getGroups(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getGroups(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const groups = await googleApiRequestAllItems.call(
this,
@ -136,29 +129,36 @@ export class GoogleContacts implements INodeType {
}
if (additionalFields.companyUi) {
const companyValues = (additionalFields.companyUi as IDataObject).companyValues as IDataObject[];
const companyValues = (additionalFields.companyUi as IDataObject)
.companyValues as IDataObject[];
body.organizations = companyValues;
}
if (additionalFields.phoneUi) {
const phoneValues = (additionalFields.phoneUi as IDataObject).phoneValues as IDataObject[];
const phoneValues = (additionalFields.phoneUi as IDataObject)
.phoneValues as IDataObject[];
body.phoneNumbers = phoneValues;
}
if (additionalFields.addressesUi) {
const addressesValues = (additionalFields.addressesUi as IDataObject).addressesValues as IDataObject[];
const addressesValues = (additionalFields.addressesUi as IDataObject)
.addressesValues as IDataObject[];
body.addresses = addressesValues;
}
if (additionalFields.relationsUi) {
const relationsValues = (additionalFields.relationsUi as IDataObject).relationsValues as IDataObject[];
const relationsValues = (additionalFields.relationsUi as IDataObject)
.relationsValues as IDataObject[];
body.relations = relationsValues;
}
if (additionalFields.eventsUi) {
const eventsValues = (additionalFields.eventsUi as IDataObject).eventsValues as IDataObject[];
const eventsValues = (additionalFields.eventsUi as IDataObject)
.eventsValues as IDataObject[];
for (let i = 0; i < eventsValues.length; i++) {
const [month, day, year] = moment(eventsValues[i].date as string).format('MM/DD/YYYY').split('/');
const [month, day, year] = moment(eventsValues[i].date as string)
.format('MM/DD/YYYY')
.split('/');
eventsValues[i] = {
date: {
day,
@ -172,7 +172,9 @@ export class GoogleContacts implements INodeType {
}
if (additionalFields.birthday) {
const [month, day, year] = moment(additionalFields.birthday as string).format('MM/DD/YYYY').split('/');
const [month, day, year] = moment(additionalFields.birthday as string)
.format('MM/DD/YYYY')
.split('/');
body.birthdays = [
{
@ -186,7 +188,8 @@ export class GoogleContacts implements INodeType {
}
if (additionalFields.emailsUi) {
const emailsValues = (additionalFields.emailsUi as IDataObject).emailsValues as IDataObject[];
const emailsValues = (additionalFields.emailsUi as IDataObject)
.emailsValues as IDataObject[];
body.emailAddresses = emailsValues;
}
@ -200,7 +203,8 @@ export class GoogleContacts implements INodeType {
}
if (additionalFields.customFieldsUi) {
const customFieldsValues = (additionalFields.customFieldsUi as IDataObject).customFieldsValues as IDataObject[];
const customFieldsValues = (additionalFields.customFieldsUi as IDataObject)
.customFieldsValues as IDataObject[];
body.userDefined = customFieldsValues;
}
@ -225,7 +229,6 @@ export class GoogleContacts implements INodeType {
);
responseData.contactId = responseData.resourceName.split('/')[1];
}
//https://developers.google.com/people/api/rest/v1/people/deleteContact
if (operation === 'delete') {
@ -250,13 +253,7 @@ export class GoogleContacts implements INodeType {
qs.personFields = (fields as string[]).join(',');
}
responseData = await googleApiRequest.call(
this,
'GET',
`/people/${contactId}`,
{},
qs,
);
responseData = await googleApiRequest.call(this, 'GET', `/people/${contactId}`, {}, qs);
if (!rawData) {
responseData = cleanData(responseData)[0];
@ -273,7 +270,7 @@ export class GoogleContacts implements INodeType {
const rawData = this.getNodeParameter('rawData', i) as boolean;
const useQuery = this.getNodeParameter('useQuery', i) as boolean;
const endpoint = (useQuery) ? ':searchContacts' : '/me/connections';
const endpoint = useQuery ? ':searchContacts' : '/me/connections';
if (useQuery) {
qs.query = this.getNodeParameter('query', i) as string;
@ -297,7 +294,7 @@ export class GoogleContacts implements INodeType {
if (returnAll) {
responseData = await googleApiRequestAllItems.call(
this,
(useQuery) ? 'results' : 'connections',
useQuery ? 'results' : 'connections',
'GET',
`/people${endpoint}`,
{},
@ -307,18 +304,14 @@ export class GoogleContacts implements INodeType {
if (useQuery) {
responseData = responseData.map((result: IDataObject) => result.person);
}
} else {
qs.pageSize = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(
this,
'GET',
`/people${endpoint}`,
{},
qs,
);
responseData = await googleApiRequest.call(this, 'GET', `/people${endpoint}`, {}, qs);
responseData = responseData.connections || responseData.results?.map((result: IDataObject) => result.person) || [];
responseData =
responseData.connections ||
responseData.results?.map((result: IDataObject) => result.person) ||
[];
}
if (!rawData) {
@ -342,11 +335,8 @@ export class GoogleContacts implements INodeType {
let etag;
if (updateFields.etag) {
etag = updateFields.etag as string;
} else {
const data = await googleApiRequest.call(
this,
'GET',
@ -356,7 +346,6 @@ export class GoogleContacts implements INodeType {
);
etag = data.etag;
}
if (fields.includes('*')) {
@ -367,9 +356,7 @@ export class GoogleContacts implements INodeType {
const body: IDataObject = {
etag,
names: [
{},
],
names: [{}],
};
if (updateFields.givenName) {
@ -398,33 +385,40 @@ export class GoogleContacts implements INodeType {
}
if (updateFields.companyUi) {
const companyValues = (updateFields.companyUi as IDataObject).companyValues as IDataObject[];
const companyValues = (updateFields.companyUi as IDataObject)
.companyValues as IDataObject[];
body.organizations = companyValues;
updatePersonFields.push('organizations');
}
if (updateFields.phoneUi) {
const phoneValues = (updateFields.phoneUi as IDataObject).phoneValues as IDataObject[];
const phoneValues = (updateFields.phoneUi as IDataObject)
.phoneValues as IDataObject[];
body.phoneNumbers = phoneValues;
updatePersonFields.push('phoneNumbers');
}
if (updateFields.addressesUi) {
const addressesValues = (updateFields.addressesUi as IDataObject).addressesValues as IDataObject[];
const addressesValues = (updateFields.addressesUi as IDataObject)
.addressesValues as IDataObject[];
body.addresses = addressesValues;
updatePersonFields.push('addresses');
}
if (updateFields.relationsUi) {
const relationsValues = (updateFields.relationsUi as IDataObject).relationsValues as IDataObject[];
const relationsValues = (updateFields.relationsUi as IDataObject)
.relationsValues as IDataObject[];
body.relations = relationsValues;
updatePersonFields.push('relations');
}
if (updateFields.eventsUi) {
const eventsValues = (updateFields.eventsUi as IDataObject).eventsValues as IDataObject[];
const eventsValues = (updateFields.eventsUi as IDataObject)
.eventsValues as IDataObject[];
for (let i = 0; i < eventsValues.length; i++) {
const [month, day, year] = moment(eventsValues[i].date as string).format('MM/DD/YYYY').split('/');
const [month, day, year] = moment(eventsValues[i].date as string)
.format('MM/DD/YYYY')
.split('/');
eventsValues[i] = {
date: {
day,
@ -439,7 +433,9 @@ export class GoogleContacts implements INodeType {
}
if (updateFields.birthday) {
const [month, day, year] = moment(updateFields.birthday as string).format('MM/DD/YYYY').split('/');
const [month, day, year] = moment(updateFields.birthday as string)
.format('MM/DD/YYYY')
.split('/');
body.birthdays = [
{
@ -455,7 +451,8 @@ export class GoogleContacts implements INodeType {
}
if (updateFields.emailsUi) {
const emailsValues = (updateFields.emailsUi as IDataObject).emailsValues as IDataObject[];
const emailsValues = (updateFields.emailsUi as IDataObject)
.emailsValues as IDataObject[];
body.emailAddresses = emailsValues;
updatePersonFields.push('emailAddresses');
}
@ -471,7 +468,8 @@ export class GoogleContacts implements INodeType {
}
if (updateFields.customFieldsUi) {
const customFieldsValues = (updateFields.customFieldsUi as IDataObject).customFieldsValues as IDataObject[];
const customFieldsValues = (updateFields.customFieldsUi as IDataObject)
.customFieldsValues as IDataObject[];
body.userDefined = customFieldsValues;
updatePersonFields.push('userDefined');
}

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const documentOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const documentOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'document',
],
resource: ['document'],
},
},
options: [
@ -44,7 +40,8 @@ export const documentFields: INodeProperties[] = [
displayName: 'Drive Name or ID',
name: 'driveId',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getDrives',
},
@ -52,12 +49,8 @@ export const documentFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'document',
],
operation: ['create'],
resource: ['document'],
},
},
},
@ -65,23 +58,18 @@ export const documentFields: INodeProperties[] = [
displayName: 'Folder Name or ID',
name: 'folderId',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsDependsOn: [
'driveId',
],
loadOptionsDependsOn: ['driveId'],
loadOptionsMethod: 'getFolders',
},
default: '',
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'document',
],
operation: ['create'],
resource: ['document'],
},
},
},
@ -93,12 +81,8 @@ export const documentFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'document',
],
operation: ['create'],
resource: ['document'],
},
},
},
@ -113,12 +97,8 @@ export const documentFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'document',
],
operation: ['get'],
resource: ['document'],
},
},
default: '',
@ -130,12 +110,8 @@ export const documentFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'document',
],
operation: ['get'],
resource: ['document'],
},
},
default: true,
@ -152,12 +128,8 @@ export const documentFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'document',
],
operation: ['update'],
resource: ['document'],
},
},
default: '',
@ -169,12 +141,8 @@ export const documentFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'document',
],
operation: ['update'],
resource: ['document'],
},
},
default: true,
@ -202,12 +170,8 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'document',
],
operation: ['update'],
resource: ['document'],
},
},
options: [
@ -282,9 +246,7 @@ export const documentFields: INodeProperties[] = [
],
displayOptions: {
show: {
object: [
'text',
],
object: ['text'],
},
},
description: 'The update action',
@ -306,12 +268,7 @@ export const documentFields: INodeProperties[] = [
],
displayOptions: {
show: {
object: [
'footer',
'header',
'namedRange',
'paragraphBullets',
],
object: ['footer', 'header', 'namedRange', 'paragraphBullets'],
},
},
description: 'The update action',
@ -333,10 +290,7 @@ export const documentFields: INodeProperties[] = [
],
displayOptions: {
show: {
object: [
'tableColumn',
'tableRow',
],
object: ['tableColumn', 'tableRow'],
},
},
description: 'The update action',
@ -354,10 +308,7 @@ export const documentFields: INodeProperties[] = [
],
displayOptions: {
show: {
object: [
'pageBreak',
'table',
],
object: ['pageBreak', 'table'],
},
},
description: 'The update action',
@ -375,9 +326,7 @@ export const documentFields: INodeProperties[] = [
],
displayOptions: {
show: {
object: [
'positionedObject',
],
object: ['positionedObject'],
},
},
description: 'The update action',
@ -406,15 +355,8 @@ export const documentFields: INodeProperties[] = [
default: 'body',
displayOptions: {
show: {
object: [
'footer',
'header',
'paragraphBullets',
'namedRange',
],
action: [
'create',
],
object: ['footer', 'header', 'paragraphBullets', 'namedRange'],
action: ['create'],
},
},
},
@ -422,24 +364,16 @@ export const documentFields: INodeProperties[] = [
displayName: 'Segment ID',
name: 'segmentId',
type: 'string',
description: 'The ID of the header, footer or footnote. The <code>Document → Get</code> operation lists all segment IDs (make sure you disable the <code>simple</code> toggle).',
description:
'The ID of the header, footer or footnote. The <code>Document → Get</code> operation lists all segment IDs (make sure you disable the <code>simple</code> toggle).',
default: '',
displayOptions: {
show: {
object: [
'footer',
'header',
'paragraphBullets',
'namedRange',
],
action: [
'create',
],
object: ['footer', 'header', 'paragraphBullets', 'namedRange'],
action: ['create'],
},
hide: {
insertSegment: [
'body',
],
insertSegment: ['body'],
},
},
},
@ -454,13 +388,8 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'footer',
'header',
],
action: [
'create',
],
object: ['footer', 'header'],
action: ['create'],
},
},
},
@ -473,12 +402,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
object: [
'namedRange',
],
action: [
'create',
],
object: ['namedRange'],
action: ['create'],
},
},
},
@ -490,12 +415,8 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'namedRange',
],
action: [
'create',
],
object: ['namedRange'],
action: ['create'],
},
},
},
@ -507,12 +428,8 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'namedRange',
],
action: [
'create',
],
object: ['namedRange'],
action: ['create'],
},
},
},
@ -525,29 +442,28 @@ export const documentFields: INodeProperties[] = [
{
name: 'Bullet List',
value: 'BULLET_DISC_CIRCLE_SQUARE',
description: 'A bulleted list with a <code>DISC</code>, <code>CIRCLE</code> and <code>SQUARE</code> bullet glyph for the first 3 list nesting levels',
description:
'A bulleted list with a <code>DISC</code>, <code>CIRCLE</code> and <code>SQUARE</code> bullet glyph for the first 3 list nesting levels',
},
{
name: 'Checkbox List',
value: 'BULLET_CHECKBOX',
description: 'A bulleted list with CHECKBOX bullet glyphs for all list nesting levels',
description:
'A bulleted list with CHECKBOX bullet glyphs for all list nesting levels',
},
{
name: 'Numbered List',
value: 'NUMBERED_DECIMAL_NESTED',
description: 'A numbered list with <code>DECIMAL</code> numeric glyphs separated by periods, where each nesting level uses the previous nesting level\'s glyph as a prefix. For example: 1., 1.1., 2., 2.2 .',
description:
"A numbered list with <code>DECIMAL</code> numeric glyphs separated by periods, where each nesting level uses the previous nesting level's glyph as a prefix. For example: 1., 1.1., 2., 2.2 .",
},
],
description: 'The Preset pattern of bullet glyphs for list',
default: 'BULLET_DISC_CIRCLE_SQUARE',
displayOptions: {
show: {
object: [
'paragraphBullets',
],
action: [
'create',
],
object: ['paragraphBullets'],
action: ['create'],
},
},
},
@ -556,16 +472,13 @@ export const documentFields: INodeProperties[] = [
displayName: 'Footer ID',
name: 'footerId',
type: 'string',
description: 'The ID of the footer to delete. To retrieve it, use the <code>get document</code> where you can find under <code>footers</code> attribute.',
description:
'The ID of the footer to delete. To retrieve it, use the <code>get document</code> where you can find under <code>footers</code> attribute.',
default: '',
displayOptions: {
show: {
object: [
'footer',
],
action: [
'delete',
],
object: ['footer'],
action: ['delete'],
},
},
},
@ -574,16 +487,13 @@ export const documentFields: INodeProperties[] = [
displayName: 'Header ID',
name: 'headerId',
type: 'string',
description: 'The ID of the header to delete. To retrieve it, use the <code>get document</code> where you can find under <code>headers</code> attribute.',
description:
'The ID of the header to delete. To retrieve it, use the <code>get document</code> where you can find under <code>headers</code> attribute.',
default: '',
displayOptions: {
show: {
object: [
'header',
],
action: [
'delete',
],
object: ['header'],
action: ['delete'],
},
},
},
@ -606,12 +516,8 @@ export const documentFields: INodeProperties[] = [
default: 'namedRangeId',
displayOptions: {
show: {
object: [
'namedRange',
],
action: [
'delete',
],
object: ['namedRange'],
action: ['delete'],
},
},
},
@ -623,15 +529,9 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
object: [
'namedRange',
],
action: [
'delete',
],
namedRangeReference: [
'namedRangeId',
],
object: ['namedRange'],
action: ['delete'],
namedRangeReference: ['namedRangeId'],
},
},
},
@ -643,15 +543,9 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
object: [
'namedRange',
],
action: [
'delete',
],
namedRangeReference: [
'name',
],
object: ['namedRange'],
action: ['delete'],
namedRangeReference: ['name'],
},
},
},
@ -661,16 +555,13 @@ export const documentFields: INodeProperties[] = [
displayName: 'Object ID',
name: 'objectId',
type: 'string',
description: 'The ID of the positioned object to delete (An object that is tied to a paragraph and positioned relative to its beginning), See the Google <a href="https://developers.google.com/docs/api/reference/rest/v1/PositionedObject">documentation</a>',
description:
'The ID of the positioned object to delete (An object that is tied to a paragraph and positioned relative to its beginning), See the Google <a href="https://developers.google.com/docs/api/reference/rest/v1/PositionedObject">documentation</a>',
default: '',
displayOptions: {
show: {
object: [
'positionedObject',
],
action: [
'delete',
],
object: ['positionedObject'],
action: ['delete'],
},
},
},
@ -699,16 +590,8 @@ export const documentFields: INodeProperties[] = [
default: 'body',
displayOptions: {
show: {
object: [
'pageBreak',
'table',
'tableColumn',
'tableRow',
'text',
],
action: [
'insert',
],
object: ['pageBreak', 'table', 'tableColumn', 'tableRow', 'text'],
action: ['insert'],
},
},
},
@ -716,25 +599,16 @@ export const documentFields: INodeProperties[] = [
displayName: 'Segment ID',
name: 'segmentId',
type: 'string',
description: 'The ID of the header, footer or footnote. The <code>Document → Get</code> operation lists all segment IDs (make sure you disable the <code>simple</code> toggle).',
description:
'The ID of the header, footer or footnote. The <code>Document → Get</code> operation lists all segment IDs (make sure you disable the <code>simple</code> toggle).',
default: '',
displayOptions: {
show: {
object: [
'pageBreak',
'table',
'tableColumn',
'tableRow',
'text',
],
action: [
'insert',
],
object: ['pageBreak', 'table', 'tableColumn', 'tableRow', 'text'],
action: ['insert'],
},
hide: {
insertSegment: [
'body',
],
insertSegment: ['body'],
},
},
},
@ -747,7 +621,8 @@ export const documentFields: INodeProperties[] = [
{
name: 'At End of Specific Position',
value: 'endOfSegmentLocation',
description: 'Inserts the text at the end of a header, footer, footnote, or document body',
description:
'Inserts the text at the end of a header, footer, footnote, or document body',
},
{
name: 'At Index',
@ -758,12 +633,8 @@ export const documentFields: INodeProperties[] = [
default: 'endOfSegmentLocation',
displayOptions: {
show: {
object: [
'pageBreak',
],
action: [
'insert',
],
object: ['pageBreak'],
action: ['insert'],
},
},
},
@ -774,15 +645,9 @@ export const documentFields: INodeProperties[] = [
description: 'The zero-based index, relative to the beginning of the specified segment',
displayOptions: {
show: {
locationChoice: [
'location',
],
object: [
'pageBreak',
],
action: [
'insert',
],
locationChoice: ['location'],
object: ['pageBreak'],
action: ['insert'],
},
},
typeOptions: {
@ -799,7 +664,8 @@ export const documentFields: INodeProperties[] = [
{
name: 'At End of Specific Position',
value: 'endOfSegmentLocation',
description: 'Inserts the text at the end of a header, footer, footnote, or document body',
description:
'Inserts the text at the end of a header, footer, footnote, or document body',
},
{
name: 'At Index',
@ -810,12 +676,8 @@ export const documentFields: INodeProperties[] = [
default: 'endOfSegmentLocation',
displayOptions: {
show: {
object: [
'table',
],
action: [
'insert',
],
object: ['table'],
action: ['insert'],
},
},
},
@ -823,18 +685,13 @@ export const documentFields: INodeProperties[] = [
displayName: 'Index',
name: 'index',
type: 'number',
description: 'The zero-based index, relative to the beginning of the specified segment (use index + 1 to refer to a table)',
description:
'The zero-based index, relative to the beginning of the specified segment (use index + 1 to refer to a table)',
displayOptions: {
show: {
locationChoice: [
'location',
],
object: [
'table',
],
action: [
'insert',
],
locationChoice: ['location'],
object: ['table'],
action: ['insert'],
},
},
default: 1,
@ -850,12 +707,8 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'table',
],
action: [
'insert',
],
object: ['table'],
action: ['insert'],
},
},
},
@ -867,12 +720,8 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'table',
],
action: [
'insert',
],
object: ['table'],
action: ['insert'],
},
},
},
@ -885,7 +734,8 @@ export const documentFields: INodeProperties[] = [
{
name: 'At End of Specific Position',
value: 'endOfSegmentLocation',
description: 'Inserts the text at the end of a header, footer, footnote, or document body',
description:
'Inserts the text at the end of a header, footer, footnote, or document body',
},
{
name: 'At Index',
@ -896,12 +746,8 @@ export const documentFields: INodeProperties[] = [
default: 'endOfSegmentLocation',
displayOptions: {
show: {
object: [
'text',
],
action: [
'insert',
],
object: ['text'],
action: ['insert'],
},
},
},
@ -915,15 +761,9 @@ export const documentFields: INodeProperties[] = [
description: 'The zero-based index, relative to the beginning of the specified segment',
displayOptions: {
show: {
locationChoice: [
'location',
],
object: [
'text',
],
action: [
'insert',
],
locationChoice: ['location'],
object: ['text'],
action: ['insert'],
},
},
default: 1,
@ -936,12 +776,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
object: [
'text',
],
action: [
'insert',
],
object: ['text'],
action: ['insert'],
},
},
},
@ -954,12 +790,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
object: [
'text',
],
action: [
'replaceAll',
],
object: ['text'],
action: ['replaceAll'],
},
},
},
@ -971,12 +803,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
object: [
'text',
],
action: [
'replaceAll',
],
object: ['text'],
action: ['replaceAll'],
},
},
},
@ -988,12 +816,8 @@ export const documentFields: INodeProperties[] = [
default: false,
displayOptions: {
show: {
object: [
'text',
],
action: [
'replaceAll',
],
object: ['text'],
action: ['replaceAll'],
},
},
},
@ -1020,14 +844,8 @@ export const documentFields: INodeProperties[] = [
default: 'body',
displayOptions: {
show: {
object: [
'paragraphBullets',
'tableColumn',
'tableRow',
],
action: [
'delete',
],
object: ['paragraphBullets', 'tableColumn', 'tableRow'],
action: ['delete'],
},
},
},
@ -1035,23 +853,16 @@ export const documentFields: INodeProperties[] = [
displayName: 'Segment ID',
name: 'segmentId',
type: 'string',
description: 'The ID of the header, footer or footnote. The <code>Document → Get</code> operation lists all segment IDs (make sure you disable the <code>simple</code> toggle).',
description:
'The ID of the header, footer or footnote. The <code>Document → Get</code> operation lists all segment IDs (make sure you disable the <code>simple</code> toggle).',
default: '',
displayOptions: {
show: {
object: [
'paragraphBullets',
'tableColumn',
'tableRow',
],
action: [
'delete',
],
object: ['paragraphBullets', 'tableColumn', 'tableRow'],
action: ['delete'],
},
hide: {
insertSegment: [
'body',
],
insertSegment: ['body'],
},
},
},
@ -1064,9 +875,7 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'paragraphBullets',
],
object: ['paragraphBullets'],
},
},
},
@ -1078,9 +887,7 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'paragraphBullets',
],
object: ['paragraphBullets'],
},
},
},
@ -1102,13 +909,8 @@ export const documentFields: INodeProperties[] = [
default: true,
displayOptions: {
show: {
object: [
'tableColumn',
'tableRow',
],
action: [
'insert',
],
object: ['tableColumn', 'tableRow'],
action: ['insert'],
},
},
},
@ -1116,17 +918,15 @@ export const documentFields: INodeProperties[] = [
displayName: 'Index',
name: 'index',
type: 'number',
description: 'The zero-based index, relative to the beginning of the specified segment (use index + 1 to refer to a table)',
description:
'The zero-based index, relative to the beginning of the specified segment (use index + 1 to refer to a table)',
default: 1,
typeOptions: {
minValue: 1,
},
displayOptions: {
show: {
object: [
'tableColumn',
'tableRow',
],
object: ['tableColumn', 'tableRow'],
},
},
},
@ -1138,10 +938,7 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'tableColumn',
'tableRow',
],
object: ['tableColumn', 'tableRow'],
},
},
},
@ -1153,10 +950,7 @@ export const documentFields: INodeProperties[] = [
default: 0,
displayOptions: {
show: {
object: [
'tableColumn',
'tableRow',
],
object: ['tableColumn', 'tableRow'],
},
},
},
@ -1172,12 +966,8 @@ export const documentFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'document',
],
operation: ['update'],
resource: ['document'],
},
},
options: [
@ -1193,12 +983,14 @@ export const documentFields: INodeProperties[] = [
{
name: 'Target',
value: 'targetRevisionId',
description: 'Apply changes to the latest revision. Otherwise changes will not be processed.',
description:
'Apply changes to the latest revision. Otherwise changes will not be processed.',
},
{
name: 'Required',
value: 'requiredRevisionId',
description: 'Apply changes to the provided revision while incorporating other collaborators\' changes. This mode is used for the recent revision, Otherwise changes will not be processed.',
description:
"Apply changes to the provided revision while incorporating other collaborators' changes. This mode is used for the recent revision, Otherwise changes will not be processed.",
},
],
default: 'requiredRevisionId',

View file

@ -1,17 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import moment from 'moment-timezone';
@ -32,7 +23,11 @@ export async function googleApiRequest(
qs?: IDataObject,
uri?: string,
) {
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
const options: OptionsWithUri = {
headers: {
@ -49,11 +44,13 @@ export async function googleApiRequest(
delete options.body;
}
try {
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
return await this.helpers.request!(options);
@ -66,8 +63,16 @@ export async function googleApiRequest(
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: IDataObject = {}, qs?: IDataObject, uri?: string): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
body: IDataObject = {},
qs?: IDataObject,
uri?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -79,15 +84,15 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query, uri);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
function getAccessToken(this: IExecuteFunctions | ILoadOptionsFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
function getAccessToken(
this: IExecuteFunctions | ILoadOptionsFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
@ -103,20 +108,20 @@ function getAccessToken(this: IExecuteFunctions | ILoadOptionsFunctions, credent
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey as string,
{
algorithm: 'RS256',
header: {
'kid': privateKey as string,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey as string,
typ: 'JWT',
alg: 'RS256',
},
},
);

View file

@ -1,7 +1,4 @@
import {
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject,
@ -20,15 +17,9 @@ import {
upperFirst,
} from './GenericFunctions';
import {
documentFields,
documentOperations,
} from './DocumentDescription';
import { documentFields, documentOperations } from './DocumentDescription';
import {
IUpdateBody,
IUpdateFields,
} from './interfaces';
import { IUpdateBody, IUpdateFields } from './interfaces';
export class GoogleDocs implements INodeType {
description: INodeTypeDescription = {
@ -50,9 +41,7 @@ export class GoogleDocs implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -61,9 +50,7 @@ export class GoogleDocs implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -86,9 +73,7 @@ export class GoogleDocs implements INodeType {
default: 'serviceAccount',
displayOptions: {
show: {
'@version': [
1,
],
'@version': [1],
},
},
},
@ -109,9 +94,7 @@ export class GoogleDocs implements INodeType {
default: 'oAuth2',
displayOptions: {
show: {
'@version': [
2,
],
'@version': [2],
},
},
},
@ -149,7 +132,15 @@ export class GoogleDocs implements INodeType {
];
let drives;
try {
drives = await googleApiRequestAllItems.call(this, 'drives', 'GET', '', {}, {}, 'https://www.googleapis.com/drive/v3/drives');
drives = await googleApiRequestAllItems.call(
this,
'drives',
'GET',
'',
{},
{},
'https://www.googleapis.com/drive/v3/drives',
);
} catch (error) {
throw new NodeApiError(this.getNode(), error, { message: 'Error in loading Drives' });
}
@ -172,13 +163,23 @@ export class GoogleDocs implements INodeType {
const driveId = this.getNodeParameter('driveId');
const qs = {
q: `mimeType = \'application/vnd.google-apps.folder\' ${driveId === 'sharedWithMe' ? 'and sharedWithMe = true' : ' and \'root\' in parents'}`,
...(driveId && driveId !== 'myDrive' && driveId !== 'sharedWithMe') ? { driveId } : {},
q: `mimeType = \'application/vnd.google-apps.folder\' ${
driveId === 'sharedWithMe' ? 'and sharedWithMe = true' : " and 'root' in parents"
}`,
...(driveId && driveId !== 'myDrive' && driveId !== 'sharedWithMe' ? { driveId } : {}),
};
let folders;
try {
folders = await googleApiRequestAllItems.call(this, 'files', 'GET', '', {}, qs, 'https://www.googleapis.com/drive/v3/files');
folders = await googleApiRequestAllItems.call(
this,
'files',
'GET',
'',
{},
qs,
'https://www.googleapis.com/drive/v3/files',
);
} catch (error) {
throw new NodeApiError(this.getNode(), error, { message: 'Error in loading Folders' });
}
@ -204,13 +205,9 @@ export class GoogleDocs implements INodeType {
const operation = this.getNodeParameter('operation', 0) as string;
for (let i = 0; i < length; i++) {
try {
if (resource === 'document') {
if (operation === 'create') {
// https://developers.google.com/docs/api/reference/rest/v1/documents/create
const folderId = this.getNodeParameter('folderId', i) as string;
@ -218,13 +215,18 @@ export class GoogleDocs implements INodeType {
const body: IDataObject = {
name: this.getNodeParameter('title', i) as string,
mimeType: 'application/vnd.google-apps.document',
...(folderId && folderId !== 'default') ? { parents: [folderId] } : {},
...(folderId && folderId !== 'default' ? { parents: [folderId] } : {}),
};
responseData = await googleApiRequest.call(this, 'POST', '', body, {}, 'https://www.googleapis.com/drive/v3/files');
responseData = await googleApiRequest.call(
this,
'POST',
'',
body,
{},
'https://www.googleapis.com/drive/v3/files',
);
} else if (operation === 'get') {
// https://developers.google.com/docs/api/reference/rest/v1/documents/get
const documentURL = this.getNodeParameter('documentURL', i) as string;
@ -236,16 +238,16 @@ export class GoogleDocs implements INodeType {
}
responseData = await googleApiRequest.call(this, 'GET', `/documents/${documentId}`);
if (simple) {
const content = (responseData.body.content as IDataObject[])
.reduce((arr: string[], contentItem) => {
if (contentItem && contentItem.paragraph) {
const texts = ((contentItem.paragraph as IDataObject).elements as IDataObject[])
.map(element => {
if (element && element.textRun) {
return (element.textRun as IDataObject).content as string;
}
}) as string[];
const texts = (
(contentItem.paragraph as IDataObject).elements as IDataObject[]
).map((element) => {
if (element && element.textRun) {
return (element.textRun as IDataObject).content as string;
}
}) as string[];
arr = [...arr, ...texts];
}
return arr;
@ -256,20 +258,20 @@ export class GoogleDocs implements INodeType {
documentId,
content,
};
}
} else if (operation === 'update') {
// https://developers.google.com/docs/api/reference/rest/v1/documents/batchUpdate
const documentURL = this.getNodeParameter('documentURL', i) as string;
let documentId = extractID(documentURL);
const simple = this.getNodeParameter('simple', i) as boolean;
const actionsUi = this.getNodeParameter('actionsUi', i) as {
actionFields: IDataObject[]
actionFields: IDataObject[];
};
const { writeControlObject } = this.getNodeParameter('updateFields', i) as IUpdateFields;
const { writeControlObject } = this.getNodeParameter(
'updateFields',
i,
) as IUpdateFields;
if (!documentId) {
documentId = documentURL;
@ -287,9 +289,8 @@ export class GoogleDocs implements INodeType {
}
if (actionsUi) {
let requestBody: IDataObject;
actionsUi.actionFields.forEach(actionField => {
actionsUi.actionFields.forEach((actionField) => {
const { action, object } = actionField;
if (object === 'positionedObject') {
if (action === 'delete') {
@ -297,42 +298,37 @@ export class GoogleDocs implements INodeType {
objectId: actionField.objectId,
};
}
} else if (object === 'pageBreak') {
if (action === 'insert') {
const { insertSegment, segmentId, locationChoice, index } = actionField;
requestBody = {
[locationChoice as string]: {
segmentId: (insertSegment !== 'body') ? segmentId : '',
...(locationChoice === 'location') ? { index } : {},
segmentId: insertSegment !== 'body' ? segmentId : '',
...(locationChoice === 'location' ? { index } : {}),
},
};
}
} else if (object === 'table') {
if (action === 'insert') {
const { rows, columns, insertSegment, locationChoice, segmentId, index } = actionField;
const { rows, columns, insertSegment, locationChoice, segmentId, index } =
actionField;
requestBody = {
rows,
columns,
[locationChoice as string]: {
segmentId: (insertSegment !== 'body') ? segmentId : '',
...(locationChoice === 'location') ? { index } : {},
segmentId: insertSegment !== 'body' ? segmentId : '',
...(locationChoice === 'location' ? { index } : {}),
},
};
}
} else if (object === 'footer') {
if (action === 'create') {
const { insertSegment, locationChoice, segmentId, index } = actionField;
requestBody = {
type: 'DEFAULT',
sectionBreakLocation: {
segmentId: (insertSegment !== 'body') ? segmentId : '',
...(locationChoice === 'location') ? { index } : {},
segmentId: insertSegment !== 'body' ? segmentId : '',
...(locationChoice === 'location' ? { index } : {}),
},
};
} else if (action === 'delete') {
@ -340,16 +336,14 @@ export class GoogleDocs implements INodeType {
footerId: actionField.footerId,
};
}
} else if (object === 'header') {
if (action === 'create') {
const { insertSegment, locationChoice, segmentId, index } = actionField;
requestBody = {
type: 'DEFAULT',
sectionBreakLocation: {
segmentId: (insertSegment !== 'body') ? segmentId : '',
...(locationChoice === 'location') ? { index } : {},
segmentId: insertSegment !== 'body' ? segmentId : '',
...(locationChoice === 'location' ? { index } : {}),
},
};
} else if (action === 'delete') {
@ -357,17 +351,25 @@ export class GoogleDocs implements INodeType {
headerId: actionField.headerId,
};
}
} else if (object === 'tableColumn') {
if (action === 'insert') {
const { insertPosition, rowIndex, columnIndex, insertSegment, segmentId, index } = actionField;
const {
insertPosition,
rowIndex,
columnIndex,
insertSegment,
segmentId,
index,
} = actionField;
requestBody = {
insertRight: insertPosition,
tableCellLocation: {
rowIndex,
columnIndex,
tableStartLocation: { segmentId: (insertSegment !== 'body') ? segmentId : '', index, },
tableStartLocation: {
segmentId: insertSegment !== 'body' ? segmentId : '',
index,
},
},
};
} else if (action === 'delete') {
@ -376,21 +378,32 @@ export class GoogleDocs implements INodeType {
tableCellLocation: {
rowIndex,
columnIndex,
tableStartLocation: { segmentId: (insertSegment !== 'body') ? segmentId : '', index, },
tableStartLocation: {
segmentId: insertSegment !== 'body' ? segmentId : '',
index,
},
},
};
}
} else if (object === 'tableRow') {
if (action === 'insert') {
const { insertPosition, rowIndex, columnIndex, insertSegment, segmentId, index } = actionField;
const {
insertPosition,
rowIndex,
columnIndex,
insertSegment,
segmentId,
index,
} = actionField;
requestBody = {
insertBelow: insertPosition,
tableCellLocation: {
rowIndex,
columnIndex,
tableStartLocation: { segmentId: (insertSegment !== 'body') ? segmentId : '', index, },
tableStartLocation: {
segmentId: insertSegment !== 'body' ? segmentId : '',
index,
},
},
};
} else if (action === 'delete') {
@ -399,20 +412,21 @@ export class GoogleDocs implements INodeType {
tableCellLocation: {
rowIndex,
columnIndex,
tableStartLocation: { segmentId: (insertSegment !== 'body') ? segmentId : '', index, },
tableStartLocation: {
segmentId: insertSegment !== 'body' ? segmentId : '',
index,
},
},
};
}
} else if (object === 'text') {
if (action === 'insert') {
const { text, locationChoice, insertSegment, segmentId, index } = actionField;
requestBody = {
text,
[locationChoice as string]: {
segmentId: (insertSegment !== 'body') ? segmentId : '',
...(locationChoice === 'location') ? { index } : {},
segmentId: insertSegment !== 'body' ? segmentId : '',
...(locationChoice === 'location' ? { index } : {}),
},
};
} else if (action === 'replaceAll') {
@ -422,18 +436,26 @@ export class GoogleDocs implements INodeType {
containsText: { text, matchCase },
};
}
} else if (object === 'paragraphBullets') {
if (action === 'create') {
const { bulletPreset, startIndex, insertSegment, segmentId, endIndex } = actionField;
const { bulletPreset, startIndex, insertSegment, segmentId, endIndex } =
actionField;
requestBody = {
bulletPreset,
range: { segmentId: (insertSegment !== 'body') ? segmentId : '', startIndex, endIndex },
range: {
segmentId: insertSegment !== 'body' ? segmentId : '',
startIndex,
endIndex,
},
};
} else if (action === 'delete') {
const { startIndex, insertSegment, segmentId, endIndex } = actionField;
requestBody = {
range: { segmentId: (insertSegment !== 'body') ? segmentId : '', startIndex, endIndex },
range: {
segmentId: insertSegment !== 'body' ? segmentId : '',
startIndex,
endIndex,
},
};
}
} else if (object === 'namedRange') {
@ -441,7 +463,11 @@ export class GoogleDocs implements INodeType {
const { name, insertSegment, segmentId, startIndex, endIndex } = actionField;
requestBody = {
name,
range: { segmentId: (insertSegment !== 'body') ? segmentId : '', startIndex, endIndex },
range: {
segmentId: insertSegment !== 'body' ? segmentId : '',
startIndex,
endIndex,
},
};
} else if (action === 'delete') {
const { namedRangeReference, value } = actionField;
@ -454,11 +480,15 @@ export class GoogleDocs implements INodeType {
body.requests.push({
[`${action}${upperFirst(object as string)}`]: requestBody,
});
});
}
responseData = await googleApiRequest.call(this, 'POST', `/documents/${documentId}:batchUpdate`, body);
responseData = await googleApiRequest.call(
this,
'POST',
`/documents/${documentId}:batchUpdate`,
body,
);
if (simple === true) {
if (Object.keys(responseData.replies[0]).length !== 0) {
@ -471,7 +501,6 @@ export class GoogleDocs implements INodeType {
responseData.documentId = documentId;
}
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });

View file

@ -7,7 +7,7 @@ export interface IUpdateBody extends IDataObject {
export interface IUpdateFields {
writeControlObject: {
control: string,
value: string,
control: string;
value: string;
};
}

View file

@ -1,19 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject,
IPollFunctions,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, IPollFunctions, NodeApiError, NodeOperationError } from 'n8n-workflow';
import moment from 'moment-timezone';
@ -26,8 +15,22 @@ interface IGoogleAuthCredentials {
privateKey: string;
}
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
let options: OptionsWithUri = {
headers: {
@ -50,7 +53,10 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
return await this.helpers.request!(options);
@ -67,8 +73,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -78,15 +92,15 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
do {
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
function getAccessToken(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
@ -102,20 +116,20 @@ function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoa
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey as string,
{
algorithm: 'RS256',
header: {
'kid': privateKey as string,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey as string,
typ: 'JWT',
alg: 'RS256',
},
},
);

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,4 @@
import {
IPollFunctions,
} from 'n8n-core';
import { IPollFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,11 +10,7 @@ import {
NodeApiError,
} from 'n8n-workflow';
import {
extractId,
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { extractId, googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
import moment from 'moment';
@ -38,9 +32,7 @@ export class GoogleDriveTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -49,9 +41,7 @@ export class GoogleDriveTrigger implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -103,13 +93,12 @@ export class GoogleDriveTrigger implements INodeType {
type: 'string',
displayOptions: {
show: {
triggerOn: [
'specificFile',
],
triggerOn: ['specificFile'],
},
},
default: '',
description: 'The address of this file when you view it in your browser (or just the ID contained within the URL)',
description:
'The address of this file when you view it in your browser (or just the ID contained within the URL)',
required: true,
},
{
@ -118,9 +107,7 @@ export class GoogleDriveTrigger implements INodeType {
type: 'options',
displayOptions: {
show: {
triggerOn: [
'specificFile',
],
triggerOn: ['specificFile'],
},
},
required: true,
@ -139,13 +126,12 @@ export class GoogleDriveTrigger implements INodeType {
type: 'string',
displayOptions: {
show: {
triggerOn: [
'specificFolder',
],
triggerOn: ['specificFolder'],
},
},
default: '',
description: 'The address of this folder when you view it in your browser (or just the ID contained within the URL)',
description:
'The address of this folder when you view it in your browser (or just the ID contained within the URL)',
required: true,
},
{
@ -154,9 +140,7 @@ export class GoogleDriveTrigger implements INodeType {
type: 'options',
displayOptions: {
show: {
triggerOn: [
'specificFolder',
],
triggerOn: ['specificFolder'],
},
},
required: true,
@ -190,19 +174,15 @@ export class GoogleDriveTrigger implements INodeType {
],
},
{
displayName: 'Changes within subfolders won\'t trigger this node',
displayName: "Changes within subfolders won't trigger this node",
name: 'asas',
type: 'notice',
displayOptions: {
show: {
triggerOn: [
'specificFolder',
],
triggerOn: ['specificFolder'],
},
hide: {
event: [
'watchFolderUpdated',
],
event: ['watchFolderUpdated'],
},
},
default: '',
@ -214,9 +194,7 @@ export class GoogleDriveTrigger implements INodeType {
type: 'options',
displayOptions: {
show: {
triggerOn: [
'anyFileFolder',
],
triggerOn: ['anyFileFolder'],
},
},
typeOptions: {
@ -224,7 +202,8 @@ export class GoogleDriveTrigger implements INodeType {
},
default: 'root',
required: true,
description: 'The drive to monitor. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The drive to monitor. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Watch For',
@ -232,9 +211,7 @@ export class GoogleDriveTrigger implements INodeType {
type: 'options',
displayOptions: {
show: {
triggerOn: [
'anyFileFolder',
],
triggerOn: ['anyFileFolder'],
},
},
required: true,
@ -269,15 +246,10 @@ export class GoogleDriveTrigger implements INodeType {
type: 'collection',
displayOptions: {
show: {
event: [
'fileCreated',
'fileUpdated',
],
event: ['fileCreated', 'fileUpdated'],
},
hide: {
triggerOn: [
'specificFile',
],
triggerOn: ['specificFile'],
},
},
placeholder: 'Add Option',
@ -333,11 +305,14 @@ export class GoogleDriveTrigger implements INodeType {
loadOptions: {
// Get all the calendars to display them to user so that he can
// select them easily
async getDrives(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getDrives(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const drives = await googleApiRequestAllItems.call(this, 'drives', 'GET', `/drive/v3/drives`);
const drives = await googleApiRequestAllItems.call(
this,
'drives',
'GET',
`/drive/v3/drives`,
);
returnData.push({
name: 'Root',
value: 'root',
@ -362,13 +337,11 @@ export class GoogleDriveTrigger implements INodeType {
const now = moment().utc().format();
const startDate = webhookData.lastTimeChecked as string || now;
const startDate = (webhookData.lastTimeChecked as string) || now;
const endDate = now;
const query = [
'trashed = false',
];
const query = ['trashed = false'];
if (triggerOn === 'specificFolder' && event !== 'watchFolderUpdated') {
const folderToWatch = extractId(this.getNodeParameter('folderToWatch') as string);
@ -417,7 +390,11 @@ export class GoogleDriveTrigger implements INodeType {
files = files.filter((file: { id: string }) => file.id === fileToWatch);
}
if (triggerOn === 'specificFolder' && event === 'watchFolderUpdated' && this.getMode() !== 'manual') {
if (
triggerOn === 'specificFolder' &&
event === 'watchFolderUpdated' &&
this.getMode() !== 'manual'
) {
const folderToWatch = extractId(this.getNodeParameter('folderToWatch') as string);
files = files.filter((file: { id: string }) => file.id === folderToWatch);
}
@ -429,7 +406,9 @@ export class GoogleDriveTrigger implements INodeType {
}
if (this.getMode() === 'manual') {
throw new NodeApiError(this.getNode(), { message: 'No data with the current filter could be found' });
throw new NodeApiError(this.getNode(), {
message: 'No data with the current filter could be found',
});
}
return null;

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const collectionOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const collectionOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'collection',
],
resource: ['collection'],
},
},
options: [
@ -41,15 +37,12 @@ export const collectionFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'collection',
],
operation: [
'getAll',
],
resource: ['collection'],
operation: ['getAll'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -59,12 +52,8 @@ export const collectionFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'collection',
],
operation: [
'getAll',
],
resource: ['collection'],
operation: ['getAll'],
},
},
description: 'Usually the provided default value will work',
@ -77,12 +66,8 @@ export const collectionFields: INodeProperties[] = [
default: false,
displayOptions: {
show: {
resource: [
'collection',
],
operation: [
'getAll',
],
resource: ['collection'],
operation: ['getAll'],
},
},
description: 'Whether to return all results or only up to a given limit',
@ -94,15 +79,9 @@ export const collectionFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
resource: [
'collection',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['collection'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const documentOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const documentOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'document',
],
resource: ['document'],
},
},
options: [
@ -25,7 +21,8 @@ export const documentOperations: INodeProperties[] = [
{
name: 'Create or Update',
value: 'upsert',
description: 'Create a new document, or update the current one if it already exists (upsert)',
description:
'Create a new document, or update the current one if it already exists (upsert)',
action: 'Create or update a document',
},
{
@ -76,15 +73,12 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'create',
],
resource: ['document'],
operation: ['create'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -94,12 +88,8 @@ export const documentFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'create',
],
resource: ['document'],
operation: ['create'],
},
},
description: 'Usually the provided default value will work',
@ -112,12 +102,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'create',
],
resource: ['document'],
operation: ['create'],
},
},
description: 'Collection name',
@ -130,12 +116,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'create',
],
resource: ['document'],
operation: ['create'],
},
},
description: 'List of attributes to save',
@ -148,12 +130,8 @@ export const documentFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'document',
],
operation: ['create'],
resource: ['document'],
},
},
default: true,
@ -173,15 +151,12 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'get',
],
resource: ['document'],
operation: ['get'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -191,12 +166,8 @@ export const documentFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'get',
],
resource: ['document'],
operation: ['get'],
},
},
description: 'Usually the provided default value will work',
@ -209,12 +180,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'get',
],
resource: ['document'],
operation: ['get'],
},
},
description: 'Collection name',
@ -226,12 +193,8 @@ export const documentFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'document',
],
operation: ['get'],
resource: ['document'],
},
},
default: '',
@ -243,12 +206,8 @@ export const documentFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'document',
],
operation: ['get'],
resource: ['document'],
},
},
default: true,
@ -268,15 +227,12 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'getAll',
],
resource: ['document'],
operation: ['getAll'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -286,12 +242,8 @@ export const documentFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'getAll',
],
resource: ['document'],
operation: ['getAll'],
},
},
description: 'Usually the provided default value will work',
@ -304,12 +256,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'getAll',
],
resource: ['document'],
operation: ['getAll'],
},
},
description: 'Collection name',
@ -322,12 +270,8 @@ export const documentFields: INodeProperties[] = [
default: false,
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'getAll',
],
resource: ['document'],
operation: ['getAll'],
},
},
description: 'Whether to return all results or only up to a given limit',
@ -339,15 +283,9 @@ export const documentFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'getAll',
],
returnAll: [
false,
],
resource: ['document'],
operation: ['getAll'],
returnAll: [false],
},
},
typeOptions: {
@ -363,12 +301,8 @@ export const documentFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'document',
],
operation: ['getAll'],
resource: ['document'],
},
},
default: true,
@ -388,15 +322,12 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'delete',
],
resource: ['document'],
operation: ['delete'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -406,12 +337,8 @@ export const documentFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'delete',
],
resource: ['document'],
operation: ['delete'],
},
},
description: 'Usually the provided default value will work',
@ -424,12 +351,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'delete',
],
resource: ['document'],
operation: ['delete'],
},
},
description: 'Collection name',
@ -441,12 +364,8 @@ export const documentFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'document',
],
operation: ['delete'],
resource: ['document'],
},
},
default: '',
@ -580,15 +499,12 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'upsert',
],
resource: ['document'],
operation: ['upsert'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -598,12 +514,8 @@ export const documentFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'upsert',
],
resource: ['document'],
operation: ['upsert'],
},
},
description: 'Usually the provided default value will work',
@ -616,12 +528,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'upsert',
],
resource: ['document'],
operation: ['upsert'],
},
},
description: 'Collection name',
@ -633,12 +541,8 @@ export const documentFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'upsert',
],
resource: ['document'],
operation: ['upsert'],
},
},
default: '',
@ -653,12 +557,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'upsert',
],
resource: ['document'],
operation: ['upsert'],
},
},
description: 'Columns to insert',
@ -678,15 +578,12 @@ export const documentFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'query',
],
resource: ['document'],
operation: ['query'],
},
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -696,12 +593,8 @@ export const documentFields: INodeProperties[] = [
default: '(default)',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'query',
],
resource: ['document'],
operation: ['query'],
},
},
description: 'Usually the provided default value will work',
@ -714,12 +607,8 @@ export const documentFields: INodeProperties[] = [
default: '',
displayOptions: {
show: {
resource: [
'document',
],
operation: [
'query',
],
resource: ['document'],
operation: ['query'],
},
},
description: 'JSON query to execute',
@ -727,7 +616,8 @@ export const documentFields: INodeProperties[] = [
typeOptions: {
alwaysOpenEditWindow: true,
},
placeholder: '{"structuredQuery": {"where": {"fieldFilter": {"field": {"fieldPath": "age"},"op": "EQUAL", "value": {"integerValue": 28}}}, "from": [{"collectionId": "users-collection"}]}}',
placeholder:
'{"structuredQuery": {"where": {"fieldFilter": {"field": {"fieldPath": "age"},"op": "EQUAL", "value": {"integerValue": 28}}}, "from": [{"collectionId": "users-collection"}]}}',
},
{
displayName: 'Simplify',
@ -735,12 +625,8 @@ export const documentFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'query',
],
resource: [
'document',
],
operation: ['query'],
resource: ['document'],
},
},
default: true,

View file

@ -1,21 +1,21 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
import moment from 'moment-timezone';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri: string | null = null): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri: string | null = null,
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -35,14 +35,27 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
//@ts-ignore
return await this.helpers.requestOAuth2.call(this, 'googleFirebaseCloudFirestoreOAuth2Api', options);
return await this.helpers.requestOAuth2.call(
this,
'googleFirebaseCloudFirestoreOAuth2Api',
options,
);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri: string | null = null): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri: string | null = null,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -52,44 +65,42 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query, uri);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
const isValidDate = (str: string) => moment(str, ['YYYY-MM-DD HH:mm:ss Z', moment.ISO_8601], true).isValid();
const isValidDate = (str: string) =>
moment(str, ['YYYY-MM-DD HH:mm:ss Z', moment.ISO_8601], true).isValid();
// Both functions below were taken from Stack Overflow jsonToDocument was fixed as it was unable to handle null values correctly
// https://stackoverflow.com/questions/62246410/how-to-convert-a-firestore-document-to-plain-json-and-vice-versa
// Great thanks to https://stackoverflow.com/users/3915246/mahindar
export function jsonToDocument(value: string | number | IDataObject | IDataObject[]): IDataObject {
if (value === 'true' || value === 'false' || typeof value === 'boolean') {
return { 'booleanValue': value };
return { booleanValue: value };
} else if (value === null) {
return { 'nullValue': null };
return { nullValue: null };
} else if (!isNaN(value as number)) {
if (value.toString().indexOf('.') !== -1) {
return { 'doubleValue': value };
return { doubleValue: value };
} else {
return { 'integerValue': value };
return { integerValue: value };
}
} else if (isValidDate(value as string)) {
const date = new Date(Date.parse(value as string));
return { 'timestampValue': date.toISOString() };
return { timestampValue: date.toISOString() };
} else if (typeof value === 'string') {
return { 'stringValue': value };
return { stringValue: value };
} else if (value && value.constructor === Array) {
return { 'arrayValue': { values: value.map(v => jsonToDocument(v)) } };
return { arrayValue: { values: value.map((v) => jsonToDocument(v)) } };
} else if (typeof value === 'object') {
const obj = {};
for (const o of Object.keys(value)) {
//@ts-ignore
obj[o] = jsonToDocument(value[o]);
}
return { 'mapValue': { fields: obj } };
return { mapValue: { fields: obj } };
}
return {};
@ -109,17 +120,33 @@ export function fullDocumentToJson(data: IDataObject): IDataObject {
};
}
export function documentToJson(fields: IDataObject): IDataObject {
if (fields === undefined) return {};
const result = {};
for (const f of Object.keys(fields)) {
const key = f, value = fields[f],
isDocumentType = ['stringValue', 'booleanValue', 'doubleValue',
'integerValue', 'timestampValue', 'mapValue', 'arrayValue', 'nullValue', 'geoPointValue'].find(t => t === key);
const key = f,
value = fields[f],
isDocumentType = [
'stringValue',
'booleanValue',
'doubleValue',
'integerValue',
'timestampValue',
'mapValue',
'arrayValue',
'nullValue',
'geoPointValue',
].find((t) => t === key);
if (isDocumentType) {
const item = ['stringValue', 'booleanValue', 'doubleValue', 'integerValue', 'timestampValue', 'nullValue', 'geoPointValue']
.find(t => t === key);
const item = [
'stringValue',
'booleanValue',
'doubleValue',
'integerValue',
'timestampValue',
'nullValue',
'geoPointValue',
].find((t) => t === key);
if (item) {
return value as IDataObject;
} else if ('mapValue' === key) {
@ -129,7 +156,7 @@ export function documentToJson(fields: IDataObject): IDataObject {
// @ts-ignore
const list = value.values as IDataObject[];
// @ts-ignore
return !!list ? list.map(l => documentToJson(l)) : [];
return !!list ? list.map((l) => documentToJson(l)) : [];
}
} else {
// @ts-ignore

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -15,18 +13,12 @@ import {
fullDocumentToJson,
googleApiRequest,
googleApiRequestAllItems,
jsonToDocument
jsonToDocument,
} from './GenericFunctions';
import {
collectionFields,
collectionOperations,
} from './CollectionDescription';
import { collectionFields, collectionOperations } from './CollectionDescription';
import {
documentFields,
documentOperations,
} from './DocumentDescription';
import { documentFields, documentOperations } from './DocumentDescription';
export class GoogleFirebaseCloudFirestore implements INodeType {
description: INodeTypeDescription = {
@ -76,9 +68,7 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
methods = {
loadOptions: {
async getProjects(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getProjects(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const collections = await googleApiRequestAllItems.call(
this,
'results',
@ -89,14 +79,16 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
'https://firebase.googleapis.com/v1beta1/projects',
);
// @ts-ignore
const returnData = collections.map(o => ({ name: o.projectId, value: o.projectId })) as INodePropertyOptions[];
const returnData = collections.map((o) => ({
name: o.projectId,
value: o.projectId,
})) as INodePropertyOptions[];
return returnData;
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
let responseData;
@ -121,7 +113,7 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
{ documents: documentList },
);
responseData = responseData.map((element: { found: { id: string, name: string } }) => {
responseData = responseData.map((element: { found: { id: string; name: string } }) => {
if (element.found) {
element.found.id = (element.found.name as string).split('/').pop() as string;
}
@ -131,39 +123,52 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
if (simple === false) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else {
returnData.push.apply(returnData, responseData.map((element: IDataObject) => {
return fullDocumentToJson(element.found as IDataObject);
}).filter((el: IDataObject) => !!el));
returnData.push.apply(
returnData,
responseData
.map((element: IDataObject) => {
return fullDocumentToJson(element.found as IDataObject);
})
.filter((el: IDataObject) => !!el),
);
}
} else if (operation === 'create') {
const projectId = this.getNodeParameter('projectId', 0) as string;
const database = this.getNodeParameter('database', 0) as string;
const simple = this.getNodeParameter('simple', 0) as boolean;
await Promise.all(items.map(async (item: IDataObject, i: number) => {
const collection = this.getNodeParameter('collection', i) as string;
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map(column => column.trim());
const document = { fields: {} };
columnList.map(column => {
// @ts-ignore
document.fields[column] = item['json'][column] ? jsonToDocument(item['json'][column]) : jsonToDocument(null);
});
responseData = await googleApiRequest.call(
this,
'POST',
`/${projectId}/databases/${database}/documents/${collection}`,
document,
);
await Promise.all(
items.map(async (item: IDataObject, i: number) => {
const collection = this.getNodeParameter('collection', i) as string;
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map((column) => column.trim());
const document = { fields: {} };
columnList.map((column) => {
// @ts-ignore
if (item['json'][column]) {
// @ts-ignore
document.fields[column] = jsonToDocument(item['json'][column]);
} else {
// @ts-ignore
document.fields[column] = jsonToDocument(null);
}
});
responseData = await googleApiRequest.call(
this,
'POST',
`/${projectId}/databases/${database}/documents/${collection}`,
document,
);
responseData.id = (responseData.name as string).split('/').pop();
responseData.id = (responseData.name as string).split('/').pop();
if (simple === false) {
returnData.push(responseData);
} else {
returnData.push(fullDocumentToJson(responseData as IDataObject));
}
}));
if (simple === false) {
returnData.push(responseData);
} else {
returnData.push(fullDocumentToJson(responseData as IDataObject));
}
}),
);
} else if (operation === 'getAll') {
const projectId = this.getNodeParameter('projectId', 0) as string;
const database = this.getNodeParameter('database', 0) as string;
@ -180,13 +185,13 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', 0) as string;
const getAllResponse = await googleApiRequest.call(
const getAllResponse = (await googleApiRequest.call(
this,
'GET',
`/${projectId}/databases/${database}/documents/${collection}`,
{},
{ pageSize: limit },
) as IDataObject;
)) as IDataObject;
responseData = getAllResponse.documents;
}
responseData = responseData.map((element: IDataObject) => {
@ -196,29 +201,31 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
if (simple === false) {
returnData.push.apply(returnData, responseData);
} else {
returnData.push.apply(returnData, responseData.map((element: IDataObject) => fullDocumentToJson(element as IDataObject)));
returnData.push.apply(
returnData,
responseData.map((element: IDataObject) => fullDocumentToJson(element as IDataObject)),
);
}
} else if (operation === 'delete') {
const responseData: IDataObject[] = [];
await Promise.all(items.map(async (item: IDataObject, i: number) => {
const projectId = this.getNodeParameter('projectId', i) as string;
const database = this.getNodeParameter('database', i) as string;
const collection = this.getNodeParameter('collection', i) as string;
const documentId = this.getNodeParameter('documentId', i) as string;
await Promise.all(
items.map(async (item: IDataObject, i: number) => {
const projectId = this.getNodeParameter('projectId', i) as string;
const database = this.getNodeParameter('database', i) as string;
const collection = this.getNodeParameter('collection', i) as string;
const documentId = this.getNodeParameter('documentId', i) as string;
await googleApiRequest.call(
this,
'DELETE',
`/${projectId}/databases/${database}/documents/${collection}/${documentId}`,
);
await googleApiRequest.call(
this,
'DELETE',
`/${projectId}/databases/${database}/documents/${collection}/${documentId}`,
);
responseData.push({ success: true });
}));
responseData.push({ success: true });
}),
);
returnData.push.apply(returnData, responseData);
} else if (operation === 'upsert') {
const projectId = this.getNodeParameter('projectId', 0) as string;
const database = this.getNodeParameter('database', 0) as string;
@ -229,11 +236,17 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
// @ts-ignore
const documentId = item['json'][updateKey] as string;
const columns = this.getNodeParameter('columns', i) as string;
const columnList = columns.split(',').map(column => column.trim()) as string[];
const columnList = columns.split(',').map((column) => column.trim()) as string[];
const document = {};
columnList.map(column => {
columnList.map((column) => {
// @ts-ignore
document[column] = item['json'].hasOwnProperty(column) ? jsonToDocument(item['json'][column]) : jsonToDocument(null);
if (item['json'].hasOwnProperty(column)) {
// @ts-ignore
document[column] = jsonToDocument(item['json'][column]);
} else {
// @ts-ignore
document[column] = jsonToDocument(null);
}
});
return {
@ -245,7 +258,6 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
fieldPaths: columnList,
},
};
});
responseData = [];
@ -295,38 +307,47 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
// returnData.push(fullDocumentToJson(responseData as IDataObject));
// }
// }));
} else if (operation === 'query') {
const projectId = this.getNodeParameter('projectId', 0) as string;
const database = this.getNodeParameter('database', 0) as string;
const simple = this.getNodeParameter('simple', 0) as boolean;
await Promise.all(
items.map(async (item: IDataObject, i: number) => {
const query = this.getNodeParameter('query', i) as string;
responseData = await googleApiRequest.call(
this,
'POST',
`/${projectId}/databases/${database}/documents:runQuery`,
JSON.parse(query),
);
await Promise.all(items.map(async (item: IDataObject, i: number) => {
const query = this.getNodeParameter('query', i) as string;
responseData = await googleApiRequest.call(
this,
'POST',
`/${projectId}/databases/${database}/documents:runQuery`,
JSON.parse(query),
);
responseData = responseData.map(
(element: { document: { id: string; name: string } }) => {
if (element.document) {
element.document.id = (element.document.name as string)
.split('/')
.pop() as string;
}
return element;
},
);
responseData = responseData.map((element: { document: { id: string, name: string } }) => {
if (element.document) {
element.document.id = (element.document.name as string).split('/').pop() as string;
if (simple === false) {
returnData.push.apply(returnData, responseData);
} else {
//@ts-ignore
returnData.push.apply(
returnData,
responseData
.map((element: IDataObject) => {
return fullDocumentToJson(element.document as IDataObject);
})
.filter((element: IDataObject) => !!element),
);
}
return element;
});
if (simple === false) {
returnData.push.apply(returnData, responseData);
} else {
//@ts-ignore
returnData.push.apply(returnData, responseData.map((element: IDataObject) => {
return fullDocumentToJson(element.document as IDataObject);
}).filter((element: IDataObject) => !!element));
}
}));
}),
);
}
} else if (resource === 'collection') {
if (operation === 'getAll') {
@ -342,18 +363,18 @@ export class GoogleFirebaseCloudFirestore implements INodeType {
`/${projectId}/databases/${database}/documents:listCollectionIds`,
);
// @ts-ignore
responseData = getAllResponse.map(o => ({ name: o }));
responseData = getAllResponse.map((o) => ({ name: o }));
} else {
const limit = this.getNodeParameter('limit', 0) as string;
const getAllResponse = await googleApiRequest.call(
const getAllResponse = (await googleApiRequest.call(
this,
'POST',
`/${projectId}/databases/${database}/documents:listCollectionIds`,
{},
{ pageSize: limit },
) as IDataObject;
)) as IDataObject;
// @ts-ignore
responseData = getAllResponse.collectionIds.map(o => ({ name: o }));
responseData = getAllResponse.collectionIds.map((o) => ({ name: o }));
}
returnData.push.apply(returnData, responseData);
}

View file

@ -1,20 +1,24 @@
import {
OptionsWithUrl,
} from 'request';
import { OptionsWithUrl } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, JsonObject, NodeApiError,
} from 'n8n-workflow';
import { IDataObject, JsonObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, projectId: string, method: string, resource: string, body: any = {}, qs: IDataObject = {}, headers: IDataObject = {}, uri: string | null = null): Promise<any> { // tslint:disable-line:no-any
const { region } = await this.getCredentials('googleFirebaseRealtimeDatabaseOAuth2Api') as IDataObject;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
projectId: string,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
headers: IDataObject = {},
uri: string | null = null,
// tslint:disable-next-line:no-any
): Promise<any> {
const { region } = (await this.getCredentials(
'googleFirebaseRealtimeDatabaseOAuth2Api',
)) as IDataObject;
const options: OptionsWithUrl = {
headers: {
@ -35,28 +39,47 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
delete options.body;
}
return await this.helpers.requestOAuth2!.call(this, 'googleFirebaseRealtimeDatabaseOAuth2Api', options);
return await this.helpers.requestOAuth2!.call(
this,
'googleFirebaseRealtimeDatabaseOAuth2Api',
options,
);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, projectId: string, method: string, resource: string, body: any = {}, qs: IDataObject = {}, headers: IDataObject = {}, uri: string | null = null): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
projectId: string,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
headers: IDataObject = {},
uri: string | null = null,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
qs.pageSize = 100;
do {
responseData = await googleApiRequest.call(this, projectId, method, resource, body, qs, {}, uri);
responseData = await googleApiRequest.call(
this,
projectId,
method,
resource,
body,
qs,
{},
uri,
);
qs.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[resource]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -14,10 +12,7 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
export class GoogleFirebaseRealtimeDatabase implements INodeType {
description: INodeTypeDescription = {
@ -47,7 +42,8 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
typeOptions: {
loadOptionsMethod: 'getProjects',
},
description: 'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'As displayed in firebase console URL. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
},
{
@ -101,7 +97,7 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
required: true,
displayOptions: {
hide: {
'operation': [ 'get' ],
operation: ['get'],
},
},
},
@ -116,7 +112,7 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
hint: 'Leave blank to get a whole database object',
displayOptions: {
show: {
'operation': [ 'get' ],
operation: ['get'],
},
},
},
@ -127,11 +123,7 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
default: '',
displayOptions: {
show: {
operation: [
'create',
'push',
'update',
],
operation: ['create', 'push', 'update'],
},
},
description: 'Attributes to save',
@ -143,9 +135,7 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
methods = {
loadOptions: {
async getProjects(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getProjects(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const projects = await googleApiRequestAllItems.call(
this,
'',
@ -158,14 +148,14 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
);
const returnData = projects
// select only realtime database projects
.filter((project: IDataObject) => (project.resources as IDataObject).realtimeDatabaseInstance )
.map((project: IDataObject) => (
{
name: project.projectId,
value: (project.resources as IDataObject).realtimeDatabaseInstance,
}
)) as INodePropertyOptions[];
// select only realtime database projects
.filter(
(project: IDataObject) => (project.resources as IDataObject).realtimeDatabaseInstance,
)
.map((project: IDataObject) => ({
name: project.projectId,
value: (project.resources as IDataObject).realtimeDatabaseInstance,
})) as INodePropertyOptions[];
return returnData;
},
@ -180,8 +170,11 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
const operation = this.getNodeParameter('operation', 0) as string;
//https://firebase.google.com/docs/reference/rest/database
if (['push', 'create', 'update'].includes(operation) && items.length === 1 && Object.keys(items[0].json).length === 0) {
if (
['push', 'create', 'update'].includes(operation) &&
items.length === 1 &&
Object.keys(items[0].json).length === 0
) {
throw new NodeOperationError(this.getNode(), `The ${operation} operation needs input data`);
}
@ -189,7 +182,8 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
try {
const projectId = this.getNodeParameter('projectId', i) as string;
let method = 'GET', attributes = '';
let method = 'GET',
attributes = '';
const document: IDataObject = {};
if (operation === 'create') {
method = 'PUT';
@ -207,7 +201,7 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
}
if (attributes) {
const attributeList = attributes.split(',').map(el => el.trim());
const attributeList = attributes.split(',').map((el) => el.trim());
attributeList.map((attribute: string) => {
if (items[i].json.hasOwnProperty(attribute)) {
document[attribute] = items[i].json[attribute];
@ -225,7 +219,9 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
if (responseData === null) {
if (operation === 'get') {
throw new NodeApiError(this.getNode(), responseData, { message: `Requested entity was not found.` });
throw new NodeApiError(this.getNode(), responseData, {
message: `Requested entity was not found.`,
});
} else if (method === 'DELETE') {
responseData = { success: true };
}
@ -240,7 +236,9 @@ export class GoogleFirebaseRealtimeDatabase implements INodeType {
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (typeof responseData === 'string' || typeof responseData === 'number') {
returnData.push({ [this.getNodeParameter('path', i) as string]: responseData } as IDataObject);
returnData.push({
[this.getNodeParameter('path', i) as string]: responseData,
} as IDataObject);
} else {
returnData.push(responseData as IDataObject);
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,20 +10,11 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
import {
userFields,
userOperations,
} from './UserDescription';
import { userFields, userOperations } from './UserDescription';
import {
groupFields,
groupOperations,
} from './GroupDescripion';
import { groupFields, groupOperations } from './GroupDescripion';
export class GSuiteAdmin implements INodeType {
description: INodeTypeDescription = {
@ -77,9 +66,7 @@ export class GSuiteAdmin implements INodeType {
loadOptions: {
// Get all the domains to display them to user so that he can
// select them easily
async getDomains(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getDomains(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const domains = await googleApiRequestAllItems.call(
this,
@ -99,9 +86,7 @@ export class GSuiteAdmin implements INodeType {
},
// Get all the schemas to display them to user so that he can
// select them easily
async getSchemas(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getSchemas(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const schemas = await googleApiRequestAllItems.call(
this,
@ -144,12 +129,7 @@ export class GSuiteAdmin implements INodeType {
Object.assign(body, additionalFields);
responseData = await googleApiRequest.call(
this,
'POST',
`/directory/v1/groups`,
body,
);
responseData = await googleApiRequest.call(this, 'POST', `/directory/v1/groups`, body);
}
//https://developers.google.com/admin-sdk/directory/v1/reference/groups/delete
@ -199,17 +179,10 @@ export class GSuiteAdmin implements INodeType {
{},
qs,
);
} else {
qs.maxResults = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(
this,
'GET',
`/directory/v1/groups`,
{},
qs,
);
responseData = await googleApiRequest.call(this, 'GET', `/directory/v1/groups`, {}, qs);
responseData = responseData.groups;
}
@ -278,13 +251,7 @@ export class GSuiteAdmin implements INodeType {
delete body.emailUi;
}
responseData = await googleApiRequest.call(
this,
'POST',
`/directory/v1/users`,
body,
qs,
);
responseData = await googleApiRequest.call(this, 'POST', `/directory/v1/users`, body, qs);
if (makeAdmin) {
await googleApiRequest.call(
@ -329,7 +296,11 @@ export class GSuiteAdmin implements INodeType {
}
if (qs.projection === 'custom' && qs.customFieldMask === undefined) {
throw new NodeOperationError(this.getNode(), 'When projection is set to custom, the custom schemas field must be defined', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'When projection is set to custom, the custom schemas field must be defined',
{ itemIndex: i },
);
}
responseData = await googleApiRequest.call(
@ -362,7 +333,11 @@ export class GSuiteAdmin implements INodeType {
}
if (qs.projection === 'custom' && qs.customFieldMask === undefined) {
throw new NodeOperationError(this.getNode(), 'When projection is set to custom, the custom schemas field must be defined', { itemIndex: i });
throw new NodeOperationError(
this.getNode(),
'When projection is set to custom, the custom schemas field must be defined',
{ itemIndex: i },
);
}
if (returnAll) {
@ -374,17 +349,10 @@ export class GSuiteAdmin implements INodeType {
{},
qs,
);
} else {
qs.maxResults = this.getNodeParameter('limit', i) as number;
responseData = await googleApiRequest.call(
this,
'GET',
`/directory/v1/users`,
{},
qs,
);
responseData = await googleApiRequest.call(this, 'GET', `/directory/v1/users`, {}, qs);
responseData = responseData.users;
}
@ -396,7 +364,11 @@ export class GSuiteAdmin implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
const body: { name: { givenName?: string, familyName?: string }, emails?: IDataObject[], phones?: IDataObject[] } = { name: {} };
const body: {
name: { givenName?: string; familyName?: string };
emails?: IDataObject[];
phones?: IDataObject[];
} = { name: {} };
Object.assign(body, updateFields);
@ -451,7 +423,6 @@ export class GSuiteAdmin implements INodeType {
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else if (responseData !== undefined) {
returnData.push(responseData as IDataObject);
}

View file

@ -1,19 +1,20 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject,
NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -38,8 +39,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -49,10 +58,7 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const groupOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const groupOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'group',
],
resource: ['group'],
},
},
options: [
@ -63,16 +59,13 @@ export const groupFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'group',
],
operation: ['create'],
resource: ['group'],
},
},
default: '',
description: 'The group\'s email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique',
description:
"The group's email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique",
},
{
displayName: 'Additional Fields',
@ -82,12 +75,8 @@ export const groupFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'group',
],
operation: ['create'],
resource: ['group'],
},
},
options: [
@ -96,14 +85,15 @@ export const groupFields: INodeProperties[] = [
name: 'description',
type: 'string',
default: '',
description: 'An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups.',
description:
'An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups.',
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'The group\'s display name',
description: "The group's display name",
},
],
},
@ -117,16 +107,13 @@ export const groupFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'group',
],
operation: ['delete'],
resource: ['group'],
},
},
default: '',
description: 'Identifies the group in the API request. The value can be the group\'s email address, group alias, or the unique group ID.',
description:
"Identifies the group in the API request. The value can be the group's email address, group alias, or the unique group ID.",
},
/* -------------------------------------------------------------------------- */
/* group:get */
@ -138,16 +125,13 @@ export const groupFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'group',
],
operation: ['get'],
resource: ['group'],
},
},
default: '',
description: 'Identifies the group in the API request. The value can be the group\'s email address, group alias, or the unique group ID.',
description:
"Identifies the group in the API request. The value can be the group's email address, group alias, or the unique group ID.",
},
/* -------------------------------------------------------------------------- */
/* group:getAll */
@ -158,12 +142,8 @@ export const groupFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'group',
],
operation: ['getAll'],
resource: ['group'],
},
},
default: false,
@ -175,15 +155,9 @@ export const groupFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'group',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['group'],
returnAll: [false],
},
},
typeOptions: {
@ -201,12 +175,8 @@ export const groupFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'group',
],
operation: ['getAll'],
resource: ['group'],
},
},
options: [
@ -215,7 +185,8 @@ export const groupFields: INodeProperties[] = [
name: 'customer',
type: 'string',
default: '',
description: 'The unique ID for the customer\'s G Suite account. In case of a multi-domain account, to fetch all groups for a customer, fill this field instead of domain.',
description:
"The unique ID for the customer's G Suite account. In case of a multi-domain account, to fetch all groups for a customer, fill this field instead of domain.",
},
{
displayName: 'Domain',
@ -242,7 +213,8 @@ export const groupFields: INodeProperties[] = [
name: 'query',
type: 'string',
default: '',
description: 'Query string search. Complete documentation is <a href="https://developers.google.com/admin-sdk/directory/v1/guides/search-groups">at</a>.',
description:
'Query string search. Complete documentation is <a href="https://developers.google.com/admin-sdk/directory/v1/guides/search-groups">at</a>.',
},
{
displayName: 'Sort Order',
@ -266,7 +238,8 @@ export const groupFields: INodeProperties[] = [
name: 'userId',
type: 'string',
default: '',
description: 'Email or immutable ID of the user if only those groups are to be listed, the given user is a member of. If it\'s an ID, it should match with the ID of the user object.',
description:
"Email or immutable ID of the user if only those groups are to be listed, the given user is a member of. If it's an ID, it should match with the ID of the user object.",
},
],
},
@ -280,16 +253,13 @@ export const groupFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'group',
],
operation: ['update'],
resource: ['group'],
},
},
default: '',
description: 'Identifies the group in the API request. The value can be the group\'s email address, group alias, or the unique group ID.',
description:
"Identifies the group in the API request. The value can be the group's email address, group alias, or the unique group ID.",
},
{
displayName: 'Update Fields',
@ -299,12 +269,8 @@ export const groupFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'group',
],
operation: ['update'],
resource: ['group'],
},
},
options: [
@ -313,7 +279,8 @@ export const groupFields: INodeProperties[] = [
name: 'description',
type: 'string',
default: '',
description: 'An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups.',
description:
'An extended description to help users determine the purpose of a group. For example, you can include information about who should join the group, the types of messages to send to the group, links to FAQs about the group, or related groups.',
},
{
displayName: 'Email',
@ -321,14 +288,15 @@ export const groupFields: INodeProperties[] = [
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'The group\'s email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique.',
description:
"The group's email address. If your account has multiple domains, select the appropriate domain for the email address. The email must be unique.",
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'The group\'s display name',
description: "The group's display name",
},
],
},

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const userOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const userOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'user',
],
resource: ['user'],
},
},
options: [
@ -62,12 +58,8 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
default: '',
@ -79,12 +71,8 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
default: '',
@ -99,34 +87,28 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
default: '',
description: 'Stores the password for the user account. A minimum of 8 characters is required. The maximum length is 100 characters.',
description:
'Stores the password for the user account. A minimum of 8 characters is required. The maximum length is 100 characters.',
},
{
displayName: 'Domain Name or ID',
name: 'domain',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getDomains',
},
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
default: '',
@ -137,16 +119,13 @@ export const userFields: INodeProperties[] = [
type: 'string',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
default: '',
description: 'The username that will be set to the user. Example: If you domain is example.com and you set the username to jhon then the user\'s final email address will be jhon@example.com.',
description:
"The username that will be set to the user. Example: If you domain is example.com and you set the username to jhon then the user's final email address will be jhon@example.com.",
},
{
displayName: 'Make Admin',
@ -155,12 +134,8 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
default: false,
@ -174,12 +149,8 @@ export const userFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'user',
],
operation: ['create'],
resource: ['user'],
},
},
options: [
@ -310,7 +281,8 @@ export const userFields: INodeProperties[] = [
name: 'primary',
type: 'boolean',
default: false,
description: 'Whether this is the user\'s primary phone number. A user may only have one primary phone number.',
description:
"Whether this is the user's primary phone number. A user may only have one primary phone number.",
},
],
},
@ -373,16 +345,13 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'user',
],
operation: ['delete'],
resource: ['user'],
},
},
default: '',
description: 'The value can be the user\'s primary email address, alias email address, or unique user ID',
description:
"The value can be the user's primary email address, alias email address, or unique user ID",
},
/* -------------------------------------------------------------------------- */
/* user:get */
@ -394,16 +363,13 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'user',
],
operation: ['get'],
resource: ['user'],
},
},
default: '',
description: 'The value can be the user\'s primary email address, alias email address, or unique user ID',
description:
"The value can be the user's primary email address, alias email address, or unique user ID",
},
{
displayName: 'Projection',
@ -429,12 +395,8 @@ export const userFields: INodeProperties[] = [
],
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'user',
],
operation: ['get'],
resource: ['user'],
},
},
default: 'basic',
@ -448,12 +410,8 @@ export const userFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'user',
],
operation: ['get'],
resource: ['user'],
},
},
options: [
@ -463,16 +421,15 @@ export const userFields: INodeProperties[] = [
type: 'multiOptions',
displayOptions: {
show: {
'/projection': [
'custom',
],
'/projection': ['custom'],
},
},
typeOptions: {
loadOptionsMethod: 'getSchemas',
},
default: [],
description: 'A comma-separated list of schema names. All fields from these schemas are fetched. This should only be set when projection=custom. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'A comma-separated list of schema names. All fields from these schemas are fetched. This should only be set when projection=custom. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'View Type',
@ -482,16 +439,19 @@ export const userFields: INodeProperties[] = [
{
name: 'Admin View',
value: 'admin_view',
description: 'Results include both administrator-only and domain-public fields for the user',
description:
'Results include both administrator-only and domain-public fields for the user',
},
{
name: 'Descending',
value: 'DESCENDING',
description: 'Results only include fields for the user that are publicly visible to other users in the domain',
description:
'Results only include fields for the user that are publicly visible to other users in the domain',
},
],
default: 'admin_view',
description: 'Whether to fetch the administrator-only or domain-wide public view of the user. For more information, see Retrieve a user as a non-administrator.',
description:
'Whether to fetch the administrator-only or domain-wide public view of the user. For more information, see Retrieve a user as a non-administrator.',
},
],
},
@ -504,12 +464,8 @@ export const userFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'user',
],
operation: ['getAll'],
resource: ['user'],
},
},
default: false,
@ -521,15 +477,9 @@ export const userFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'user',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['user'],
returnAll: [false],
},
},
typeOptions: {
@ -563,12 +513,8 @@ export const userFields: INodeProperties[] = [
],
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'user',
],
operation: ['getAll'],
resource: ['user'],
},
},
default: 'basic',
@ -582,12 +528,8 @@ export const userFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'user',
],
operation: ['getAll'],
resource: ['user'],
},
},
options: [
@ -597,23 +539,23 @@ export const userFields: INodeProperties[] = [
type: 'multiOptions',
displayOptions: {
show: {
'/projection': [
'custom',
],
'/projection': ['custom'],
},
},
typeOptions: {
loadOptionsMethod: 'getSchemas',
},
default: [],
description: 'A comma-separated list of schema names. All fields from these schemas are fetched. This should only be set when projection=custom. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'A comma-separated list of schema names. All fields from these schemas are fetched. This should only be set when projection=custom. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Customer',
name: 'customer',
type: 'string',
default: '',
description: 'The unique ID for the customer\'s G Suite account. In case of a multi-domain account, to fetch all groups for a customer, fill this field instead of domain.',
description:
"The unique ID for the customer's G Suite account. In case of a multi-domain account, to fetch all groups for a customer, fill this field instead of domain.",
},
{
displayName: 'Domain',
@ -648,7 +590,8 @@ export const userFields: INodeProperties[] = [
name: 'query',
type: 'string',
default: '',
description: 'Free text search terms to find users that match these terms in any field, except for extended properties. For more information on constructing user queries, see <a href="https://developers.google.com/admin-sdk/directory/v1/guides/search-users">Search for Users</a>.',
description:
'Free text search terms to find users that match these terms in any field, except for extended properties. For more information on constructing user queries, see <a href="https://developers.google.com/admin-sdk/directory/v1/guides/search-users">Search for Users</a>.',
},
{
displayName: 'Show Deleted',
@ -682,16 +625,19 @@ export const userFields: INodeProperties[] = [
{
name: 'Admin View',
value: 'admin_view',
description: 'Results include both administrator-only and domain-public fields for the user',
description:
'Results include both administrator-only and domain-public fields for the user',
},
{
name: 'Descending',
value: 'DESCENDING',
description: 'Results only include fields for the user that are publicly visible to other users in the domain',
description:
'Results only include fields for the user that are publicly visible to other users in the domain',
},
],
default: 'admin_view',
description: 'Whether to fetch the administrator-only or domain-wide public view of the user. For more information, see Retrieve a user as a non-administrator.',
description:
'Whether to fetch the administrator-only or domain-wide public view of the user. For more information, see Retrieve a user as a non-administrator.',
},
],
},
@ -705,16 +651,13 @@ export const userFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'user',
],
operation: ['update'],
resource: ['user'],
},
},
default: '',
description: 'The value can be the user\'s primary email address, alias email address, or unique user ID',
description:
"The value can be the user's primary email address, alias email address, or unique user ID",
},
{
displayName: 'Update Fields',
@ -724,12 +667,8 @@ export const userFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'user',
],
operation: ['update'],
resource: ['user'],
},
},
options: [
@ -764,7 +703,8 @@ export const userFields: INodeProperties[] = [
name: 'password',
type: 'string',
default: '',
description: 'Stores the password for the user account. A minimum of 8 characters is required. The maximum length is 100 characters.',
description:
'Stores the password for the user account. A minimum of 8 characters is required. The maximum length is 100 characters.',
},
{
displayName: 'Phones',
@ -884,7 +824,8 @@ export const userFields: INodeProperties[] = [
name: 'primary',
type: 'boolean',
default: false,
description: 'Whether this is the user\'s primary phone number. A user may only have one primary phone number.',
description:
"Whether this is the user's primary phone number. A user may only have one primary phone number.",
},
],
},
@ -895,7 +836,8 @@ export const userFields: INodeProperties[] = [
name: 'primaryEmail',
type: 'string',
default: '',
description: 'The user\'s primary email address. This property is required in a request to create a user account. The primaryEmail must be unique and cannot be an alias of another user.',
description:
"The user's primary email address. This property is required in a request to create a user account. The primaryEmail must be unique and cannot be an alias of another user.",
},
{
displayName: 'Secondary Emails',

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const draftOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const draftOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'draft',
],
resource: ['draft'],
},
},
options: [
@ -54,13 +50,8 @@ export const draftFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'draft',
],
operation: [
'delete',
'get',
],
resource: ['draft'],
operation: ['delete', 'get'],
},
},
placeholder: 'r-3254521568507167962',
@ -74,12 +65,8 @@ export const draftFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'draft',
],
operation: [
'create',
],
resource: ['draft'],
operation: ['create'],
},
},
placeholder: 'Hello World!',
@ -91,12 +78,8 @@ export const draftFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'draft',
],
operation: [
'create',
],
resource: ['draft'],
operation: ['create'],
},
},
default: false,
@ -110,15 +93,9 @@ export const draftFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
includeHtml: [
true,
],
resource: [
'draft',
],
operation: [
'create',
],
includeHtml: [true],
resource: ['draft'],
operation: ['create'],
},
},
description: 'The HTML message body',
@ -131,16 +108,13 @@ export const draftFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'draft',
],
operation: [
'create',
],
resource: ['draft'],
operation: ['create'],
},
},
placeholder: 'Hello World!',
description: 'The message body. If HTML formatted, then you have to add and activate the option "HTML content" in the "Additional Options" section.',
description:
'The message body. If HTML formatted, then you have to add and activate the option "HTML content" in the "Additional Options" section.',
},
{
displayName: 'Additional Fields',
@ -149,12 +123,8 @@ export const draftFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'draft',
],
operation: [
'create',
],
resource: ['draft'],
operation: ['create'],
},
},
default: {},
@ -213,7 +183,8 @@ export const draftFields: INodeProperties[] = [
name: 'property',
type: 'string',
default: '',
description: 'Name of the binary property containing the data to be added to the email as an attachment. Multiple properties can be set separated by comma.',
description:
'Name of the binary property containing the data to be added to the email as an attachment. Multiple properties can be set separated by comma.',
},
],
},
@ -230,12 +201,8 @@ export const draftFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'draft',
],
operation: [
'get',
],
resource: ['draft'],
operation: ['get'],
},
},
default: {},
@ -247,15 +214,11 @@ export const draftFields: INodeProperties[] = [
default: 'attachment_',
displayOptions: {
hide: {
format: [
'full',
'metadata',
'minimal',
'raw',
],
format: ['full', 'metadata', 'minimal', 'raw'],
},
},
description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
description:
'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
},
{
displayName: 'Format',
@ -265,7 +228,8 @@ export const draftFields: INodeProperties[] = [
{
name: 'Full',
value: 'full',
description: 'Returns the full email message data with body content parsed in the payload field',
description:
'Returns the full email message data with body content parsed in the payload field',
},
{
name: 'Metadata',
@ -275,17 +239,20 @@ export const draftFields: INodeProperties[] = [
{
name: 'Minimal',
value: 'minimal',
description: 'Returns only email message ID and labels; does not return the email headers, body, or payload',
description:
'Returns only email message ID and labels; does not return the email headers, body, or payload',
},
{
name: 'RAW',
value: 'raw',
description: 'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
description:
'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
},
{
name: 'Resolved',
value: 'resolved',
description: 'Returns the full email with all data resolved and attachments saved as binary data',
description:
'Returns the full email with all data resolved and attachments saved as binary data',
},
],
default: 'resolved',
@ -303,12 +270,8 @@ export const draftFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'draft',
],
operation: ['getAll'],
resource: ['draft'],
},
},
default: false,
@ -320,15 +283,9 @@ export const draftFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'draft',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['draft'],
returnAll: [false],
},
},
typeOptions: {
@ -346,12 +303,8 @@ export const draftFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'draft',
],
operation: ['getAll'],
resource: ['draft'],
},
},
options: [
@ -362,16 +315,11 @@ export const draftFields: INodeProperties[] = [
default: 'attachment_',
displayOptions: {
hide: {
format: [
'full',
'ids',
'metadata',
'minimal',
'raw',
],
format: ['full', 'ids', 'metadata', 'minimal', 'raw'],
},
},
description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
description:
'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
},
{
displayName: 'Format',
@ -381,7 +329,8 @@ export const draftFields: INodeProperties[] = [
{
name: 'Full',
value: 'full',
description: 'Returns the full email message data with body content parsed in the payload field',
description:
'Returns the full email message data with body content parsed in the payload field',
},
{
name: 'IDs',
@ -396,17 +345,20 @@ export const draftFields: INodeProperties[] = [
{
name: 'Minimal',
value: 'minimal',
description: 'Returns only email message ID and labels; does not return the email headers, body, or payload',
description:
'Returns only email message ID and labels; does not return the email headers, body, or payload',
},
{
name: 'RAW',
value: 'raw',
description: 'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
description:
'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
},
{
name: 'Resolved',
value: 'resolved',
description: 'Returns the full email with all data resolved and attachments saved as binary data',
description:
'Returns the full email with all data resolved and attachments saved as binary data',
},
],
default: 'resolved',

View file

@ -1,16 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
simpleParser,
} from 'mailparser';
import { simpleParser } from 'mailparser';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IBinaryKeyData,
@ -20,9 +12,7 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
IEmail,
} from './Gmail.node';
import { IEmail } from './Gmail.node';
import moment from 'moment-timezone';
@ -37,12 +27,25 @@ interface IGoogleAuthCredentials {
const mailComposer = require('nodemailer/lib/mail-composer');
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string,
endpoint: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
let options: OptionsWithUri = {
headers: {
'Accept': 'application/json',
Accept: 'application/json',
'Content-Type': 'application/json',
},
method,
@ -65,7 +68,10 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
//@ts-ignore
@ -74,7 +80,6 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
//@ts-ignore
return await this.helpers.requestOAuth2.call(this, 'gmailOAuth2', options);
}
} catch (error) {
if (error.code === 'ERR_OSSL_PEM_NO_START_LINE') {
error.statusCode = '401';
@ -84,9 +89,12 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function parseRawEmail(this: IExecuteFunctions, messageData: any, dataPropertyNameDownload: string): Promise<INodeExecutionData> { // tslint:disable-line:no-any
export async function parseRawEmail(
this: IExecuteFunctions,
// tslint:disable-next-line:no-any
messageData: any,
dataPropertyNameDownload: string,
): Promise<INodeExecutionData> {
const messageEncoded = Buffer.from(messageData.raw, 'base64').toString('utf8');
let responseData = await simpleParser(messageEncoded);
@ -103,10 +111,13 @@ export async function parseRawEmail(this: IExecuteFunctions, messageData: any, d
const binaryData: IBinaryKeyData = {};
if (responseData.attachments) {
for (let i = 0; i < responseData.attachments.length; i++) {
const attachment = responseData.attachments[i];
binaryData[`${dataPropertyNameDownload}${i}`] = await this.helpers.prepareBinaryData(attachment.content, attachment.filename, attachment.contentType);
binaryData[`${dataPropertyNameDownload}${i}`] = await this.helpers.prepareBinaryData(
attachment.content,
attachment.filename,
attachment.contentType,
);
}
// @ts-ignore
responseData.attachments = undefined;
@ -114,12 +125,7 @@ export async function parseRawEmail(this: IExecuteFunctions, messageData: any, d
const mailBaseData: IDataObject = {};
const resolvedModeAddProperties = [
'id',
'threadId',
'labelIds',
'sizeEstimate',
];
const resolvedModeAddProperties = ['id', 'threadId', 'labelIds', 'sizeEstimate'];
for (const key of resolvedModeAddProperties) {
// @ts-ignore
@ -134,7 +140,6 @@ export async function parseRawEmail(this: IExecuteFunctions, messageData: any, d
} as INodeExecutionData;
}
//------------------------------------------------------------------------------------------------------------------------------------------
// This function converts an email object into a MIME encoded email and then converts that string into base64 encoding
// for more info on MIME, https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/aa494197(v%3Dexchg.140)
@ -158,7 +163,11 @@ export async function encodeEmail(email: IEmail) {
mailOptions.html = email.htmlBody;
}
if (email.attachments !== undefined && Array.isArray(email.attachments) && email.attachments.length > 0) {
if (
email.attachments !== undefined &&
Array.isArray(email.attachments) &&
email.attachments.length > 0
) {
const attachments = email.attachments.map((attachment) => ({
filename: attachment.name,
content: attachment.content,
@ -182,8 +191,16 @@ export async function encodeEmail(email: IEmail) {
return mailBody.toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -193,10 +210,7 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
@ -206,7 +220,10 @@ export function extractEmail(s: string) {
return data.substring(0, data.length - 1);
}
function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
function getAccessToken(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
@ -225,20 +242,20 @@ function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoa
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey,
{
algorithm: 'RS256',
header: {
'kid': privateKey,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey,
typ: 'JWT',
alg: 'RS256',
},
},
);

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IBinaryKeyData,
@ -20,29 +18,15 @@ import {
parseRawEmail,
} from './GenericFunctions';
import {
messageFields,
messageOperations,
} from './MessageDescription';
import { messageFields, messageOperations } from './MessageDescription';
import {
messageLabelFields,
messageLabelOperations,
} from './MessageLabelDescription';
import { messageLabelFields, messageLabelOperations } from './MessageLabelDescription';
import {
labelFields,
labelOperations,
} from './LabelDescription';
import { labelFields, labelOperations } from './LabelDescription';
import {
draftFields,
draftOperations,
} from './DraftDescription';
import { draftFields, draftOperations } from './DraftDescription';
import {
isEmpty,
} from 'lodash';
import { isEmpty } from 'lodash';
export interface IEmail {
from?: string;
@ -83,9 +67,7 @@ export class Gmail implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -94,9 +76,7 @@ export class Gmail implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -170,9 +150,7 @@ export class Gmail implements INodeType {
loadOptions: {
// Get all the labels to display them to user so that he can
// select them easily
async getLabels(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getLabels(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const labels = await googleApiRequestAllItems.call(
this,
@ -212,7 +190,10 @@ export class Gmail implements INodeType {
//https://developers.google.com/gmail/api/v1/reference/users/labels/create
const labelName = this.getNodeParameter('name', i) as string;
const labelListVisibility = this.getNodeParameter('labelListVisibility', i) as string;
const messageListVisibility = this.getNodeParameter('messageListVisibility', i) as string;
const messageListVisibility = this.getNodeParameter(
'messageListVisibility',
i,
) as string;
method = 'POST';
endpoint = '/gmail/v1/users/me/labels';
@ -233,7 +214,6 @@ export class Gmail implements INodeType {
endpoint = `/gmail/v1/users/me/labels/${labelId}`;
responseData = await googleApiRequest.call(this, method, endpoint, body, qs);
responseData = { success: true };
}
if (operation === 'get') {
// https://developers.google.com/gmail/api/v1/reference/users/labels/get
@ -328,15 +308,20 @@ export class Gmail implements INodeType {
const attachmentsUi = additionalFields.attachmentsUi as IDataObject;
const attachmentsBinary = [];
if (!isEmpty(attachmentsUi)) {
if (attachmentsUi.hasOwnProperty('attachmentsBinary')
&& !isEmpty(attachmentsUi.attachmentsBinary)
&& items[i].binary) {
if (
attachmentsUi.hasOwnProperty('attachmentsBinary') &&
!isEmpty(attachmentsUi.attachmentsBinary) &&
items[i].binary
) {
// @ts-ignore
for (const { property } of attachmentsUi.attachmentsBinary as IDataObject[]) {
for (const binaryProperty of (property as string).split(',')) {
if (items[i].binary![binaryProperty] !== undefined) {
const binaryData = items[i].binary![binaryProperty];
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(
i,
binaryProperty,
);
attachmentsBinary.push({
name: binaryData.fileName || 'unknown',
content: binaryDataBuffer,
@ -356,7 +341,7 @@ export class Gmail implements INodeType {
}
const email: IEmail = {
from: additionalFields.senderName as string || '',
from: (additionalFields.senderName as string) || '',
to: toStr,
cc: ccStr,
bcc: bccStr,
@ -365,7 +350,7 @@ export class Gmail implements INodeType {
attachments: attachmentsList,
};
if (this.getNodeParameter('includeHtml', i, false) as boolean === true) {
if ((this.getNodeParameter('includeHtml', i, false) as boolean) === true) {
email.htmlBody = this.getNodeParameter('htmlMessage', i) as string;
}
@ -379,7 +364,6 @@ export class Gmail implements INodeType {
responseData = await googleApiRequest.call(this, method, endpoint, body, qs);
}
if (operation === 'reply') {
const id = this.getNodeParameter('messageId', i) as string;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
@ -415,15 +399,20 @@ export class Gmail implements INodeType {
const attachmentsUi = additionalFields.attachmentsUi as IDataObject;
const attachmentsBinary = [];
if (!isEmpty(attachmentsUi)) {
if (attachmentsUi.hasOwnProperty('attachmentsBinary')
&& !isEmpty(attachmentsUi.attachmentsBinary)
&& items[i].binary) {
if (
attachmentsUi.hasOwnProperty('attachmentsBinary') &&
!isEmpty(attachmentsUi.attachmentsBinary) &&
items[i].binary
) {
// @ts-ignore
for (const { property } of attachmentsUi.attachmentsBinary as IDataObject[]) {
for (const binaryProperty of (property as string).split(',')) {
if (items[i].binary![binaryProperty] !== undefined) {
const binaryData = items[i].binary![binaryProperty];
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(
i,
binaryProperty,
);
attachmentsBinary.push({
name: binaryData.fileName || 'unknown',
content: binaryDataBuffer,
@ -458,7 +447,7 @@ export class Gmail implements INodeType {
}
const email: IEmail = {
from: additionalFields.senderName as string || '',
from: (additionalFields.senderName as string) || '',
to: toStr,
cc: ccStr,
bcc: bccStr,
@ -467,7 +456,7 @@ export class Gmail implements INodeType {
attachments: attachmentsList,
};
if (this.getNodeParameter('includeHtml', i, false) as boolean === true) {
if ((this.getNodeParameter('includeHtml', i, false) as boolean) === true) {
email.htmlBody = this.getNodeParameter('htmlMessage', i) as string;
}
@ -505,9 +494,14 @@ export class Gmail implements INodeType {
let nodeExecutionData: INodeExecutionData;
if (format === 'resolved') {
const dataPropertyNameDownload = additionalFields.dataPropertyAttachmentsPrefixName as string || 'attachment_';
const dataPropertyNameDownload =
(additionalFields.dataPropertyAttachmentsPrefixName as string) || 'attachment_';
nodeExecutionData = await parseRawEmail.call(this, responseData, dataPropertyNameDownload);
nodeExecutionData = await parseRawEmail.call(
this,
responseData,
dataPropertyNameDownload,
);
} else {
nodeExecutionData = {
json: responseData,
@ -558,7 +552,6 @@ export class Gmail implements INodeType {
const format = additionalFields.format || 'resolved';
if (format !== 'ids') {
if (format === 'resolved') {
qs.format = 'raw';
} else {
@ -575,9 +568,14 @@ export class Gmail implements INodeType {
);
if (format === 'resolved') {
const dataPropertyNameDownload = additionalFields.dataPropertyAttachmentsPrefixName as string || 'attachment_';
const dataPropertyNameDownload =
(additionalFields.dataPropertyAttachmentsPrefixName as string) || 'attachment_';
responseData[i] = await parseRawEmail.call(this, responseData[i], dataPropertyNameDownload);
responseData[i] = await parseRawEmail.call(
this,
responseData[i],
dataPropertyNameDownload,
);
}
}
}
@ -585,7 +583,6 @@ export class Gmail implements INodeType {
if (format !== 'resolved') {
responseData = this.helpers.returnJsonArray(responseData);
}
}
if (operation === 'delete') {
// https://developers.google.com/gmail/api/v1/reference/users/messages/delete
@ -639,14 +636,19 @@ export class Gmail implements INodeType {
const attachmentsBinary = [];
if (!isEmpty(attachmentsUi)) {
if (!isEmpty(attachmentsUi)) {
if (attachmentsUi.hasOwnProperty('attachmentsBinary')
&& !isEmpty(attachmentsUi.attachmentsBinary)
&& items[i].binary) {
if (
attachmentsUi.hasOwnProperty('attachmentsBinary') &&
!isEmpty(attachmentsUi.attachmentsBinary) &&
items[i].binary
) {
for (const { property } of attachmentsUi.attachmentsBinary as IDataObject[]) {
for (const binaryProperty of (property as string).split(',')) {
if (items[i].binary![binaryProperty] !== undefined) {
const binaryData = items[i].binary![binaryProperty];
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(
i,
binaryProperty,
);
attachmentsBinary.push({
name: binaryData.fileName || 'unknown',
content: binaryDataBuffer,
@ -676,7 +678,7 @@ export class Gmail implements INodeType {
attachments: attachmentsList,
};
if (this.getNodeParameter('includeHtml', i, false) as boolean === true) {
if ((this.getNodeParameter('includeHtml', i, false) as boolean) === true) {
email.htmlBody = this.getNodeParameter('htmlMessage', i) as string;
}
@ -713,9 +715,14 @@ export class Gmail implements INodeType {
let nodeExecutionData: INodeExecutionData;
if (format === 'resolved') {
const dataPropertyNameDownload = additionalFields.dataPropertyAttachmentsPrefixName as string || 'attachment_';
const dataPropertyNameDownload =
(additionalFields.dataPropertyAttachmentsPrefixName as string) || 'attachment_';
nodeExecutionData = await parseRawEmail.call(this, responseData.message, dataPropertyNameDownload);
nodeExecutionData = await parseRawEmail.call(
this,
responseData.message,
dataPropertyNameDownload,
);
// Add the draft-id
nodeExecutionData.json.messageId = nodeExecutionData.json.id;
@ -780,7 +787,6 @@ export class Gmail implements INodeType {
}
for (let i = 0; i < responseData.length; i++) {
responseData[i] = await googleApiRequest.call(
this,
'GET',
@ -790,9 +796,14 @@ export class Gmail implements INodeType {
);
if (format === 'resolved') {
const dataPropertyNameDownload = additionalFields.dataPropertyAttachmentsPrefixName as string || 'attachment_';
const dataPropertyNameDownload =
(additionalFields.dataPropertyAttachmentsPrefixName as string) || 'attachment_';
const id = responseData[i].id;
responseData[i] = await parseRawEmail.call(this, responseData[i].message, dataPropertyNameDownload);
responseData[i] = await parseRawEmail.call(
this,
responseData[i].message,
dataPropertyNameDownload,
);
// Add the draft-id
responseData[i].json.messageId = responseData[i].json.id;

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const labelOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const labelOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'label',
],
resource: ['label'],
},
},
options: [
@ -54,12 +50,8 @@ export const labelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'label',
],
operation: [
'create',
],
resource: ['label'],
operation: ['create'],
},
},
placeholder: 'invoices',
@ -73,13 +65,8 @@ export const labelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'label',
],
operation: [
'get',
'delete',
],
resource: ['label'],
operation: ['get', 'delete'],
},
},
description: 'The ID of the label',
@ -106,12 +93,8 @@ export const labelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'label',
],
operation: [
'create',
],
resource: ['label'],
operation: ['create'],
},
},
description: 'The visibility of the label in the label list in the Gmail web interface',
@ -134,15 +117,12 @@ export const labelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'label',
],
operation: [
'create',
],
resource: ['label'],
operation: ['create'],
},
},
description: 'The visibility of messages with this label in the message list in the Gmail web interface',
description:
'The visibility of messages with this label in the message list in the Gmail web interface',
},
/* -------------------------------------------------------------------------- */
/* label:getAll */
@ -153,12 +133,8 @@ export const labelFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'label',
],
operation: ['getAll'],
resource: ['label'],
},
},
default: false,
@ -170,15 +146,9 @@ export const labelFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'label',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['label'],
returnAll: [false],
},
},
typeOptions: {

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const messageOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const messageOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'message',
],
resource: ['message'],
},
},
options: [
@ -60,13 +56,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'get',
'delete',
],
resource: ['message'],
operation: ['get', 'delete'],
},
},
placeholder: '172ce2c4a72cc243',
@ -80,12 +71,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'reply',
],
resource: ['message'],
operation: ['reply'],
},
},
placeholder: '172ce2c4a72cc243',
@ -99,12 +86,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'reply',
],
resource: ['message'],
operation: ['reply'],
},
},
placeholder: 'CAHNQoFsC6JMMbOBJgtjsqN0eEc+gDg2a=SQj-tWUebQeHMDgqQ@mail.gmail.com',
@ -118,13 +101,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'reply',
'send',
],
resource: ['message'],
operation: ['reply', 'send'],
},
},
placeholder: 'Hello World!',
@ -136,13 +114,8 @@ export const messageFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'send',
'reply',
],
resource: ['message'],
operation: ['send', 'reply'],
},
},
default: false,
@ -156,16 +129,9 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
includeHtml: [
true,
],
resource: [
'message',
],
operation: [
'reply',
'send',
],
includeHtml: [true],
resource: ['message'],
operation: ['reply', 'send'],
},
},
description: 'The HTML message body',
@ -178,13 +144,8 @@ export const messageFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'reply',
'send',
],
resource: ['message'],
operation: ['reply', 'send'],
},
},
description: 'Plain text message body',
@ -201,13 +162,8 @@ export const messageFields: INodeProperties[] = [
},
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'reply',
'send',
],
resource: ['message'],
operation: ['reply', 'send'],
},
},
placeholder: 'info@example.com',
@ -220,13 +176,8 @@ export const messageFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'send',
'reply',
],
resource: ['message'],
operation: ['send', 'reply'],
},
},
default: {},
@ -249,7 +200,8 @@ export const messageFields: INodeProperties[] = [
name: 'property',
type: 'string',
default: '',
description: 'Name of the binary property containing the data to be added to the email as an attachment. Multiple properties can be set separated by comma.',
description:
'Name of the binary property containing the data to be added to the email as an attachment. Multiple properties can be set separated by comma.',
},
],
},
@ -287,7 +239,8 @@ export const messageFields: INodeProperties[] = [
type: 'string',
placeholder: 'Name <test@gmail.com>',
default: '',
description: 'The name displayed in your contacts inboxes. It has to be in the format: "Display-Name &#60;name@gmail.com&#62;". The email address has to match the email address of the logged in user for the API',
description:
'The name displayed in your contacts inboxes. It has to be in the format: "Display-Name &#60;name@gmail.com&#62;". The email address has to match the email address of the logged in user for the API',
},
],
},
@ -298,12 +251,8 @@ export const messageFields: INodeProperties[] = [
placeholder: 'Add Field',
displayOptions: {
show: {
resource: [
'message',
],
operation: [
'get',
],
resource: ['message'],
operation: ['get'],
},
},
default: {},
@ -316,7 +265,8 @@ export const messageFields: INodeProperties[] = [
{
name: 'Full',
value: 'full',
description: 'Returns the full email message data with body content parsed in the payload field',
description:
'Returns the full email message data with body content parsed in the payload field',
},
{
name: 'Metadata',
@ -326,17 +276,20 @@ export const messageFields: INodeProperties[] = [
{
name: 'Minimal',
value: 'minimal',
description: 'Returns only email message ID and labels; does not return the email headers, body, or payload',
description:
'Returns only email message ID and labels; does not return the email headers, body, or payload',
},
{
name: 'RAW',
value: 'raw',
description: 'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
description:
'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
},
{
name: 'Resolved',
value: 'resolved',
description: 'Returns the full email with all data resolved and attachments saved as binary data',
description:
'Returns the full email with all data resolved and attachments saved as binary data',
},
],
default: 'resolved',
@ -349,15 +302,11 @@ export const messageFields: INodeProperties[] = [
default: 'attachment_',
displayOptions: {
hide: {
format: [
'full',
'metadata',
'minimal',
'raw',
],
format: ['full', 'metadata', 'minimal', 'raw'],
},
},
description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
description:
'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
},
],
},
@ -371,12 +320,8 @@ export const messageFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'message',
],
operation: ['getAll'],
resource: ['message'],
},
},
default: false,
@ -388,15 +333,9 @@ export const messageFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'message',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['message'],
returnAll: [false],
},
},
typeOptions: {
@ -414,12 +353,8 @@ export const messageFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'message',
],
operation: ['getAll'],
resource: ['message'],
},
},
options: [
@ -430,16 +365,11 @@ export const messageFields: INodeProperties[] = [
default: 'attachment_',
displayOptions: {
hide: {
format: [
'full',
'ids',
'metadata',
'minimal',
'raw',
],
format: ['full', 'ids', 'metadata', 'minimal', 'raw'],
},
},
description: 'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
description:
'Prefix for name of the binary property to which to write the attachments. An index starting with 0 will be added. So if name is "attachment_" the first attachment is saved to "attachment_0"',
},
{
displayName: 'Format',
@ -449,7 +379,8 @@ export const messageFields: INodeProperties[] = [
{
name: 'Full',
value: 'full',
description: 'Returns the full email message data with body content parsed in the payload field',
description:
'Returns the full email message data with body content parsed in the payload field',
},
{
name: 'IDs',
@ -464,17 +395,20 @@ export const messageFields: INodeProperties[] = [
{
name: 'Minimal',
value: 'minimal',
description: 'Returns only email message ID and labels; does not return the email headers, body, or payload',
description:
'Returns only email message ID and labels; does not return the email headers, body, or payload',
},
{
name: 'RAW',
value: 'raw',
description: 'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
description:
'Returns the full email message data with body content in the raw field as a base64url encoded string; the payload field is not used',
},
{
name: 'Resolved',
value: 'resolved',
description: 'Returns the full email with all data resolved and attachments saved as binary data',
description:
'Returns the full email with all data resolved and attachments saved as binary data',
},
],
default: 'resolved',
@ -495,7 +429,8 @@ export const messageFields: INodeProperties[] = [
loadOptionsMethod: 'getLabels',
},
default: [],
description: 'Only return messages with labels that match all of the specified label IDs. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Only return messages with labels that match all of the specified label IDs. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Query',
@ -505,9 +440,9 @@ export const messageFields: INodeProperties[] = [
alwaysOpenEditWindow: true,
},
default: '',
description: 'Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, "from:someuser@example.com rfc822msgid:&lt;somemsgid@example.com&gt; is:unread". Parameter cannot be used when accessing the api using the gmail.metadata scope.',
description:
'Only return messages matching the specified query. Supports the same query format as the Gmail search box. For example, "from:someuser@example.com rfc822msgid:&lt;somemsgid@example.com&gt; is:unread". Parameter cannot be used when accessing the api using the gmail.metadata scope.',
},
],
},
];

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const messageLabelOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const messageLabelOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'messageLabel',
],
resource: ['messageLabel'],
},
},
options: [
@ -42,13 +38,8 @@ export const messageLabelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'messageLabel',
],
operation: [
'add',
'remove',
],
resource: ['messageLabel'],
operation: ['add', 'remove'],
},
},
placeholder: '172ce2c4a72cc243',
@ -65,15 +56,11 @@ export const messageLabelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
resource: [
'messageLabel',
],
operation: [
'add',
'remove',
],
resource: ['messageLabel'],
operation: ['add', 'remove'],
},
},
description: 'The ID of the label. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The ID of the label. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
];

View file

@ -1,15 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(
this: IExecuteFunctions,

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -12,16 +10,9 @@ import {
NodeOperationError,
} from 'n8n-workflow';
import {
AttributesValuesUi,
CommentAnalyzeBody,
Language,
RequestedAttributes,
} from './types';
import { AttributesValuesUi, CommentAnalyzeBody, Language, RequestedAttributes } from './types';
import {
googleApiRequest,
} from './GenericFunctions';
import { googleApiRequest } from './GenericFunctions';
const ISO6391 = require('iso-639-1');
@ -30,21 +21,15 @@ export class GooglePerspective implements INodeType {
displayName: 'Google Perspective',
name: 'googlePerspective',
icon: 'file:perspective.svg',
group: [
'transform',
],
group: ['transform'],
version: 1,
description: 'Consume Google Perspective API',
subtitle: '={{$parameter["operation"]}}',
defaults: {
name: 'Google Perspective',
},
inputs: [
'main',
],
outputs: [
'main',
],
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'googlePerspectiveOAuth2Api',
@ -73,9 +58,7 @@ export class GooglePerspective implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'analyzeComment',
],
operation: ['analyzeComment'],
},
},
},
@ -91,9 +74,7 @@ export class GooglePerspective implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'analyzeComment',
],
operation: ['analyzeComment'],
},
},
options: [
@ -139,7 +120,8 @@ export class GooglePerspective implements INodeType {
value: 'toxicity',
},
],
description: 'Attribute to analyze in the text. Details <a href="https://developers.perspectiveapi.com/s/about-the-api-attributes-and-languages">here</a>.',
description:
'Attribute to analyze in the text. Details <a href="https://developers.perspectiveapi.com/s/about-the-api-attributes-and-languages">here</a>.',
default: 'flirtation',
},
{
@ -151,7 +133,8 @@ export class GooglePerspective implements INodeType {
minValue: 0,
maxValue: 1,
},
description: 'Score above which to return results. At zero, all scores are returned.',
description:
'Score above which to return results. At zero, all scores are returned.',
default: 0,
},
],
@ -164,9 +147,7 @@ export class GooglePerspective implements INodeType {
type: 'collection',
displayOptions: {
show: {
operation: [
'analyzeComment',
],
operation: ['analyzeComment'],
},
},
default: {},
@ -180,7 +161,8 @@ export class GooglePerspective implements INodeType {
loadOptionsMethod: 'getLanguages',
},
default: '',
description: 'Languages of the text input. If unspecified, the API will auto-detect the comment language. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'Languages of the text input. If unspecified, the API will auto-detect the comment language. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
],
},
@ -203,7 +185,9 @@ export class GooglePerspective implements INodeType {
'Russian',
];
const languages = ISO6391.getAllNames().filter((language: string) => supportedLanguages.includes(language));
const languages = ISO6391.getAllNames().filter((language: string) =>
supportedLanguages.includes(language),
);
for (const language of languages) {
const languageName = language;
const languageId = ISO6391.getCode(language);
@ -226,22 +210,21 @@ export class GooglePerspective implements INodeType {
let responseData;
for (let i = 0; i < items.length; i++) {
try {
if (operation === 'analyzeComment') {
// https://developers.perspectiveapi.com/s/about-the-api-methods
const attributes = this.getNodeParameter(
'requestedAttributesUi.requestedAttributesValues', i, [],
'requestedAttributesUi.requestedAttributesValues',
i,
[],
) as AttributesValuesUi[];
if (!attributes.length) {
throw new NodeOperationError(
this.getNode(),
'Please enter at least one attribute to analyze.', { itemIndex: i },
'Please enter at least one attribute to analyze.',
{ itemIndex: i },
);
}
@ -268,10 +251,13 @@ export class GooglePerspective implements INodeType {
body.languages = languages;
}
responseData = await googleApiRequest.call(this, 'POST', '/v1alpha1/comments:analyze', body);
responseData = await googleApiRequest.call(
this,
'POST',
'/v1alpha1/comments:analyze',
body,
);
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });
@ -283,7 +269,6 @@ export class GooglePerspective implements INodeType {
Array.isArray(responseData)
? returnData.push(...responseData)
: returnData.push(responseData);
}
return [this.helpers.returnJsonArray(responseData)];

View file

@ -15,7 +15,7 @@ export type RequestedAttributes = {
[key: string]: {
scoreType?: string;
scoreThreshold?: {
value: number
value: number;
};
};
};

View file

@ -1,16 +1,12 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
ICredentialTestFunctions,
IDataObject, NodeApiError, NodeOperationError,
IDataObject,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
import moment from 'moment-timezone';
@ -24,8 +20,22 @@ export interface IGoogleAuthCredentials {
privateKey: string;
}
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -47,7 +57,10 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
//@ts-ignore
@ -65,8 +78,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -76,15 +97,19 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
export function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | ICredentialTestFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
export function getAccessToken(
this:
| IExecuteFunctions
| IExecuteSingleFunctions
| ILoadOptionsFunctions
| ICredentialTestFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
@ -100,20 +125,20 @@ export function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.delegatedEmail || credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.delegatedEmail || (credentials.email as string),
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey,
{
algorithm: 'RS256',
header: {
'kid': privateKey,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey,
typ: 'JWT',
alg: 'RS256',
},
},
);
@ -144,9 +169,14 @@ export function hexToRgb(hex: string) {
});
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16),
} : null;
if (result) {
return {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16),
};
}
return null;
}

View file

@ -1,19 +1,10 @@
import {
IDataObject, NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, NodeOperationError } from 'n8n-workflow';
import {
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
googleApiRequest,
} from './GenericFunctions';
import { googleApiRequest } from './GenericFunctions';
import {
utils as xlsxUtils,
} from 'xlsx';
import { utils as xlsxUtils } from 'xlsx';
import { get } from 'lodash';
@ -56,7 +47,11 @@ export class GoogleSheet {
id: string;
executeFunctions: IExecuteFunctions | ILoadOptionsFunctions;
constructor(spreadsheetId: string, executeFunctions: IExecuteFunctions | ILoadOptionsFunctions, options?: ISheetOptions | undefined) {
constructor(
spreadsheetId: string,
executeFunctions: IExecuteFunctions | ILoadOptionsFunctions,
options?: ISheetOptions | undefined,
) {
// options = <SheetOptions>options || {};
if (!options) {
options = {} as ISheetOptions;
@ -66,7 +61,6 @@ export class GoogleSheet {
this.id = spreadsheetId;
}
/**
* Encodes the range that also none latin character work
*
@ -82,7 +76,6 @@ export class GoogleSheet {
return range;
}
/**
* Clears values from a sheet
*
@ -91,13 +84,17 @@ export class GoogleSheet {
* @memberof GoogleSheet
*/
async clearData(range: string): Promise<object> {
const body = {
spreadsheetId: this.id,
range,
};
const response = await googleApiRequest.call(this.executeFunctions, 'POST', `/v4/spreadsheets/${this.id}/values/${range}:clear`, body);
const response = await googleApiRequest.call(
this.executeFunctions,
'POST',
`/v4/spreadsheets/${this.id}/values/${range}:clear`,
body,
);
return response;
}
@ -105,85 +102,106 @@ export class GoogleSheet {
/**
* Returns the cell values
*/
async getData(range: string, valueRenderMode: ValueRenderOption): Promise<string[][] | undefined> {
async getData(
range: string,
valueRenderMode: ValueRenderOption,
): Promise<string[][] | undefined> {
const query = {
valueRenderOption: valueRenderMode,
};
const response = await googleApiRequest.call(this.executeFunctions, 'GET', `/v4/spreadsheets/${this.id}/values/${range}`, {}, query);
const response = await googleApiRequest.call(
this.executeFunctions,
'GET',
`/v4/spreadsheets/${this.id}/values/${range}`,
{},
query,
);
return response.values as string[][] | undefined;
}
/**
* Returns the sheets in a Spreadsheet
*/
async spreadsheetGetSheets() {
const query = {
fields: 'sheets.properties',
};
const response = await googleApiRequest.call(this.executeFunctions, 'GET', `/v4/spreadsheets/${this.id}`, {}, query);
const response = await googleApiRequest.call(
this.executeFunctions,
'GET',
`/v4/spreadsheets/${this.id}`,
{},
query,
);
return response;
}
/**
* Sets values in one or more ranges of a spreadsheet.
*/
async spreadsheetBatchUpdate(requests: IDataObject[]) { // tslint:disable-line:no-any
async spreadsheetBatchUpdate(requests: IDataObject[]) {
// tslint:disable-line:no-any
const body = {
requests,
};
const response = await googleApiRequest.call(this.executeFunctions, 'POST', `/v4/spreadsheets/${this.id}:batchUpdate`, body);
const response = await googleApiRequest.call(
this.executeFunctions,
'POST',
`/v4/spreadsheets/${this.id}:batchUpdate`,
body,
);
return response;
}
/**
* Sets the cell values
*/
async batchUpdate(updateData: ISheetUpdateData[], valueInputMode: ValueInputOption) {
const body = {
data: updateData,
valueInputOption: valueInputMode,
};
const response = await googleApiRequest.call(this.executeFunctions, 'POST', `/v4/spreadsheets/${this.id}/values:batchUpdate`, body);
const response = await googleApiRequest.call(
this.executeFunctions,
'POST',
`/v4/spreadsheets/${this.id}/values:batchUpdate`,
body,
);
return response;
}
/**
* Sets the cell values
*/
async setData(range: string, data: string[][], valueInputMode: ValueInputOption) {
const body = {
valueInputOption: valueInputMode,
values: data,
};
const response = await googleApiRequest.call(this.executeFunctions, 'POST', `/v4/spreadsheets/${this.id}/values/${range}`, body);
const response = await googleApiRequest.call(
this.executeFunctions,
'POST',
`/v4/spreadsheets/${this.id}/values/${range}`,
body,
);
return response;
}
/**
* Appends the cell values
*/
async appendData(range: string, data: string[][], valueInputMode: ValueInputOption) {
const body = {
range: decodeURIComponent(range),
values: data,
@ -193,7 +211,13 @@ export class GoogleSheet {
valueInputOption: valueInputMode,
};
const response = await googleApiRequest.call(this.executeFunctions, 'POST', `/v4/spreadsheets/${this.id}/values/${range}:append`, body, query);
const response = await googleApiRequest.call(
this.executeFunctions,
'POST',
`/v4/spreadsheets/${this.id}/values/${range}:append`,
body,
query,
);
return response;
}
@ -201,7 +225,12 @@ export class GoogleSheet {
/**
* Returns the given sheet data in a structured way
*/
structureData(inputData: string[][], startRow: number, keys: string[], addEmpty?: boolean): IDataObject[] {
structureData(
inputData: string[][],
startRow: number,
keys: string[],
addEmpty?: boolean,
): IDataObject[] {
const returnData = [];
let tempEntry: IDataObject, rowIndex: number, columnIndex: number, key: string;
@ -224,13 +253,15 @@ export class GoogleSheet {
return returnData;
}
/**
* Returns the given sheet data in a structured way using
* the startRow as the one with the name of the key
*/
structureArrayDataByColumn(inputData: string[][], keyRow: number, dataStartRow: number): IDataObject[] {
structureArrayDataByColumn(
inputData: string[][],
keyRow: number,
dataStartRow: number,
): IDataObject[] {
const keys: string[] = [];
if (keyRow < 0 || dataStartRow < keyRow || keyRow >= inputData.length) {
@ -246,19 +277,27 @@ export class GoogleSheet {
return this.structureData(inputData, dataStartRow, keys);
}
async appendSheetData(inputData: IDataObject[], range: string, keyRowIndex: number, valueInputMode: ValueInputOption, usePathForKeyRow: boolean): Promise<string[][]> {
const data = await this.convertStructuredDataToArray(inputData, range, keyRowIndex, usePathForKeyRow);
async appendSheetData(
inputData: IDataObject[],
range: string,
keyRowIndex: number,
valueInputMode: ValueInputOption,
usePathForKeyRow: boolean,
): Promise<string[][]> {
const data = await this.convertStructuredDataToArray(
inputData,
range,
keyRowIndex,
usePathForKeyRow,
);
return this.appendData(range, data, valueInputMode);
}
getColumnWithOffset(startColumn: string, offset: number): string {
const columnIndex = xlsxUtils.decode_col(startColumn) + offset;
return xlsxUtils.encode_col(columnIndex);
}
/**
* Updates data in a sheet
*
@ -271,15 +310,15 @@ export class GoogleSheet {
* @memberof GoogleSheet
*/
async updateSheetData(
inputData: IDataObject[],
indexKey: string,
range: string,
keyRowIndex: number,
dataStartRowIndex: number,
valueInputMode: ValueInputOption,
valueRenderMode: ValueRenderOption,
upsert = false,
): Promise<string[][]> {
inputData: IDataObject[],
indexKey: string,
range: string,
keyRowIndex: number,
dataStartRowIndex: number,
valueInputMode: ValueInputOption,
valueRenderMode: ValueRenderOption,
upsert = false,
): Promise<string[][]> {
// Get current data in Google Sheet
let rangeStart: string, rangeEnd: string, rangeFull: string;
let sheet: string | undefined = undefined;
@ -293,16 +332,29 @@ export class GoogleSheet {
const rangeStartSplit = rangeStart.match(/([a-zA-Z]{1,10})([0-9]{0,10})/);
const rangeEndSplit = rangeEnd.match(/([a-zA-Z]{1,10})([0-9]{0,10})/);
if (rangeStartSplit === null || rangeStartSplit.length !== 3 || rangeEndSplit === null || rangeEndSplit.length !== 3) {
throw new NodeOperationError(this.executeFunctions.getNode(), `The range "${range}" is not valid.`);
if (
rangeStartSplit === null ||
rangeStartSplit.length !== 3 ||
rangeEndSplit === null ||
rangeEndSplit.length !== 3
) {
throw new NodeOperationError(
this.executeFunctions.getNode(),
`The range "${range}" is not valid.`,
);
}
const keyRowRange = `${sheet ? sheet + '!' : ''}${rangeStartSplit[1]}${keyRowIndex + 1}:${rangeEndSplit[1]}${keyRowIndex + 1}`;
const keyRowRange = `${sheet ? sheet + '!' : ''}${rangeStartSplit[1]}${keyRowIndex + 1}:${
rangeEndSplit[1]
}${keyRowIndex + 1}`;
const sheetDatakeyRow = await this.getData(this.encodeRange(keyRowRange), valueRenderMode);
if (sheetDatakeyRow === undefined) {
throw new NodeOperationError(this.executeFunctions.getNode(), 'Could not retrieve the key row!');
throw new NodeOperationError(
this.executeFunctions.getNode(),
'Could not retrieve the key row!',
);
}
const keyColumnOrder = sheetDatakeyRow[0];
@ -310,19 +362,30 @@ export class GoogleSheet {
const keyIndex = keyColumnOrder.indexOf(indexKey);
if (keyIndex === -1) {
throw new NodeOperationError(this.executeFunctions.getNode(), `Could not find column for key "${indexKey}"!`);
throw new NodeOperationError(
this.executeFunctions.getNode(),
`Could not find column for key "${indexKey}"!`,
);
}
const startRowIndex = rangeStartSplit[2] || dataStartRowIndex;
const endRowIndex = rangeEndSplit[2] || '';
const keyColumn = this.getColumnWithOffset(rangeStartSplit[1], keyIndex);
const keyColumnRange = `${sheet ? sheet + '!' : ''}${keyColumn}${startRowIndex}:${keyColumn}${endRowIndex}`;
const keyColumnRange = `${
sheet ? sheet + '!' : ''
}${keyColumn}${startRowIndex}:${keyColumn}${endRowIndex}`;
const sheetDataKeyColumn = await this.getData(this.encodeRange(keyColumnRange), valueRenderMode);
const sheetDataKeyColumn = await this.getData(
this.encodeRange(keyColumnRange),
valueRenderMode,
);
if (sheetDataKeyColumn === undefined) {
throw new NodeOperationError(this.executeFunctions.getNode(), 'Could not retrieve the key column!');
throw new NodeOperationError(
this.executeFunctions.getNode(),
'Could not retrieve the key column!',
);
}
// TODO: The data till here can be cached optionally. Maybe add an option which can
@ -346,7 +409,13 @@ export class GoogleSheet {
if (itemKey === undefined || itemKey === null) {
// Item does not have the indexKey so we can ignore it or append it if upsert true
if (upsert) {
const data = await this.appendSheetData([inputItem], this.encodeRange(range), keyRowIndex, valueInputMode, false);
const data = await this.appendSheetData(
[inputItem],
this.encodeRange(range),
keyRowIndex,
valueInputMode,
false,
);
}
continue;
}
@ -356,7 +425,13 @@ export class GoogleSheet {
if (itemKeyIndex === -1) {
// Key does not exist in the Sheet so it can not be updated so skip it or append it if upsert true
if (upsert) {
const data = await this.appendSheetData([inputItem], this.encodeRange(range), keyRowIndex, valueInputMode, false);
const data = await this.appendSheetData(
[inputItem],
this.encodeRange(range),
keyRowIndex,
valueInputMode,
false,
);
}
continue;
}
@ -380,24 +455,21 @@ export class GoogleSheet {
// Property exists so add it to the data to update
// Get the column name in which the property data can be found
updateColumnName = this.getColumnWithOffset(rangeStartSplit[1], keyColumnOrder.indexOf(propertyName));
updateColumnName = this.getColumnWithOffset(
rangeStartSplit[1],
keyColumnOrder.indexOf(propertyName),
);
updateData.push({
range: `${sheet ? sheet + '!' : ''}${updateColumnName}${updateRowIndex}`,
values: [
[
inputItem[propertyName] as string,
],
],
values: [[inputItem[propertyName] as string]],
});
}
}
return this.batchUpdate(updateData, valueInputMode);
}
/**
* Looks for a specific value in a column and if it gets found it returns the whole row
*
@ -409,7 +481,13 @@ export class GoogleSheet {
* @returns {Promise<IDataObject[]>}
* @memberof GoogleSheet
*/
async lookupValues(inputData: string[][], keyRowIndex: number, dataStartRowIndex: number, lookupValues: ILookupValues[], returnAllMatches?: boolean): Promise<IDataObject[]> {
async lookupValues(
inputData: string[][],
keyRowIndex: number,
dataStartRowIndex: number,
lookupValues: ILookupValues[],
returnAllMatches?: boolean,
): Promise<IDataObject[]> {
const keys: string[] = [];
if (keyRowIndex < 0 || dataStartRowIndex < keyRowIndex || keyRowIndex >= inputData.length) {
@ -422,9 +500,7 @@ export class GoogleSheet {
keys.push(inputData[keyRowIndex][columnIndex]);
}
const returnData = [
inputData[keyRowIndex],
];
const returnData = [inputData[keyRowIndex]];
// Standardise values array, if rows is [[]], map it to [['']] (Keep the columns into consideration)
for (let rowIndex = 0; rowIndex < inputData?.length; rowIndex++) {
@ -444,17 +520,21 @@ export class GoogleSheet {
let rowIndex: number;
let returnColumnIndex: number;
lookupLoop:
for (const lookupValue of lookupValues) {
lookupLoop: for (const lookupValue of lookupValues) {
returnColumnIndex = keys.indexOf(lookupValue.lookupColumn);
if (returnColumnIndex === -1) {
throw new NodeOperationError(this.executeFunctions.getNode(), `The column "${lookupValue.lookupColumn}" could not be found!`);
throw new NodeOperationError(
this.executeFunctions.getNode(),
`The column "${lookupValue.lookupColumn}" could not be found!`,
);
}
// Loop over all the items and find the one with the matching value
for (rowIndex = dataStartRowIndex; rowIndex < inputData.length; rowIndex++) {
if (inputData[rowIndex][returnColumnIndex]?.toString() === lookupValue.lookupValue.toString()) {
if (
inputData[rowIndex][returnColumnIndex]?.toString() === lookupValue.lookupValue.toString()
) {
returnData.push(inputData[rowIndex]);
if (returnAllMatches !== true) {
@ -473,8 +553,12 @@ export class GoogleSheet {
return this.structureData(returnData, 1, keys, true);
}
async convertStructuredDataToArray(inputData: IDataObject[], range: string, keyRowIndex: number, usePathForKeyRow: boolean): Promise<string[][]> {
async convertStructuredDataToArray(
inputData: IDataObject[],
range: string,
keyRowIndex: number,
usePathForKeyRow: boolean,
): Promise<string[][]> {
let startColumn, endColumn;
let sheet: string | undefined = undefined;
if (range.includes('!')) {
@ -482,7 +566,6 @@ export class GoogleSheet {
}
[startColumn, endColumn] = range.split(':');
let getRange = `${startColumn}${keyRowIndex + 1}:${endColumn}${keyRowIndex + 1}`;
if (sheet !== undefined) {
@ -492,7 +575,10 @@ export class GoogleSheet {
const keyColumnData = await this.getData(getRange, 'UNFORMATTED_VALUE');
if (keyColumnData === undefined) {
throw new NodeOperationError(this.executeFunctions.getNode(), 'Could not retrieve the column data!');
throw new NodeOperationError(
this.executeFunctions.getNode(),
'Could not retrieve the column data!',
);
}
const keyColumnOrder = keyColumnData[0];
@ -504,9 +590,16 @@ export class GoogleSheet {
rowData = [];
keyColumnOrder.forEach((key) => {
const value = get(item, key) as string;
if (usePathForKeyRow && value !== undefined && value !== null) { //match by key path
if (usePathForKeyRow && value !== undefined && value !== null) {
//match by key path
rowData.push(value!.toString());
} else if (!usePathForKeyRow && item.hasOwnProperty(key) && item[key] !== null && item[key] !== undefined) { //match by exact key name
} else if (
!usePathForKeyRow &&
item.hasOwnProperty(key) &&
item[key] !== null &&
item[key] !== undefined
) {
//match by exact key name
rowData.push(item[key]!.toString());
} else {
rowData.push('');

View file

@ -1,7 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
ICredentialsDecrypted,
@ -52,9 +49,7 @@ export class GoogleSheets implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
testedBy: 'googleApiCredentialTest',
@ -64,9 +59,7 @@ export class GoogleSheets implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -89,9 +82,7 @@ export class GoogleSheets implements INodeType {
default: 'serviceAccount',
displayOptions: {
show: {
'@version': [
1,
],
'@version': [1],
},
},
},
@ -112,9 +103,7 @@ export class GoogleSheets implements INodeType {
default: 'oAuth2',
displayOptions: {
show: {
'@version': [
2,
],
'@version': [2],
},
},
},
@ -132,7 +121,6 @@ export class GoogleSheets implements INodeType {
name: 'Sheet',
value: 'sheet',
},
],
default: 'sheet',
},
@ -143,9 +131,7 @@ export class GoogleSheets implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'sheet',
],
resource: ['sheet'],
},
},
options: [
@ -170,7 +156,8 @@ export class GoogleSheets implements INodeType {
{
name: 'Create or Update',
value: 'upsert',
description: 'Create a new record, or update the current one if it already exists (upsert)',
description:
'Create a new record, or update the current one if it already exists (upsert)',
action: 'Create or update a sheet',
},
{
@ -216,14 +203,13 @@ export class GoogleSheets implements INodeType {
type: 'string',
displayOptions: {
show: {
resource: [
'sheet',
],
resource: ['sheet'],
},
},
default: '',
required: true,
description: 'The ID of the Google Spreadsheet. Found as part of the sheet URL https://docs.google.com/spreadsheets/d/{ID}/.',
description:
'The ID of the Google Spreadsheet. Found as part of the sheet URL https://docs.google.com/spreadsheets/d/{ID}/.',
},
{
displayName: 'Range',
@ -231,21 +217,16 @@ export class GoogleSheets implements INodeType {
type: 'string',
displayOptions: {
show: {
resource: [
'sheet',
],
resource: ['sheet'],
},
hide: {
operation: [
'create',
'delete',
'remove',
],
operation: ['create', 'delete', 'remove'],
},
},
default: 'A:F',
required: true,
description: 'The table range to read from or to append data to. See the Google <a href="https://developers.google.com/sheets/api/guides/values#writing">documentation</a> for the details. If it contains multiple sheets it can also be added like this: "MySheet!A:F"',
description:
'The table range to read from or to append data to. See the Google <a href="https://developers.google.com/sheets/api/guides/values#writing">documentation</a> for the details. If it contains multiple sheets it can also be added like this: "MySheet!A:F"',
},
// ----------------------------------
@ -262,12 +243,8 @@ export class GoogleSheets implements INodeType {
},
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'delete',
],
resource: ['sheet'],
operation: ['delete'],
},
},
default: {},
@ -286,7 +263,8 @@ export class GoogleSheets implements INodeType {
options: [],
default: '',
required: true,
description: 'The sheet to delete columns from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The sheet to delete columns from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Start Index',
@ -324,7 +302,8 @@ export class GoogleSheets implements INodeType {
options: [],
default: '',
required: true,
description: 'The sheet to delete columns from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The sheet to delete columns from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Start Index',
@ -351,7 +330,6 @@ export class GoogleSheets implements INodeType {
],
},
// ----------------------------------
// Read
// ----------------------------------
@ -361,16 +339,13 @@ export class GoogleSheets implements INodeType {
type: 'boolean',
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'read',
],
resource: ['sheet'],
operation: ['read'],
},
},
default: false,
description: 'Whether the data should be returned RAW instead of parsed into keys according to their header',
description:
'Whether the data should be returned RAW instead of parsed into keys according to their header',
},
{
displayName: 'Data Property',
@ -379,15 +354,9 @@ export class GoogleSheets implements INodeType {
default: 'data',
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'read',
],
rawData: [
true,
],
resource: ['sheet'],
operation: ['read'],
rawData: [true],
},
},
description: 'The name of the property into which to write the RAW data',
@ -402,13 +371,8 @@ export class GoogleSheets implements INodeType {
type: 'boolean',
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'update',
'upsert',
],
resource: ['sheet'],
operation: ['update', 'upsert'],
},
},
default: false,
@ -421,16 +385,9 @@ export class GoogleSheets implements INodeType {
default: 'data',
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'update',
'upsert',
],
rawData: [
true,
],
resource: ['sheet'],
operation: ['update', 'upsert'],
rawData: [true],
},
},
description: 'The name of the property from which to read the RAW data',
@ -449,24 +406,15 @@ export class GoogleSheets implements INodeType {
default: 1,
displayOptions: {
show: {
resource: [
'sheet',
],
resource: ['sheet'],
},
hide: {
operation: [
'append',
'create',
'clear',
'delete',
'remove',
],
rawData: [
true,
],
operation: ['append', 'create', 'clear', 'delete', 'remove'],
rawData: [true],
},
},
description: 'Index of the first row which contains the actual data and not the keys. Starts with 0.',
description:
'Index of the first row which contains the actual data and not the keys. Starts with 0.',
},
// ----------------------------------
@ -481,27 +429,18 @@ export class GoogleSheets implements INodeType {
},
displayOptions: {
show: {
resource: [
'sheet',
],
resource: ['sheet'],
},
hide: {
operation: [
'clear',
'create',
'delete',
'remove',
],
rawData: [
true,
],
operation: ['clear', 'create', 'delete', 'remove'],
rawData: [true],
},
},
default: 0,
description: 'Index of the row which contains the keys. Starts at 0. The incoming node data is matched to the keys for assignment. The matching is case sensitive.',
description:
'Index of the row which contains the keys. Starts at 0. The incoming node data is matched to the keys for assignment. The matching is case sensitive.',
},
// ----------------------------------
// lookup
// ----------------------------------
@ -514,12 +453,8 @@ export class GoogleSheets implements INodeType {
required: true,
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'lookup',
],
resource: ['sheet'],
operation: ['lookup'],
},
},
description: 'The name of the column in which to look for value',
@ -532,12 +467,8 @@ export class GoogleSheets implements INodeType {
placeholder: 'frank@example.com',
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'lookup',
],
resource: ['sheet'],
operation: ['lookup'],
},
},
description: 'The value to look for in column',
@ -553,16 +484,9 @@ export class GoogleSheets implements INodeType {
default: 'id',
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'update',
'upsert',
],
rawData: [
false,
],
resource: ['sheet'],
operation: ['update', 'upsert'],
rawData: [false],
},
},
description: 'The name of the key to identify which data should be updated in the sheet',
@ -576,16 +500,8 @@ export class GoogleSheets implements INodeType {
default: {},
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'append',
'lookup',
'read',
'update',
'upsert',
],
resource: ['sheet'],
operation: ['append', 'lookup', 'read', 'update', 'upsert'],
},
},
options: [
@ -596,14 +512,12 @@ export class GoogleSheets implements INodeType {
default: false,
displayOptions: {
show: {
'/operation': [
'lookup',
'read',
],
'/operation': ['lookup', 'read'],
},
},
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'By default, the workflow stops executing if the lookup/read does not return values',
description:
'By default, the workflow stops executing if the lookup/read does not return values',
},
{
displayName: 'Return All Matches',
@ -612,13 +526,12 @@ export class GoogleSheets implements INodeType {
default: false,
displayOptions: {
show: {
'/operation': [
'lookup',
],
'/operation': ['lookup'],
},
},
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'By default only the first result gets returned. If options gets set all found matches get returned.',
description:
'By default only the first result gets returned. If options gets set all found matches get returned.',
},
{
displayName: 'Use Header Names as JSON Paths',
@ -627,12 +540,11 @@ export class GoogleSheets implements INodeType {
default: false,
displayOptions: {
show: {
'/operation': [
'append',
],
'/operation': ['append'],
},
},
description: 'Whether you want to match the headers as path, for example, the row header "category.name" will match the "category" object and get the field "name" from it. By default "category.name" will match with the field with exact name, not nested object.',
description:
'Whether you want to match the headers as path, for example, the row header "category.name" will match the "category" object and get the field "name" from it. By default "category.name" will match with the field with exact name, not nested object.',
},
{
displayName: 'Value Input Mode',
@ -640,11 +552,7 @@ export class GoogleSheets implements INodeType {
type: 'options',
displayOptions: {
show: {
'/operation': [
'append',
'update',
'upsert',
],
'/operation': ['append', 'update', 'upsert'],
},
},
options: [
@ -656,7 +564,8 @@ export class GoogleSheets implements INodeType {
{
name: 'User Entered',
value: 'USER_ENTERED',
description: 'The values will be parsed as if the user typed them into the UI. Numbers will stay as numbers, but strings may be converted to numbers, dates, etc. following the same rules that are applied when entering text into a cell via the Google Sheets UI.',
description:
'The values will be parsed as if the user typed them into the UI. Numbers will stay as numbers, but strings may be converted to numbers, dates, etc. following the same rules that are applied when entering text into a cell via the Google Sheets UI.',
},
],
default: 'RAW',
@ -668,27 +577,27 @@ export class GoogleSheets implements INodeType {
type: 'options',
displayOptions: {
show: {
'/operation': [
'lookup',
'read',
],
'/operation': ['lookup', 'read'],
},
},
options: [
{
name: 'Formatted Value',
value: 'FORMATTED_VALUE',
description: 'Values will be calculated & formatted in the reply according to the cell\'s formatting.Formatting is based on the spreadsheet\'s locale, not the requesting user\'s locale.For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "$1.23"',
description:
"Values will be calculated & formatted in the reply according to the cell's formatting.Formatting is based on the spreadsheet's locale, not the requesting user's locale.For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return \"$1.23\"",
},
{
name: 'Formula',
value: 'FORMULA',
description: 'Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".',
description:
'Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".',
},
{
name: 'Unformatted Value',
value: 'UNFORMATTED_VALUE',
description: 'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.',
description:
'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.',
},
],
default: 'UNFORMATTED_VALUE',
@ -700,30 +609,28 @@ export class GoogleSheets implements INodeType {
type: 'options',
displayOptions: {
show: {
'/operation': [
'update',
'upsert',
],
'/rawData': [
false,
],
'/operation': ['update', 'upsert'],
'/rawData': [false],
},
},
options: [
{
name: 'Formatted Value',
value: 'FORMATTED_VALUE',
description: 'Values will be calculated & formatted in the reply according to the cell\'s formatting.Formatting is based on the spreadsheet\'s locale, not the requesting user\'s locale. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "$1.23".',
description:
"Values will be calculated & formatted in the reply according to the cell's formatting.Formatting is based on the spreadsheet's locale, not the requesting user's locale. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return \"$1.23\".",
},
{
name: 'Formula',
value: 'FORMULA',
description: 'Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".',
description:
'Values will not be calculated. The reply will include the formulas. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return "=A1".',
},
{
name: 'Unformatted Value',
value: 'UNFORMATTED_VALUE',
description: 'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.',
description:
'Values will be calculated, but not formatted in the reply. For example, if A1 is 1.23 and A2 is =A1 and formatted as currency, then A2 would return the number 1.23.',
},
],
default: 'UNFORMATTED_VALUE',
@ -739,9 +646,7 @@ export class GoogleSheets implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'spreadsheet',
],
resource: ['spreadsheet'],
},
},
options: [
@ -764,12 +669,8 @@ export class GoogleSheets implements INodeType {
default: '',
displayOptions: {
show: {
resource: [
'spreadsheet',
],
operation: [
'create',
],
resource: ['spreadsheet'],
operation: ['create'],
},
},
description: 'The title of the spreadsheet',
@ -785,12 +686,8 @@ export class GoogleSheets implements INodeType {
default: {},
displayOptions: {
show: {
resource: [
'spreadsheet',
],
operation: [
'create',
],
resource: ['spreadsheet'],
operation: ['create'],
},
},
options: [
@ -833,12 +730,8 @@ export class GoogleSheets implements INodeType {
default: {},
displayOptions: {
show: {
resource: [
'spreadsheet',
],
operation: [
'create',
],
resource: ['spreadsheet'],
operation: ['create'],
},
},
options: [
@ -897,15 +790,12 @@ export class GoogleSheets implements INodeType {
default: true,
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'create',
],
resource: ['sheet'],
operation: ['create'],
},
},
description: 'Whether to return a simplified version of the response instead of the raw data',
description:
'Whether to return a simplified version of the response instead of the raw data',
},
{
displayName: 'Options',
@ -915,12 +805,8 @@ export class GoogleSheets implements INodeType {
default: {},
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'create',
],
resource: ['sheet'],
operation: ['create'],
},
},
options: [
@ -964,7 +850,7 @@ export class GoogleSheets implements INodeType {
name: 'hideGridlines',
type: 'boolean',
default: false,
description: 'Whether the grid isn\'t showing gridlines in the UI',
description: "Whether the grid isn't showing gridlines in the UI",
},
{
displayName: 'Row Count',
@ -980,7 +866,6 @@ export class GoogleSheets implements INodeType {
default: false,
description: 'Whether the row grouping control toggle is shown after the group',
},
],
description: 'The type of the sheet',
},
@ -989,7 +874,7 @@ export class GoogleSheets implements INodeType {
name: 'hidden',
type: 'boolean',
default: false,
description: 'Whether the sheet is hidden in the UI, false if it\'s visible',
description: "Whether the sheet is hidden in the UI, false if it's visible",
},
{
displayName: 'Right To Left',
@ -1003,7 +888,8 @@ export class GoogleSheets implements INodeType {
name: 'sheetId',
type: 'number',
default: 0,
description: 'The ID of the sheet. Must be non-negative. This field cannot be changed once set.',
description:
'The ID of the sheet. Must be non-negative. This field cannot be changed once set.',
},
{
displayName: 'Sheet Index',
@ -1040,12 +926,8 @@ export class GoogleSheets implements INodeType {
required: true,
displayOptions: {
show: {
resource: [
'sheet',
],
operation: [
'remove',
],
resource: ['sheet'],
operation: ['remove'],
},
},
description: 'The ID of the sheet to delete',
@ -1053,7 +935,6 @@ export class GoogleSheets implements INodeType {
],
};
methods = {
loadOptions: {
// Get all the sheets in a Spreadsheet
@ -1083,16 +964,22 @@ export class GoogleSheets implements INodeType {
},
},
credentialTest: {
async googleApiCredentialTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult> {
async googleApiCredentialTest(
this: ICredentialTestFunctions,
credential: ICredentialsDecrypted,
): Promise<INodeCredentialTestResult> {
try {
const tokenRequest = await getAccessToken.call(this, credential.data! as unknown as IGoogleAuthCredentials);
const tokenRequest = await getAccessToken.call(
this,
credential.data! as unknown as IGoogleAuthCredentials,
);
if (!tokenRequest.access_token) {
return {
status: 'Error',
message: 'Could not generate a token from your private key.',
};
}
} catch(err) {
} catch (err) {
return {
status: 'Error',
message: `Private key validation failed: ${err.message}`,
@ -1103,19 +990,15 @@ export class GoogleSheets implements INodeType {
status: 'OK',
message: 'Connection successful!',
};
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const operation = this.getNodeParameter('operation', 0) as string;
const resource = this.getNodeParameter('resource', 0) as string;
if (resource === 'sheet') {
const spreadsheetId = this.getNodeParameter('sheetId', 0) as string;
const sheet = new GoogleSheet(spreadsheetId, this);
@ -1147,7 +1030,13 @@ export class GoogleSheets implements INodeType {
const usePathForKeyRow = (options.usePathForKeyRow || false) as boolean;
// Convert data into array format
const data = await sheet.appendSheetData(setData, sheet.encodeRange(range), keyRow, valueInputMode, usePathForKeyRow);
const data = await sheet.appendSheetData(
setData,
sheet.encodeRange(range),
keyRow,
valueInputMode,
usePathForKeyRow,
);
// TODO: Should add this data somewhere
// TODO: Should have something like add metadata which does not get passed through
@ -1155,7 +1044,7 @@ export class GoogleSheets implements INodeType {
return this.prepareOutputData(items);
} catch (error) {
if (this.continueOnFail()) {
return this.prepareOutputData([{json:{ error: error.message }}]);
return this.prepareOutputData([{ json: { error: error.message } }]);
}
throw error;
}
@ -1170,11 +1059,10 @@ export class GoogleSheets implements INodeType {
return this.prepareOutputData(items);
} catch (error) {
if (this.continueOnFail()) {
return this.prepareOutputData([{json:{ error: error.message }}]);
return this.prepareOutputData([{ json: { error: error.message } }]);
}
throw error;
}
} else if (operation === 'create') {
const returnData: IDataObject[] = [];
@ -1191,13 +1079,20 @@ export class GoogleSheets implements INodeType {
properties.tabColor = { red: red / 255, green: green / 255, blue: blue / 255 };
}
const requests = [{
addSheet: {
properties,
const requests = [
{
addSheet: {
properties,
},
},
}];
];
responseData = await googleApiRequest.call(this, 'POST', `/v4/spreadsheets/${spreadsheetId}:batchUpdate`, { requests });
responseData = await googleApiRequest.call(
this,
'POST',
`/v4/spreadsheets/${spreadsheetId}:batchUpdate`,
{ requests },
);
if (simple === true) {
Object.assign(responseData, responseData.replies[0].addSheet.properties);
@ -1214,7 +1109,6 @@ export class GoogleSheets implements INodeType {
}
return [this.helpers.returnJsonArray(returnData)];
} else if (operation === 'delete') {
// ----------------------------------
// delete
@ -1225,20 +1119,22 @@ export class GoogleSheets implements INodeType {
const toDelete = this.getNodeParameter('toDelete', 0) as IToDelete;
const deletePropertyToDimensions: IDataObject = {
'columns': 'COLUMNS',
'rows': 'ROWS',
columns: 'COLUMNS',
rows: 'ROWS',
};
for (const propertyName of Object.keys(deletePropertyToDimensions)) {
if (toDelete[propertyName] !== undefined) {
toDelete[propertyName]!.forEach(range => {
toDelete[propertyName]!.forEach((range) => {
requests.push({
deleteDimension: {
range: {
sheetId: range.sheetId,
dimension: deletePropertyToDimensions[propertyName] as string,
startIndex: range.startIndex,
endIndex: parseInt(range.startIndex.toString(), 10) + parseInt(range.amount.toString(), 10),
endIndex:
parseInt(range.startIndex.toString(), 10) +
parseInt(range.amount.toString(), 10),
},
},
});
@ -1252,7 +1148,7 @@ export class GoogleSheets implements INodeType {
return this.prepareOutputData(items);
} catch (error) {
if (this.continueOnFail()) {
return this.prepareOutputData([{json:{ error: error.message }}]);
return this.prepareOutputData([{ json: { error: error.message } }]);
}
throw error;
}
@ -1280,11 +1176,22 @@ export class GoogleSheets implements INodeType {
});
}
let returnData = await sheet.lookupValues(sheetData, keyRow, dataStartRow, lookupValues, options.returnAllMatches as boolean | undefined);
let returnData = await sheet.lookupValues(
sheetData,
keyRow,
dataStartRow,
lookupValues,
options.returnAllMatches as boolean | undefined,
);
if (returnData.length === 0 && options.continue && options.returnAllMatches) {
returnData = [{}];
} else if (returnData.length === 1 && Object.keys(returnData[0]).length === 0 && !options.continue && !options.returnAllMatches) {
} else if (
returnData.length === 1 &&
Object.keys(returnData[0]).length === 0 &&
!options.continue &&
!options.returnAllMatches
) {
returnData = [];
}
@ -1332,7 +1239,6 @@ export class GoogleSheets implements INodeType {
}
throw error;
}
} else if (operation === 'remove') {
const returnData: IDataObject[] = [];
@ -1342,13 +1248,20 @@ export class GoogleSheets implements INodeType {
const sheetId = this.getNodeParameter('id', i) as string;
const spreadsheetId = this.getNodeParameter('sheetId', i) as string;
const requests = [{
deleteSheet: {
sheetId,
const requests = [
{
deleteSheet: {
sheetId,
},
},
}];
];
responseData = await googleApiRequest.call(this, 'POST', `/v4/spreadsheets/${spreadsheetId}:batchUpdate`, { requests });
responseData = await googleApiRequest.call(
this,
'POST',
`/v4/spreadsheets/${spreadsheetId}:batchUpdate`,
{ requests },
);
delete responseData.replies;
returnData.push(responseData);
} catch (error) {
@ -1393,25 +1306,31 @@ export class GoogleSheets implements INodeType {
setData.push(item.json);
});
const data = await sheet.updateSheetData(setData, keyName, range, keyRow, dataStartRow, valueInputMode, valueRenderMode, upsert);
const data = await sheet.updateSheetData(
setData,
keyName,
range,
keyRow,
dataStartRow,
valueInputMode,
valueRenderMode,
upsert,
);
}
// TODO: Should add this data somewhere
// TODO: Should have something like add metadata which does not get passed through
return this.prepareOutputData(items);
} catch (error) {
if (this.continueOnFail()) {
return this.prepareOutputData([{json:{ error: error.message }}]);
return this.prepareOutputData([{ json: { error: error.message } }]);
}
throw error;
}
}
}
if (resource === 'spreadsheet') {
const returnData: IDataObject[] = [];
let responseData;
@ -1450,7 +1369,9 @@ export class GoogleSheets implements INodeType {
body.sheets = data;
}
body.properties!.autoRecalc = options.autoRecalc ? (options.autoRecalc as string) : undefined;
body.properties!.autoRecalc = options.autoRecalc
? (options.autoRecalc as string)
: undefined;
body.properties!.locale = options.locale ? (options.locale as string) : undefined;
responseData = await googleApiRequest.call(this, 'POST', `/v4/spreadsheets`, body);
@ -1464,7 +1385,6 @@ export class GoogleSheets implements INodeType {
throw error;
}
}
}
return [this.helpers.returnJsonArray(returnData)];

View file

@ -1,11 +1,6 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
ICredentialDataDecryptedObject,
@ -32,7 +27,11 @@ export async function googleApiRequest(
body: IDataObject = {},
qs: IDataObject = {},
) {
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
const options: OptionsWithUri & { headers: IDataObject } = {
headers: {
'Content-Type': 'application/json',
@ -56,10 +55,12 @@ export async function googleApiRequest(
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers.Authorization = `Bearer ${access_token}`;
return await this.helpers.request!(options);
} else {
return await this.helpers.requestOAuth2!.call(this, 'googleSlidesOAuth2Api', options);
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -11,9 +9,7 @@ import {
INodeTypeDescription,
} from 'n8n-workflow';
import {
googleApiRequest,
} from './GenericFunctions';
import { googleApiRequest } from './GenericFunctions';
export class GoogleSlides implements INodeType {
description: INodeTypeDescription = {
@ -35,9 +31,7 @@ export class GoogleSlides implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -46,9 +40,7 @@ export class GoogleSlides implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -71,9 +63,7 @@ export class GoogleSlides implements INodeType {
default: 'serviceAccount',
displayOptions: {
show: {
'@version': [
1,
],
'@version': [1],
},
},
},
@ -94,9 +84,7 @@ export class GoogleSlides implements INodeType {
default: 'oAuth2',
displayOptions: {
show: {
'@version': [
2,
],
'@version': [2],
},
},
},
@ -150,9 +138,7 @@ export class GoogleSlides implements INodeType {
],
displayOptions: {
show: {
resource: [
'presentation',
],
resource: ['presentation'],
},
},
default: 'create',
@ -178,9 +164,7 @@ export class GoogleSlides implements INodeType {
],
displayOptions: {
show: {
resource: [
'page',
],
resource: ['page'],
},
},
default: 'get',
@ -194,35 +178,24 @@ export class GoogleSlides implements INodeType {
required: true,
displayOptions: {
show: {
resource: [
'presentation',
],
operation: [
'create',
],
resource: ['presentation'],
operation: ['create'],
},
},
},
{
displayName: 'Presentation ID',
name: 'presentationId',
description: 'ID of the presentation to retrieve. Found in the presentation URL: <code>https://docs.google.com/presentation/d/PRESENTATION_ID/edit</code>',
description:
'ID of the presentation to retrieve. Found in the presentation URL: <code>https://docs.google.com/presentation/d/PRESENTATION_ID/edit</code>',
placeholder: '1wZtNFZ8MO-WKrxhYrOLMvyiqSgFwdSz5vn8_l_7eNqw',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: [
'presentation',
'page',
],
operation: [
'get',
'getThumbnail',
'getSlides',
'replaceText',
],
resource: ['presentation', 'page'],
operation: ['get', 'getThumbnail', 'getSlides', 'replaceText'],
},
},
},
@ -232,12 +205,8 @@ export class GoogleSlides implements INodeType {
type: 'boolean',
displayOptions: {
show: {
operation: [
'getSlides',
],
resource: [
'presentation',
],
operation: ['getSlides'],
resource: ['presentation'],
},
},
default: false,
@ -249,15 +218,9 @@ export class GoogleSlides implements INodeType {
type: 'number',
displayOptions: {
show: {
operation: [
'getSlides',
],
resource: [
'presentation',
],
returnAll: [
false,
],
operation: ['getSlides'],
resource: ['presentation'],
returnAll: [false],
},
},
typeOptions: {
@ -276,13 +239,8 @@ export class GoogleSlides implements INodeType {
required: true,
displayOptions: {
show: {
resource: [
'page',
],
operation: [
'get',
'getThumbnail',
],
resource: ['page'],
operation: ['get', 'getThumbnail'],
},
},
},
@ -296,12 +254,8 @@ export class GoogleSlides implements INodeType {
},
displayOptions: {
show: {
resource: [
'presentation',
],
operation: [
'replaceText',
],
resource: ['presentation'],
operation: ['replaceText'],
},
},
default: {},
@ -315,7 +269,8 @@ export class GoogleSlides implements INodeType {
name: 'matchCase',
type: 'boolean',
default: false,
description: 'Whether the search should respect case. True : the search is case sensitive. False : the search is case insensitive.',
description:
'Whether the search should respect case. True : the search is case sensitive. False : the search is case insensitive.',
},
{
displayName: 'Page Names or IDs',
@ -324,11 +279,10 @@ export class GoogleSlides implements INodeType {
default: [],
typeOptions: {
loadOptionsMethod: 'getPages',
loadOptionsDependsOn: [
'presentationId',
],
loadOptionsDependsOn: ['presentationId'],
},
description: 'If non-empty, limits the matches to page elements only on the given pages. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'If non-empty, limits the matches to page elements only on the given pages. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'Replace Text',
@ -355,12 +309,8 @@ export class GoogleSlides implements INodeType {
placeholder: 'Add Option',
displayOptions: {
show: {
operation: [
'replaceText',
],
resource: [
'presentation',
],
operation: ['replaceText'],
resource: ['presentation'],
},
},
default: {},
@ -370,7 +320,8 @@ export class GoogleSlides implements INodeType {
name: 'revisionId',
type: 'string',
default: '',
description: 'The revision ID of the presentation required for the write request. If specified and the requiredRevisionId doesn\'t exactly match the presentation\'s current revisionId, the request will not be processed and will return a 400 bad request error.',
description:
"The revision ID of the presentation required for the write request. If specified and the requiredRevisionId doesn't exactly match the presentation's current revisionId, the request will not be processed and will return a 400 bad request error.",
},
],
},
@ -382,12 +333,8 @@ export class GoogleSlides implements INodeType {
default: false,
displayOptions: {
show: {
resource: [
'page',
],
operation: [
'getThumbnail',
],
resource: ['page'],
operation: ['getThumbnail'],
},
},
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
@ -402,15 +349,9 @@ export class GoogleSlides implements INodeType {
description: 'Name of the binary property to which to write to',
displayOptions: {
show: {
resource: [
'page',
],
operation: [
'getThumbnail',
],
download: [
true,
],
resource: ['page'],
operation: ['getThumbnail'],
download: [true],
},
},
},
@ -421,12 +362,16 @@ export class GoogleSlides implements INodeType {
loadOptions: {
// Get all the pages to display them to user so that he can
// select them easily
async getPages(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getPages(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const presentationId = this.getCurrentNodeParameter('presentationId') as string;
const { slides } = await googleApiRequest.call(this, 'GET', `/presentations/${presentationId}`, {}, { fields: 'slides' });
const { slides } = await googleApiRequest.call(
this,
'GET',
`/presentations/${presentationId}`,
{},
{ fields: 'slides' },
);
for (const slide of slides) {
returnData.push({
name: slide.objectId,
@ -438,7 +383,6 @@ export class GoogleSlides implements INodeType {
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
@ -449,35 +393,37 @@ export class GoogleSlides implements INodeType {
const returnData: INodeExecutionData[] = [];
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'page') {
// *********************************************************************
// page
// *********************************************************************
if (operation === 'get') {
// ----------------------------------
// page: get
// ----------------------------------
const presentationId = this.getNodeParameter('presentationId', i) as string;
const pageObjectId = this.getNodeParameter('pageObjectId', i) as string;
responseData = await googleApiRequest.call(this, 'GET', `/presentations/${presentationId}/pages/${pageObjectId}`);
responseData = await googleApiRequest.call(
this,
'GET',
`/presentations/${presentationId}/pages/${pageObjectId}`,
);
returnData.push({ json: responseData });
} else if (operation === 'getThumbnail') {
// ----------------------------------
// page: getThumbnail
// ----------------------------------
const presentationId = this.getNodeParameter('presentationId', i) as string;
const pageObjectId = this.getNodeParameter('pageObjectId', i) as string;
responseData = await googleApiRequest.call(this, 'GET', `/presentations/${presentationId}/pages/${pageObjectId}/thumbnail`);
responseData = await googleApiRequest.call(
this,
'GET',
`/presentations/${presentationId}/pages/${pageObjectId}/thumbnail`,
);
const download = this.getNodeParameter('download', 0) as boolean;
if (download === true) {
@ -502,15 +448,12 @@ export class GoogleSlides implements INodeType {
returnData.push({ json: responseData });
}
}
} else if (resource === 'presentation') {
// *********************************************************************
// presentation
// *********************************************************************
if (operation === 'create') {
// ----------------------------------
// presentation: create
// ----------------------------------
@ -521,41 +464,45 @@ export class GoogleSlides implements INodeType {
responseData = await googleApiRequest.call(this, 'POST', '/presentations', body);
returnData.push({ json: responseData });
} else if (operation === 'get') {
// ----------------------------------
// presentation: get
// ----------------------------------
const presentationId = this.getNodeParameter('presentationId', i) as string;
responseData = await googleApiRequest.call(this, 'GET', `/presentations/${presentationId}`);
responseData = await googleApiRequest.call(
this,
'GET',
`/presentations/${presentationId}`,
);
returnData.push({ json: responseData });
} else if (operation === 'getSlides') {
// ----------------------------------
// presentation: getSlides
// ----------------------------------
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const presentationId = this.getNodeParameter('presentationId', i) as string;
responseData = await googleApiRequest.call(this, 'GET', `/presentations/${presentationId}`, {}, { fields: 'slides' });
responseData = await googleApiRequest.call(
this,
'GET',
`/presentations/${presentationId}`,
{},
{ fields: 'slides' },
);
responseData = responseData.slides;
if (returnAll === false) {
const limit = this.getNodeParameter('limit', i) as number;
responseData = responseData.slice(0, limit);
}
returnData.push(...this.helpers.returnJsonArray(responseData));
} else if (operation === 'replaceText') {
// ----------------------------------
// presentation: replaceText
// ----------------------------------
const presentationId = this.getNodeParameter('presentationId', i) as string;
const texts = this.getNodeParameter('textUi.textValues', i, []) as IDataObject[];
const options = this.getNodeParameter('options', i) as IDataObject;
const requests = texts.map((text => {
const requests = texts.map((text) => {
return {
replaceAllText: {
replaceText: text.replaceText,
@ -566,7 +513,7 @@ export class GoogleSlides implements INodeType {
},
},
};
}));
});
const body: IDataObject = {
requests,
@ -578,15 +525,18 @@ export class GoogleSlides implements INodeType {
};
}
responseData = await googleApiRequest.call(this, 'POST', `/presentations/${presentationId}:batchUpdate`, { requests });
responseData = await googleApiRequest.call(
this,
'POST',
`/presentations/${presentationId}:batchUpdate`,
{ requests },
);
returnData.push({ json: responseData });
}
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({json:{ error: error.message }});
returnData.push({ json: { error: error.message } });
continue;
}
throw error;

View file

@ -1,16 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError } from 'n8n-workflow';
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
@ -20,7 +12,8 @@ export async function googleApiRequest(
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
): Promise<any> { // tslint:disable-line:no-any
// tslint:disable-next-line:no-any
): Promise<any> {
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -40,11 +33,7 @@ export async function googleApiRequest(
delete options.body;
}
//@ts-ignore
return await this.helpers.requestOAuth2.call(
this,
'googleTasksOAuth2Api',
options,
);
return await this.helpers.requestOAuth2.call(this, 'googleTasksOAuth2Api', options);
} catch (error) {
throw new NodeApiError(this.getNode(), error);
}
@ -57,26 +46,18 @@ export async function googleApiRequestAllItems(
endpoint: string,
body: IDataObject = {},
query: IDataObject = {},
): Promise<any> { // tslint:disable-line:no-any
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
query.maxResults = 100;
do {
responseData = await googleApiRequest.call(
this,
method,
endpoint,
body,
query,
);
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}

View file

@ -1,6 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
IDataObject,
@ -11,15 +9,9 @@ import {
INodeTypeDescription,
} from 'n8n-workflow';
import {
googleApiRequest,
googleApiRequestAllItems,
} from './GenericFunctions';
import { googleApiRequest, googleApiRequestAllItems } from './GenericFunctions';
import {
taskFields,
taskOperations,
} from './TaskDescription';
import { taskFields, taskOperations } from './TaskDescription';
export class GoogleTasks implements INodeType {
description: INodeTypeDescription = {
@ -64,9 +56,7 @@ export class GoogleTasks implements INodeType {
loadOptions: {
// Get all the tasklists to display them to user so that he can select them easily
async getTasks(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getTasks(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const tasks = await googleApiRequestAllItems.call(
this,
@ -104,10 +94,7 @@ export class GoogleTasks implements INodeType {
//https://developers.google.com/tasks/v1/reference/tasks/insert
const taskId = this.getNodeParameter('task', i) as string;
body.title = this.getNodeParameter('title', i) as string;
const additionalFields = this.getNodeParameter(
'additionalFields',
i,
) as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (additionalFields.parent) {
qs.parent = additionalFields.parent as string;
@ -172,10 +159,12 @@ export class GoogleTasks implements INodeType {
//https://developers.google.com/tasks/v1/reference/tasks/list
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const taskListId = this.getNodeParameter('task', i) as string;
const { showCompleted = true, showDeleted = false, showHidden = false, ...options } = this.getNodeParameter(
'additionalFields',
i,
) as IDataObject;
const {
showCompleted = true,
showDeleted = false,
showHidden = false,
...options
} = this.getNodeParameter('additionalFields', i) as IDataObject;
if (options.completedMax) {
qs.completedMax = options.completedMax as string;
}
@ -223,10 +212,7 @@ export class GoogleTasks implements INodeType {
//https://developers.google.com/tasks/v1/reference/tasks/patch
const taskListId = this.getNodeParameter('task', i) as string;
const taskId = this.getNodeParameter('taskId', i) as string;
const updateFields = this.getNodeParameter(
'updateFields',
i,
) as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (updateFields.previous) {
qs.previous = updateFields.previous as string;

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const taskOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const taskOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'task',
],
resource: ['task'],
},
},
options: [
@ -59,19 +55,16 @@ export const taskFields: INodeProperties[] = [
displayName: 'TaskList Name or ID',
name: 'task',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTasks',
},
required: true,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'task',
],
operation: ['create'],
resource: ['task'],
},
},
default: '',
@ -84,12 +77,8 @@ export const taskFields: INodeProperties[] = [
description: 'Title of the task',
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'task',
],
operation: ['create'],
resource: ['task'],
},
},
},
@ -101,12 +90,8 @@ export const taskFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'task',
],
operation: ['create'],
resource: ['task'],
},
},
options: [
@ -115,7 +100,8 @@ export const taskFields: INodeProperties[] = [
name: 'completed',
type: 'dateTime',
default: '',
description: 'Completion date of the task (as a RFC 3339 timestamp). This field is omitted if the task has not been completed.',
description:
'Completion date of the task (as a RFC 3339 timestamp). This field is omitted if the task has not been completed.',
},
{
displayName: 'Deleted',
@ -143,14 +129,16 @@ export const taskFields: INodeProperties[] = [
name: 'parent',
type: 'string',
default: '',
description: 'Parent task identifier. If the task is created at the top level, this parameter is omitted.',
description:
'Parent task identifier. If the task is created at the top level, this parameter is omitted.',
},
{
displayName: 'Previous',
name: 'previous',
type: 'string',
default: '',
description: 'Previous sibling task identifier. If the task is created at the first position among its siblings, this parameter is omitted.',
description:
'Previous sibling task identifier. If the task is created at the first position among its siblings, this parameter is omitted.',
},
{
displayName: 'Status',
@ -169,7 +157,6 @@ export const taskFields: INodeProperties[] = [
default: '',
description: 'Current status of the task',
},
],
},
/* -------------------------------------------------------------------------- */
@ -179,19 +166,16 @@ export const taskFields: INodeProperties[] = [
displayName: 'TaskList Name or ID',
name: 'task',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTasks',
},
required: true,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'task',
],
operation: ['delete'],
resource: ['task'],
},
},
default: '',
@ -203,12 +187,8 @@ export const taskFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'task',
],
operation: ['delete'],
resource: ['task'],
},
},
default: '',
@ -220,19 +200,16 @@ export const taskFields: INodeProperties[] = [
displayName: 'TaskList Name or ID',
name: 'task',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTasks',
},
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'task',
],
operation: ['get'],
resource: ['task'],
},
},
default: '',
@ -244,12 +221,8 @@ export const taskFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'task',
],
operation: ['get'],
resource: ['task'],
},
},
default: '',
@ -261,19 +234,16 @@ export const taskFields: INodeProperties[] = [
displayName: 'TaskList Name or ID',
name: 'task',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTasks',
},
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'task',
],
operation: ['getAll'],
resource: ['task'],
},
},
default: '',
@ -284,12 +254,8 @@ export const taskFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'task',
],
operation: ['getAll'],
resource: ['task'],
},
},
default: false,
@ -301,15 +267,9 @@ export const taskFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'task',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['task'],
returnAll: [false],
},
},
typeOptions: {
@ -327,12 +287,8 @@ export const taskFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'task',
],
operation: ['getAll'],
resource: ['task'],
},
},
options: [
@ -341,14 +297,16 @@ export const taskFields: INodeProperties[] = [
name: 'completedMax',
type: 'dateTime',
default: '',
description: 'Upper bound for a task completion date (as a RFC 3339 timestamp) to filter by',
description:
'Upper bound for a task completion date (as a RFC 3339 timestamp) to filter by',
},
{
displayName: 'Completed Min',
name: 'completedMin',
type: 'dateTime',
default: '',
description: 'Lower bound for a task completion date (as a RFC 3339 timestamp) to filter by',
description:
'Lower bound for a task completion date (as a RFC 3339 timestamp) to filter by',
},
{
displayName: 'Due Min',
@ -370,7 +328,8 @@ export const taskFields: INodeProperties[] = [
type: 'boolean',
default: true,
// eslint-disable-next-line n8n-nodes-base/node-param-description-unencoded-angle-brackets
description: 'Whether completed tasks are returned in the result. <strong>Show Hidden</strong> must also be True to show tasks completed in first party clients such as the web UI or Google\'s mobile apps.',
description:
"Whether completed tasks are returned in the result. <strong>Show Hidden</strong> must also be True to show tasks completed in first party clients such as the web UI or Google's mobile apps.",
},
{
displayName: 'Show Deleted',
@ -391,7 +350,8 @@ export const taskFields: INodeProperties[] = [
name: 'updatedMin',
type: 'dateTime',
default: '',
description: 'Lower bound for a task last modification time (as a RFC 3339 timestamp) to filter by',
description:
'Lower bound for a task last modification time (as a RFC 3339 timestamp) to filter by',
},
],
},
@ -402,19 +362,16 @@ export const taskFields: INodeProperties[] = [
displayName: 'TaskList Name or ID',
name: 'task',
type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: {
loadOptionsMethod: 'getTasks',
},
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'task',
],
operation: ['update'],
resource: ['task'],
},
},
default: '',
@ -426,12 +383,8 @@ export const taskFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'task',
],
operation: ['update'],
resource: ['task'],
},
},
default: '',
@ -444,12 +397,8 @@ export const taskFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'task',
],
operation: ['update'],
resource: ['task'],
},
},
options: [
@ -458,7 +407,8 @@ export const taskFields: INodeProperties[] = [
name: 'completed',
type: 'dateTime',
default: '',
description: 'Completion date of the task (as a RFC 3339 timestamp). This field is omitted if the task has not been completed.',
description:
'Completion date of the task (as a RFC 3339 timestamp). This field is omitted if the task has not been completed.',
},
{
@ -490,7 +440,8 @@ export const taskFields: INodeProperties[] = [
name: 'previous',
type: 'string',
default: '',
description: 'Previous sibling task identifier. If the task is created at the first position among its siblings, this parameter is omitted.',
description:
'Previous sibling task identifier. If the task is created at the first position among its siblings, this parameter is omitted.',
},
{
displayName: 'Status',

View file

@ -1,16 +1,8 @@
import {
OptionsWithUri,
} from 'request';
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
import {
IDataObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
import moment from 'moment-timezone';
@ -23,8 +15,22 @@ interface IGoogleAuthCredentials {
privateKey: string;
}
export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const authenticationMethod = this.getNodeParameter('authentication', 0, 'serviceAccount') as string;
export async function googleApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
headers: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter(
'authentication',
0,
'serviceAccount',
) as string;
const options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
@ -46,7 +52,10 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
if (authenticationMethod === 'serviceAccount') {
const credentials = await this.getCredentials('googleApi');
const { access_token } = await getAccessToken.call(this, credentials as unknown as IGoogleAuthCredentials);
const { access_token } = await getAccessToken.call(
this,
credentials as unknown as IGoogleAuthCredentials,
);
options.headers!.Authorization = `Bearer ${access_token}`;
//@ts-ignore
@ -60,8 +69,16 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
}
}
export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
export async function googleApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
@ -71,15 +88,15 @@ export async function googleApiRequestAllItems(this: IExecuteFunctions | ILoadOp
responseData = await googleApiRequest.call(this, method, endpoint, body, query);
query.pageToken = responseData['nextPageToken'];
returnData.push.apply(returnData, responseData[propertyName]);
} while (
responseData['nextPageToken'] !== undefined &&
responseData['nextPageToken'] !== ''
);
} while (responseData['nextPageToken'] !== undefined && responseData['nextPageToken'] !== '');
return returnData;
}
function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, credentials: IGoogleAuthCredentials): Promise<IDataObject> {
function getAccessToken(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
credentials: IGoogleAuthCredentials,
): Promise<IDataObject> {
//https://developers.google.com/identity/protocols/oauth2/service-account#httprest
const scopes = [
@ -94,20 +111,20 @@ function getAccessToken(this: IExecuteFunctions | IExecuteSingleFunctions | ILoa
const signature = jwt.sign(
{
'iss': credentials.email as string,
'sub': credentials.email as string,
'scope': scopes.join(' '),
'aud': `https://oauth2.googleapis.com/token`,
'iat': now,
'exp': now + 3600,
iss: credentials.email as string,
sub: credentials.email as string,
scope: scopes.join(' '),
aud: `https://oauth2.googleapis.com/token`,
iat: now,
exp: now + 3600,
},
privateKey as string,
{
algorithm: 'RS256',
header: {
'kid': privateKey as string,
'typ': 'JWT',
'alg': 'RS256',
kid: privateKey as string,
typ: 'JWT',
alg: 'RS256',
},
},
);

View file

@ -1,7 +1,4 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import { IExecuteFunctions } from 'n8n-core';
import {
ILoadOptionsFunctions,
@ -11,9 +8,7 @@ import {
INodeTypeDescription,
} from 'n8n-workflow';
import {
googleApiRequest,
} from './GenericFunctions';
import { googleApiRequest } from './GenericFunctions';
export interface IGoogleAuthCredentials {
email: string;
@ -41,9 +36,7 @@ export class GoogleTranslate implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
authentication: ['serviceAccount'],
},
},
},
@ -52,9 +45,7 @@ export class GoogleTranslate implements INodeType {
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
authentication: ['oAuth2'],
},
},
},
@ -77,9 +68,7 @@ export class GoogleTranslate implements INodeType {
default: 'serviceAccount',
displayOptions: {
show: {
'@version': [
1,
],
'@version': [1],
},
},
},
@ -100,9 +89,7 @@ export class GoogleTranslate implements INodeType {
default: 'oAuth2',
displayOptions: {
show: {
'@version': [
2,
],
'@version': [2],
},
},
},
@ -126,9 +113,7 @@ export class GoogleTranslate implements INodeType {
noDataExpression: true,
displayOptions: {
show: {
resource: [
'language',
],
resource: ['language'],
},
},
options: [
@ -153,9 +138,7 @@ export class GoogleTranslate implements INodeType {
required: true,
displayOptions: {
show: {
operation: [
'translate',
],
operation: ['translate'],
},
},
},
@ -168,13 +151,12 @@ export class GoogleTranslate implements INodeType {
loadOptionsMethod: 'getLanguages',
},
default: '',
description: 'The language to use for translation of the input text, set to one of the language codes listed in <a href="https://cloud.google.com/translate/docs/languages">Language Support</a>. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The language to use for translation of the input text, set to one of the language codes listed in <a href="https://cloud.google.com/translate/docs/languages">Language Support</a>. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
required: true,
displayOptions: {
show: {
operation: [
'translate',
],
operation: ['translate'],
},
},
},
@ -183,15 +165,11 @@ export class GoogleTranslate implements INodeType {
methods = {
loadOptions: {
async getLanguages(
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
async getLanguages(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { data: { languages } } = await googleApiRequest.call(
this,
'GET',
'/language/translate/v2/languages',
);
const {
data: { languages },
} = await googleApiRequest.call(this, 'GET', '/language/translate/v2/languages');
for (const language of languages) {
returnData.push({
name: language.language.toUpperCase(),
@ -216,7 +194,10 @@ export class GoogleTranslate implements INodeType {
const text = this.getNodeParameter('text', i) as string;
const translateTo = this.getNodeParameter('translateTo', i) as string;
const response = await googleApiRequest.call(this, 'POST', `/language/translate/v2`, { q: text, target: translateTo });
const response = await googleApiRequest.call(this, 'POST', `/language/translate/v2`, {
q: text,
target: translateTo,
});
responseData.push(response.data.translations[0]);
}
}

View file

@ -1,6 +1,4 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { INodeProperties } from 'n8n-workflow';
export const channelOperations: INodeProperties[] = [
{
@ -10,9 +8,7 @@ export const channelOperations: INodeProperties[] = [
noDataExpression: true,
displayOptions: {
show: {
resource: [
'channel',
],
resource: ['channel'],
},
},
options: [
@ -98,15 +94,12 @@ export const channelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'channel',
],
operation: ['getAll'],
resource: ['channel'],
},
},
description: 'The fields parameter specifies a comma-separated list of one or more channel resource properties that the API response will include',
description:
'The fields parameter specifies a comma-separated list of one or more channel resource properties that the API response will include',
default: ['*'],
},
{
@ -115,12 +108,8 @@ export const channelFields: INodeProperties[] = [
type: 'boolean',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'channel',
],
operation: ['getAll'],
resource: ['channel'],
},
},
default: false,
@ -132,15 +121,9 @@ export const channelFields: INodeProperties[] = [
type: 'number',
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'channel',
],
returnAll: [
false,
],
operation: ['getAll'],
resource: ['channel'],
returnAll: [false],
},
},
typeOptions: {
@ -158,12 +141,8 @@ export const channelFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'channel',
],
operation: ['getAll'],
resource: ['channel'],
},
},
options: [
@ -172,28 +151,32 @@ export const channelFields: INodeProperties[] = [
name: 'categoryId',
type: 'string',
default: '',
description: 'The categoryId parameter specifies a YouTube guide category, thereby requesting YouTube channels associated with that category',
description:
'The categoryId parameter specifies a YouTube guide category, thereby requesting YouTube channels associated with that category',
},
{
displayName: 'For Username',
name: 'forUsername',
type: 'string',
default: '',
description: 'The forUsername parameter specifies a YouTube username, thereby requesting the channel associated with that username',
description:
'The forUsername parameter specifies a YouTube username, thereby requesting the channel associated with that username',
},
{
displayName: 'ID',
name: 'id',
type: 'string',
default: '',
description: 'The ID parameter specifies a comma-separated list of the YouTube channel ID(s) for the resource(s) that are being retrieved. In a channel resource, the ID property specifies the channel\'s YouTube channel ID.',
description:
"The ID parameter specifies a comma-separated list of the YouTube channel ID(s) for the resource(s) that are being retrieved. In a channel resource, the ID property specifies the channel's YouTube channel ID.",
},
{
displayName: 'Managed By Me',
name: 'managedByMe',
type: 'boolean',
default: false,
description: 'Whether to instruct the API to only return channels managed by the content owner that the onBehalfOfContentOwner parameter specifies',
description:
'Whether to instruct the API to only return channels managed by the content owner that the onBehalfOfContentOwner parameter specifies',
},
],
},
@ -205,12 +188,8 @@ export const channelFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'getAll',
],
resource: [
'channel',
],
operation: ['getAll'],
resource: ['channel'],
},
},
options: [
@ -223,14 +202,16 @@ export const channelFields: INodeProperties[] = [
loadOptionsMethod: 'getLanguages',
},
default: '',
description: 'The hl parameter instructs the API to retrieve localized resource metadata for a specific application language that the YouTube website supports. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
description:
'The hl parameter instructs the API to retrieve localized resource metadata for a specific application language that the YouTube website supports. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
},
{
displayName: 'On Behalf Of Content Owner',
name: 'onBehalfOfContentOwner',
type: 'string',
default: '',
description: 'The onBehalfOfContentOwner parameter indicates that the request\'s authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value',
description:
"The onBehalfOfContentOwner parameter indicates that the request's authorization credentials identify a YouTube CMS user who is acting on behalf of the content owner specified in the parameter value",
},
],
},
@ -244,12 +225,8 @@ export const channelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'channel',
],
operation: ['get'],
resource: ['channel'],
},
},
description: 'ID of the video',
@ -304,15 +281,12 @@ export const channelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'channel',
],
operation: ['get'],
resource: ['channel'],
},
},
description: 'The fields parameter specifies a comma-separated list of one or more channel resource properties that the API response will include',
description:
'The fields parameter specifies a comma-separated list of one or more channel resource properties that the API response will include',
default: ['*'],
},
/* -------------------------------------------------------------------------- */
@ -325,12 +299,8 @@ export const channelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'channel',
],
operation: ['update'],
resource: ['channel'],
},
},
default: '',
@ -343,12 +313,8 @@ export const channelFields: INodeProperties[] = [
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'channel',
],
operation: ['update'],
resource: ['channel'],
},
},
options: [
@ -382,34 +348,39 @@ export const channelFields: INodeProperties[] = [
name: 'country',
type: 'string',
default: '',
description: 'The country with which the channel is associated. Update this property to set the value of the snippet.country property.',
description:
'The country with which the channel is associated. Update this property to set the value of the snippet.country property.',
},
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
description: 'The channel description, which appears in the channel information box on your channel page. The property\'s value has a maximum length of 1000 characters.',
description:
"The channel description, which appears in the channel information box on your channel page. The property's value has a maximum length of 1000 characters.",
},
{
displayName: 'Default Language',
name: 'defaultLanguage',
type: 'string',
default: '',
description: 'The content tab that users should display by default when viewers arrive at your channel page',
description:
'The content tab that users should display by default when viewers arrive at your channel page',
},
{
displayName: 'Default Tab',
name: 'defaultTab',
type: 'string',
default: 'The content tab that users should display by default when viewers arrive at your channel page.',
default:
'The content tab that users should display by default when viewers arrive at your channel page.',
},
{
displayName: 'Featured Channels Title',
name: 'featuredChannelsTitle',
type: 'string',
default: '',
description: 'The title that displays above the featured channels module. The title has a maximum length of 30 characters.',
description:
'The title that displays above the featured channels module. The title has a maximum length of 30 characters.',
},
{
displayName: 'Featured Channels Urls',
@ -418,7 +389,8 @@ export const channelFields: INodeProperties[] = [
typeOptions: {
multipleValues: true,
},
description: 'A list of up to 100 channels that you would like to link to from the featured channels module. The property value is a list of YouTube channel ID values, each of which uniquely identifies a channel.',
description:
'A list of up to 100 channels that you would like to link to from the featured channels module. The property value is a list of YouTube channel ID values, each of which uniquely identifies a channel.',
default: [],
},
{
@ -429,14 +401,16 @@ export const channelFields: INodeProperties[] = [
alwaysOpenEditWindow: true,
},
placeholder: 'tech,news',
description: 'Keywords associated with your channel. The value is a space-separated list of strings.',
description:
'Keywords associated with your channel. The value is a space-separated list of strings.',
default: '',
},
{
displayName: 'Moderate Comments',
name: 'moderateComments',
type: 'boolean',
description: 'Whether user-submitted comments left on the channel page need to be approved by the channel owner to be publicly visible',
description:
'Whether user-submitted comments left on the channel page need to be approved by the channel owner to be publicly visible',
default: false,
},
{
@ -445,34 +419,38 @@ export const channelFields: INodeProperties[] = [
// eslint-disable-next-line n8n-nodes-base/node-param-color-type-unused
type: 'string',
default: '',
description: 'A prominent color that complements the channel\'s content',
description: "A prominent color that complements the channel's content",
},
{
displayName: 'Show Related Channels',
name: 'showRelatedChannels',
type: 'boolean',
description: 'Whether YouTube should show an algorithmically generated list of related channels on your channel page',
description:
'Whether YouTube should show an algorithmically generated list of related channels on your channel page',
default: false,
},
{
displayName: 'Show Browse View',
name: 'showBrowseView',
type: 'boolean',
description: 'Whether the channel page should display content in a browse or feed view',
description:
'Whether the channel page should display content in a browse or feed view',
default: false,
},
{
displayName: 'Tracking Analytics AccountId',
name: 'trackingAnalyticsAccountId',
type: 'string',
description: 'The ID for a Google Analytics account that you want to use to track and measure traffic to your channel',
description:
'The ID for a Google Analytics account that you want to use to track and measure traffic to your channel',
default: '',
},
{
displayName: 'Unsubscribed Trailer',
name: 'unsubscribedTrailer',
type: 'string',
description: 'The video that should play in the featured video module in the channel page\'s browse view for unsubscribed viewers',
description:
"The video that should play in the featured video module in the channel page's browse view for unsubscribed viewers",
default: '',
},
],
@ -490,7 +468,8 @@ export const channelFields: INodeProperties[] = [
type: 'collection',
default: {},
placeholder: 'Add Channel Settings',
description: 'The image object encapsulates information about images that display on the channel\'s channel page or video watch pages',
description:
"The image object encapsulates information about images that display on the channel's channel page or video watch pages",
typeOptions: {
multipleValues: false,
},
@ -561,12 +540,8 @@ export const channelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'uploadBanner',
],
resource: [
'channel',
],
operation: ['uploadBanner'],
resource: ['channel'],
},
},
description: 'ID of the channel',
@ -579,12 +554,8 @@ export const channelFields: INodeProperties[] = [
required: true,
displayOptions: {
show: {
operation: [
'uploadBanner',
],
resource: [
'channel',
],
operation: ['uploadBanner'],
resource: ['channel'],
},
},
default: 'data',

Some files were not shown because too many files have changed in this diff Show more