diff --git a/packages/nodes-base/credentials/MauticApi.credentials.ts b/packages/nodes-base/credentials/MauticApi.credentials.ts index 28938b2443..052a8818b5 100644 --- a/packages/nodes-base/credentials/MauticApi.credentials.ts +++ b/packages/nodes-base/credentials/MauticApi.credentials.ts @@ -12,6 +12,7 @@ export class MauticApi implements ICredentialType { name: 'url', type: 'string' as NodePropertyTypes, default: '', + placeholder: 'https://name.mautic.net', }, { displayName: 'Username', @@ -22,7 +23,7 @@ export class MauticApi implements ICredentialType { { displayName: 'Password', name: 'password', - type: 'string' as NodePropertyTypes, + type: 'password' as NodePropertyTypes, default: '', }, ]; diff --git a/packages/nodes-base/nodes/Mautic/ContactDescription.ts b/packages/nodes-base/nodes/Mautic/ContactDescription.ts index 092690e7d3..01b164d8e5 100644 --- a/packages/nodes-base/nodes/Mautic/ContactDescription.ts +++ b/packages/nodes-base/nodes/Mautic/ContactDescription.ts @@ -1,4 +1,4 @@ -import { INodeProperties } from "n8n-workflow"; +import { INodeProperties } from 'n8n-workflow'; export const contactOperations = [ { @@ -104,7 +104,7 @@ export const contactFields = [ }, }, default: '', - description: 'LastName', + description: 'Last Name', }, { displayName: 'Primary Company', @@ -394,6 +394,7 @@ export const contactFields = [ }, ], }, + /* -------------------------------------------------------------------------- */ /* contact:get */ /* -------------------------------------------------------------------------- */ @@ -414,6 +415,7 @@ export const contactFields = [ default: '', description: 'Contact ID', }, + /* -------------------------------------------------------------------------- */ /* contact:getAll */ /* -------------------------------------------------------------------------- */ @@ -458,74 +460,7 @@ export const contactFields = [ default: 30, description: 'How many results to return.', }, - { - displayName: 'Filters', - name: 'filters', - type: 'collection', - placeholder: 'Add Filter', - default: {}, - displayOptions: { - show: { - resource: [ - 'contact', - ], - operation: [ - 'getAll', - ], - }, - }, - options: [ - { - displayName: 'Search', - name: 'search', - type: 'string', - default: '', - description: 'String or search command to filter entities by.', - }, - { - displayName: 'Order By', - name: 'orderBy', - type: 'string', - default: '', - description: `Column to sort by. Can use any column listed in the response.
- However, all properties in the response that are written in camelCase need to be
- changed a bit. Before every capital add an underscore _ and then change the capital
- letters to non-capital letters. So dateIdentified becomes date_identified, modifiedByUser - becomes modified_by_user etc.`, - }, - { - displayName: 'Order By Dir', - name: 'orderByDir', - type: 'options', - default: '', - options: [ - { - name: 'ASC', - valie: 'asc', - }, - { - name: 'Desc', - valie: 'desc', - }, - ], - description: 'Sort direction: asc or desc.', - }, - { - displayName: 'Published Only', - name: 'publishedOnly', - type: 'boolean', - default: false, - description: 'Only return currently published entities.', - }, - { - displayName: 'Minimal', - name: 'minimal', - type: 'boolean', - default: false, - description: 'Return only array of entities without additional lists in it.', - }, - ] - }, + /* -------------------------------------------------------------------------- */ /* contact:delete */ /* -------------------------------------------------------------------------- */ @@ -546,4 +481,128 @@ export const contactFields = [ default: '', description: 'Contact ID', }, + +/* -------------------------------------------------------------------------- */ +/* contact:all */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Options', + name: 'options', + type: 'collection', + displayOptions: { + show: { + 'resource': [ + 'contact', + ], + }, + }, + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Search', + name: 'search', + type: 'string', + displayOptions: { + show: { + '/resource': [ + 'contact', + ], + '/operation': [ + 'getAll', + ], + }, + }, + default: '', + description: 'String or search command to filter entities by.', + }, + { + displayName: 'Order By', + name: 'orderBy', + type: 'string', + displayOptions: { + show: { + '/resource': [ + 'contact', + ], + '/operation': [ + 'getAll', + ], + }, + }, + default: '', + description: 'Column to sort by. Can use any column listed in the response.', + }, + { + displayName: 'Order By Dir', + name: 'orderByDir', + type: 'options', + displayOptions: { + show: { + '/resource': [ + 'contact', + ], + '/operation': [ + 'getAll', + ], + }, + }, + default: '', + options: [ + { + name: 'ASC', + value: 'asc', + }, + { + name: 'DESC', + value: 'desc', + }, + ], + description: 'Sort direction: ASC or DESC.', + }, + { + displayName: 'Published Only', + name: 'publishedOnly', + type: 'boolean', + displayOptions: { + show: { + '/resource': [ + 'contact', + ], + '/operation': [ + 'getAll', + ], + }, + }, + default: false, + description: 'Only return currently published entities.', + }, + { + displayName: 'Minimal', + name: 'minimal', + type: 'boolean', + displayOptions: { + show: { + '/resource': [ + 'contact', + ], + '/operation': [ + 'getAll', + ], + }, + }, + default: false, + description: 'Return only array of entities without additional lists in it.', + }, + { + displayName: 'RAW Data', + name: 'rawData', + type: 'boolean', + default: false, + description: `By default only the data of the fields get returned. If this
+ options gets set the RAW response with all data gets returned.`, + }, + ] + }, + ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts index 9d37f97e6a..92cc1eed8e 100644 --- a/packages/nodes-base/nodes/Mautic/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Mautic/GenericFunctions.ts @@ -31,9 +31,9 @@ export async function mauticApiRequest(this: IHookFunctions | IExecuteFunctions const errorMessage = err.error || err.error.message; if (errorMessage !== undefined) { - throw errorMessage; + throw new Error(errorMessage); } - throw err + throw err; } } @@ -50,20 +50,18 @@ export async function mauticApiRequestAllItems(this: IHookFunctions | IExecuteFu query.limit = 30; query.start = 0; - let uri: string | undefined; - do { - responseData = await mauticApiRequest.call(this, method, endpoint, body, query, uri); - const values = Object.values(responseData[propertyName]) + responseData = await mauticApiRequest.call(this, method, endpoint, body, query); + const values = Object.values(responseData[propertyName]); for (const value of values) { - data.push(value as IDataObject) + data.push(value as IDataObject); } returnData.push.apply(returnData, data); query.start++; data = []; } while ( responseData.total !== undefined && - ((query.limit * query.start) - parseInt(responseData.total)) < 0 + ((query.limit * query.start) - parseInt(responseData.total, 10)) < 0 ); return returnData; diff --git a/packages/nodes-base/nodes/Mautic/Mautic.node.ts b/packages/nodes-base/nodes/Mautic/Mautic.node.ts index b223f28e5d..e8e2a69c09 100644 --- a/packages/nodes-base/nodes/Mautic/Mautic.node.ts +++ b/packages/nodes-base/nodes/Mautic/Mautic.node.ts @@ -1,3 +1,5 @@ +import { snakeCase } from 'change-case'; + import { IExecuteFunctions, } from 'n8n-core'; @@ -89,10 +91,14 @@ export class Mautic implements INodeType { const length = items.length as unknown as number; let 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++) { qs = {}; - const resource = this.getNodeParameter('resource', 0) as string; - const operation = this.getNodeParameter('operation', 0) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + if (resource === 'contact') { //https://developer.mautic.org/?php#create-contact if (operation === 'create') { @@ -115,7 +121,7 @@ export class Mautic implements INodeType { if (json !== undefined) { body = { ...json }; } else { - throw new Error('Invalid JSON') + throw new Error('Invalid JSON'); } } if (additionalFields.ipAddress) { @@ -159,7 +165,7 @@ export class Mautic implements INodeType { if (json !== undefined) { body = { ...json }; } else { - throw new Error('Invalid JSON') + throw new Error('Invalid JSON'); } } if (updateFields.ipAddress) { @@ -191,8 +197,14 @@ export class Mautic implements INodeType { //https://developer.mautic.org/?php#list-contacts if (operation === 'getAll') { const returnAll = this.getNodeParameter('returnAll', i) as boolean; - const filters = this.getNodeParameter('filters', i) as IDataObject; - qs = Object.assign(qs, filters); + qs = Object.assign(qs, options); + if (qs.orderBy) { + // For some reason does camelCase get used in the returned data + // but snake_case here. So convert it automatically to not confuse + // the users. + qs.orderBy = snakeCase(qs.orderBy as string); + } + try { if (returnAll === true) { responseData = await mauticApiRequestAllItems.call(this, 'contacts', 'GET', '/contacts', {}, qs); @@ -203,6 +215,7 @@ export class Mautic implements INodeType { responseData = responseData.contacts; responseData = Object.values(responseData); } + } catch (err) { throw new Error(`Mautic Error: ${JSON.stringify(err)}`); } @@ -218,12 +231,22 @@ export class Mautic implements INodeType { } } } + if (Array.isArray(responseData)) { + if (options.rawData !== true) { + // @ts-ignore + responseData = responseData.map(item => item.fields.all); + } returnData.push.apply(returnData, responseData as IDataObject[]); } else { + if (options.rawData !== true) { + // @ts-ignore + responseData = responseData.fields.all; + } returnData.push(responseData as IDataObject); } } + return [this.helpers.returnJsonArray(returnData)]; } } diff --git a/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts b/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts index 18ad63225d..a3ba20f28a 100644 --- a/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts +++ b/packages/nodes-base/nodes/Mautic/MauticTrigger.node.ts @@ -62,14 +62,14 @@ export class MauticTrigger implements INodeType { displayName: 'Events Order', name: 'eventsOrder', type: 'options', - default: '', + default: 'ASC', options: [ { - name: 'Asc', + name: 'ASC', value: 'ASC', }, { - name: 'Desc', + name: 'DESC', value: 'DESC', }, ], @@ -122,12 +122,12 @@ export class MauticTrigger implements INodeType { const urlParts = urlParse(webhookUrl); const body: IDataObject = { name: `n8n-webhook:${urlParts.path}`, - description: `n8n webhook`, - webhookUrl: webhookUrl, + description: 'n8n webhook', + webhookUrl, triggers: events, eventsOrderbyDir: eventsOrder, isPublished: true, - } + }; const { hook } = await mauticApiRequest.call(this, 'POST', '/hooks/new', body); webhookData.webhookId = hook.id; return true; diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 863001b2ba..f68ef4e6bb 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -208,6 +208,7 @@ "dependencies": { "aws4": "^1.8.0", "basic-auth": "^2.0.1", + "camel-case": "^4.1.1", "cheerio": "^1.0.0-rc.3", "cron": "^1.7.2", "eventsource": "^1.0.7",