mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
feat(Trello Node) Add support for board members and credential tests (#3201)
* adds support for trello board member operations: inviteMemberByEmail, addMember, removeMember, getMembers * lintfix * format fixes * remove unnecessary variable and assign to qs on same line * fix description * Moved Board Members to their own resource * Removed members from board resource... * Added return all limits to get members * adds info about Trello premium feature in description * Improvements from internal review * ⚡ Improvements * Changed credentials to use new system and implemented test * ⚡ Improvements * fix(core): Fix issue with fixedCollection having all default values * 👕 Fix lint issue Co-authored-by: Jonathan Bennetts <jonathan.bennetts@gmail.com> Co-authored-by: ricardo <ricardoespinoza105@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
parent
7ced65484f
commit
d8870ecbff
|
@ -1,9 +1,11 @@
|
|||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
IHttpRequestOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
|
||||
export class TrelloApi implements ICredentialType {
|
||||
name = 'trelloApi';
|
||||
displayName = 'Trello API';
|
||||
|
@ -13,19 +15,36 @@ export class TrelloApi implements ICredentialType {
|
|||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'API Token',
|
||||
name: 'apiToken',
|
||||
type: 'string',
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'OAuth Secret',
|
||||
name: 'oauthSecret',
|
||||
type: 'string',
|
||||
type: 'hidden',
|
||||
default: '',
|
||||
},
|
||||
];
|
||||
|
||||
async authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions> {
|
||||
requestOptions.qs = {
|
||||
...requestOptions.qs,
|
||||
'key': credentials.apiKey,
|
||||
'token': credentials.apiToken,
|
||||
};
|
||||
return requestOptions;
|
||||
}
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.trello.com',
|
||||
url: '=/1/tokens/{{$credentials.apiToken}}/member',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3663,7 +3663,7 @@ export class Pipedrive implements INodeType {
|
|||
loadOptionsMethod: 'getFilters',
|
||||
},
|
||||
default: '',
|
||||
description: 'ID of the filter to use.',
|
||||
description: 'ID of the filter to use',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -455,5 +455,4 @@ export const boardFields: INodeProperties[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
|
||||
];
|
||||
|
|
337
packages/nodes-base/nodes/Trello/BoardMemberDescription.ts
Normal file
337
packages/nodes-base/nodes/Trello/BoardMemberDescription.ts
Normal file
|
@ -0,0 +1,337 @@
|
|||
import {
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export const boardMemberOperations: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// boardMember
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Add',
|
||||
value: 'add',
|
||||
description: 'Add member to board using member ID',
|
||||
},
|
||||
{
|
||||
name: 'Get All',
|
||||
value: 'getAll',
|
||||
description: 'Get all members of a board',
|
||||
},
|
||||
{
|
||||
name: 'Invite',
|
||||
value: 'invite',
|
||||
description: 'Invite a new member to a board via email',
|
||||
},
|
||||
{
|
||||
name: 'Remove',
|
||||
value: 'remove',
|
||||
description: 'Remove member from board using member ID',
|
||||
},
|
||||
],
|
||||
default: 'add',
|
||||
description: 'The operation to perform.',
|
||||
},
|
||||
];
|
||||
|
||||
export const boardMemberFields: INodeProperties[] = [
|
||||
// ----------------------------------
|
||||
// boardMember:getAll
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to get members from',
|
||||
},
|
||||
{
|
||||
displayName: 'Return All',
|
||||
name: 'returnAll',
|
||||
type: 'boolean',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: false,
|
||||
description: 'Whether to return all results or only up to a given limit',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
description: 'Max number of results to return',
|
||||
default: 20,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'getAll',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
returnAll: [
|
||||
false,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// boardMember:add
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'add',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to add member to',
|
||||
},
|
||||
{
|
||||
displayName: 'Member ID',
|
||||
name: 'idMember',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'add',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the member to add to the board',
|
||||
},
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
required: true,
|
||||
default: 'normal',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'add',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Normal',
|
||||
value: 'normal',
|
||||
description: 'Invite as normal member',
|
||||
},
|
||||
{
|
||||
name: 'Admin',
|
||||
value: 'admin',
|
||||
description: 'Invite as admin',
|
||||
},
|
||||
{
|
||||
name: 'Observer',
|
||||
value: 'observer',
|
||||
description: 'Invite as observer (Trello premium feature)',
|
||||
},
|
||||
],
|
||||
description: 'Determines the type of membership the user being added should have',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'add',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Allow Billable Guest',
|
||||
name: 'allowBillableGuest',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Allows organization admins to add multi-board guests onto a board',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// boardMember:invite
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'invite',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to invite member to',
|
||||
},
|
||||
{
|
||||
displayName: 'Email',
|
||||
name: 'email',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'invite',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to update',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'additionalFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'invite',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Type',
|
||||
name: 'type',
|
||||
type: 'options',
|
||||
default: 'normal',
|
||||
options: [
|
||||
{
|
||||
name: 'Normal',
|
||||
value: 'normal',
|
||||
description: 'Invite as normal member',
|
||||
},
|
||||
{
|
||||
name: 'Admin',
|
||||
value: 'admin',
|
||||
description: 'Invite as admin',
|
||||
},
|
||||
{
|
||||
name: 'Observer',
|
||||
value: 'observer',
|
||||
description: 'Invite as observer (Trello premium feature)',
|
||||
},
|
||||
],
|
||||
description: 'Determines the type of membership the user being added should have',
|
||||
},
|
||||
{
|
||||
displayName: 'Full Name',
|
||||
name: 'fullName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'The full name of the user to add as a member of the board. Must have a length of at least 1 and cannot begin nor end with a space.',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ----------------------------------
|
||||
// boardMember:remove
|
||||
// ----------------------------------
|
||||
{
|
||||
displayName: 'Board ID',
|
||||
name: 'id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'remove',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the board to remove member from',
|
||||
},
|
||||
{
|
||||
displayName: 'Member ID',
|
||||
name: 'idMember',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
operation: [
|
||||
'remove',
|
||||
],
|
||||
resource: [
|
||||
'boardMember',
|
||||
],
|
||||
},
|
||||
},
|
||||
description: 'The ID of the member to remove from the board',
|
||||
},
|
||||
];
|
|
@ -9,7 +9,9 @@ import {
|
|||
} from 'request';
|
||||
|
||||
import {
|
||||
IDataObject, NodeApiError, NodeOperationError,
|
||||
IDataObject,
|
||||
JsonObject,
|
||||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
|
@ -22,16 +24,9 @@ import {
|
|||
* @returns {Promise<any>}
|
||||
*/
|
||||
export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise<any> { // tslint:disable-line:no-any
|
||||
const credentials = await this.getCredentials('trelloApi');
|
||||
|
||||
query = query || {};
|
||||
|
||||
query.key = credentials.apiKey;
|
||||
query.token = credentials.apiToken;
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
},
|
||||
method,
|
||||
body,
|
||||
qs: query,
|
||||
|
@ -40,9 +35,9 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa
|
|||
};
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
return await this.helpers.requestWithAuthentication.call(this, 'trelloApi', options);
|
||||
} catch(error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,11 @@ import {
|
|||
boardOperations,
|
||||
} from './BoardDescription';
|
||||
|
||||
import {
|
||||
boardMemberFields,
|
||||
boardMemberOperations,
|
||||
} from './BoardMemberDescription';
|
||||
|
||||
import {
|
||||
cardFields,
|
||||
cardOperations,
|
||||
|
@ -84,6 +89,10 @@ export class Trello implements INodeType {
|
|||
name: 'Board',
|
||||
value: 'board',
|
||||
},
|
||||
{
|
||||
name: 'Board Member',
|
||||
value: 'boardMember',
|
||||
},
|
||||
{
|
||||
name: 'Card',
|
||||
value: 'card',
|
||||
|
@ -114,6 +123,7 @@ export class Trello implements INodeType {
|
|||
// ----------------------------------
|
||||
...attachmentOperations,
|
||||
...boardOperations,
|
||||
...boardMemberOperations,
|
||||
...cardOperations,
|
||||
...cardCommentOperations,
|
||||
...checklistOperations,
|
||||
|
@ -125,6 +135,7 @@ export class Trello implements INodeType {
|
|||
// ----------------------------------
|
||||
...attachmentFields,
|
||||
...boardFields,
|
||||
...boardMemberFields,
|
||||
...cardFields,
|
||||
...cardCommentFields,
|
||||
...checklistFields,
|
||||
|
@ -216,7 +227,68 @@ export class Trello implements INodeType {
|
|||
} else {
|
||||
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`);
|
||||
}
|
||||
} else if (resource === 'boardMember') {
|
||||
if (operation === 'getAll') {
|
||||
// ----------------------------------
|
||||
// getAll
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'GET';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
returnAll = this.getNodeParameter('returnAll', i) as boolean;
|
||||
if (returnAll === false) {
|
||||
qs.limit = this.getNodeParameter('limit', i) as number;
|
||||
}
|
||||
|
||||
endpoint = `boards/${id}/members`;
|
||||
|
||||
} else if (operation === 'add') {
|
||||
// ----------------------------------
|
||||
// add
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'PUT';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
const idMember = this.getNodeParameter('idMember', i) as string;
|
||||
|
||||
endpoint = `boards/${id}/members/${idMember}`;
|
||||
|
||||
qs.type = this.getNodeParameter('type', i) as string;
|
||||
qs.allowBillableGuest = this.getNodeParameter('additionalFields.allowBillableGuest', i, false) as boolean;
|
||||
|
||||
} else if (operation === 'invite') {
|
||||
// ----------------------------------
|
||||
// invite
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'PUT';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
|
||||
endpoint = `boards/${id}/members`;
|
||||
|
||||
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
|
||||
|
||||
qs.email = this.getNodeParameter('email', i) as string;
|
||||
qs.type = additionalFields.type as string;
|
||||
body.fullName = additionalFields.fullName as string;
|
||||
} else if (operation === 'remove') {
|
||||
// ----------------------------------
|
||||
// remove
|
||||
// ----------------------------------
|
||||
|
||||
requestMethod = 'DELETE';
|
||||
|
||||
const id = this.getNodeParameter('id', i) as string;
|
||||
const idMember = this.getNodeParameter('idMember', i) as string;
|
||||
|
||||
endpoint = `boards/${id}/members/${idMember}`;
|
||||
|
||||
} else {
|
||||
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`);
|
||||
}
|
||||
} else if (resource === 'card') {
|
||||
|
||||
if (operation === 'create') {
|
||||
|
|
|
@ -159,10 +159,10 @@ export class TrelloTrigger implements INodeType {
|
|||
|
||||
const bodyData = this.getBodyData();
|
||||
|
||||
const credentials = await this.getCredentials('trelloApi');
|
||||
|
||||
// TODO: Check why that does not work as expected even though it gets done as described
|
||||
// https://developers.trello.com/page/webhooks
|
||||
|
||||
//const credentials = await this.getCredentials('trelloApi');
|
||||
// // Check if the request is valid
|
||||
// const headerData = this.getHeaderData() as IDataObject;
|
||||
// const webhookUrl = this.getNodeWebhookUrl('default');
|
||||
|
|
Loading…
Reference in a new issue