mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 06:34:05 -08:00
Merge branch 'oauth-support' into feature/infusionsoft-node
This commit is contained in:
commit
a13e2f01b1
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class HelpScoutOAuth2Api implements ICredentialType {
|
||||
name = 'helpScoutOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'HelpScout OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://secure.helpscout.net/authentication/authorizeClientApplication',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'https://api.helpscout.net/v2/oauth2/token',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class MicrosoftExcelOAuth2Api implements ICredentialType {
|
||||
name = 'microsoftExcelOAuth2Api';
|
||||
extends = [
|
||||
'microsoftOAuth2Api',
|
||||
];
|
||||
displayName = 'Microsoft OAuth2 API';
|
||||
properties = [
|
||||
//https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'openid offline_access Files.ReadWrite',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class MicrosoftOAuth2Api implements ICredentialType {
|
||||
name = 'microsoftOAuth2Api';
|
||||
extends = [
|
||||
'oAuth2Api',
|
||||
];
|
||||
displayName = 'Microsoft OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Authorization URL',
|
||||
name: 'authUrl',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: 'https://login.microsoftonline.com/{yourtenantid}/oauth2/v2.0/authorize',
|
||||
},
|
||||
{
|
||||
displayName: 'Access Token URL',
|
||||
name: 'accessTokenUrl',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: 'https://login.microsoftonline.com/{yourtenantid}/oauth2/v2.0/token',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
name: 'authQueryParameters',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'response_mode=query',
|
||||
},
|
||||
{
|
||||
displayName: 'Authentication',
|
||||
name: 'authentication',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'body',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class MicrosoftOneDriveOAuth2Api implements ICredentialType {
|
||||
name = 'microsoftOneDriveOAuth2Api';
|
||||
extends = [
|
||||
'microsoftOAuth2Api',
|
||||
];
|
||||
displayName = 'Microsoft OAuth2 API';
|
||||
properties = [
|
||||
//https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'openid offline_access Files.ReadWrite.All',
|
||||
},
|
||||
];
|
||||
}
|
26
packages/nodes-base/credentials/TestOAuth2Api.credentials.ts
Normal file
26
packages/nodes-base/credentials/TestOAuth2Api.credentials.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import {
|
||||
ICredentialType,
|
||||
NodePropertyTypes,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
const scopes = [
|
||||
'https://www.googleapis.com/auth/calendar',
|
||||
'https://www.googleapis.com/auth/calendar.events',
|
||||
];
|
||||
|
||||
export class TestOAuth2Api implements ICredentialType {
|
||||
name = 'testOAuth2Api';
|
||||
extends = [
|
||||
'googleOAuth2Api',
|
||||
];
|
||||
displayName = 'Test OAuth2 API';
|
||||
properties = [
|
||||
{
|
||||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'string' as NodePropertyTypes,
|
||||
default: '',
|
||||
placeholder: 'asdf',
|
||||
},
|
||||
];
|
||||
}
|
|
@ -62,7 +62,7 @@ export class ZohoOAuth2Api implements ICredentialType {
|
|||
displayName: 'Scope',
|
||||
name: 'scope',
|
||||
type: 'hidden' as NodePropertyTypes,
|
||||
default: 'ZohoCRM.modules.ALL',
|
||||
default: 'ZohoCRM.modules.ALL,ZohoCRM.settings.all,ZohoCRM.users.all',
|
||||
},
|
||||
{
|
||||
displayName: 'Auth URI Query Parameters',
|
||||
|
|
293
packages/nodes-base/nodes/Google/GoogleDriveTrigger.node.ts
Normal file
293
packages/nodes-base/nodes/Google/GoogleDriveTrigger.node.ts
Normal file
|
@ -0,0 +1,293 @@
|
|||
// import { google } from 'googleapis';
|
||||
|
||||
// import {
|
||||
// IHookFunctions,
|
||||
// IWebhookFunctions,
|
||||
// } from 'n8n-core';
|
||||
|
||||
// import {
|
||||
// IDataObject,
|
||||
// INodeTypeDescription,
|
||||
// INodeType,
|
||||
// IWebhookResponseData,
|
||||
// } from 'n8n-workflow';
|
||||
|
||||
// import { getAuthenticationClient } from './GoogleApi';
|
||||
|
||||
|
||||
// export class GoogleDriveTrigger implements INodeType {
|
||||
// description: INodeTypeDescription = {
|
||||
// displayName: 'Google Drive Trigger',
|
||||
// name: 'googleDriveTrigger',
|
||||
// icon: 'file:googleDrive.png',
|
||||
// group: ['trigger'],
|
||||
// version: 1,
|
||||
// subtitle: '={{$parameter["owner"] + "/" + $parameter["repository"] + ": " + $parameter["events"].join(", ")}}',
|
||||
// description: 'Starts the workflow when a file on Google Drive got changed.',
|
||||
// defaults: {
|
||||
// name: 'Google Drive Trigger',
|
||||
// color: '#3f87f2',
|
||||
// },
|
||||
// inputs: [],
|
||||
// outputs: ['main'],
|
||||
// credentials: [
|
||||
// {
|
||||
// name: 'googleApi',
|
||||
// required: true,
|
||||
// }
|
||||
// ],
|
||||
// webhooks: [
|
||||
// {
|
||||
// name: 'default',
|
||||
// httpMethod: 'POST',
|
||||
// responseMode: 'onReceived',
|
||||
// path: 'webhook',
|
||||
// },
|
||||
// ],
|
||||
// properties: [
|
||||
// {
|
||||
// displayName: 'Resource Id',
|
||||
// name: 'resourceId',
|
||||
// type: 'string',
|
||||
// default: '',
|
||||
// required: true,
|
||||
// placeholder: '',
|
||||
// description: 'ID of the resource to watch, for example a file ID.',
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
|
||||
// // @ts-ignore (because of request)
|
||||
// webhookMethods = {
|
||||
// default: {
|
||||
// async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
// // const webhookData = this.getWorkflowStaticData('node');
|
||||
|
||||
// // if (webhookData.webhookId === undefined) {
|
||||
// // // No webhook id is set so no webhook can exist
|
||||
// // return false;
|
||||
// // }
|
||||
|
||||
// // // Webhook got created before so check if it still exists
|
||||
// // const owner = this.getNodeParameter('owner') as string;
|
||||
// // const repository = this.getNodeParameter('repository') as string;
|
||||
// // const endpoint = `/repos/${owner}/${repository}/hooks/${webhookData.webhookId}`;
|
||||
|
||||
// // try {
|
||||
// // await githubApiRequest.call(this, 'GET', endpoint, {});
|
||||
// // } catch (e) {
|
||||
// // if (e.message.includes('[404]:')) {
|
||||
// // // Webhook does not exist
|
||||
// // delete webhookData.webhookId;
|
||||
// // delete webhookData.webhookEvents;
|
||||
|
||||
// // return false;
|
||||
// // }
|
||||
|
||||
// // // Some error occured
|
||||
// // throw e;
|
||||
// // }
|
||||
|
||||
// // If it did not error then the webhook exists
|
||||
// // return true;
|
||||
// return false;
|
||||
// },
|
||||
// async create(this: IHookFunctions): Promise<boolean> {
|
||||
// const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
|
||||
// const resourceId = this.getNodeParameter('resourceId') as string;
|
||||
|
||||
// const credentials = this.getCredentials('googleApi');
|
||||
|
||||
// if (credentials === undefined) {
|
||||
// throw new Error('No credentials got returned!');
|
||||
// }
|
||||
|
||||
// const scopes = [
|
||||
// 'https://www.googleapis.com/auth/drive',
|
||||
// 'https://www.googleapis.com/auth/drive.appdata',
|
||||
// 'https://www.googleapis.com/auth/drive.photos.readonly',
|
||||
// ];
|
||||
|
||||
// const client = await getAuthenticationClient(credentials.email as string, credentials.privateKey as string, scopes);
|
||||
|
||||
// const drive = google.drive({
|
||||
// version: 'v3',
|
||||
// auth: client,
|
||||
// });
|
||||
|
||||
|
||||
// const accessToken = await client.getAccessToken();
|
||||
// console.log('accessToken: ');
|
||||
// console.log(accessToken);
|
||||
|
||||
// const asdf = await drive.changes.getStartPageToken();
|
||||
// // console.log('asdf: ');
|
||||
// // console.log(asdf);
|
||||
|
||||
|
||||
|
||||
|
||||
// const response = await drive.changes.watch({
|
||||
// //
|
||||
// pageToken: asdf.data.startPageToken,
|
||||
// requestBody: {
|
||||
// id: 'asdf-test-2',
|
||||
// address: webhookUrl,
|
||||
// resourceId,
|
||||
// type: 'web_hook',
|
||||
// // page_token: '',
|
||||
// }
|
||||
// });
|
||||
|
||||
// console.log('...response...CREATE');
|
||||
// console.log(JSON.stringify(response, null, 2));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// // const endpoint = `/repos/${owner}/${repository}/hooks`;
|
||||
|
||||
// // const body = {
|
||||
// // name: 'web',
|
||||
// // config: {
|
||||
// // url: webhookUrl,
|
||||
// // content_type: 'json',
|
||||
// // // secret: '...later...',
|
||||
// // insecure_ssl: '1', // '0' -> not allow inscure ssl | '1' -> allow insercure SSL
|
||||
// // },
|
||||
// // events,
|
||||
// // active: true,
|
||||
// // };
|
||||
|
||||
|
||||
// // let responseData;
|
||||
// // try {
|
||||
// // responseData = await githubApiRequest.call(this, 'POST', endpoint, body);
|
||||
// // } catch (e) {
|
||||
// // if (e.message.includes('[422]:')) {
|
||||
// // throw new Error('A webhook with the identical URL exists already. Please delete it manually on Github!');
|
||||
// // }
|
||||
|
||||
// // throw e;
|
||||
// // }
|
||||
|
||||
// // if (responseData.id === undefined || responseData.active !== true) {
|
||||
// // // Required data is missing so was not successful
|
||||
// // throw new Error('Github webhook creation response did not contain the expected data.');
|
||||
// // }
|
||||
|
||||
// // const webhookData = this.getWorkflowStaticData('node');
|
||||
// // webhookData.webhookId = responseData.id as string;
|
||||
// // webhookData.webhookEvents = responseData.events as string[];
|
||||
|
||||
// return true;
|
||||
// },
|
||||
// async delete(this: IHookFunctions): Promise<boolean> {
|
||||
// const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
|
||||
// const resourceId = this.getNodeParameter('resourceId') as string;
|
||||
|
||||
// const credentials = this.getCredentials('googleApi');
|
||||
|
||||
// if (credentials === undefined) {
|
||||
// throw new Error('No credentials got returned!');
|
||||
// }
|
||||
|
||||
// const scopes = [
|
||||
// 'https://www.googleapis.com/auth/drive',
|
||||
// 'https://www.googleapis.com/auth/drive.appdata',
|
||||
// 'https://www.googleapis.com/auth/drive.photos.readonly',
|
||||
// ];
|
||||
|
||||
// const client = await getAuthenticationClient(credentials.email as string, credentials.privateKey as string, scopes);
|
||||
|
||||
// const drive = google.drive({
|
||||
// version: 'v3',
|
||||
// auth: client,
|
||||
// });
|
||||
|
||||
// // Remove channel
|
||||
// const response = await drive.channels.stop({
|
||||
// requestBody: {
|
||||
// id: 'asdf-test-2',
|
||||
// address: webhookUrl,
|
||||
// resourceId,
|
||||
// type: 'web_hook',
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
// console.log('...response...DELETE');
|
||||
// console.log(JSON.stringify(response, null, 2));
|
||||
|
||||
|
||||
|
||||
// // const webhookData = this.getWorkflowStaticData('node');
|
||||
|
||||
// // if (webhookData.webhookId !== undefined) {
|
||||
// // const owner = this.getNodeParameter('owner') as string;
|
||||
// // const repository = this.getNodeParameter('repository') as string;
|
||||
// // const endpoint = `/repos/${owner}/${repository}/hooks/${webhookData.webhookId}`;
|
||||
// // const body = {};
|
||||
|
||||
// // try {
|
||||
// // await githubApiRequest.call(this, 'DELETE', endpoint, body);
|
||||
// // } catch (e) {
|
||||
// // return false;
|
||||
// // }
|
||||
|
||||
// // // Remove from the static workflow data so that it is clear
|
||||
// // // that no webhooks are registred anymore
|
||||
// // delete webhookData.webhookId;
|
||||
// // delete webhookData.webhookEvents;
|
||||
// // }
|
||||
|
||||
// return true;
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
// const bodyData = this.getBodyData();
|
||||
|
||||
// console.log('');
|
||||
// console.log('');
|
||||
// console.log('GOT WEBHOOK CALL');
|
||||
// console.log(JSON.stringify(bodyData, null, 2));
|
||||
|
||||
|
||||
|
||||
// // Check if the webhook is only the ping from Github to confirm if it workshook_id
|
||||
// if (bodyData.hook_id !== undefined && bodyData.action === undefined) {
|
||||
// // Is only the ping and not an actual webhook call. So return 'OK'
|
||||
// // but do not start the workflow.
|
||||
|
||||
// return {
|
||||
// webhookResponse: 'OK'
|
||||
// };
|
||||
// }
|
||||
|
||||
// // Is a regular webhoook call
|
||||
|
||||
// // TODO: Add headers & requestPath
|
||||
// const returnData: IDataObject[] = [];
|
||||
|
||||
// returnData.push(
|
||||
// {
|
||||
// body: bodyData,
|
||||
// headers: this.getHeaderData(),
|
||||
// query: this.getQueryData(),
|
||||
// }
|
||||
// );
|
||||
|
||||
// return {
|
||||
// workflowData: [
|
||||
// this.helpers.returnJsonArray(returnData)
|
||||
// ],
|
||||
// };
|
||||
// }
|
||||
// }
|
638
packages/nodes-base/nodes/HelpScout/ConversationDescription.ts
Normal file
638
packages/nodes-base/nodes/HelpScout/ConversationDescription.ts
Normal file
|
@ -0,0 +1,638 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const conversationOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new conversation',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a conversation',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a conversation',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get all conversations',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const conversationFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* conversation:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Mailbox',
|
||||
name: 'mailboxId',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getMailboxes',
|
||||
},
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'ID of a mailbox where the conversation is being created',
|
||||
},
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'options',
|
||||
required: true,
|
||||
options: [
|
||||
{
|
||||
name: 'Active',
|
||||
value: 'active',
|
||||
},
|
||||
{
|
||||
name: 'Closed',
|
||||
value: 'closed',
|
||||
},
|
||||
{
|
||||
name: 'Pending',
|
||||
value: 'pending',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Conversation status',
|
||||
},
|
||||
{
|
||||
displayName: 'Subject',
|
||||
name: 'subject',
|
||||
type: 'string',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: `Conversation’s subject`,
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
required: true,
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Chat',
|
||||
value: 'chat',
|
||||
},
|
||||
{
|
||||
name: 'Email',
|
||||
value: 'email',
|
||||
},
|
||||
{
|
||||
name: 'Phone',
|
||||
value: 'phone',
|
||||
},
|
||||
],
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Conversation type',
|
||||
},
|
||||
{
|
||||
displayName: 'Resolve Data',
|
||||
name: 'resolveData',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'By default the response only contain the ID to resource<br />. If this option gets activated it<br />will resolve the data automatically.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Assign To',
|
||||
name: 'assignTo',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'The Help Scout user assigned to the conversation.',
|
||||
},
|
||||
{
|
||||
displayName: 'Auto Reply',
|
||||
name: 'autoReply',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: `When autoReply is set to true, an auto reply will be sent</br>
|
||||
as long as there is at least one customer thread in the conversation.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Closed At',
|
||||
name: 'closedAt',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: `When the conversation was closed, only applicable for imported conversations`,
|
||||
},
|
||||
{
|
||||
displayName: 'Created At',
|
||||
name: 'createdAt',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: `When this conversation was created - ISO 8601 date time`,
|
||||
},
|
||||
{
|
||||
displayName: 'Customer Email',
|
||||
name: 'customerEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Customer ID',
|
||||
name: 'customerId',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Imported',
|
||||
name: 'imported',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: `When imported is set to true, no outgoing emails or notifications will be generated.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTags',
|
||||
},
|
||||
default: [],
|
||||
description: 'List of tags to be be added to the conversation',
|
||||
},
|
||||
{
|
||||
displayName: 'User ID',
|
||||
name: 'user',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'ID of the user who is adding the conversation and threads.',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Threads',
|
||||
name: 'threadsUi',
|
||||
placeholder: 'Add Thread',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Thread',
|
||||
name: 'threadsValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Chat',
|
||||
value: 'chat'
|
||||
},
|
||||
{
|
||||
name: 'Customer',
|
||||
value: 'customer'
|
||||
},
|
||||
{
|
||||
name: 'Note',
|
||||
value: 'note'
|
||||
},
|
||||
{
|
||||
name: 'Phone',
|
||||
value: 'phone'
|
||||
},
|
||||
{
|
||||
name: 'Reply',
|
||||
value: 'reply'
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true
|
||||
},
|
||||
default: '',
|
||||
description: 'The message text.'
|
||||
},
|
||||
{
|
||||
displayName: 'Bcc',
|
||||
name: 'bcc',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: [
|
||||
'customer'
|
||||
],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
multipleValueButtonText: 'Add Email',
|
||||
},
|
||||
default: [],
|
||||
description: 'Email addresses.'
|
||||
},
|
||||
{
|
||||
displayName: 'Cc',
|
||||
name: 'cc',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: [
|
||||
'customer'
|
||||
],
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
multipleValueButtonText: 'Add Email',
|
||||
},
|
||||
default: [],
|
||||
description: 'Email addresses.'
|
||||
},
|
||||
{
|
||||
displayName: 'Draft',
|
||||
name: 'draft',
|
||||
displayOptions: {
|
||||
show: {
|
||||
type: [
|
||||
'reply'
|
||||
],
|
||||
},
|
||||
},
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'If set to true, a draft reply is created',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* conversation:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Conversation ID',
|
||||
name: 'conversationId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'conversation ID',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* conversation:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Conversation ID',
|
||||
name: 'conversationId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'conversation ID',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* conversation:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'conversation',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Assign To',
|
||||
name: 'assignTo',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
description: 'Filters conversations by assignee id',
|
||||
},
|
||||
{
|
||||
displayName: 'Embed',
|
||||
name: 'embed',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Threads',
|
||||
value: 'threads',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Allows embedding/loading of sub-entities',
|
||||
},
|
||||
{
|
||||
displayName: 'Folder ID',
|
||||
name: 'folder',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Filters conversations from a specific folder id',
|
||||
},
|
||||
{
|
||||
displayName: 'Mailbox ID',
|
||||
name: 'mailbox',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Filters conversations from a specific mailbox',
|
||||
},
|
||||
{
|
||||
displayName: 'Modified Since',
|
||||
name: 'modifiedSince',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns only conversations that were modified after this date',
|
||||
},
|
||||
{
|
||||
displayName: 'Number',
|
||||
name: 'number',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
description: 'Looks up conversation by conversation number',
|
||||
},
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
description: 'Advanced search <a href="https://developer.helpscout.com/mailbox-api/endpoints/conversations/list/#query">Examples</a>'
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Field',
|
||||
name: 'sortField',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Created At',
|
||||
value: 'createdAt',
|
||||
},
|
||||
{
|
||||
name: 'customer Email',
|
||||
value: 'customerEmail',
|
||||
},
|
||||
{
|
||||
name: 'customer Name',
|
||||
value: 'customerName',
|
||||
},
|
||||
{
|
||||
name: 'Mailbox ID',
|
||||
value: 'mailboxid',
|
||||
},
|
||||
{
|
||||
name: 'Modified At',
|
||||
value: 'modifiedAt',
|
||||
},
|
||||
{
|
||||
name: 'Number',
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
name: 'Score',
|
||||
value: 'score',
|
||||
},
|
||||
{
|
||||
name: 'Status',
|
||||
value: 'status',
|
||||
},
|
||||
{
|
||||
name: 'Subject',
|
||||
value: 'subject',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Sorts the result by specified field',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
name: 'sortOrder',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
},
|
||||
],
|
||||
default: 'desc',
|
||||
},
|
||||
{
|
||||
displayName: 'Status',
|
||||
name: 'status',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Active',
|
||||
value: 'active',
|
||||
},
|
||||
{
|
||||
name: 'All',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: 'Closed',
|
||||
value: 'closed',
|
||||
},
|
||||
{
|
||||
name: 'Open',
|
||||
value: 'open',
|
||||
},
|
||||
{
|
||||
name: 'Pending',
|
||||
value: 'pending',
|
||||
},
|
||||
{
|
||||
name: 'Spam',
|
||||
value: 'spam',
|
||||
},
|
||||
],
|
||||
default: 'active',
|
||||
description: 'Filter conversation by status',
|
||||
},
|
||||
{
|
||||
displayName: 'Tags',
|
||||
name: 'tags',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTags',
|
||||
},
|
||||
default: [],
|
||||
description: 'Filter conversation by tags',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
18
packages/nodes-base/nodes/HelpScout/ConversationInterface.ts
Normal file
18
packages/nodes-base/nodes/HelpScout/ConversationInterface.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export interface IConversation {
|
||||
assignTo?: number;
|
||||
autoReply?: boolean;
|
||||
closedAt?: string;
|
||||
createdAt?: string;
|
||||
customer?: IDataObject;
|
||||
fields?: IDataObject[];
|
||||
imported?: boolean;
|
||||
mailboxId?: number;
|
||||
status?: string;
|
||||
subject?: string;
|
||||
tags?: IDataObject[];
|
||||
threads?: IDataObject[];
|
||||
type?: string;
|
||||
user?: number;
|
||||
}
|
1579
packages/nodes-base/nodes/HelpScout/CountriesCodes.ts
Normal file
1579
packages/nodes-base/nodes/HelpScout/CountriesCodes.ts
Normal file
File diff suppressed because it is too large
Load diff
851
packages/nodes-base/nodes/HelpScout/CustomerDescription.ts
Normal file
851
packages/nodes-base/nodes/HelpScout/CustomerDescription.ts
Normal file
|
@ -0,0 +1,851 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const customerOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new customer',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a customer',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get all customers',
|
||||
},
|
||||
{
|
||||
name: 'Properties',
|
||||
value: 'properties',
|
||||
description: 'Get customer property definitions',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a customer',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const customerFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* customer:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Resolve Data',
|
||||
name: 'resolveData',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'By default the response only contain the ID to resource<br />. If this option gets activated it<br />will resolve the data automatically.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Age',
|
||||
name: 'age',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 1,
|
||||
description: `Customer’s age`,
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `First name of the customer. When defined it must be between 1 and 40 characters.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Gender',
|
||||
name: 'gender',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Female',
|
||||
value: 'female',
|
||||
},
|
||||
{
|
||||
name: 'Male',
|
||||
value: 'male',
|
||||
},
|
||||
{
|
||||
name: 'Unknown',
|
||||
value: 'unknown',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Gender of this customer.',
|
||||
},
|
||||
{
|
||||
displayName: 'Job Title',
|
||||
name: 'jobTitle',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Job title. Max length 60 characters.',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Last name of the customer',
|
||||
},
|
||||
{
|
||||
displayName: 'Location',
|
||||
name: 'location',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Location of the customer.',
|
||||
},
|
||||
{
|
||||
displayName: 'Notes',
|
||||
name: 'background',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
description: `Notes`,
|
||||
},
|
||||
{
|
||||
displayName: 'Organization',
|
||||
name: 'organization',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Organization',
|
||||
},
|
||||
{
|
||||
displayName: 'Photo Url',
|
||||
name: 'photoUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'URL of the customer’s photo',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'addressUi',
|
||||
placeholder: 'Add Address',
|
||||
type: 'fixedCollection',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'addressValue',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Line 1',
|
||||
name: 'line1',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'line1',
|
||||
},
|
||||
{
|
||||
displayName: 'Line 2',
|
||||
name: 'line2',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'line2',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'City',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'State',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCountriesCodes',
|
||||
},
|
||||
default: '',
|
||||
description: 'Country',
|
||||
},
|
||||
{
|
||||
displayName: 'Postal Code',
|
||||
name: 'postalCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Postal code',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Chat Handles',
|
||||
name: 'chatsUi',
|
||||
placeholder: 'Add Chat Handle',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Chat Handle',
|
||||
name: 'chatsValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'AIM',
|
||||
value: 'aim',
|
||||
},
|
||||
{
|
||||
name: 'Google Talk',
|
||||
value: 'gtalk',
|
||||
},
|
||||
{
|
||||
name: 'ICQ',
|
||||
value: 'icq',
|
||||
},
|
||||
{
|
||||
name: 'MSN',
|
||||
value: 'msn',
|
||||
},
|
||||
{
|
||||
name: 'Other',
|
||||
value: 'other',
|
||||
},
|
||||
{
|
||||
name: 'QQ',
|
||||
value: 'qq',
|
||||
},
|
||||
{
|
||||
name: 'Skype',
|
||||
value: 'skype',
|
||||
},
|
||||
{
|
||||
name: 'XMPP',
|
||||
value: 'xmpp',
|
||||
},
|
||||
{
|
||||
name: 'Yahoo',
|
||||
value: 'yahoo',
|
||||
},
|
||||
],
|
||||
description: 'Chat type',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Chat handle',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Emails',
|
||||
name: 'emailsUi',
|
||||
placeholder: 'Add Email',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'emailsValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Home',
|
||||
value: 'home',
|
||||
},
|
||||
{
|
||||
name: 'Other',
|
||||
value: 'other',
|
||||
},
|
||||
{
|
||||
name: 'Work',
|
||||
value: 'work',
|
||||
},
|
||||
],
|
||||
description: 'Location for this email address',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Email',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Phones',
|
||||
name: 'phonesUi',
|
||||
placeholder: 'Add Phone',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'phonesValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Fax',
|
||||
value: 'fax',
|
||||
},
|
||||
{
|
||||
name: 'Home',
|
||||
value: 'home',
|
||||
},
|
||||
{
|
||||
name: 'Other',
|
||||
value: 'other',
|
||||
},
|
||||
{
|
||||
name: 'Pager',
|
||||
value: 'pager',
|
||||
},
|
||||
{
|
||||
name: 'Work',
|
||||
value: 'work',
|
||||
},
|
||||
],
|
||||
description: 'Location for this phone',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Phone',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Social Profiles',
|
||||
name: 'socialProfilesUi',
|
||||
placeholder: 'Add Social Profile',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Social Profile',
|
||||
name: 'socialProfilesValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'About Me',
|
||||
value: 'aboutMe',
|
||||
},
|
||||
{
|
||||
name: 'Facebook',
|
||||
value: 'facebook',
|
||||
},
|
||||
{
|
||||
name: 'Flickr',
|
||||
value: 'flickr',
|
||||
},
|
||||
{
|
||||
name: 'Forsquare',
|
||||
value: 'forsquare',
|
||||
},
|
||||
{
|
||||
name: 'Google',
|
||||
value: 'google',
|
||||
},
|
||||
{
|
||||
name: 'Google Plus',
|
||||
value: 'googleplus',
|
||||
},
|
||||
{
|
||||
name: 'Linkedin',
|
||||
value: 'linkedin',
|
||||
},
|
||||
{
|
||||
name: 'Other',
|
||||
value: 'other',
|
||||
},
|
||||
{
|
||||
name: 'Quora',
|
||||
value: 'quora',
|
||||
},
|
||||
{
|
||||
name: 'Tungleme',
|
||||
value: 'tungleme',
|
||||
},
|
||||
{
|
||||
name: 'Twitter',
|
||||
value: 'twitter',
|
||||
},
|
||||
{
|
||||
name: 'Youtube',
|
||||
value: 'youtube',
|
||||
},
|
||||
],
|
||||
description: 'Type of social profile',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Social Profile handle (url for example)',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Websites',
|
||||
name: 'websitesUi',
|
||||
placeholder: 'Add Website',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'websitesValues',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Value',
|
||||
name: 'value',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Website URL',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* customer:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Filters customers by first name',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Filters customers by last name',
|
||||
},
|
||||
{
|
||||
displayName: 'Mailbox ID',
|
||||
name: 'mailbox',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Filters customers from a specific mailbox',
|
||||
},
|
||||
{
|
||||
displayName: 'Modified Since',
|
||||
name: 'modifiedSince',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
description: 'Returns only customers that were modified after this date',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Field',
|
||||
name: 'sortField',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Score',
|
||||
value: 'score',
|
||||
},
|
||||
{
|
||||
name: 'First Name',
|
||||
value: 'firstName',
|
||||
},
|
||||
{
|
||||
name: 'Last Name',
|
||||
value: 'lastName',
|
||||
},
|
||||
{
|
||||
name: 'Modified At',
|
||||
value: 'modifiedAt',
|
||||
},
|
||||
],
|
||||
default: 'score',
|
||||
description: 'Sorts the result by specified field',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
name: 'sortOrder',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
},
|
||||
],
|
||||
default: 'desc',
|
||||
},
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
description: 'Advanced search <a href="https://developer.helpscout.com/mailbox-api/endpoints/customers/list/#query">Examples</a>'
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* customer:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Customer ID',
|
||||
name: 'customerId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'Customer ID',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* customer:update */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Customer ID',
|
||||
name: 'customerId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'Customer ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Fields',
|
||||
name: 'updateFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'customer',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Age',
|
||||
name: 'age',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 1,
|
||||
description: `Customer’s age`,
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `First name of the customer. When defined it must be between 1 and 40 characters.`,
|
||||
},
|
||||
{
|
||||
displayName: 'Gender',
|
||||
name: 'gender',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Female',
|
||||
value: 'female',
|
||||
},
|
||||
{
|
||||
name: 'Male',
|
||||
value: 'male',
|
||||
},
|
||||
{
|
||||
name: 'Unknown',
|
||||
value: 'unknown',
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Gender of this customer.',
|
||||
},
|
||||
{
|
||||
displayName: 'Job Title',
|
||||
name: 'jobTitle',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Job title. Max length 60 characters.',
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Last name of the customer',
|
||||
},
|
||||
{
|
||||
displayName: 'Location',
|
||||
name: 'location',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Location of the customer.',
|
||||
},
|
||||
{
|
||||
displayName: 'Notes',
|
||||
name: 'background',
|
||||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
default: '',
|
||||
description: `Notes`,
|
||||
},
|
||||
{
|
||||
displayName: 'Organization',
|
||||
name: 'organization',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Organization',
|
||||
},
|
||||
{
|
||||
displayName: 'Photo Url',
|
||||
name: 'photoUrl',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'URL of the customer’s photo',
|
||||
},
|
||||
],
|
||||
},
|
||||
] as INodeProperties[];
|
20
packages/nodes-base/nodes/HelpScout/CustomerInterface.ts
Normal file
20
packages/nodes-base/nodes/HelpScout/CustomerInterface.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export interface ICustomer {
|
||||
address?: IDataObject;
|
||||
age?: string;
|
||||
background?: string;
|
||||
chats?: IDataObject[];
|
||||
emails?: IDataObject[];
|
||||
firstName?: string;
|
||||
gender?: string;
|
||||
jobTitle?: string;
|
||||
lastName?: string;
|
||||
location?: string;
|
||||
organization?: string;
|
||||
phones?: IDataObject[];
|
||||
photoUrl?: string;
|
||||
properties?: IDataObject;
|
||||
socialProfiles?: IDataObject[];
|
||||
websites?: IDataObject[];
|
||||
}
|
72
packages/nodes-base/nodes/HelpScout/GenericFunctions.ts
Normal file
72
packages/nodes-base/nodes/HelpScout/GenericFunctions.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { OptionsWithUri } from 'request';
|
||||
import {
|
||||
IHookFunctions,
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
import {
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
get,
|
||||
} from 'lodash';
|
||||
|
||||
export async function helpscoutApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IHookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
let options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: uri || `https://api.helpscout.net${resource}`,
|
||||
json: true
|
||||
};
|
||||
try {
|
||||
if (Object.keys(option).length !== 0) {
|
||||
options = Object.assign({}, options, option);
|
||||
}
|
||||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
//@ts-ignore
|
||||
return await this.helpers.requestOAuth.call(this, 'helpScoutOAuth2Api', options);
|
||||
} catch (error) {
|
||||
if (error.response && error.response.body
|
||||
&& error.response.body._embedded
|
||||
&& error.response.body._embedded.errors) {
|
||||
// Try to return the error prettier
|
||||
//@ts-ignore
|
||||
throw new Error(`HelpScout error response [${error.statusCode}]: ${error.response.body.message} - ${error.response.body._embedded.errors.map(error => {
|
||||
return `${error.path} ${error.message}`;
|
||||
}).join('-')}`);
|
||||
}
|
||||
|
||||
throw new Error(`HelpScout error response [${error.statusCode}]: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function helpscoutApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
let uri;
|
||||
|
||||
do {
|
||||
responseData = await helpscoutApiRequest.call(this, method, endpoint, body, query, uri);
|
||||
uri = get(responseData, '_links.next.href');
|
||||
returnData.push.apply(returnData, get(responseData, propertyName));
|
||||
if (query.limit && query.limit <= returnData.length) {
|
||||
return returnData;
|
||||
}
|
||||
} while (
|
||||
responseData['_links'] !== undefined &&
|
||||
responseData['_links'].next !== undefined &&
|
||||
responseData['_links'].next.href !== undefined
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
439
packages/nodes-base/nodes/HelpScout/HelpScout.node.ts
Normal file
439
packages/nodes-base/nodes/HelpScout/HelpScout.node.ts
Normal file
|
@ -0,0 +1,439 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IBinaryKeyData,
|
||||
IDataObject,
|
||||
ILoadOptionsFunctions,
|
||||
INodeExecutionData,
|
||||
INodePropertyOptions,
|
||||
INodeTypeDescription,
|
||||
INodeType,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
countriesCodes
|
||||
} from './CountriesCodes';
|
||||
|
||||
import {
|
||||
conversationFields,
|
||||
conversationOperations,
|
||||
} from './ConversationDescription';
|
||||
|
||||
import {
|
||||
customerFields,
|
||||
customerOperations,
|
||||
} from './CustomerDescription';
|
||||
|
||||
import {
|
||||
ICustomer,
|
||||
} from './CustomerInterface';
|
||||
|
||||
import {
|
||||
IConversation,
|
||||
} from './ConversationInterface';
|
||||
|
||||
import {
|
||||
helpscoutApiRequest,
|
||||
helpscoutApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import {
|
||||
mailboxFields,
|
||||
mailboxOperations,
|
||||
} from './MailboxDescription';
|
||||
|
||||
import {
|
||||
threadFields,
|
||||
threadOperations,
|
||||
} from './ThreadDescription';
|
||||
|
||||
import {
|
||||
IAttachment,
|
||||
IThread,
|
||||
} from './ThreadInterface';
|
||||
|
||||
|
||||
export class HelpScout implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'HelpScout',
|
||||
name: 'helpScout',
|
||||
icon: 'file:helpScout.png',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Help Scout API.',
|
||||
defaults: {
|
||||
name: 'HelpScout',
|
||||
color: '#1392ee',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'helpScoutOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Conversation',
|
||||
value: 'conversation',
|
||||
},
|
||||
{
|
||||
name: 'Customer',
|
||||
value: 'customer',
|
||||
},
|
||||
{
|
||||
name: 'Mailbox',
|
||||
value: 'mailbox',
|
||||
},
|
||||
{
|
||||
name: 'Thread',
|
||||
value: 'thread',
|
||||
},
|
||||
],
|
||||
default: 'conversation',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
...conversationOperations,
|
||||
...conversationFields,
|
||||
...customerOperations,
|
||||
...customerFields,
|
||||
...mailboxOperations,
|
||||
...mailboxFields,
|
||||
...threadOperations,
|
||||
...threadFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
// Get all the countries codes to display them to user so that he can
|
||||
// select them easily
|
||||
async getCountriesCodes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
for (const countryCode of countriesCodes) {
|
||||
const countryCodeName = `${countryCode.name} - ${countryCode.alpha2}`;
|
||||
const countryCodeId = countryCode.alpha2;
|
||||
returnData.push({
|
||||
name: countryCodeName,
|
||||
value: countryCodeId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the tags to display them to user so that he can
|
||||
// select them easily
|
||||
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const tags = await helpscoutApiRequestAllItems.call(this, '_embedded.tags', 'GET', '/v2/tags');
|
||||
for (const tag of tags) {
|
||||
const tagName = tag.name;
|
||||
const tagId = tag.id;
|
||||
returnData.push({
|
||||
name: tagName,
|
||||
value: tagId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the mailboxes to display them to user so that he can
|
||||
// select them easily
|
||||
async getMailboxes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const mailboxes = await helpscoutApiRequestAllItems.call(this, '_embedded.mailboxes', 'GET', '/v2/mailboxes');
|
||||
for (const mailbox of mailboxes) {
|
||||
const mailboxName = mailbox.name;
|
||||
const mailboxId = mailbox.id;
|
||||
returnData.push({
|
||||
name: mailboxName,
|
||||
value: mailboxId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (resource === 'conversation') {
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/conversations/create
|
||||
if (operation === 'create') {
|
||||
const mailboxId = this.getNodeParameter('mailboxId', i) as number;
|
||||
const status = this.getNodeParameter('status', i) as string;
|
||||
const subject = this.getNodeParameter('subject', i) as string;
|
||||
const type = this.getNodeParameter('type', i) as string;
|
||||
const resolveData = this.getNodeParameter('resolveData', i) as boolean;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const threads = (this.getNodeParameter('threadsUi', i) as IDataObject).threadsValues as IDataObject[];
|
||||
const body: IConversation = {
|
||||
mailboxId,
|
||||
status,
|
||||
subject,
|
||||
type,
|
||||
};
|
||||
Object.assign(body, additionalFields);
|
||||
if (additionalFields.customerId) {
|
||||
body.customer = {
|
||||
id: additionalFields.customerId,
|
||||
};
|
||||
//@ts-ignore
|
||||
delete body.customerId;
|
||||
}
|
||||
if (additionalFields.customerEmail) {
|
||||
body.customer = {
|
||||
email: additionalFields.customerEmail,
|
||||
};
|
||||
//@ts-ignore
|
||||
delete body.customerEmail;
|
||||
}
|
||||
if (body.customer === undefined) {
|
||||
throw new Error('Either customer email or customer ID must be set');
|
||||
}
|
||||
if (threads) {
|
||||
for (let i = 0; i < threads.length; i++) {
|
||||
if (threads[i].type === '' || threads[i].text === '') {
|
||||
throw new Error('Chat Threads cannot be empty');
|
||||
}
|
||||
if (threads[i].type !== 'note') {
|
||||
threads[i].customer = body.customer;
|
||||
}
|
||||
}
|
||||
body.threads = threads;
|
||||
}
|
||||
responseData = await helpscoutApiRequest.call(this, 'POST', '/v2/conversations', body, qs, undefined, { resolveWithFullResponse: true });
|
||||
const id = responseData.headers['resource-id'];
|
||||
const uri = responseData.headers.location;
|
||||
if (resolveData) {
|
||||
responseData = await helpscoutApiRequest.call(this, 'GET', '', {}, {}, uri);
|
||||
} else {
|
||||
responseData = {
|
||||
id,
|
||||
uri,
|
||||
};
|
||||
}
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/conversations/delete
|
||||
if (operation === 'delete') {
|
||||
const conversationId = this.getNodeParameter('conversationId', i) as string;
|
||||
responseData = await helpscoutApiRequest.call(this, 'DELETE', `/v2/conversations/${conversationId}`);
|
||||
responseData = { success: true };
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/conversations/get
|
||||
if (operation === 'get') {
|
||||
const conversationId = this.getNodeParameter('conversationId', i) as string;
|
||||
responseData = await helpscoutApiRequest.call(this, 'GET', `/v2/conversations/${conversationId}`);
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/conversations/list
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
Object.assign(qs, options);
|
||||
if (returnAll) {
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.conversations', 'GET', '/v2/conversations', {}, qs);
|
||||
} else {
|
||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.conversations', 'GET', '/v2/conversations', {}, qs);
|
||||
responseData = responseData.splice(0, qs.limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'customer') {
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/customers/create
|
||||
if (operation === 'create') {
|
||||
const resolveData = this.getNodeParameter('resolveData', i) as boolean;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const chats = (this.getNodeParameter('chatsUi', i) as IDataObject).chatsValues as IDataObject[];
|
||||
const address = (this.getNodeParameter('addressUi', i) as IDataObject).addressValue as IDataObject;
|
||||
const emails = (this.getNodeParameter('emailsUi', i) as IDataObject).emailsValues as IDataObject[];
|
||||
const phones = (this.getNodeParameter('phonesUi', i) as IDataObject).phonesValues as IDataObject[];
|
||||
const socialProfiles = (this.getNodeParameter('socialProfilesUi', i) as IDataObject).socialProfilesValues as IDataObject[];
|
||||
const websites = (this.getNodeParameter('websitesUi', i) as IDataObject).websitesValues as IDataObject[];
|
||||
let body: ICustomer = {};
|
||||
body = Object.assign({}, additionalFields);
|
||||
if (body.age) {
|
||||
body.age = body.age.toString();
|
||||
}
|
||||
if (chats) {
|
||||
body.chats = chats;
|
||||
}
|
||||
if (address) {
|
||||
body.address = address;
|
||||
body.address.lines = [address.line1, address.line2];
|
||||
}
|
||||
if (emails) {
|
||||
body.emails = emails;
|
||||
}
|
||||
if (phones) {
|
||||
body.phones = phones;
|
||||
}
|
||||
if (socialProfiles) {
|
||||
body.socialProfiles = socialProfiles;
|
||||
}
|
||||
if (websites) {
|
||||
body.websites = websites;
|
||||
}
|
||||
if (Object.keys(body).length === 0) {
|
||||
throw new Error('You have to set at least one field');
|
||||
}
|
||||
responseData = await helpscoutApiRequest.call(this, 'POST', '/v2/customers', body, qs, undefined, { resolveWithFullResponse: true });
|
||||
const id = responseData.headers['resource-id'];
|
||||
const uri = responseData.headers.location;
|
||||
if (resolveData) {
|
||||
responseData = await helpscoutApiRequest.call(this, 'GET', '', {}, {}, uri);
|
||||
} else {
|
||||
responseData = {
|
||||
id,
|
||||
uri,
|
||||
};
|
||||
}
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/customer_properties/list
|
||||
if (operation === 'properties') {
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.customer-properties', 'GET', '/v2/customer-properties', {}, qs);
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/customers/get
|
||||
if (operation === 'get') {
|
||||
const customerId = this.getNodeParameter('customerId', i) as string;
|
||||
responseData = await helpscoutApiRequest.call(this, 'GET', `/v2/customers/${customerId}`);
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/customers/list
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
Object.assign(qs, options);
|
||||
if (returnAll) {
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.customers', 'GET', '/v2/customers', {}, qs);
|
||||
} else {
|
||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.customers', 'GET', '/v2/customers', {}, qs);
|
||||
responseData = responseData.splice(0, qs.limit);
|
||||
}
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/customers/overwrite/
|
||||
if (operation === 'update') {
|
||||
const customerId = this.getNodeParameter('customerId', i) as string;
|
||||
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
|
||||
let body: ICustomer = {};
|
||||
body = Object.assign({}, updateFields);
|
||||
if (body.age) {
|
||||
body.age = body.age.toString();
|
||||
}
|
||||
if (Object.keys(body).length === 0) {
|
||||
throw new Error('You have to set at least one field');
|
||||
}
|
||||
responseData = await helpscoutApiRequest.call(this, 'PUT', `/v2/customers/${customerId}`, body, qs, undefined, { resolveWithFullResponse: true });
|
||||
responseData = { success: true };
|
||||
}
|
||||
}
|
||||
if (resource === 'mailbox') {
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/mailboxes/get
|
||||
if (operation === 'get') {
|
||||
const mailboxId = this.getNodeParameter('mailboxId', i) as string;
|
||||
responseData = await helpscoutApiRequest.call(this, 'GET', `/v2/mailboxes/${mailboxId}`, {}, qs);
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/mailboxes/list
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
if (returnAll) {
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.mailboxes', 'GET', '/v2/mailboxes', {}, qs);
|
||||
} else {
|
||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.mailboxes', 'GET', '/v2/mailboxes', {}, qs);
|
||||
responseData = responseData.splice(0, qs.limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'thread') {
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/chat
|
||||
if (operation === 'create') {
|
||||
const conversationId = this.getNodeParameter('conversationId', i) as string;
|
||||
const type = this.getNodeParameter('type', i) as string;
|
||||
const text = this.getNodeParameter('text', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const attachments = this.getNodeParameter('attachmentsUi', i) as IDataObject;
|
||||
const body: IThread = {
|
||||
text,
|
||||
attachments: [],
|
||||
};
|
||||
Object.assign(body, additionalFields);
|
||||
if (additionalFields.customerId) {
|
||||
body.customer = {
|
||||
id: additionalFields.customerId,
|
||||
};
|
||||
//@ts-ignore
|
||||
delete body.customerId;
|
||||
}
|
||||
if (additionalFields.customerEmail) {
|
||||
body.customer = {
|
||||
email: additionalFields.customerEmail,
|
||||
};
|
||||
//@ts-ignore
|
||||
delete body.customerEmail;
|
||||
}
|
||||
if (body.customer === undefined) {
|
||||
throw new Error('Either customer email or customer ID must be set');
|
||||
}
|
||||
if (attachments) {
|
||||
if (attachments.attachmentsValues
|
||||
&& (attachments.attachmentsValues as IDataObject[]).length !== 0) {
|
||||
body.attachments?.push.apply(body.attachments, attachments.attachmentsValues as IAttachment[]);
|
||||
}
|
||||
if (attachments.attachmentsBinary
|
||||
&& (attachments.attachmentsBinary as IDataObject[]).length !== 0
|
||||
&& items[i].binary) {
|
||||
const mapFunction = (value: IDataObject): IAttachment => {
|
||||
const binaryProperty = (items[i].binary as IBinaryKeyData)[value.property as string];
|
||||
if (binaryProperty) {
|
||||
return {
|
||||
fileName: binaryProperty.fileName || 'unknown',
|
||||
data: binaryProperty.data,
|
||||
mimeType: binaryProperty.mimeType,
|
||||
};
|
||||
} else {
|
||||
throw new Error(`Binary property ${value.property} does not exist on input`);
|
||||
}
|
||||
};
|
||||
body.attachments?.push.apply(body.attachments, (attachments.attachmentsBinary as IDataObject[]).map(mapFunction) as IAttachment[]);
|
||||
}
|
||||
}
|
||||
responseData = await helpscoutApiRequest.call(this, 'POST', `/v2/conversations/${conversationId}/chats`, body);
|
||||
responseData = { success: true };
|
||||
}
|
||||
//https://developer.helpscout.com/mailbox-api/endpoints/conversations/threads/list
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const conversationId = this.getNodeParameter('conversationId', i) as string;
|
||||
if (returnAll) {
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.threads', 'GET', `/v2/conversations/${conversationId}/threads`);
|
||||
} else {
|
||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await helpscoutApiRequestAllItems.call(this, '_embedded.threads', 'GET', `/v2/conversations/${conversationId}/threads`, {}, qs);
|
||||
responseData = responseData.splice(0, qs.limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else if (responseData !== undefined) {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
203
packages/nodes-base/nodes/HelpScout/HelpScoutTrigger.node.ts
Normal file
203
packages/nodes-base/nodes/HelpScout/HelpScoutTrigger.node.ts
Normal file
|
@ -0,0 +1,203 @@
|
|||
import {
|
||||
IHookFunctions,
|
||||
IWebhookFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
IWebhookResponseData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
helpscoutApiRequest,
|
||||
helpscoutApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import { createHmac } from 'crypto';
|
||||
|
||||
export class HelpScoutTrigger implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'HelpScout Trigger',
|
||||
name: 'helpScoutTrigger',
|
||||
icon: 'file:helpScout.png',
|
||||
group: ['trigger'],
|
||||
version: 1,
|
||||
description: 'Starts the workflow when HelpScout events occure.',
|
||||
defaults: {
|
||||
name: 'HelpScout Trigger',
|
||||
color: '#1392ee',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'helpScoutOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
name: 'default',
|
||||
httpMethod: 'POST',
|
||||
responseMode: 'onReceived',
|
||||
path: 'webhook',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Events',
|
||||
name: 'events',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
|
||||
{
|
||||
name: 'Conversation - Assigned',
|
||||
value: 'convo.assigned',
|
||||
},
|
||||
{
|
||||
name: 'Conversation - Created',
|
||||
value: 'convo.created',
|
||||
},
|
||||
{
|
||||
name: 'Conversation - Deleted',
|
||||
value: 'convo.deleted',
|
||||
},
|
||||
{
|
||||
name: 'Conversation - Merged',
|
||||
value: 'convo.merged',
|
||||
},
|
||||
{
|
||||
name: 'Conversation - Moved',
|
||||
value: 'convo.moved',
|
||||
},
|
||||
{
|
||||
name: 'Conversation - Status',
|
||||
value: 'convo.status',
|
||||
},
|
||||
{
|
||||
name: 'Conversation - Tags',
|
||||
value: 'convo.tags',
|
||||
},
|
||||
{
|
||||
name: 'Conversation Agent Reply - Created',
|
||||
value: 'convo.agent.reply.created',
|
||||
},
|
||||
{
|
||||
name: 'Conversation Customer Reply - Created',
|
||||
value: 'convo.customer.reply.created',
|
||||
},
|
||||
{
|
||||
name: 'Conversation Note - Created',
|
||||
value: 'convo.note.created',
|
||||
},
|
||||
{
|
||||
name: 'Customer - Created',
|
||||
value: 'customer.created',
|
||||
},
|
||||
{
|
||||
name: 'Rating - Received',
|
||||
value: 'satisfaction.ratings',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
// @ts-ignore (because of request)
|
||||
webhookMethods = {
|
||||
default: {
|
||||
async checkExists(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const events = this.getNodeParameter('events') as string;
|
||||
|
||||
// Check all the webhooks which exist already if it is identical to the
|
||||
// one that is supposed to get created.
|
||||
const endpoint = '/v2/webhooks';
|
||||
const data = await helpscoutApiRequestAllItems.call(this, '_embedded.webhooks', 'GET', endpoint, {});
|
||||
|
||||
for (const webhook of data) {
|
||||
if (webhook.url === webhookUrl) {
|
||||
for (const event of events) {
|
||||
if (!webhook.events.includes(event)
|
||||
&& webhook.state === 'enabled') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set webhook-id to be sure that it can be deleted
|
||||
webhookData.webhookId = webhook.id as string;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async create(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
const events = this.getNodeParameter('events') as string;
|
||||
|
||||
const endpoint = '/v2/webhooks';
|
||||
|
||||
const body = {
|
||||
url: webhookUrl,
|
||||
events,
|
||||
secret: Math.random().toString(36).substring(2, 15),
|
||||
};
|
||||
|
||||
const responseData = await helpscoutApiRequest.call(this, 'POST', endpoint, body, {}, undefined, { resolveWithFullResponse: true });
|
||||
|
||||
if (responseData.headers['resource-id'] === undefined) {
|
||||
// Required data is missing so was not successful
|
||||
return false;
|
||||
}
|
||||
|
||||
webhookData.webhookId = responseData.headers['resource-id'] as string;
|
||||
webhookData.secret = body.secret;
|
||||
return true;
|
||||
},
|
||||
async delete(this: IHookFunctions): Promise<boolean> {
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
if (webhookData.webhookId !== undefined) {
|
||||
|
||||
const endpoint = `/v2/webhooks/${webhookData.webhookId}`;
|
||||
try {
|
||||
await helpscoutApiRequest.call(this, 'DELETE', endpoint);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove from the static workflow data so that it is clear
|
||||
// that no webhooks are registred anymore
|
||||
delete webhookData.webhookId;
|
||||
delete webhookData.secret;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||
const req = this.getRequestObject();
|
||||
const bodyData = this.getBodyData();
|
||||
const headerData = this.getHeaderData() as IDataObject;
|
||||
const webhookData = this.getWorkflowStaticData('node');
|
||||
if (headerData['x-helpscout-signature'] === undefined) {
|
||||
return {};
|
||||
}
|
||||
//@ts-ignore
|
||||
const computedSignature = createHmac('sha1', webhookData.secret as string).update(req.rawBody).digest('base64');
|
||||
if (headerData['x-helpscout-signature'] !== computedSignature) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
workflowData: [
|
||||
this.helpers.returnJsonArray(bodyData),
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
97
packages/nodes-base/nodes/HelpScout/MailboxDescription.ts
Normal file
97
packages/nodes-base/nodes/HelpScout/MailboxDescription.ts
Normal file
|
@ -0,0 +1,97 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const mailboxOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'mailbox',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get data of a mailbox',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get all mailboxes',
|
||||
},
|
||||
],
|
||||
default: 'get',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const mailboxFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* mailbox:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Mailbox ID',
|
||||
name: 'mailboxId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'mailbox',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* mailbox:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'mailbox',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'mailbox',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
] as INodeProperties[];
|
297
packages/nodes-base/nodes/HelpScout/ThreadDescription.ts
Normal file
297
packages/nodes-base/nodes/HelpScout/ThreadDescription.ts
Normal file
|
@ -0,0 +1,297 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const threadOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a new chat thread',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get all chat threads',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const threadFields = [
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* thread:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Conversation ID',
|
||||
name: 'conversationId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'conversation ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Chat',
|
||||
value: 'chat'
|
||||
},
|
||||
{
|
||||
name: 'Customer',
|
||||
value: 'customer'
|
||||
},
|
||||
{
|
||||
name: 'Note',
|
||||
value: 'note'
|
||||
},
|
||||
{
|
||||
name: 'Phone',
|
||||
value: 'phone'
|
||||
},
|
||||
{
|
||||
name: 'Reply',
|
||||
value: 'reply'
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
},
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The chat text',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Created At',
|
||||
name: 'createdAt',
|
||||
type: 'dateTime',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Customer Email',
|
||||
name: 'customerEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Customer ID',
|
||||
name: 'customerId',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Draft',
|
||||
name: 'draft',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
'/type': [
|
||||
'note',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'If set to true, a draft reply is created',
|
||||
},
|
||||
{
|
||||
displayName: 'Imported',
|
||||
name: 'imported',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'When imported is set to true, no outgoing emails or notifications will be generated.',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Attachments',
|
||||
name: 'attachmentsUi',
|
||||
placeholder: 'Add Attachments',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'attachmentsValues',
|
||||
displayName: 'Attachments Values',
|
||||
values: [
|
||||
{
|
||||
displayName: 'FileName',
|
||||
name: 'fileName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Attachment’s file name',
|
||||
},
|
||||
{
|
||||
displayName: 'Mime Type',
|
||||
name: 'mimeType',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Attachment’s mime type',
|
||||
},
|
||||
{
|
||||
displayName: 'Data',
|
||||
name: 'data',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'ZXhhbXBsZSBmaWxl',
|
||||
description: 'Base64-encoded stream of data.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'attachmentsBinary',
|
||||
displayName: 'Attachments Binary',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Property',
|
||||
name: 'property',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
description: 'Name of the binary properties which contain data which should be added to email as attachment',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
default: '',
|
||||
description: 'Array of supported attachments to add to the message.',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* thread:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Conversation ID',
|
||||
name: 'conversationId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'conversation ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'thread',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 50,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
] as INodeProperties[];
|
15
packages/nodes-base/nodes/HelpScout/ThreadInterface.ts
Normal file
15
packages/nodes-base/nodes/HelpScout/ThreadInterface.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { IDataObject } from 'n8n-workflow';
|
||||
|
||||
export interface IAttachment {
|
||||
fileName?: string;
|
||||
mimeType?: string;
|
||||
data?: string;
|
||||
}
|
||||
|
||||
export interface IThread {
|
||||
createdAt?: string;
|
||||
customer?: IDataObject;
|
||||
imported?: boolean;
|
||||
text?: string;
|
||||
attachments?: IAttachment[];
|
||||
}
|
BIN
packages/nodes-base/nodes/HelpScout/helpScout.png
Normal file
BIN
packages/nodes-base/nodes/HelpScout/helpScout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 870 B |
|
@ -0,0 +1,73 @@
|
|||
import { OptionsWithUri } from 'request';
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
import {
|
||||
IDataObject
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export async function microsoftApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: uri || `https://graph.microsoft.com/v1.0/me${resource}`,
|
||||
json: true
|
||||
};
|
||||
try {
|
||||
if (Object.keys(headers).length !== 0) {
|
||||
options.headers = Object.assign({}, options.headers, headers);
|
||||
}
|
||||
//@ts-ignore
|
||||
return await this.helpers.requestOAuth.call(this, 'microsoftExcelOAuth2Api', options);
|
||||
} catch (error) {
|
||||
if (error.response && error.response.body && error.response.body.error && error.response.body.error.message) {
|
||||
// Try to return the error prettier
|
||||
throw new Error(`Microsoft error response [${error.statusCode}]: ${error.response.body.error.message}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function microsoftApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
let uri: string | undefined;
|
||||
query['$top'] = 100;
|
||||
|
||||
do {
|
||||
responseData = await microsoftApiRequest.call(this, method, endpoint, body, query, uri);
|
||||
uri = responseData['@odata.nextLink'];
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
} while (
|
||||
responseData['@odata.nextLink'] !== undefined
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export async function microsoftApiRequestAllItemsSkip(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
query['$top'] = 100;
|
||||
query['$skip'] = 0;
|
||||
|
||||
do {
|
||||
responseData = await microsoftApiRequest.call(this, method, endpoint, body, query);
|
||||
query['$skip'] += query['$top'];
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
} while (
|
||||
responseData['value'].length !== 0
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
421
packages/nodes-base/nodes/Microsoft/Excel/MicrosoftExcel.node.ts
Normal file
421
packages/nodes-base/nodes/Microsoft/Excel/MicrosoftExcel.node.ts
Normal file
|
@ -0,0 +1,421 @@
|
|||
import {
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeTypeDescription,
|
||||
INodeType,
|
||||
ILoadOptionsFunctions,
|
||||
INodePropertyOptions,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
microsoftApiRequest,
|
||||
microsoftApiRequestAllItems,
|
||||
microsoftApiRequestAllItemsSkip,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import {
|
||||
workbookOperations,
|
||||
workbookFields,
|
||||
} from './WorkbookDescription';
|
||||
|
||||
import {
|
||||
worksheetOperations,
|
||||
worksheetFields,
|
||||
} from './WorksheetDescription';
|
||||
|
||||
import {
|
||||
tableOperations,
|
||||
tableFields,
|
||||
} from './TableDescription';
|
||||
|
||||
export class MicrosoftExcel implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Microsoft Excel',
|
||||
name: 'microsoftExcel',
|
||||
icon: 'file:excel.png',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Microsoft Excel API.',
|
||||
defaults: {
|
||||
name: 'Microsoft Excel',
|
||||
color: '#1c6d40',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'microsoftExcelOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Table',
|
||||
value: 'table',
|
||||
description: 'Represents an Excel table.',
|
||||
},
|
||||
{
|
||||
name: 'Workbook',
|
||||
value: 'workbook',
|
||||
description: 'Workbook is the top level object which contains related workbook objects such as worksheets, tables, ranges, etc.',
|
||||
},
|
||||
{
|
||||
name: 'Worksheet',
|
||||
value: 'worksheet',
|
||||
description: 'An Excel worksheet is a grid of cells. It can contain data, tables, charts, etc.',
|
||||
},
|
||||
],
|
||||
default: 'workbook',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
...workbookOperations,
|
||||
...workbookFields,
|
||||
...worksheetOperations,
|
||||
...worksheetFields,
|
||||
...tableOperations,
|
||||
...tableFields,
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
// Get all the workbooks to display them to user so that he can
|
||||
// select them easily
|
||||
async getWorkbooks(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const qs: IDataObject = {
|
||||
select: 'id,name',
|
||||
};
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const workbooks = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/root/search(q='.xlsx')`, {}, qs);
|
||||
for (const workbook of workbooks) {
|
||||
const workbookName = workbook.name;
|
||||
const workbookId = workbook.id;
|
||||
returnData.push({
|
||||
name: workbookName,
|
||||
value: workbookId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the worksheets to display them to user so that he can
|
||||
// select them easily
|
||||
async getworksheets(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const workbookId = this.getCurrentNodeParameter('workbook');
|
||||
const qs: IDataObject = {
|
||||
select: 'id,name',
|
||||
};
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const worksheets = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets`, {}, qs);
|
||||
for (const worksheet of worksheets) {
|
||||
const worksheetName = worksheet.name;
|
||||
const worksheetId = worksheet.id;
|
||||
returnData.push({
|
||||
name: worksheetName,
|
||||
value: worksheetId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the tables to display them to user so that he can
|
||||
// select them easily
|
||||
async getTables(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const workbookId = this.getCurrentNodeParameter('workbook');
|
||||
const worksheetId = this.getCurrentNodeParameter('worksheet');
|
||||
const qs: IDataObject = {
|
||||
select: 'id,name',
|
||||
};
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const tables = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables`, {}, qs);
|
||||
for (const table of tables) {
|
||||
const tableName = table.name;
|
||||
const tableId = table.id;
|
||||
returnData.push({
|
||||
name: tableName,
|
||||
value: tableId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
let qs: IDataObject = {};
|
||||
const result: IDataObject[] = [];
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
|
||||
if (resource === 'table') {
|
||||
//https://docs.microsoft.com/en-us/graph/api/table-post-rows?view=graph-rest-1.0&tabs=http
|
||||
if (operation === 'addRow') {
|
||||
// TODO: At some point it should be possible to use item dependent parameters.
|
||||
// Is however important to then not make one separate request each.
|
||||
const workbookId = this.getNodeParameter('workbook', 0) as string;
|
||||
const worksheetId = this.getNodeParameter('worksheet', 0) as string;
|
||||
const tableId = this.getNodeParameter('table', 0) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject;
|
||||
const body: IDataObject = {};
|
||||
|
||||
if (additionalFields.index) {
|
||||
body.index = additionalFields.index as number;
|
||||
}
|
||||
|
||||
// Get table columns to eliminate any columns not needed on the input
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs);
|
||||
const columns = responseData.value.map((column: IDataObject) => (column.name));
|
||||
|
||||
const rows: any[][] = []; // tslint:disable-line:no-any
|
||||
|
||||
// Bring the items into the correct format
|
||||
for (const item of items) {
|
||||
const row = [];
|
||||
for (const column of columns) {
|
||||
row.push(item.json[column]);
|
||||
}
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
body.values = rows;
|
||||
const { id } = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/createSession`, { persistChanges: true });
|
||||
responseData = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows/add`, body, {}, '', { 'workbook-session-id': id });
|
||||
await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/closeSession`, {}, {}, '', { 'workbook-session-id': id });
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else if (responseData !== undefined) {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/graph/api/table-list-columns?view=graph-rest-1.0&tabs=http
|
||||
if (operation === 'getColumns') {
|
||||
for (let i = 0; i < length; i++) {
|
||||
qs = {};
|
||||
const workbookId = this.getNodeParameter('workbook', i) as string;
|
||||
const worksheetId = this.getNodeParameter('worksheet', i) as string;
|
||||
const tableId = this.getNodeParameter('table', i) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const rawData = this.getNodeParameter('rawData', i) as boolean;
|
||||
if (rawData) {
|
||||
const filters = this.getNodeParameter('filters', i) as IDataObject;
|
||||
if (filters.fields) {
|
||||
qs['$select'] = filters.fields;
|
||||
}
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs);
|
||||
} else {
|
||||
qs['$top'] = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs);
|
||||
responseData = responseData.value;
|
||||
}
|
||||
if (!rawData) {
|
||||
responseData = responseData.map((column: IDataObject) => ({ name: column.name }));
|
||||
} else {
|
||||
const dataProperty = this.getNodeParameter('dataProperty', i) as string;
|
||||
responseData = { [dataProperty] : responseData };
|
||||
}
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else if (responseData !== undefined) {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/graph/api/table-list-rows?view=graph-rest-1.0&tabs=http
|
||||
if (operation === 'getRows') {
|
||||
for (let i = 0; i < length; i++) {
|
||||
qs = {};
|
||||
const workbookId = this.getNodeParameter('workbook', i) as string;
|
||||
const worksheetId = this.getNodeParameter('worksheet', i) as string;
|
||||
const tableId = this.getNodeParameter('table', i) as string;
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const rawData = this.getNodeParameter('rawData', i) as boolean;
|
||||
if (rawData) {
|
||||
const filters = this.getNodeParameter('filters', i) as IDataObject;
|
||||
if (filters.fields) {
|
||||
qs['$select'] = filters.fields;
|
||||
}
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, qs);
|
||||
} else {
|
||||
const rowsQs = { ...qs };
|
||||
rowsQs['$top'] = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, rowsQs);
|
||||
responseData = responseData.value;
|
||||
}
|
||||
if (!rawData) {
|
||||
const columnsQs = { ...qs };
|
||||
columnsQs['$select'] = 'name';
|
||||
// TODO: That should probably be cached in the future
|
||||
let columns = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, columnsQs);
|
||||
//@ts-ignore
|
||||
columns = columns.map(column => column.name);
|
||||
for (let i = 0; i < responseData.length; i++) {
|
||||
const object: IDataObject = {};
|
||||
for (let y = 0; y < columns.length; y++) {
|
||||
object[columns[y]] = responseData[i].values[0][y];
|
||||
}
|
||||
returnData.push({ ...object });
|
||||
}
|
||||
} else {
|
||||
const dataProperty = this.getNodeParameter('dataProperty', i) as string;
|
||||
returnData.push({ [dataProperty]: responseData });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (operation === 'lookup') {
|
||||
for (let i = 0; i < length; i++) {
|
||||
qs = {};
|
||||
const workbookId = this.getNodeParameter('workbook', i) as string;
|
||||
const worksheetId = this.getNodeParameter('worksheet', i) as string;
|
||||
const tableId = this.getNodeParameter('table', i) as string;
|
||||
const lookupColumn = this.getNodeParameter('lookupColumn', i) as string;
|
||||
const lookupValue = this.getNodeParameter('lookupValue', i) as string;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
|
||||
responseData = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/rows`, {}, {});
|
||||
|
||||
qs['$select'] = 'name';
|
||||
// TODO: That should probably be cached in the future
|
||||
let columns = await microsoftApiRequestAllItemsSkip.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/tables/${tableId}/columns`, {}, qs);
|
||||
columns = columns.map((column: IDataObject) => column.name);
|
||||
|
||||
if (!columns.includes(lookupColumn)) {
|
||||
throw new Error(`Column ${lookupColumn} does not exist on the table selected`);
|
||||
}
|
||||
|
||||
result.length = 0;
|
||||
for (let i = 0; i < responseData.length; i++) {
|
||||
const object: IDataObject = {};
|
||||
for (let y = 0; y < columns.length; y++) {
|
||||
object[columns[y]] = responseData[i].values[0][y];
|
||||
}
|
||||
result.push({ ...object });
|
||||
}
|
||||
|
||||
if (options.returnAllMatches) {
|
||||
responseData = result.filter((data: IDataObject) => {
|
||||
return (data[lookupColumn]?.toString() === lookupValue );
|
||||
});
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else {
|
||||
responseData = result.find((data: IDataObject) => {
|
||||
return (data[lookupColumn]?.toString() === lookupValue );
|
||||
});
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'workbook') {
|
||||
for (let i = 0; i < length; i++) {
|
||||
qs = {};
|
||||
//https://docs.microsoft.com/en-us/graph/api/worksheetcollection-add?view=graph-rest-1.0&tabs=http
|
||||
if (operation === 'addWorksheet') {
|
||||
const workbookId = this.getNodeParameter('workbook', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: IDataObject = {};
|
||||
if (additionalFields.name) {
|
||||
body.name = additionalFields.name;
|
||||
}
|
||||
const { id } = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/createSession`, { persistChanges: true });
|
||||
responseData = await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/worksheets/add`, body, {}, '', { 'workbook-session-id': id });
|
||||
await microsoftApiRequest.call(this, 'POST', `/drive/items/${workbookId}/workbook/closeSession`, {}, {}, '', { 'workbook-session-id': id });
|
||||
}
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const filters = this.getNodeParameter('filters', i) as IDataObject;
|
||||
if (filters.fields) {
|
||||
qs['$select'] = filters.fields;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/root/search(q='.xlsx')`, {}, qs);
|
||||
} else {
|
||||
qs['$top'] = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/root/search(q='.xlsx')`, {}, qs);
|
||||
responseData = responseData.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else if (responseData !== undefined) {
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'worksheet') {
|
||||
for (let i = 0; i < length; i++) {
|
||||
qs = {};
|
||||
//https://docs.microsoft.com/en-us/graph/api/workbook-list-worksheets?view=graph-rest-1.0&tabs=http
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const workbookId = this.getNodeParameter('workbook', i) as string;
|
||||
const filters = this.getNodeParameter('filters', i) as IDataObject;
|
||||
if (filters.fields) {
|
||||
qs['$select'] = filters.fields;
|
||||
}
|
||||
if (returnAll === true) {
|
||||
responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/items/${workbookId}/workbook/worksheets`, {}, qs);
|
||||
} else {
|
||||
qs['$top'] = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets`, {}, qs);
|
||||
responseData = responseData.value;
|
||||
}
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/graph/api/worksheet-range?view=graph-rest-1.0&tabs=http
|
||||
if (operation === 'getContent') {
|
||||
const workbookId = this.getNodeParameter('workbook', i) as string;
|
||||
const worksheetId = this.getNodeParameter('worksheet', i) as string;
|
||||
const range = this.getNodeParameter('range', i) as string;
|
||||
const rawData = this.getNodeParameter('rawData', i) as boolean;
|
||||
if (rawData) {
|
||||
const filters = this.getNodeParameter('filters', i) as IDataObject;
|
||||
if (filters.fields) {
|
||||
qs['$select'] = filters.fields;
|
||||
}
|
||||
}
|
||||
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${workbookId}/workbook/worksheets/${worksheetId}/range(address='${range}')`, {}, qs);
|
||||
|
||||
if (!rawData) {
|
||||
const keyRow = this.getNodeParameter('keyRow', i) as number;
|
||||
const dataStartRow = this.getNodeParameter('dataStartRow', i) as number;
|
||||
if (responseData.values === null) {
|
||||
throw new Error('Range did not return data');
|
||||
}
|
||||
const keyValues = responseData.values[keyRow];
|
||||
for (let i = dataStartRow; i < responseData.values.length; i++) {
|
||||
const object: IDataObject = {};
|
||||
for (let y = 0; y < keyValues.length; y++) {
|
||||
object[keyValues[y]] = responseData.values[i][y];
|
||||
}
|
||||
returnData.push({ ...object });
|
||||
}
|
||||
} else {
|
||||
const dataProperty = this.getNodeParameter('dataProperty', i) as string;
|
||||
returnData.push({ [dataProperty]: responseData });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
625
packages/nodes-base/nodes/Microsoft/Excel/TableDescription.ts
Normal file
625
packages/nodes-base/nodes/Microsoft/Excel/TableDescription.ts
Normal file
|
@ -0,0 +1,625 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const tableOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Add Row',
|
||||
value: 'addRow',
|
||||
description: 'Adds rows to the end of the table'
|
||||
},
|
||||
{
|
||||
name: 'Get Columns',
|
||||
value: 'getColumns',
|
||||
description: 'Retrieve a list of tablecolumns',
|
||||
},
|
||||
{
|
||||
name: 'Get Rows',
|
||||
value: 'getRows',
|
||||
description: 'Retrieve a list of tablerows',
|
||||
},
|
||||
{
|
||||
name: 'Lookup',
|
||||
value: 'lookup',
|
||||
description: 'Looks for a specific column value and then returns the matching row'
|
||||
},
|
||||
],
|
||||
default: 'addRow',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const tableFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* table:addRow */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addRow',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Worksheet',
|
||||
name: 'worksheet',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getworksheets',
|
||||
loadOptionsDependsOn: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addRow',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Table',
|
||||
name: 'table',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTables',
|
||||
loadOptionsDependsOn: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addRow',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addRow',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Index',
|
||||
name: 'index',
|
||||
type: 'number',
|
||||
default: 0,
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
description: `Specifies the relative position of the new row. If not defined,</br>
|
||||
the addition happens at the end. Any rows below the inserted row are shifted downwards. Zero-indexed`,
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* table:getRows */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Worksheet',
|
||||
name: 'worksheet',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getworksheets',
|
||||
loadOptionsDependsOn: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Table',
|
||||
name: 'table',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTables',
|
||||
loadOptionsDependsOn: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 500,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'RAW Data',
|
||||
name: 'rawData',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If the data should be returned RAW instead of parsed into keys according to their header.',
|
||||
},
|
||||
{
|
||||
displayName: 'Data Property',
|
||||
name: 'dataProperty',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows'
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
rawData: [
|
||||
true,
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The name of the property into which to write the RAW data.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getRows',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
rawData: [
|
||||
true,
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `Fields the response will containt. Multiple can be added separated by ,.`,
|
||||
},
|
||||
]
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* table:getColumns */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Worksheet',
|
||||
name: 'worksheet',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getworksheets',
|
||||
loadOptionsDependsOn: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Table',
|
||||
name: 'table',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTables',
|
||||
loadOptionsDependsOn: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 500,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'RAW Data',
|
||||
name: 'rawData',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If the data should be returned RAW instead of parsed into keys according to their header.',
|
||||
},
|
||||
{
|
||||
displayName: 'Data Property',
|
||||
name: 'dataProperty',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns'
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
rawData: [
|
||||
true,
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The name of the property into which to write the RAW data.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getColumns',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
rawData: [
|
||||
true
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `Fields the response will containt. Multiple can be added separated by ,.`,
|
||||
},
|
||||
]
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* table:lookup */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'lookup',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Worksheet',
|
||||
name: 'worksheet',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getworksheets',
|
||||
loadOptionsDependsOn: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'lookup',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Table',
|
||||
name: 'table',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getTables',
|
||||
loadOptionsDependsOn: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'lookup',
|
||||
],
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Lookup Column',
|
||||
name: 'lookupColumn',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'Email',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
operation: [
|
||||
'lookup'
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The name of the column in which to look for value.',
|
||||
},
|
||||
{
|
||||
displayName: 'Lookup Value',
|
||||
name: 'lookupValue',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'frank@example.com',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
operation: [
|
||||
'lookup'
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The value to look for in column.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'table',
|
||||
],
|
||||
operation: [
|
||||
'lookup',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Return All Matches',
|
||||
name: 'returnAllMatches',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'By default only the first result gets returned. If options gets set all found matches get returned.',
|
||||
},
|
||||
],
|
||||
}
|
||||
] as INodeProperties[];
|
154
packages/nodes-base/nodes/Microsoft/Excel/WorkbookDescription.ts
Normal file
154
packages/nodes-base/nodes/Microsoft/Excel/WorkbookDescription.ts
Normal file
|
@ -0,0 +1,154 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const workbookOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Add Worksheet',
|
||||
value: 'addWorksheet',
|
||||
description: 'Adds a new worksheet to the workbook.',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get data of all workbooks',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const workbookFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* workbook:addWorksheet */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addWorksheet',
|
||||
],
|
||||
resource: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'addWorksheet',
|
||||
],
|
||||
resource: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `The name of the worksheet to be added. If specified, name should be unqiue. </BR>
|
||||
If not specified, Excel determines the name of the new worksheet.`,
|
||||
},
|
||||
]
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* workbook:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'workbook',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 500,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `Fields the response will containt. Multiple can be added separated by ,.`,
|
||||
},
|
||||
]
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,303 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const worksheetOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get all worksheets',
|
||||
},
|
||||
{
|
||||
name: 'Get Content',
|
||||
value: 'getContent',
|
||||
description: 'Get worksheet content',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const worksheetFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* worksheet:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 500,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `Fields the response will containt. Multiple can be added separated by ,.`,
|
||||
},
|
||||
]
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* worksheet:getContent */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Workbook',
|
||||
name: 'workbook',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getWorkbooks',
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Worksheet',
|
||||
name: 'worksheet',
|
||||
type: 'options',
|
||||
required: true,
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getworksheets',
|
||||
loadOptionsDependsOn: [
|
||||
'workbook',
|
||||
],
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Range',
|
||||
name: 'range',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: 'A1:C3',
|
||||
required: true,
|
||||
description: 'The address or the name of the range. If not specified, the entire worksheet range is returned.',
|
||||
},
|
||||
{
|
||||
displayName: 'RAW Data',
|
||||
name: 'rawData',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If the data should be returned RAW instead of parsed into keys according to their header.',
|
||||
},
|
||||
{
|
||||
displayName: 'Data Property',
|
||||
name: 'dataProperty',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent'
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
rawData: [
|
||||
true,
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The name of the property into which to write the RAW data.',
|
||||
},
|
||||
{
|
||||
displayName: 'Data Start Row',
|
||||
name: 'dataStartRow',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
},
|
||||
default: 1,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
hide: {
|
||||
rawData: [
|
||||
true
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'Index of the first row which contains<br />the actual data and not the keys. Starts with 0.',
|
||||
},
|
||||
{
|
||||
displayName: 'Key Row',
|
||||
name: 'keyRow',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
},
|
||||
hide: {
|
||||
rawData: [
|
||||
true
|
||||
],
|
||||
},
|
||||
},
|
||||
default: 0,
|
||||
description: 'Index of the row which contains the keys. Starts at 0.<br />The incoming node data is matched to the keys for assignment. The matching is case sensitve.',
|
||||
},
|
||||
{
|
||||
displayName: 'Filters',
|
||||
name: 'filters',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Filter',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getContent',
|
||||
],
|
||||
resource: [
|
||||
'worksheet',
|
||||
],
|
||||
rawData: [
|
||||
true,
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `Fields the response will containt. Multiple can be added separated by ,.`,
|
||||
},
|
||||
]
|
||||
},
|
||||
] as INodeProperties[];
|
BIN
packages/nodes-base/nodes/Microsoft/Excel/excel.png
Normal file
BIN
packages/nodes-base/nodes/Microsoft/Excel/excel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
377
packages/nodes-base/nodes/Microsoft/OneDrive/FileDescription.ts
Normal file
377
packages/nodes-base/nodes/Microsoft/OneDrive/FileDescription.ts
Normal file
|
@ -0,0 +1,377 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const fileOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Copy',
|
||||
value: 'copy',
|
||||
description: 'Copy a file',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a file',
|
||||
},
|
||||
{
|
||||
name: 'Download',
|
||||
value: 'download',
|
||||
description: 'Download a file',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
description: 'Get a file',
|
||||
},
|
||||
{
|
||||
name: 'Search',
|
||||
value: 'search',
|
||||
description: 'Search a file',
|
||||
},
|
||||
{
|
||||
name: 'Upload',
|
||||
value: 'upload',
|
||||
description: 'Upload a file up to 4MB in size',
|
||||
},
|
||||
],
|
||||
default: 'upload',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const fileFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* file:copy */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'File ID',
|
||||
name: 'fileId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'copy',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'File ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'copy',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `The new name for the copy. If this isn't provided, the same name will be used as the original.`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Parent Reference',
|
||||
name: 'parentReference',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Parent Reference',
|
||||
description: 'Reference to the parent item the copy will be created in <a href="https://docs.microsoft.com/en-us/onedrive/developer/rest-api/resources/itemreference?view=odsp-graph-online"> Details </a>',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'copy',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Drive ID',
|
||||
name: 'driveId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifier of the drive instance that contains the item.',
|
||||
},
|
||||
{
|
||||
displayName: 'Drive Type',
|
||||
name: 'driveType',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifies the type of drive.',
|
||||
},
|
||||
{
|
||||
displayName: 'ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifier of the item in the drive.',
|
||||
},
|
||||
{
|
||||
displayName: 'List ID',
|
||||
name: 'listId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifier of the list.',
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The name of the item being referenced',
|
||||
},
|
||||
{
|
||||
displayName: 'Path',
|
||||
name: 'path',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Path that can be used to navigate to the item',
|
||||
},
|
||||
{
|
||||
displayName: 'Share ID',
|
||||
name: 'shareId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifier for a shared resource that can be accessed via the Shares API.',
|
||||
},
|
||||
{
|
||||
displayName: 'Site ID',
|
||||
name: 'siteId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifier of the site.',
|
||||
},
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* file:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'File ID',
|
||||
name: 'fileId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Field ID',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* file:download */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'File ID',
|
||||
name: 'fileId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'download',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'File ID',
|
||||
},
|
||||
{
|
||||
displayName: 'Binary Property',
|
||||
name: 'binaryPropertyName',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: 'data',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'download'
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'Name of the binary property to which to<br />write the data of the read file.',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* file:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'File ID',
|
||||
name: 'fileId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Field ID',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* file:search */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'search',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: `The query text used to search for items. Values may be matched
|
||||
across several fields including filename, metadata, and file content.`,
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* file:upload */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'File Name',
|
||||
name: 'fileName',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'upload',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'The name the file should be saved as.',
|
||||
},
|
||||
{
|
||||
displayName: 'Parent ID',
|
||||
name: 'parentId',
|
||||
required: true,
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'upload',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'ID of the parent folder that will contain the file.',
|
||||
},
|
||||
{
|
||||
displayName: 'Binary Data',
|
||||
name: 'binaryData',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'upload',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'If the data to upload should be taken from binary field.',
|
||||
},
|
||||
{
|
||||
displayName: 'File Content',
|
||||
name: 'fileContent',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
binaryData: [
|
||||
false,
|
||||
],
|
||||
operation: [
|
||||
'upload',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
|
||||
},
|
||||
placeholder: '',
|
||||
description: 'The text content of the file.',
|
||||
},
|
||||
{
|
||||
displayName: 'Binary Property',
|
||||
name: 'binaryPropertyName',
|
||||
type: 'string',
|
||||
default: 'data',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
binaryData: [
|
||||
true,
|
||||
],
|
||||
operation: [
|
||||
'upload',
|
||||
],
|
||||
resource: [
|
||||
'file',
|
||||
],
|
||||
},
|
||||
|
||||
},
|
||||
placeholder: '',
|
||||
description: 'Name of the binary property which contains<br />the data for the file.',
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,101 @@
|
|||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const folderOperations = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'folder',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Create',
|
||||
value: 'create',
|
||||
description: 'Create a folder',
|
||||
},
|
||||
{
|
||||
name: 'Get Children',
|
||||
value: 'getChildren',
|
||||
description: 'Get items inside a folder',
|
||||
},
|
||||
{
|
||||
name: 'Search',
|
||||
value: 'search',
|
||||
description: 'Search a folder',
|
||||
},
|
||||
],
|
||||
default: 'getChildren',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
||||
export const folderFields = [
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* folder:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
required: true,
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
resource: [
|
||||
'folder',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: `Folder's name`,
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* folder:getChildren */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Folder ID',
|
||||
name: 'folderId',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getChildren',
|
||||
],
|
||||
resource: [
|
||||
'folder',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: 'Folder ID',
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* folder:search */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'search',
|
||||
],
|
||||
resource: [
|
||||
'folder',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '',
|
||||
description: `The query text used to search for items. Values may be matched
|
||||
across several fields including filename, metadata, and file content.`,
|
||||
},
|
||||
] as INodeProperties[];
|
|
@ -0,0 +1,84 @@
|
|||
import {
|
||||
OptionsWithUri
|
||||
} from 'request';
|
||||
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IExecuteSingleFunctions,
|
||||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IDataObject
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export async function microsoftApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, headers: IDataObject = {}, option: IDataObject = { json: true }): Promise<any> { // tslint:disable-line:no-any
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs,
|
||||
uri: uri || `https://graph.microsoft.com/v1.0/me${resource}`,
|
||||
};
|
||||
try {
|
||||
Object.assign(options, option);
|
||||
if (Object.keys(headers).length !== 0) {
|
||||
options.headers = Object.assign({}, options.headers, headers);
|
||||
}
|
||||
if (Object.keys(qs).length === 0) {
|
||||
delete options.qs;
|
||||
}
|
||||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
return await this.helpers.requestOAuth.call(this, 'microsoftOneDriveOAuth2Api', options);
|
||||
} catch (error) {
|
||||
if (error.response && error.response.body && error.response.body.error && error.response.body.error.message) {
|
||||
// Try to return the error prettier
|
||||
throw new Error(`Microsoft OneDrive response [${error.statusCode}]: ${error.response.body.error.message}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function microsoftApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
let uri: string | undefined;
|
||||
query['$top'] = 100;
|
||||
|
||||
do {
|
||||
responseData = await microsoftApiRequest.call(this, method, endpoint, body, query, uri);
|
||||
uri = responseData['@odata.nextLink'];
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
} while (
|
||||
responseData['@odata.nextLink'] !== undefined
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export async function microsoftApiRequestAllItemsSkip(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
|
||||
|
||||
const returnData: IDataObject[] = [];
|
||||
|
||||
let responseData;
|
||||
query['$top'] = 100;
|
||||
query['$skip'] = 0;
|
||||
|
||||
do {
|
||||
responseData = await microsoftApiRequest.call(this, method, endpoint, body, query);
|
||||
query['$skip'] += query['$top'];
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
} while (
|
||||
responseData['value'].length !== 0
|
||||
);
|
||||
|
||||
return returnData;
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
import {
|
||||
BINARY_ENCODING,
|
||||
IExecuteFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import {
|
||||
IBinaryKeyData,
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
microsoftApiRequest,
|
||||
microsoftApiRequestAllItems,
|
||||
} from './GenericFunctions';
|
||||
|
||||
import {
|
||||
fileFields,
|
||||
fileOperations,
|
||||
} from './FileDescription';
|
||||
|
||||
import {
|
||||
folderFields,
|
||||
folderOperations,
|
||||
} from './FolderDescription';
|
||||
|
||||
export class MicrosoftOneDrive implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Microsoft OneDrive',
|
||||
name: 'microsoftOneDrive',
|
||||
icon: 'file:oneDrive.png',
|
||||
group: ['input'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Consume Microsoft OneDrive API.',
|
||||
defaults: {
|
||||
name: 'Microsoft OneDrive',
|
||||
color: '#1d4bab',
|
||||
},
|
||||
inputs: ['main'],
|
||||
outputs: ['main'],
|
||||
credentials: [
|
||||
{
|
||||
name: 'microsoftOneDriveOAuth2Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'File',
|
||||
value: 'file',
|
||||
},
|
||||
{
|
||||
name: 'Folder',
|
||||
value: 'folder',
|
||||
},
|
||||
],
|
||||
default: 'file',
|
||||
description: 'The resource to operate on.',
|
||||
},
|
||||
...fileOperations,
|
||||
...fileFields,
|
||||
...folderOperations,
|
||||
...folderFields,
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (resource === 'file') {
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_copy?view=odsp-graph-online
|
||||
if (operation === 'copy') {
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const parentReference = this.getNodeParameter('parentReference', i) as IDataObject;
|
||||
const body: IDataObject = {};
|
||||
if (parentReference) {
|
||||
body.parentReference = { ...parentReference };
|
||||
}
|
||||
if (additionalFields.name) {
|
||||
body.name = additionalFields.name as string;
|
||||
}
|
||||
responseData = await microsoftApiRequest.call(this, 'POST', `/drive/items/${fileId}/copy`, body, {}, undefined, {}, { json: true, resolveWithFullResponse: true });
|
||||
responseData = { location : responseData.headers.location };
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_delete?view=odsp-graph-online
|
||||
if (operation === 'delete') {
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
responseData = await microsoftApiRequest.call(this, 'DELETE', `/drive/items/${fileId}`);
|
||||
responseData = { success: true };
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_list_children?view=odsp-graph-online
|
||||
if (operation === 'download') {
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i) as string;
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${fileId}`);
|
||||
|
||||
const fileName = responseData.name;
|
||||
|
||||
if (responseData.file === undefined) {
|
||||
throw new Error('The ID you provided does not belong to a file.');
|
||||
}
|
||||
|
||||
let mimeType: string | undefined;
|
||||
if (responseData.file.mimeType) {
|
||||
mimeType = responseData.file.mimeType;
|
||||
}
|
||||
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${fileId}/content`, {}, {}, undefined, {}, { encoding: null, resolveWithFullResponse: true });
|
||||
|
||||
const newItem: INodeExecutionData = {
|
||||
json: items[i].json,
|
||||
binary: {},
|
||||
};
|
||||
|
||||
if (mimeType === undefined && responseData.headers['content-type']) {
|
||||
mimeType = responseData.headers['content-type'];
|
||||
}
|
||||
|
||||
if (items[i].binary !== undefined) {
|
||||
// Create a shallow copy of the binary data so that the old
|
||||
// data references which do not get changed still stay behind
|
||||
// but the incoming data does not get changed.
|
||||
Object.assign(newItem.binary, items[i].binary);
|
||||
}
|
||||
|
||||
items[i] = newItem;
|
||||
|
||||
const data = Buffer.from(responseData.body);
|
||||
|
||||
items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(data as unknown as Buffer, fileName, mimeType);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get?view=odsp-graph-online
|
||||
if (operation === 'get') {
|
||||
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||
responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${fileId}`);
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_search?view=odsp-graph-online
|
||||
if (operation === 'search') {
|
||||
const query = this.getNodeParameter('query', i) as string;
|
||||
responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/root/search(q='${query}')`);
|
||||
responseData = responseData.filter((item: IDataObject) => item.file);
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_put_content?view=odsp-graph-online#example-upload-a-new-file
|
||||
if (operation === 'upload') {
|
||||
const parentId = this.getNodeParameter('parentId', i) as string;
|
||||
const isBinaryData = this.getNodeParameter('binaryData', i) as boolean;
|
||||
const fileName = this.getNodeParameter('fileName', i) as string;
|
||||
|
||||
if (isBinaryData) {
|
||||
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0) as string;
|
||||
|
||||
if (items[i].binary === undefined) {
|
||||
throw new Error('No binary data exists on item!');
|
||||
}
|
||||
//@ts-ignore
|
||||
if (items[i].binary[binaryPropertyName] === undefined) {
|
||||
throw new Error(`No binary data property "${binaryPropertyName}" does not exists on item!`);
|
||||
}
|
||||
|
||||
const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName];
|
||||
|
||||
const body = Buffer.from(binaryData.data, BINARY_ENCODING);
|
||||
responseData = await microsoftApiRequest.call(this, 'PUT', `/drive/items/${parentId}:/${fileName || binaryData.fileName}:/content`, body, {}, undefined, { 'Content-Type': binaryData.mimeType, 'Content-length': body.length }, {} );
|
||||
|
||||
returnData.push(JSON.parse(responseData) as IDataObject);
|
||||
} else {
|
||||
const body = this.getNodeParameter('fileContent', i) as string;
|
||||
if (fileName === '') {
|
||||
throw new Error('File name must be set!');
|
||||
}
|
||||
responseData = await microsoftApiRequest.call(this, 'PUT', `/drive/items/${parentId}:/${fileName}:/content`, body , {}, undefined, { 'Content-Type': 'text/plain' } );
|
||||
returnData.push(responseData as IDataObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'folder') {
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_post_children?view=odsp-graph-online
|
||||
if (operation === 'create') {
|
||||
const name = this.getNodeParameter('name', i) as string;
|
||||
const body: IDataObject = {
|
||||
name,
|
||||
folder: {},
|
||||
};
|
||||
responseData = await microsoftApiRequest.call(this, 'POST', '/drive/root/children', body);
|
||||
returnData.push(responseData);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_list_children?view=odsp-graph-online
|
||||
if (operation === 'getChildren') {
|
||||
const folderId = this.getNodeParameter('folderId', i) as string;
|
||||
responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/items/${folderId}/children`);
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
}
|
||||
//https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_search?view=odsp-graph-online
|
||||
if (operation === 'search') {
|
||||
const query = this.getNodeParameter('query', i) as string;
|
||||
responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/drive/root/search(q='${query}')`);
|
||||
responseData = responseData.filter((item: IDataObject) => item.folder);
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resource === 'file' && operation === 'download') {
|
||||
// For file downloads the files get attached to the existing items
|
||||
return this.prepareOutputData(items);
|
||||
} else {
|
||||
return [this.helpers.returnJsonArray(returnData)];
|
||||
}
|
||||
}
|
||||
}
|
BIN
packages/nodes-base/nodes/Microsoft/OneDrive/oneDrive.png
Normal file
BIN
packages/nodes-base/nodes/Microsoft/OneDrive/oneDrive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -41,14 +41,17 @@ export async function zohoApiRequestAllItems(this: IExecuteFunctions | ILoadOpti
|
|||
|
||||
let responseData;
|
||||
let uri: string | undefined;
|
||||
query.per_page = 200;
|
||||
query.page = 0;
|
||||
|
||||
do {
|
||||
responseData = await zohoApiRequest.call(this, method, endpoint, body, query, uri);
|
||||
uri = responseData.nextRecordsUrl;
|
||||
uri = responseData.info.more_records;
|
||||
returnData.push.apply(returnData, responseData[propertyName]);
|
||||
query.page++;
|
||||
} while (
|
||||
responseData.nextRecordsUrl !== undefined &&
|
||||
responseData.nextRecordsUrl !== null
|
||||
responseData.info.more_records !== undefined &&
|
||||
responseData.info.more_records === true
|
||||
);
|
||||
|
||||
return returnData;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { INodeProperties } from "n8n-workflow";
|
||||
import { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const leadOperations = [
|
||||
{
|
||||
|
@ -18,6 +18,11 @@ export const leadOperations = [
|
|||
value: 'create',
|
||||
description: 'Create a new lead',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a lead',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
|
@ -29,15 +34,15 @@ export const leadOperations = [
|
|||
description: 'Get data of all leads',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update new lead',
|
||||
name: 'Get Fields',
|
||||
value: 'getFields',
|
||||
description: `Get the fields' metadata`,
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
description: 'Delete a lead',
|
||||
}
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a lead',
|
||||
},
|
||||
],
|
||||
default: 'create',
|
||||
description: 'The operation to perform.',
|
||||
|
@ -49,7 +54,6 @@ export const leadFields = [
|
|||
/* -------------------------------------------------------------------------- */
|
||||
/* lead:create */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
|
@ -86,86 +90,617 @@ export const leadFields = [
|
|||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Avatar',
|
||||
name: 'avatar',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An avatar image URL. note: the image url needs to be https.',
|
||||
displayName: 'Annual Revenue',
|
||||
name: 'annualRevenue',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
numberPrecision: 2,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Name',
|
||||
name: 'name',
|
||||
displayName: 'Company',
|
||||
name: 'company',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Name of the user',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email Opt Out',
|
||||
name: 'emailOptOut',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Fax',
|
||||
name: 'fax',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Industry',
|
||||
name: 'industry',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getIndustries',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Record Duplicate',
|
||||
name: 'isRecordDuplicate',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Lead Source',
|
||||
name: 'leadSource',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLeadSources',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Lead Status',
|
||||
name: 'leadStatus',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLeadStatuses'
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Mobile',
|
||||
name: 'mobile',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'No. of Employees',
|
||||
name: 'numberOfEmployees',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Owner',
|
||||
name: 'owner',
|
||||
type: 'options',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getUsers',
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Phone',
|
||||
name: 'phone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The phone number of the user',
|
||||
},
|
||||
{
|
||||
displayName: 'Unsubscribed From Emails',
|
||||
name: 'unsubscribedFromEmails',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether the Lead is unsubscribed from emails',
|
||||
},
|
||||
{
|
||||
displayName: 'Update Last Request At',
|
||||
name: 'updateLastRequestAt',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'A boolean value, which if true, instructs Intercom to update the<br />users last_request_at value to the current API service time in<br />UTC. default value if not sent is false.',
|
||||
},
|
||||
{
|
||||
displayName: 'Companies',
|
||||
name: 'companies',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getCompanies',
|
||||
},
|
||||
default: [],
|
||||
description: 'Identifies the companies this user belongs to.',
|
||||
},
|
||||
{
|
||||
displayName: 'UTM Source',
|
||||
name: 'utmSource',
|
||||
displayName: 'Salutation',
|
||||
name: 'salutation',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'An avatar image URL. note: the image url needs to be https.',
|
||||
},
|
||||
{
|
||||
displayName: 'UTM Medium',
|
||||
name: 'utmMedium',
|
||||
displayName: 'Secondary Email',
|
||||
name: 'secondaryEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifies what type of link was used',
|
||||
},
|
||||
{
|
||||
displayName: 'UTM Campaign',
|
||||
name: 'utmCampaign',
|
||||
displayName: 'Skype ID',
|
||||
name: 'SkypeId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifies a specific product promotion or strategic campaign',
|
||||
},
|
||||
{
|
||||
displayName: 'UTM Term',
|
||||
name: 'utmTerm',
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifies search terms',
|
||||
},
|
||||
{
|
||||
displayName: 'UTM Content',
|
||||
name: 'utmContent',
|
||||
displayName: 'Twitter',
|
||||
name: 'twitter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'website',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'Identifies what specifically was clicked to bring the user to the site',
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'addressUi',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
placeholder: 'Add Address',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
required: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'create',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'addressValues',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Street',
|
||||
name: 'street',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Zip Code',
|
||||
name: 'zipCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* lead:update */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Lead ID',
|
||||
name: 'leadId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Annual Revenue',
|
||||
name: 'annualRevenue',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
numberPrecision: 2,
|
||||
},
|
||||
default: 0,
|
||||
},
|
||||
{
|
||||
displayName: 'Company',
|
||||
name: 'company',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Email Opt Out',
|
||||
name: 'emailOptOut',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Fax',
|
||||
name: 'fax',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'First Name',
|
||||
name: 'firstName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Industry',
|
||||
name: 'industry',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getIndustries',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Is Record Duplicate',
|
||||
name: 'isRecordDuplicate',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
displayName: 'Last Name',
|
||||
name: 'lastName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: `User's last name`,
|
||||
},
|
||||
{
|
||||
displayName: 'Lead Source',
|
||||
name: 'leadSource',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLeadSources',
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Lead Status',
|
||||
name: 'leadStatus',
|
||||
type: 'options',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLeadStatuses'
|
||||
},
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Mobile',
|
||||
name: 'mobile',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'No. of Employees',
|
||||
name: 'numberOfEmployees',
|
||||
type: 'number',
|
||||
default: 1,
|
||||
},
|
||||
{
|
||||
displayName: 'Owner',
|
||||
name: 'owner',
|
||||
type: 'options',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getUsers',
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Phone',
|
||||
name: 'phone',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Salutation',
|
||||
name: 'salutation',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Secondary Email',
|
||||
name: 'secondaryEmail',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Skype ID',
|
||||
name: 'SkypeId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Title',
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Twitter',
|
||||
name: 'twitter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Website',
|
||||
name: 'website',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
displayName: 'Address',
|
||||
name: 'addressUi',
|
||||
type: 'fixedCollection',
|
||||
default: {},
|
||||
placeholder: 'Add Address',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
required: false,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'update',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'addressValues',
|
||||
displayName: 'Address',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Street',
|
||||
name: 'street',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'City',
|
||||
name: 'city',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'State',
|
||||
name: 'state',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Country',
|
||||
name: 'country',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Zip Code',
|
||||
name: 'zipCode',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* lead:get */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Lead ID',
|
||||
name: 'leadId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'get',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* lead:getAll */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'If all results should be returned or only up to a given limit.',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 200,
|
||||
},
|
||||
default: 100,
|
||||
description: 'How many results to return.',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Option',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Approved',
|
||||
name: 'approved',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'To get the list of approved records. Default value is true.',
|
||||
},
|
||||
{
|
||||
displayName: 'Converted',
|
||||
name: 'converted',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'To get the list of converted records. Default value is false',
|
||||
},
|
||||
{
|
||||
displayName: 'Fields',
|
||||
name: 'fields',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLeadFields',
|
||||
},
|
||||
default: [],
|
||||
},
|
||||
{
|
||||
displayName: 'Include Child',
|
||||
name: 'includeChild',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'To include records from the child territories. True includes child territory records',
|
||||
},
|
||||
{
|
||||
displayName: 'Sort By',
|
||||
name: 'sortBy',
|
||||
type: 'multiOptions',
|
||||
typeOptions: {
|
||||
loadOptionsMethod: 'getLeadFields',
|
||||
},
|
||||
default: [],
|
||||
},
|
||||
{
|
||||
displayName: 'Sort Order',
|
||||
name: 'sortOrder',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'ASC',
|
||||
value: 'asc',
|
||||
},
|
||||
{
|
||||
name: 'DESC',
|
||||
value: 'desc',
|
||||
},
|
||||
],
|
||||
default: 'desc',
|
||||
description: 'Order sort attribute ascending or descending.',
|
||||
},
|
||||
{
|
||||
displayName: 'Territory ID',
|
||||
name: 'territoryId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'To get the list of records based on the territory ',
|
||||
},
|
||||
]
|
||||
},
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* lead:delete */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{
|
||||
displayName: 'Lead ID',
|
||||
name: 'leadId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'lead',
|
||||
],
|
||||
operation: [
|
||||
'delete',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as INodeProperties[];
|
||||
|
|
37
packages/nodes-base/nodes/Zoho/LeadInterface.ts
Normal file
37
packages/nodes-base/nodes/Zoho/LeadInterface.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
export interface ILead {
|
||||
Annual_Revenue?: number;
|
||||
City?: string;
|
||||
Company?: string;
|
||||
Country?: string;
|
||||
Description?: string;
|
||||
Designation?: string;
|
||||
Email?: string;
|
||||
Email_Opt_Out?: boolean;
|
||||
Fax?: string;
|
||||
First_Name?: string;
|
||||
Industry?: string;
|
||||
Is_Record_Duplicate?: boolean;
|
||||
Last_Name?: string;
|
||||
Lead_Owner?: string;
|
||||
Lead_Source?: string;
|
||||
Lead_Status?: string;
|
||||
Mobile?: string;
|
||||
No_of_Employees?: number;
|
||||
Phone?: string;
|
||||
Salutation?: string;
|
||||
Secondary_Email?: string;
|
||||
Skype_ID?: string;
|
||||
State?: string;
|
||||
Street?: string;
|
||||
Twitter?: string;
|
||||
Website?: string;
|
||||
Zip_Code?: string;
|
||||
}
|
||||
|
||||
export interface IAddress {
|
||||
street?: string;
|
||||
city?: string;
|
||||
state?: string;
|
||||
country?: string;
|
||||
zipCode?: string;
|
||||
}
|
|
@ -4,9 +4,11 @@ import {
|
|||
|
||||
import {
|
||||
IDataObject,
|
||||
ILoadOptionsFunctions,
|
||||
INodeExecutionData,
|
||||
INodeTypeDescription,
|
||||
INodePropertyOptions,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
|
@ -15,10 +17,15 @@ import {
|
|||
} from './GenericFunctions';
|
||||
|
||||
import {
|
||||
leadOperations,
|
||||
leadFields,
|
||||
leadOperations,
|
||||
} from './LeadDescription';
|
||||
|
||||
import {
|
||||
IAddress,
|
||||
ILead,
|
||||
} from './LeadInterface';
|
||||
|
||||
export class ZohoCrm implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Zoho CRM',
|
||||
|
@ -59,34 +66,381 @@ export class ZohoCrm implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
loadOptions: {
|
||||
// Get all the available users to display them to user so that he can
|
||||
// select them easily
|
||||
async getUsers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const { users } = await zohoApiRequest.call(this, 'GET', '/users', {}, { type: 'AllUsers' });
|
||||
for (const user of users) {
|
||||
const userName = `${user.first_name} ${user.last_name}`;
|
||||
const userId = user.profile.id;
|
||||
returnData.push({
|
||||
name: userName,
|
||||
value: userId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available accounts to display them to user so that he can
|
||||
// select them easily
|
||||
async getAccounts(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const qs: IDataObject = {};
|
||||
qs.sort_by = 'Created_Time';
|
||||
qs.sort_order = 'desc';
|
||||
const { data } = await zohoApiRequest.call(this, 'GET', '/accounts', {}, qs);
|
||||
for (const account of data) {
|
||||
const accountName = account.Account_Name;
|
||||
const accountId = account.id;
|
||||
returnData.push({
|
||||
name: accountName,
|
||||
value: accountId,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available lead statuses to display them to user so that he can
|
||||
// select them easily
|
||||
async getLeadStatuses(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const qs: IDataObject = {};
|
||||
qs.module = 'leads';
|
||||
const { fields } = await zohoApiRequest.call(this, 'GET', '/settings/fields', {}, qs);
|
||||
for (const field of fields) {
|
||||
if (field.api_name === 'Lead_Status') {
|
||||
for (const value of field.pick_list_values) {
|
||||
const valueName = value.display_value;
|
||||
const valueId = value.actual_value;
|
||||
returnData.push({
|
||||
name: valueName,
|
||||
value: valueId,
|
||||
});
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available lead sources to display them to user so that he can
|
||||
// select them easily
|
||||
async getLeadSources(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const qs: IDataObject = {};
|
||||
qs.module = 'leads';
|
||||
const { fields } = await zohoApiRequest.call(this, 'GET', '/settings/fields', {}, qs);
|
||||
for (const field of fields) {
|
||||
if (field.api_name === 'Lead_Source') {
|
||||
for (const value of field.pick_list_values) {
|
||||
const valueName = value.display_value;
|
||||
const valueId = value.actual_value;
|
||||
returnData.push({
|
||||
name: valueName,
|
||||
value: valueId,
|
||||
});
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available industries to display them to user so that he can
|
||||
// select them easily
|
||||
async getIndustries(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const qs: IDataObject = {};
|
||||
qs.module = 'leads';
|
||||
const { fields } = await zohoApiRequest.call(this, 'GET', '/settings/fields', {}, qs);
|
||||
for (const field of fields) {
|
||||
if (field.api_name === 'Industry') {
|
||||
for (const value of field.pick_list_values) {
|
||||
const valueName = value.display_value;
|
||||
const valueId = value.actual_value;
|
||||
returnData.push({
|
||||
name: valueName,
|
||||
value: valueId,
|
||||
});
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
// Get all the available lead fields to display them to user so that he can
|
||||
// select them easily
|
||||
async getLeadFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
|
||||
const returnData: INodePropertyOptions[] = [];
|
||||
const qs: IDataObject = {};
|
||||
qs.module = 'leads';
|
||||
const { fields } = await zohoApiRequest.call(this, 'GET', '/settings/fields', {}, qs);
|
||||
for (const field of fields) {
|
||||
returnData.push({
|
||||
name: field.field_label,
|
||||
value: field.api_name,
|
||||
});
|
||||
}
|
||||
return returnData;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: IDataObject[] = [];
|
||||
const length = items.length as unknown as number;
|
||||
const qs: IDataObject = {};
|
||||
let responseData;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
const operation = this.getNodeParameter('operation', 0) as string;
|
||||
if (resource === 'lead') {
|
||||
//https://www.zoho.com/crm/developer/docs/api/insert-records.html
|
||||
if (operation === 'create') {
|
||||
const lastName = this.getNodeParameter('lastName', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body = {
|
||||
const body: ILead = {
|
||||
Last_Name: lastName,
|
||||
};
|
||||
// if (additionalFields.email) {
|
||||
// // @ts-ignore
|
||||
// body.email = additionalFields.email as string;
|
||||
// }
|
||||
if (additionalFields.owner) {
|
||||
body.Lead_Owner = additionalFields.owner as string;
|
||||
}
|
||||
if (additionalFields.company) {
|
||||
body.Company = additionalFields.company as string;
|
||||
}
|
||||
if (additionalFields.firstName) {
|
||||
body.First_Name = additionalFields.firstName as string;
|
||||
}
|
||||
if (additionalFields.email) {
|
||||
body.Email = additionalFields.email as string;
|
||||
}
|
||||
if (additionalFields.title) {
|
||||
body.Designation = additionalFields.title as string;
|
||||
}
|
||||
if (additionalFields.phone) {
|
||||
body.Phone = additionalFields.phone as string;
|
||||
}
|
||||
if (additionalFields.mobile) {
|
||||
body.Mobile = additionalFields.mobile as string;
|
||||
}
|
||||
if (additionalFields.leadStatus) {
|
||||
body.Lead_Status = additionalFields.leadStatus as string;
|
||||
}
|
||||
if (additionalFields.fax) {
|
||||
body.Fax = additionalFields.fax as string;
|
||||
}
|
||||
if (additionalFields.website) {
|
||||
body.Website = additionalFields.website as string;
|
||||
}
|
||||
if (additionalFields.leadSource) {
|
||||
body.Lead_Source = additionalFields.leadSource as string;
|
||||
}
|
||||
if (additionalFields.industry) {
|
||||
body.Industry = additionalFields.industry as string;
|
||||
}
|
||||
if (additionalFields.numberOfEmployees) {
|
||||
body.No_of_Employees = additionalFields.numberOfEmployees as number;
|
||||
}
|
||||
if (additionalFields.annualRevenue) {
|
||||
body.Annual_Revenue = additionalFields.annualRevenue as number;
|
||||
}
|
||||
if (additionalFields.emailOptOut) {
|
||||
body.Email_Opt_Out = additionalFields.emailOptOut as boolean;
|
||||
}
|
||||
if (additionalFields.skypeId) {
|
||||
body.Skype_ID = additionalFields.skypeId as string;
|
||||
}
|
||||
if (additionalFields.salutation) {
|
||||
body.Salutation = additionalFields.salutation as string;
|
||||
}
|
||||
if (additionalFields.secondaryEmail) {
|
||||
body.Secondary_Email = additionalFields.secondaryEmail as string;
|
||||
}
|
||||
if (additionalFields.twitter) {
|
||||
body.Twitter = additionalFields.twitter as string;
|
||||
}
|
||||
if (additionalFields.isRecordDuplicate) {
|
||||
body.Is_Record_Duplicate = additionalFields.isRecordDuplicate as boolean;
|
||||
}
|
||||
if (additionalFields.description) {
|
||||
body.Description = additionalFields.description as string;
|
||||
}
|
||||
const address = (this.getNodeParameter('addressUi', i) as IDataObject).addressValues as IAddress;
|
||||
if (address) {
|
||||
if (address.country) {
|
||||
body.Country = address.country as string;
|
||||
}
|
||||
if (address.city) {
|
||||
body.City = address.city as string;
|
||||
}
|
||||
if (address.state) {
|
||||
body.State = address.state as string;
|
||||
}
|
||||
if (address.street) {
|
||||
body.Street = address.street as string;
|
||||
}
|
||||
if (address.zipCode) {
|
||||
body.Zip_Code = address.zipCode as string;
|
||||
}
|
||||
}
|
||||
responseData = await zohoApiRequest.call(this, 'POST', '/leads', body);
|
||||
responseData = responseData.data;
|
||||
} else {
|
||||
throw new Error(`The operation "${operation}" is not known!`);
|
||||
|
||||
if (responseData.length) {
|
||||
responseData = responseData[0].details;
|
||||
}
|
||||
} else {
|
||||
throw new Error(`The resource "${resource}" is not known!`);
|
||||
}
|
||||
//https://www.zoho.com/crm/developer/docs/api/update-specific-record.html
|
||||
if (operation === 'update') {
|
||||
const leadId = this.getNodeParameter('leadId', i) as string;
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
const body: ILead = {};
|
||||
if (additionalFields.lastName) {
|
||||
body.Last_Name = additionalFields.lastName as string;
|
||||
}
|
||||
if (additionalFields.owner) {
|
||||
body.Lead_Owner = additionalFields.owner as string;
|
||||
}
|
||||
if (additionalFields.company) {
|
||||
body.Company = additionalFields.company as string;
|
||||
}
|
||||
if (additionalFields.firstName) {
|
||||
body.First_Name = additionalFields.firstName as string;
|
||||
}
|
||||
if (additionalFields.email) {
|
||||
body.Email = additionalFields.email as string;
|
||||
}
|
||||
if (additionalFields.title) {
|
||||
body.Designation = additionalFields.title as string;
|
||||
}
|
||||
if (additionalFields.phone) {
|
||||
body.Phone = additionalFields.phone as string;
|
||||
}
|
||||
if (additionalFields.mobile) {
|
||||
body.Mobile = additionalFields.mobile as string;
|
||||
}
|
||||
if (additionalFields.leadStatus) {
|
||||
body.Lead_Status = additionalFields.leadStatus as string;
|
||||
}
|
||||
if (additionalFields.fax) {
|
||||
body.Fax = additionalFields.fax as string;
|
||||
}
|
||||
if (additionalFields.website) {
|
||||
body.Website = additionalFields.website as string;
|
||||
}
|
||||
if (additionalFields.leadSource) {
|
||||
body.Lead_Source = additionalFields.leadSource as string;
|
||||
}
|
||||
if (additionalFields.industry) {
|
||||
body.Industry = additionalFields.industry as string;
|
||||
}
|
||||
if (additionalFields.numberOfEmployees) {
|
||||
body.No_of_Employees = additionalFields.numberOfEmployees as number;
|
||||
}
|
||||
if (additionalFields.annualRevenue) {
|
||||
body.Annual_Revenue = additionalFields.annualRevenue as number;
|
||||
}
|
||||
if (additionalFields.emailOptOut) {
|
||||
body.Email_Opt_Out = additionalFields.emailOptOut as boolean;
|
||||
}
|
||||
if (additionalFields.skypeId) {
|
||||
body.Skype_ID = additionalFields.skypeId as string;
|
||||
}
|
||||
if (additionalFields.salutation) {
|
||||
body.Salutation = additionalFields.salutation as string;
|
||||
}
|
||||
if (additionalFields.secondaryEmail) {
|
||||
body.Secondary_Email = additionalFields.secondaryEmail as string;
|
||||
}
|
||||
if (additionalFields.twitter) {
|
||||
body.Twitter = additionalFields.twitter as string;
|
||||
}
|
||||
if (additionalFields.isRecordDuplicate) {
|
||||
body.Is_Record_Duplicate = additionalFields.isRecordDuplicate as boolean;
|
||||
}
|
||||
if (additionalFields.description) {
|
||||
body.Description = additionalFields.description as string;
|
||||
}
|
||||
const address = (this.getNodeParameter('addressUi', i) as IDataObject).addressValues as IAddress;
|
||||
if (address) {
|
||||
if (address.country) {
|
||||
body.Country = address.country as string;
|
||||
}
|
||||
if (address.city) {
|
||||
body.City = address.city as string;
|
||||
}
|
||||
if (address.state) {
|
||||
body.State = address.state as string;
|
||||
}
|
||||
if (address.street) {
|
||||
body.Street = address.street as string;
|
||||
}
|
||||
if (address.zipCode) {
|
||||
body.Zip_Code = address.zipCode as string;
|
||||
}
|
||||
}
|
||||
responseData = await zohoApiRequest.call(this, 'PUT', `/leads/${leadId}`, body);
|
||||
responseData = responseData.data;
|
||||
|
||||
if (responseData.length) {
|
||||
responseData = responseData[0].details;
|
||||
}
|
||||
}
|
||||
//https://www.zoho.com/crm/developer/docs/api/update-specific-record.html
|
||||
if (operation === 'get') {
|
||||
const leadId = this.getNodeParameter('leadId', i) as string;
|
||||
responseData = await zohoApiRequest.call(this, 'GET', `/leads/${leadId}`);
|
||||
if (responseData !== undefined) {
|
||||
responseData = responseData.data;
|
||||
}
|
||||
|
||||
}
|
||||
//https://www.zoho.com/crm/developer/docs/api/get-records.html
|
||||
if (operation === 'getAll') {
|
||||
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||
if (options.fields) {
|
||||
qs.fields = (options.fields as string[]).join(',');
|
||||
}
|
||||
if (options.approved) {
|
||||
qs.approved = options.approved as boolean;
|
||||
}
|
||||
if (options.converted) {
|
||||
qs.converted = options.converted as boolean;
|
||||
}
|
||||
if (options.includeChild) {
|
||||
qs.include_child = options.includeChild as boolean;
|
||||
}
|
||||
if (options.sortOrder) {
|
||||
qs.sort_order = options.sortOrder as string;
|
||||
}
|
||||
if (options.sortBy) {
|
||||
qs.sort_by = options.sortBy as string;
|
||||
}
|
||||
if (options.territoryId) {
|
||||
qs.territory_id = options.territoryId as string;
|
||||
}
|
||||
if (returnAll) {
|
||||
responseData = await zohoApiRequestAllItems.call(this, 'data', 'GET', '/leads', {}, qs);
|
||||
} else {
|
||||
qs.per_page = this.getNodeParameter('limit', i) as number;
|
||||
responseData = await zohoApiRequest.call(this, 'GET', '/leads', {}, qs);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
}
|
||||
//https://www.zoho.com/crm/developer/docs/api/delete-specific-record.html
|
||||
if (operation === 'delete') {
|
||||
const leadId = this.getNodeParameter('leadId', i) as string;
|
||||
responseData = await zohoApiRequest.call(this, 'DELETE', `/leads/${leadId}`);
|
||||
responseData = responseData.data;
|
||||
}
|
||||
//https://www.zoho.com/crm/developer/docs/api/field-meta.html
|
||||
if (operation === 'getFields') {
|
||||
qs.module = 'leads';
|
||||
responseData = await zohoApiRequest.call(this, 'GET', '/settings/fields', {}, qs);
|
||||
responseData = responseData.fields;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(responseData)) {
|
||||
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||
} else if (responseData !== undefined) {
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"dist/credentials/GitlabApi.credentials.js",
|
||||
"dist/credentials/GoogleApi.credentials.js",
|
||||
"dist/credentials/GoogleOAuth2Api.credentials.js",
|
||||
"dist/credentials/HelpScoutOAuth2Api.credentials.js",
|
||||
"dist/credentials/HttpBasicAuth.credentials.js",
|
||||
"dist/credentials/HttpDigestAuth.credentials.js",
|
||||
"dist/credentials/HttpHeaderAuth.credentials.js",
|
||||
|
@ -57,6 +58,9 @@
|
|||
"dist/credentials/MailgunApi.credentials.js",
|
||||
"dist/credentials/MandrillApi.credentials.js",
|
||||
"dist/credentials/MattermostApi.credentials.js",
|
||||
"dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
|
||||
"dist/credentials/MicrosoftOAuth2Api.credentials.js",
|
||||
"dist/credentials/MicrosoftOneDriveOAuth2Api.credentials.js",
|
||||
"dist/credentials/MongoDb.credentials.js",
|
||||
"dist/credentials/MySql.credentials.js",
|
||||
"dist/credentials/NextCloudApi.credentials.js",
|
||||
|
@ -123,6 +127,8 @@
|
|||
"dist/nodes/Google/GoogleDrive.node.js",
|
||||
"dist/nodes/Google/GoogleSheets.node.js",
|
||||
"dist/nodes/GraphQL/GraphQL.node.js",
|
||||
"dist/nodes/HelpScout/HelpScout.node.js",
|
||||
"dist/nodes/HelpScout/HelpScoutTrigger.node.js",
|
||||
"dist/nodes/HtmlExtract/HtmlExtract.node.js",
|
||||
"dist/nodes/HttpRequest.node.js",
|
||||
"dist/nodes/Hubspot/Hubspot.node.js",
|
||||
|
@ -139,6 +145,8 @@
|
|||
"dist/nodes/Mandrill/Mandrill.node.js",
|
||||
"dist/nodes/Mattermost/Mattermost.node.js",
|
||||
"dist/nodes/Merge.node.js",
|
||||
"dist/nodes/Microsoft/Excel/MicrosoftExcel.node.js",
|
||||
"dist/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.js",
|
||||
"dist/nodes/MoveBinaryData.node.js",
|
||||
"dist/nodes/MongoDb/MongoDb.node.js",
|
||||
"dist/nodes/MySql/MySql.node.js",
|
||||
|
|
Loading…
Reference in a new issue