mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
✨ Box Node and Trigger (#765)
* ✨ Box Node and Trigger * ⚡ Improvements * ⚡ small fix * 🐛 Add missing interface * ⚡ add search operation
This commit is contained in:
parent
a5dd08fdbb
commit
8370940713
|
@ -15,6 +15,7 @@ import {
|
||||||
ITriggerResponse,
|
ITriggerResponse,
|
||||||
IWebhookFunctions as IWebhookFunctionsBase,
|
IWebhookFunctions as IWebhookFunctionsBase,
|
||||||
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
||||||
|
IOAuth2Options,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ export interface IExecuteFunctions extends IExecuteFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
||||||
request: requestPromise.RequestPromiseAPI,
|
request: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
||||||
};
|
};
|
||||||
|
@ -47,7 +48,7 @@ export interface IExecuteSingleFunctions extends IExecuteSingleFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
||||||
request: requestPromise.RequestPromiseAPI,
|
request: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -57,7 +58,7 @@ export interface IPollFunctions extends IPollFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
||||||
request: requestPromise.RequestPromiseAPI,
|
request: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
||||||
};
|
};
|
||||||
|
@ -73,7 +74,7 @@ export interface ITriggerFunctions extends ITriggerFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
||||||
request: requestPromise.RequestPromiseAPI,
|
request: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
||||||
};
|
};
|
||||||
|
@ -98,7 +99,7 @@ export interface IUserSettings {
|
||||||
export interface ILoadOptionsFunctions extends ILoadOptionsFunctionsBase {
|
export interface ILoadOptionsFunctions extends ILoadOptionsFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
request?: requestPromise.RequestPromiseAPI,
|
request?: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2?: (this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions) => Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2?: (this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options) => Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1?(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1?(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -107,7 +108,7 @@ export interface ILoadOptionsFunctions extends ILoadOptionsFunctionsBase {
|
||||||
export interface IHookFunctions extends IHookFunctionsBase {
|
export interface IHookFunctions extends IHookFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
request: requestPromise.RequestPromiseAPI,
|
request: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -117,7 +118,7 @@ export interface IWebhookFunctions extends IWebhookFunctionsBase {
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
prepareBinaryData(binaryData: Buffer, filePath?: string, mimeType?: string): Promise<IBinaryData>;
|
||||||
request: requestPromise.RequestPromiseAPI,
|
request: requestPromise.RequestPromiseAPI,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any>, // tslint:disable-line:no-any
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any>, // tslint:disable-line:no-any
|
||||||
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
returnJsonArray(jsonData: IDataObject | IDataObject[]): INodeExecutionData[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {
|
||||||
Workflow,
|
Workflow,
|
||||||
WorkflowDataProxy,
|
WorkflowDataProxy,
|
||||||
WorkflowExecuteMode,
|
WorkflowExecuteMode,
|
||||||
|
IOAuth2Options,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import * as clientOAuth1 from 'oauth-1.0a';
|
import * as clientOAuth1 from 'oauth-1.0a';
|
||||||
|
@ -124,9 +125,10 @@ export async function prepareBinaryData(binaryData: Buffer, filePath?: string, m
|
||||||
* @param {(OptionsWithUri | requestPromise.RequestPromiseOptions)} requestOptions
|
* @param {(OptionsWithUri | requestPromise.RequestPromiseOptions)} requestOptions
|
||||||
* @param {INode} node
|
* @param {INode} node
|
||||||
* @param {IWorkflowExecuteAdditionalData} additionalData
|
* @param {IWorkflowExecuteAdditionalData} additionalData
|
||||||
|
*
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, node: INode, additionalData: IWorkflowExecuteAdditionalData, tokenType?: string, property?: string) {
|
export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, node: INode, additionalData: IWorkflowExecuteAdditionalData, oAuth2Options?: IOAuth2Options) {
|
||||||
const credentials = this.getCredentials(credentialsType) as ICredentialDataDecryptedObject;
|
const credentials = this.getCredentials(credentialsType) as ICredentialDataDecryptedObject;
|
||||||
|
|
||||||
if (credentials === undefined) {
|
if (credentials === undefined) {
|
||||||
|
@ -145,7 +147,7 @@ export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: strin
|
||||||
|
|
||||||
const oauthTokenData = credentials.oauthTokenData as clientOAuth2.Data;
|
const oauthTokenData = credentials.oauthTokenData as clientOAuth2.Data;
|
||||||
|
|
||||||
const token = oAuthClient.createToken(get(oauthTokenData, property as string) || oauthTokenData.accessToken, oauthTokenData.refreshToken, tokenType || oauthTokenData.tokenType, oauthTokenData);
|
const token = oAuthClient.createToken(get(oauthTokenData, oAuth2Options?.property as string) || oauthTokenData.accessToken, oauthTokenData.refreshToken, oAuth2Options?.tokenType || oauthTokenData.tokenType, oauthTokenData);
|
||||||
// Signs the request by adding authorization headers or query parameters depending
|
// Signs the request by adding authorization headers or query parameters depending
|
||||||
// on the token-type used.
|
// on the token-type used.
|
||||||
const newRequestOptions = token.sign(requestOptions as clientOAuth2.RequestObject);
|
const newRequestOptions = token.sign(requestOptions as clientOAuth2.RequestObject);
|
||||||
|
@ -156,7 +158,18 @@ export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: strin
|
||||||
if (error.statusCode === 401) {
|
if (error.statusCode === 401) {
|
||||||
// TODO: Whole refresh process is not tested yet
|
// TODO: Whole refresh process is not tested yet
|
||||||
// Token is probably not valid anymore. So try refresh it.
|
// Token is probably not valid anymore. So try refresh it.
|
||||||
const newToken = await token.refresh();
|
|
||||||
|
const tokenRefreshOptions: IDataObject = {};
|
||||||
|
|
||||||
|
if (oAuth2Options?.includeCredentialsOnRefreshOnBody) {
|
||||||
|
const body: IDataObject = {
|
||||||
|
client_id: credentials.clientId as string,
|
||||||
|
client_secret: credentials.clientSecret as string,
|
||||||
|
};
|
||||||
|
tokenRefreshOptions.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newToken = await token.refresh(tokenRefreshOptions);
|
||||||
|
|
||||||
credentials.oauthTokenData = newToken.data;
|
credentials.oauthTokenData = newToken.data;
|
||||||
|
|
||||||
|
@ -543,8 +556,8 @@ export function getExecutePollFunctions(workflow: Workflow, node: INode, additio
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData,
|
prepareBinaryData,
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
@ -606,8 +619,8 @@ export function getExecuteTriggerFunctions(workflow: Workflow, node: INode, addi
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData,
|
prepareBinaryData,
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
@ -702,8 +715,8 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData,
|
prepareBinaryData,
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
@ -800,8 +813,8 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData:
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData,
|
prepareBinaryData,
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
@ -856,8 +869,8 @@ export function getLoadOptionsFunctions(workflow: Workflow, node: INode, additio
|
||||||
},
|
},
|
||||||
helpers: {
|
helpers: {
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
@ -923,8 +936,8 @@ export function getExecuteHookFunctions(workflow: Workflow, node: INode, additio
|
||||||
},
|
},
|
||||||
helpers: {
|
helpers: {
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
@ -1017,8 +1030,8 @@ export function getExecuteWebhookFunctions(workflow: Workflow, node: INode, addi
|
||||||
helpers: {
|
helpers: {
|
||||||
prepareBinaryData,
|
prepareBinaryData,
|
||||||
request: requestPromise,
|
request: requestPromise,
|
||||||
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, tokenType?: string, property?: string): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth2(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUri | requestPromise.RequestPromiseOptions, oAuth2Options?: IOAuth2Options): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, tokenType, property);
|
return requestOAuth2.call(this, credentialsType, requestOptions, node, additionalData, oAuth2Options);
|
||||||
},
|
},
|
||||||
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
requestOAuth1(this: IAllExecuteFunctions, credentialsType: string, requestOptions: OptionsWithUrl | requestPromise.RequestPromiseOptions): Promise<any> { // tslint:disable-line:no-any
|
||||||
return requestOAuth1.call(this, credentialsType, requestOptions);
|
return requestOAuth1.call(this, credentialsType, requestOptions);
|
||||||
|
|
46
packages/nodes-base/credentials/BoxOAuth2Api.credentials.ts
Normal file
46
packages/nodes-base/credentials/BoxOAuth2Api.credentials.ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import {
|
||||||
|
ICredentialType,
|
||||||
|
NodePropertyTypes,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
export class BoxOAuth2Api implements ICredentialType {
|
||||||
|
name = 'boxOAuth2Api';
|
||||||
|
extends = [
|
||||||
|
'oAuth2Api',
|
||||||
|
];
|
||||||
|
displayName = 'Box OAuth2 API';
|
||||||
|
properties = [
|
||||||
|
{
|
||||||
|
displayName: 'Authorization URL',
|
||||||
|
name: 'authUrl',
|
||||||
|
type: 'hidden' as NodePropertyTypes,
|
||||||
|
default: 'https://account.box.com/api/oauth2/authorize',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Access Token URL',
|
||||||
|
name: 'accessTokenUrl',
|
||||||
|
type: 'hidden' as NodePropertyTypes,
|
||||||
|
default: 'https://api.box.com/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',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
361
packages/nodes-base/nodes/Box/Box.node.ts
Normal file
361
packages/nodes-base/nodes/Box/Box.node.ts
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
import {
|
||||||
|
BINARY_ENCODING,
|
||||||
|
IExecuteFunctions,
|
||||||
|
} from 'n8n-core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IDataObject,
|
||||||
|
INodeTypeDescription,
|
||||||
|
INodeExecutionData,
|
||||||
|
INodeType,
|
||||||
|
IBinaryKeyData,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import {
|
||||||
|
boxApiRequest,
|
||||||
|
boxApiRequestAllItems,
|
||||||
|
} from './GenericFunctions';
|
||||||
|
|
||||||
|
import {
|
||||||
|
fileFields,
|
||||||
|
fileOperations,
|
||||||
|
} from './FileDescription';
|
||||||
|
|
||||||
|
import {
|
||||||
|
folderFields,
|
||||||
|
folderOperations,
|
||||||
|
} from './FolderDescription';
|
||||||
|
|
||||||
|
import * as moment from 'moment-timezone';
|
||||||
|
|
||||||
|
export class Box implements INodeType {
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'Box',
|
||||||
|
name: 'box',
|
||||||
|
icon: 'file:box.png',
|
||||||
|
group: ['input'],
|
||||||
|
version: 1,
|
||||||
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||||
|
description: 'Consume Box API',
|
||||||
|
defaults: {
|
||||||
|
name: 'Box',
|
||||||
|
color: '#00aeef',
|
||||||
|
},
|
||||||
|
inputs: ['main'],
|
||||||
|
outputs: ['main'],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'boxOAuth2Api',
|
||||||
|
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://developer.box.com/reference/post-files-id-copy
|
||||||
|
if (operation === 'copy') {
|
||||||
|
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||||
|
const parentId = this.getNodeParameter('parentId', i) as string;
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||||
|
const body: IDataObject = {};
|
||||||
|
if (additionalFields.name) {
|
||||||
|
body.name = additionalFields.name as string;
|
||||||
|
}
|
||||||
|
if (parentId) {
|
||||||
|
body.parent = { id: parentId };
|
||||||
|
} else {
|
||||||
|
body.parent = { id: 0 };
|
||||||
|
}
|
||||||
|
if (additionalFields.fields) {
|
||||||
|
qs.fields = additionalFields.fields as string;
|
||||||
|
}
|
||||||
|
if (additionalFields.version) {
|
||||||
|
body.version = additionalFields.version as string;
|
||||||
|
}
|
||||||
|
responseData = await boxApiRequest.call(this, 'POST', `/files/${fileId}/copy`, body, qs);
|
||||||
|
|
||||||
|
returnData.push(responseData as IDataObject);
|
||||||
|
}
|
||||||
|
//https://developer.box.com/reference/delete-files-id
|
||||||
|
if (operation === 'delete') {
|
||||||
|
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||||
|
responseData = await boxApiRequest.call(this, 'DELETE', `/files/${fileId}`);
|
||||||
|
responseData = { success: true };
|
||||||
|
returnData.push(responseData as IDataObject);
|
||||||
|
}
|
||||||
|
//https://developer.box.com/reference/get-files-id-content
|
||||||
|
if (operation === 'download') {
|
||||||
|
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||||
|
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i) as string;
|
||||||
|
responseData = await boxApiRequest.call(this, 'GET', `/files/${fileId}`);
|
||||||
|
|
||||||
|
const fileName = responseData.name;
|
||||||
|
|
||||||
|
let mimeType: string | undefined;
|
||||||
|
|
||||||
|
responseData = await boxApiRequest.call(this, 'GET', `/files/${fileId}/content`, {}, {}, undefined, { 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://developer.box.com/reference/get-files-id
|
||||||
|
if (operation === 'get') {
|
||||||
|
const fileId = this.getNodeParameter('fileId', i) as string;
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||||
|
if (additionalFields.fields) {
|
||||||
|
qs.fields = additionalFields.fields as string;
|
||||||
|
}
|
||||||
|
responseData = await boxApiRequest.call(this, 'GET', `/files/${fileId}`, {}, qs);
|
||||||
|
returnData.push(responseData as IDataObject);
|
||||||
|
}
|
||||||
|
//https://developer.box.com/reference/get-search/
|
||||||
|
if (operation === 'search') {
|
||||||
|
const query = this.getNodeParameter('query', i) as string;
|
||||||
|
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||||
|
const timezone = this.getTimezone();
|
||||||
|
qs.type = 'file';
|
||||||
|
qs.query = query;
|
||||||
|
Object.assign(qs, additionalFields);
|
||||||
|
|
||||||
|
if (qs.content_types) {
|
||||||
|
qs.content_types = (qs.content_types as string).split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalFields.createdRangeUi) {
|
||||||
|
const createdRangeValues = (additionalFields.createdRangeUi as IDataObject).createdRangeValuesUi as IDataObject;
|
||||||
|
if (createdRangeValues) {
|
||||||
|
qs.created_at_range = `${moment.tz(createdRangeValues.from, timezone).format()},${moment.tz(createdRangeValues.to, timezone).format()}`;
|
||||||
|
}
|
||||||
|
delete qs.createdRangeUi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalFields.updatedRangeUi) {
|
||||||
|
const updateRangeValues = (additionalFields.updatedRangeUi as IDataObject).updatedRangeValuesUi as IDataObject;
|
||||||
|
if (updateRangeValues) {
|
||||||
|
qs.updated_at_range = `${moment.tz(updateRangeValues.from, timezone).format()},${moment.tz(updateRangeValues.to, timezone).format()}`;
|
||||||
|
}
|
||||||
|
delete qs.updatedRangeUi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnAll) {
|
||||||
|
responseData = await boxApiRequestAllItems.call(this, 'entries', 'GET', `/search`, {}, qs);
|
||||||
|
} else {
|
||||||
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
|
responseData = await boxApiRequest.call(this, 'GET', `/search`, {}, qs);
|
||||||
|
responseData = responseData.entries;
|
||||||
|
}
|
||||||
|
returnData.push.apply(returnData, responseData as IDataObject[]);
|
||||||
|
}
|
||||||
|
//https://developer.box.com/reference/post-files-content
|
||||||
|
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;
|
||||||
|
|
||||||
|
const attributes: IDataObject = {};
|
||||||
|
|
||||||
|
if (parentId !== '') {
|
||||||
|
attributes['parent'] = { id: parentId };
|
||||||
|
} else {
|
||||||
|
// if not parent defined save it on the root directory
|
||||||
|
attributes['parent'] = { id: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
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: IDataObject = {};
|
||||||
|
|
||||||
|
attributes['name'] = fileName || binaryData.fileName;
|
||||||
|
|
||||||
|
body['attributes'] = JSON.stringify(attributes);
|
||||||
|
|
||||||
|
body['file'] = {
|
||||||
|
value: Buffer.from(binaryData.data, BINARY_ENCODING),
|
||||||
|
options: {
|
||||||
|
filename: binaryData.fileName,
|
||||||
|
contentType: binaryData.mimeType,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
responseData = await boxApiRequest.call(this, 'POST', '', {}, {}, 'https://upload.box.com/api/2.0/files/content', { formData: body });
|
||||||
|
|
||||||
|
returnData.push.apply(returnData, responseData.entries as IDataObject[]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const content = this.getNodeParameter('fileContent', i) as string;
|
||||||
|
|
||||||
|
if (fileName === '') {
|
||||||
|
throw new Error('File name must be set!');
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes['name'] = fileName;
|
||||||
|
|
||||||
|
const body: IDataObject = {};
|
||||||
|
|
||||||
|
body['attributes'] = JSON.stringify(attributes);
|
||||||
|
|
||||||
|
body['file'] = {
|
||||||
|
value: Buffer.from(content),
|
||||||
|
options: {
|
||||||
|
filename: fileName,
|
||||||
|
contentType: 'text/plain',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
responseData = await boxApiRequest.call(this, 'POST', '', {} , {}, 'https://upload.box.com/api/2.0/files/content', { formData: body });
|
||||||
|
|
||||||
|
returnData.push.apply(returnData, responseData.entries as IDataObject[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resource === 'folder') {
|
||||||
|
//https://developer.box.com/reference/post-folders
|
||||||
|
if (operation === 'create') {
|
||||||
|
const name = this.getNodeParameter('name', i) as string;
|
||||||
|
const parentId = this.getNodeParameter('parentId', i) as string;
|
||||||
|
const options = this.getNodeParameter('options', i) as IDataObject;
|
||||||
|
const body: IDataObject = {
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (parentId) {
|
||||||
|
body.parent = { id: parentId };
|
||||||
|
} else {
|
||||||
|
body.parent = { id: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.access) {
|
||||||
|
body.folder_upload_email = {
|
||||||
|
access: options.access as string,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.fields) {
|
||||||
|
qs.fields = options.fields as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData = await boxApiRequest.call(this, 'POST', '/folders', body, qs);
|
||||||
|
|
||||||
|
returnData.push(responseData);
|
||||||
|
}
|
||||||
|
//https://developer.box.com/reference/delete-folders-id
|
||||||
|
if (operation === 'delete') {
|
||||||
|
const folderId = this.getNodeParameter('folderId', i) as string;
|
||||||
|
const recursive = this.getNodeParameter('recursive', i) as boolean;
|
||||||
|
qs.recursive = recursive;
|
||||||
|
|
||||||
|
responseData = await boxApiRequest.call(this, 'DELETE', `/folders/${folderId}`, qs);
|
||||||
|
responseData = { success: true };
|
||||||
|
returnData.push(responseData as IDataObject);
|
||||||
|
}
|
||||||
|
//https://developer.box.com/reference/get-search/
|
||||||
|
if (operation === 'search') {
|
||||||
|
const query = this.getNodeParameter('query', i) as string;
|
||||||
|
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||||
|
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||||
|
const timezone = this.getTimezone();
|
||||||
|
qs.type = 'folder';
|
||||||
|
qs.query = query;
|
||||||
|
Object.assign(qs, additionalFields);
|
||||||
|
|
||||||
|
if (qs.content_types) {
|
||||||
|
qs.content_types = (qs.content_types as string).split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalFields.createdRangeUi) {
|
||||||
|
const createdRangeValues = (additionalFields.createdRangeUi as IDataObject).createdRangeValuesUi as IDataObject;
|
||||||
|
if (createdRangeValues) {
|
||||||
|
qs.created_at_range = `${moment.tz(createdRangeValues.from, timezone).format()},${moment.tz(createdRangeValues.to, timezone).format()}`;
|
||||||
|
}
|
||||||
|
delete qs.createdRangeUi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalFields.updatedRangeUi) {
|
||||||
|
const updateRangeValues = (additionalFields.updatedRangeUi as IDataObject).updatedRangeValuesUi as IDataObject;
|
||||||
|
if (updateRangeValues) {
|
||||||
|
qs.updated_at_range = `${moment.tz(updateRangeValues.from, timezone).format()},${moment.tz(updateRangeValues.to, timezone).format()}`;
|
||||||
|
}
|
||||||
|
delete qs.updatedRangeUi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnAll) {
|
||||||
|
responseData = await boxApiRequestAllItems.call(this, 'entries', 'GET', `/search`, {}, qs);
|
||||||
|
} else {
|
||||||
|
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||||
|
responseData = await boxApiRequest.call(this, 'GET', `/search`, {}, qs);
|
||||||
|
responseData = responseData.entries;
|
||||||
|
}
|
||||||
|
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)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
354
packages/nodes-base/nodes/Box/BoxTrigger.node.ts
Normal file
354
packages/nodes-base/nodes/Box/BoxTrigger.node.ts
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
import {
|
||||||
|
IHookFunctions,
|
||||||
|
IWebhookFunctions,
|
||||||
|
} from 'n8n-core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
INodeTypeDescription,
|
||||||
|
INodeType,
|
||||||
|
IWebhookResponseData,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import {
|
||||||
|
boxApiRequest,
|
||||||
|
boxApiRequestAllItems,
|
||||||
|
} from './GenericFunctions';
|
||||||
|
|
||||||
|
export class BoxTrigger implements INodeType {
|
||||||
|
description: INodeTypeDescription = {
|
||||||
|
displayName: 'Box Trigger',
|
||||||
|
name: 'boxTrigger',
|
||||||
|
icon: 'file:box.png',
|
||||||
|
group: ['trigger'],
|
||||||
|
version: 1,
|
||||||
|
description: 'Starts the workflow when a Github events occurs.',
|
||||||
|
defaults: {
|
||||||
|
name: 'Box Trigger',
|
||||||
|
color: '#00aeef',
|
||||||
|
},
|
||||||
|
inputs: [],
|
||||||
|
outputs: ['main'],
|
||||||
|
credentials: [
|
||||||
|
{
|
||||||
|
name: 'boxOAuth2Api',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
webhooks: [
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
httpMethod: 'POST',
|
||||||
|
responseMode: 'onReceived',
|
||||||
|
path: 'webhook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
displayName: 'Events',
|
||||||
|
name: 'events',
|
||||||
|
type: 'multiOptions',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Collaboration Created',
|
||||||
|
value: 'COLLABORATION.CREATED',
|
||||||
|
description: 'A collaboration is created',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Collaboration Accepted',
|
||||||
|
value: 'COLLABORATION.ACCEPTED',
|
||||||
|
description: 'A collaboration has been accepted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Collaboration Rejected',
|
||||||
|
value: 'COLLABORATION.REJECTED',
|
||||||
|
description: 'A collaboration has been rejected',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Collaboration Removed',
|
||||||
|
value: 'COLLABORATION.REMOVED',
|
||||||
|
description: 'A collaboration has been removed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Collaboration Updated',
|
||||||
|
value: 'COLLABORATION.UPDATED',
|
||||||
|
description: 'A collaboration has been updated.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Comment Created',
|
||||||
|
value: 'COMMENT.CREATED',
|
||||||
|
description: 'A comment object is created',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Comment Updated',
|
||||||
|
value: 'COMMENT.UPDATED',
|
||||||
|
description: 'A comment object is edited',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Comment Deleted',
|
||||||
|
value: 'COMMENT.DELETED',
|
||||||
|
description: 'A comment object is removed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Uploaded',
|
||||||
|
value: 'FILE.UPLOADED',
|
||||||
|
description: 'A file is uploaded to or moved to this folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Previewed',
|
||||||
|
value: 'FILE.PREVIEWED',
|
||||||
|
description: 'A file is previewed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Downloaded',
|
||||||
|
value: 'FILE.DOWNLOADED',
|
||||||
|
description: 'A file is downloaded',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Trashed',
|
||||||
|
value: 'FILE.TRASHED',
|
||||||
|
description: 'A file is moved to the trash',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Deleted',
|
||||||
|
value: 'FILE.DELETED',
|
||||||
|
description: 'A file is moved to the trash',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Restored',
|
||||||
|
value: 'FILE.RESTORED',
|
||||||
|
description: 'A file is restored from the trash',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Copied',
|
||||||
|
value: 'FILE.COPIED',
|
||||||
|
description: 'A file is copied',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Moved',
|
||||||
|
value: 'FILE.MOVED',
|
||||||
|
description: 'A file is moved from one folder to another',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Locked',
|
||||||
|
value: 'FILE.LOCKED',
|
||||||
|
description: 'A file is locked',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Unlocked',
|
||||||
|
value: 'FILE.UNLOCKED',
|
||||||
|
description: 'A file is unlocked',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'File Renamed',
|
||||||
|
value: 'FILE.RENAMED',
|
||||||
|
description: 'A file was renamed.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Created',
|
||||||
|
value: 'FOLDER.CREATED',
|
||||||
|
description: 'A folder is created',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Renamed',
|
||||||
|
value: 'FOLDER.RENAMED',
|
||||||
|
description: 'A folder was renamed.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Downloaded',
|
||||||
|
value: 'FOLDER.DOWNLOADED',
|
||||||
|
description: 'A folder is downloaded',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Restored',
|
||||||
|
value: 'FOLDER.RESTORED',
|
||||||
|
description: 'A folder is restored from the trash',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Deleted',
|
||||||
|
value: 'FOLDER.DELETED',
|
||||||
|
description: 'A folder is permanently removed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Copied',
|
||||||
|
value: 'FOLDER.COPIED',
|
||||||
|
description: 'A copy of a folder is made',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Moved',
|
||||||
|
value: 'FOLDER.MOVED',
|
||||||
|
description: 'A folder is moved to a different folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder Trashed',
|
||||||
|
value: 'FOLDER.TRASHED',
|
||||||
|
description: 'A folder is moved to the trash',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Metadata Instance Created',
|
||||||
|
value: 'METADATA_INSTANCE.CREATED',
|
||||||
|
description: 'A new metadata template instance is associated with a file or folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Metadata Instance Updated',
|
||||||
|
value: 'METADATA_INSTANCE.UPDATED',
|
||||||
|
description: 'An attribute (value) is updated/deleted for an existing metadata template instance associated with a file or folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Metadata Instance Deleted',
|
||||||
|
value: 'METADATA_INSTANCE.DELETED',
|
||||||
|
description: 'An existing metadata template instance associated with a file or folder is deleted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Sharedlink Deleted',
|
||||||
|
value: 'SHARED_LINK.DELETED',
|
||||||
|
description: 'A shared link was deleted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Sharedlink Created',
|
||||||
|
value: 'SHARED_LINK.CREATED',
|
||||||
|
description: 'A shared link was created',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Sharedlink UPDATED',
|
||||||
|
value: 'SHARED_LINK.UPDATED',
|
||||||
|
description: 'A shared link was updated',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Task Assignment Created',
|
||||||
|
value: 'TASK_ASSIGNMENT.CREATED',
|
||||||
|
description: 'A task is created',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Task Assignment Updated',
|
||||||
|
value: 'TASK_ASSIGNMENT.UPDATED',
|
||||||
|
description: 'A task is updated',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Webhook Deleted',
|
||||||
|
value: 'WEBHOOK.DELETED',
|
||||||
|
description: 'When a webhook is deleted',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
required: true,
|
||||||
|
default: [],
|
||||||
|
description: 'The events to listen to.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Target Type',
|
||||||
|
name: 'targetType',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'File',
|
||||||
|
value: 'file',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Folder',
|
||||||
|
value: 'folder',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
description: 'The type of item to trigger a webhook',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Target ID',
|
||||||
|
name: 'targetId',
|
||||||
|
type: 'string',
|
||||||
|
required: false,
|
||||||
|
default: '',
|
||||||
|
description: 'The ID of the item to trigger a webhook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// @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;
|
||||||
|
const targetId = this.getNodeParameter('targetId') as string;
|
||||||
|
const targetType = this.getNodeParameter('targetType') as string;
|
||||||
|
// Check all the webhooks which exist already if it is identical to the
|
||||||
|
// one that is supposed to get created.
|
||||||
|
const endpoint = '/webhooks';
|
||||||
|
const webhooks = await boxApiRequestAllItems.call(this, 'entries', 'GET', endpoint, {});
|
||||||
|
|
||||||
|
console.log(webhooks);
|
||||||
|
|
||||||
|
for (const webhook of webhooks) {
|
||||||
|
if (webhook.address === webhookUrl &&
|
||||||
|
webhook.target.id === targetId &&
|
||||||
|
webhook.target.type === targetType) {
|
||||||
|
for (const event of events) {
|
||||||
|
if (!webhook.triggers.includes(event)) {
|
||||||
|
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 targetId = this.getNodeParameter('targetId') as string;
|
||||||
|
const targetType = this.getNodeParameter('targetType') as string;
|
||||||
|
|
||||||
|
const endpoint = '/webhooks';
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
address: webhookUrl,
|
||||||
|
triggers: events,
|
||||||
|
target: {
|
||||||
|
id: targetId,
|
||||||
|
type: targetType,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const responseData = await boxApiRequest.call(this, 'POST', endpoint, body);
|
||||||
|
|
||||||
|
if (responseData.id === undefined) {
|
||||||
|
// Required data is missing so was not successful
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookData.webhookId = responseData.id as string;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
async delete(this: IHookFunctions): Promise<boolean> {
|
||||||
|
const webhookData = this.getWorkflowStaticData('node');
|
||||||
|
if (webhookData.webhookId !== undefined) {
|
||||||
|
|
||||||
|
const endpoint = `/webhooks/${webhookData.webhookId}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await boxApiRequest.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;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
||||||
|
const bodyData = this.getBodyData();
|
||||||
|
|
||||||
|
return {
|
||||||
|
workflowData: [
|
||||||
|
this.helpers.returnJsonArray(bodyData)
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
596
packages/nodes-base/nodes/Box/FileDescription.ts
Normal file
596
packages/nodes-base/nodes/Box/FileDescription.ts
Normal file
|
@ -0,0 +1,596 @@
|
||||||
|
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 files',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Upload',
|
||||||
|
value: 'upload',
|
||||||
|
description: 'Upload a file',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'upload',
|
||||||
|
description: 'The operation to perform.',
|
||||||
|
},
|
||||||
|
] as INodeProperties[];
|
||||||
|
|
||||||
|
export const fileFields = [
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* file:copy */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'File ID',
|
||||||
|
name: 'fileId',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'copy',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'File ID',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Parent ID',
|
||||||
|
name: 'parentId',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'copy',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'The ID of folder to copy the file to. If not defined will be copied to the root folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Additional Fields',
|
||||||
|
name: 'additionalFields',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'copy',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Fields',
|
||||||
|
name: 'fields',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'A comma-separated list of attributes to include in the response. This can be used to request fields that are not normally returned in a standard response.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Name',
|
||||||
|
name: 'name',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'An optional new name for the copied file.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Version',
|
||||||
|
name: 'version',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'An optional ID of the specific file version to copy.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* 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',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Additional Fields',
|
||||||
|
name: 'additionalFields',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'get',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Fields',
|
||||||
|
name: 'fields',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'A comma-separated list of attributes to include in the response. This can be used to request fields that are not normally returned in a standard response.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* file:search */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Query',
|
||||||
|
name: 'query',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'The string to search for. This query is matched against item names, descriptions, text content of files, and various other fields of the different item types.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Return All',
|
||||||
|
name: 'returnAll',
|
||||||
|
type: 'boolean',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
returnAll: [
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typeOptions: {
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 500,
|
||||||
|
},
|
||||||
|
default: 100,
|
||||||
|
description: 'How many results to return.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Additional Fields',
|
||||||
|
name: 'additionalFields',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Content Types',
|
||||||
|
name: 'contet_types',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Limits search results to items with the given content types.</br>
|
||||||
|
Content types are defined as a comma separated lists of Box recognized content types.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Created At Range',
|
||||||
|
name: 'createdRangeUi',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: false,
|
||||||
|
},
|
||||||
|
placeholder: 'Add Range',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Range',
|
||||||
|
name: 'createdRangeValuesUi',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'From',
|
||||||
|
name: 'from',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To',
|
||||||
|
name: 'to',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Direction',
|
||||||
|
name: 'direction',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'ASC',
|
||||||
|
value: 'ASC',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DESC',
|
||||||
|
value: 'DESC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
description: 'Defines the direction in which search results are ordered. Default value is DESC.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Fields',
|
||||||
|
name: 'fields',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'A comma-separated list of attributes to include in the response. This can be used to request fields that are not normally returned in a standard response.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'File Extensions',
|
||||||
|
name: 'file_extensions',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: 'pdf,png,gif',
|
||||||
|
description: 'Limits search results to a comma-separated list of file extensions.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Folder IDs',
|
||||||
|
name: 'ancestor_folder_ids',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Limits search results to items within the given list of folders.</br>
|
||||||
|
Folders are defined as a comma separated lists of folder IDs.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Scope',
|
||||||
|
name: 'scope',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'User Content',
|
||||||
|
value: 'user_content',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Enterprise Content',
|
||||||
|
value: 'enterprise_content',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
description: 'Limits search results to a user scope.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Size Range',
|
||||||
|
name: 'size_range',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: '1000000,5000000',
|
||||||
|
description: `Limits search results to items within a given file size range.</br>
|
||||||
|
File size ranges are defined as comma separated byte sizes.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Sort',
|
||||||
|
name: 'sort',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Relevance',
|
||||||
|
value: 'relevance',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Modified At',
|
||||||
|
value: 'modified_at',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'relevance',
|
||||||
|
description: 'returns the results ordered in descending order by date at which the item was last modified.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Trash Content',
|
||||||
|
name: 'trash_content',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Non Trashed Only',
|
||||||
|
value: 'non_trashed_only',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Trashed Only',
|
||||||
|
value: 'trashed_only',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'non_trashed_only',
|
||||||
|
description: 'Controls if search results include the trash.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Update At Range',
|
||||||
|
name: 'updatedRangeUi',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: false,
|
||||||
|
},
|
||||||
|
placeholder: 'Add Range',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Range',
|
||||||
|
name: 'updatedRangeValuesUi',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'From',
|
||||||
|
name: 'from',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To',
|
||||||
|
name: 'to',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'User IDs',
|
||||||
|
name: 'owner_user_ids',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Limits search results to items owned by the given list of owners..</br>
|
||||||
|
Owners are defined as a comma separated list of user IDs.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* file:upload */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'File Name',
|
||||||
|
name: 'fileName',
|
||||||
|
type: 'string',
|
||||||
|
placeholder: 'photo.png',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'upload',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'The name the file should be saved as.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Parent ID',
|
||||||
|
name: 'parentId',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'upload',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'file',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'ID of the parent folder that will contain the file. If not it will be uploaded to the root folder',
|
||||||
|
},
|
||||||
|
] as INodeProperties[];
|
417
packages/nodes-base/nodes/Box/FolderDescription.ts
Normal file
417
packages/nodes-base/nodes/Box/FolderDescription.ts
Normal file
|
@ -0,0 +1,417 @@
|
||||||
|
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: 'Delete',
|
||||||
|
value: 'delete',
|
||||||
|
description: 'Delete a folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Search',
|
||||||
|
value: 'search',
|
||||||
|
description: 'Search files',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'create',
|
||||||
|
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`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Parent ID',
|
||||||
|
name: 'parentId',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'create',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'ID of the folder you want to create the new folder in. if not defined it will be created on the root folder',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Options',
|
||||||
|
name: 'options',
|
||||||
|
type: 'collection',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'create',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Access',
|
||||||
|
name: 'access',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Collaborators',
|
||||||
|
value: 'collaborators',
|
||||||
|
description: 'Only emails from registered email addresses for collaborators will be accepted.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Open',
|
||||||
|
value: 'open',
|
||||||
|
description: 'It will accept emails from any email addres',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
description: 'ID of the folder you want to create the new folder in',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Fields',
|
||||||
|
name: 'fields',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'A comma-separated list of attributes to include in the response. This can be used to request fields that are not normally returned in a standard response.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* folder:delete */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Folder ID',
|
||||||
|
name: 'folderId',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'delete',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'Folder ID',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Recursive',
|
||||||
|
name: 'recursive',
|
||||||
|
type: 'boolean',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'delete',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: false,
|
||||||
|
description: 'Delete a folder that is not empty by recursively deleting the folder and all of its content.',
|
||||||
|
},
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* file:search */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
displayName: 'Query',
|
||||||
|
name: 'query',
|
||||||
|
type: 'string',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
description: 'The string to search for. This query is matched against item names, descriptions, text content of files, and various other fields of the different item types.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Return All',
|
||||||
|
name: 'returnAll',
|
||||||
|
type: 'boolean',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
returnAll: [
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typeOptions: {
|
||||||
|
minValue: 1,
|
||||||
|
maxValue: 500,
|
||||||
|
},
|
||||||
|
default: 100,
|
||||||
|
description: 'How many results to return.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Additional Fields',
|
||||||
|
name: 'additionalFields',
|
||||||
|
type: 'collection',
|
||||||
|
placeholder: 'Add Field',
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'search',
|
||||||
|
],
|
||||||
|
resource: [
|
||||||
|
'folder',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Content Types',
|
||||||
|
name: 'contet_types',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Limits search results to items with the given content types.</br>
|
||||||
|
Content types are defined as a comma separated lists of Box recognized content types.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Created At Range',
|
||||||
|
name: 'createdRangeUi',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: false,
|
||||||
|
},
|
||||||
|
placeholder: 'Add Range',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Range',
|
||||||
|
name: 'createdRangeValuesUi',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'From',
|
||||||
|
name: 'from',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To',
|
||||||
|
name: 'to',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Direction',
|
||||||
|
name: 'direction',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'ASC',
|
||||||
|
value: 'ASC',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'DESC',
|
||||||
|
value: 'DESC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
description: 'Defines the direction in which search results are ordered. Default value is DESC.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Fields',
|
||||||
|
name: 'fields',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: 'A comma-separated list of attributes to include in the response. This can be used to request fields that are not normally returned in a standard response.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'File Extensions',
|
||||||
|
name: 'file_extensions',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: 'pdf,png,gif',
|
||||||
|
description: 'Limits search results to a comma-separated list of file extensions.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Folder IDs',
|
||||||
|
name: 'ancestor_folder_ids',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Limits search results to items within the given list of folders.</br>
|
||||||
|
Folders are defined as a comma separated lists of folder IDs.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Scope',
|
||||||
|
name: 'scope',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'User Content',
|
||||||
|
value: 'user_content',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Enterprise Content',
|
||||||
|
value: 'enterprise_content',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: '',
|
||||||
|
description: 'Limits search results to a user scope.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Size Range',
|
||||||
|
name: 'size_range',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: '1000000,5000000',
|
||||||
|
description: `Limits search results to items within a given file size range.</br>
|
||||||
|
File size ranges are defined as comma separated byte sizes.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Sort',
|
||||||
|
name: 'sort',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Relevance',
|
||||||
|
value: 'relevance',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Modified At',
|
||||||
|
value: 'modified_at',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'relevance',
|
||||||
|
description: 'returns the results ordered in descending order by date at which the item was last modified.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Trash Content',
|
||||||
|
name: 'trash_content',
|
||||||
|
type: 'options',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Non Trashed Only',
|
||||||
|
value: 'non_trashed_only',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Trashed Only',
|
||||||
|
value: 'trashed_only',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: 'non_trashed_only',
|
||||||
|
description: 'Controls if search results include the trash.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Update At Range',
|
||||||
|
name: 'updatedRangeUi',
|
||||||
|
type: 'fixedCollection',
|
||||||
|
typeOptions: {
|
||||||
|
multipleValues: false,
|
||||||
|
},
|
||||||
|
placeholder: 'Add Range',
|
||||||
|
default: {},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
displayName: 'Range',
|
||||||
|
name: 'updatedRangeValuesUi',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
displayName: 'From',
|
||||||
|
name: 'from',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'To',
|
||||||
|
name: 'to',
|
||||||
|
type: 'dateTime',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'User IDs',
|
||||||
|
name: 'owner_user_ids',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
description: `Limits search results to items owned by the given list of owners..</br>
|
||||||
|
Owners are defined as a comma separated list of user IDs.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as INodeProperties[];
|
85
packages/nodes-base/nodes/Box/GenericFunctions.ts
Normal file
85
packages/nodes-base/nodes/Box/GenericFunctions.ts
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
import {
|
||||||
|
OptionsWithUri,
|
||||||
|
} from 'request';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IExecuteFunctions,
|
||||||
|
IExecuteSingleFunctions,
|
||||||
|
ILoadOptionsFunctions,
|
||||||
|
IHookFunctions,
|
||||||
|
} from 'n8n-core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
IDataObject,
|
||||||
|
IOAuth2Options,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
export async function boxApiRequest(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.box.com/2.0${resource}`,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
options = Object.assign({}, options, option);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Object.keys(body).length === 0) {
|
||||||
|
delete options.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oAuth2Options: IOAuth2Options = {
|
||||||
|
includeCredentialsOnRefreshOnBody: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
return await this.helpers.requestOAuth2.call(this, 'boxOAuth2Api', options, oAuth2Options);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
let errorMessage;
|
||||||
|
|
||||||
|
if (error.response && error.response.body) {
|
||||||
|
|
||||||
|
if (error.response.body.context_info && error.response.body.context_info.errors) {
|
||||||
|
|
||||||
|
const errors = error.response.body.context_info.errors;
|
||||||
|
|
||||||
|
errorMessage = errors.map((e: IDataObject) => e.message);
|
||||||
|
|
||||||
|
errorMessage = errorMessage.join('|');
|
||||||
|
|
||||||
|
} else if (error.response.body.message) {
|
||||||
|
|
||||||
|
errorMessage = error.response.body.message;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Box error response [${error.statusCode}]: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function boxApiRequestAllItems(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;
|
||||||
|
query.limit = 100;
|
||||||
|
query.offset = 0;
|
||||||
|
do {
|
||||||
|
responseData = await boxApiRequest.call(this, method, endpoint, body, query);
|
||||||
|
query.offset = responseData['offset'] + query.limit;
|
||||||
|
returnData.push.apply(returnData, responseData[propertyName]);
|
||||||
|
} while (
|
||||||
|
responseData[propertyName].length !== 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return returnData;
|
||||||
|
}
|
BIN
packages/nodes-base/nodes/Box/box.png
Normal file
BIN
packages/nodes-base/nodes/Box/box.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -45,7 +45,7 @@ export async function hubspotApiRequest(this: IHookFunctions | IExecuteFunctions
|
||||||
return await this.helpers.request!(options);
|
return await this.helpers.request!(options);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return await this.helpers.requestOAuth2!.call(this, 'hubspotOAuth2Api', options, 'Bearer');
|
return await this.helpers.requestOAuth2!.call(this, 'hubspotOAuth2Api', options, { tokenType: 'Bearer' });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let errorMessages;
|
let errorMessages;
|
||||||
|
|
|
@ -57,7 +57,7 @@ export async function mailchimpApiRequest(this: IHookFunctions | IExecuteFunctio
|
||||||
|
|
||||||
options.url = `${api_endpoint}/3.0${endpoint}`;
|
options.url = `${api_endpoint}/3.0${endpoint}`;
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return await this.helpers.requestOAuth2!.call(this, 'mailchimpOAuth2Api', options, 'Bearer');
|
return await this.helpers.requestOAuth2!.call(this, 'mailchimpOAuth2Api', options, { tokenType: 'Bearer' });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.respose && error.response.body && error.response.body.detail) {
|
if (error.respose && error.response.body && error.response.body.detail) {
|
||||||
|
|
|
@ -9,8 +9,10 @@ import {
|
||||||
} from 'n8n-core';
|
} from 'n8n-core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IDataObject
|
IDataObject,
|
||||||
|
IOAuth2Options,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
export async function slackApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: object = {}, query: object = {}, headers: {} | undefined = undefined, option: {} = {}): Promise<any> { // tslint:disable-line:no-any
|
export async function slackApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: object = {}, query: object = {}, headers: {} | undefined = undefined, option: {} = {}): Promise<any> { // tslint:disable-line:no-any
|
||||||
|
@ -42,8 +44,13 @@ export async function slackApiRequest(this: IExecuteFunctions | IExecuteSingleFu
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return await this.helpers.request(options);
|
return await this.helpers.request(options);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
const oAuth2Options: IOAuth2Options = {
|
||||||
|
tokenType: 'Bearer',
|
||||||
|
property: 'authed_user.access_token',
|
||||||
|
};
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
return await this.helpers.requestOAuth2.call(this, 'slackOAuth2Api', options, 'bearer', 'authed_user.access_token');
|
return await this.helpers.requestOAuth2.call(this, 'slackOAuth2Api', options, oAuth2Options);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.statusCode === 401) {
|
if (error.statusCode === 401) {
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"dist/credentials/BannerbearApi.credentials.js",
|
"dist/credentials/BannerbearApi.credentials.js",
|
||||||
"dist/credentials/BitbucketApi.credentials.js",
|
"dist/credentials/BitbucketApi.credentials.js",
|
||||||
"dist/credentials/BitlyApi.credentials.js",
|
"dist/credentials/BitlyApi.credentials.js",
|
||||||
|
"dist/credentials/BoxOAuth2Api.credentials.js",
|
||||||
"dist/credentials/ChargebeeApi.credentials.js",
|
"dist/credentials/ChargebeeApi.credentials.js",
|
||||||
"dist/credentials/CircleCiApi.credentials.js",
|
"dist/credentials/CircleCiApi.credentials.js",
|
||||||
"dist/credentials/ClearbitApi.credentials.js",
|
"dist/credentials/ClearbitApi.credentials.js",
|
||||||
|
@ -177,6 +178,8 @@
|
||||||
"dist/nodes/Bannerbear/Bannerbear.node.js",
|
"dist/nodes/Bannerbear/Bannerbear.node.js",
|
||||||
"dist/nodes/Bitbucket/BitbucketTrigger.node.js",
|
"dist/nodes/Bitbucket/BitbucketTrigger.node.js",
|
||||||
"dist/nodes/Bitly/Bitly.node.js",
|
"dist/nodes/Bitly/Bitly.node.js",
|
||||||
|
"dist/nodes/Box/Box.node.js",
|
||||||
|
"dist/nodes/Box/BoxTrigger.node.js",
|
||||||
"dist/nodes/Calendly/CalendlyTrigger.node.js",
|
"dist/nodes/Calendly/CalendlyTrigger.node.js",
|
||||||
"dist/nodes/Chargebee/Chargebee.node.js",
|
"dist/nodes/Chargebee/Chargebee.node.js",
|
||||||
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
|
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
|
||||||
|
|
|
@ -12,6 +12,11 @@ export interface IBinaryData {
|
||||||
fileExtension?: string;
|
fileExtension?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IOAuth2Options {
|
||||||
|
includeCredentialsOnRefreshOnBody?: boolean;
|
||||||
|
property?: string;
|
||||||
|
tokenType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IConnection {
|
export interface IConnection {
|
||||||
// The node the connection is to
|
// The node the connection is to
|
||||||
|
@ -180,7 +185,6 @@ export interface IExecuteData {
|
||||||
node: INode;
|
node: INode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type IContextObject = {
|
export type IContextObject = {
|
||||||
[key: string]: any; // tslint:disable-line:no-any
|
[key: string]: any; // tslint:disable-line:no-any
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue