n8n-nodes-mautic-advanced 0.2.0 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nodes/MauticAdvanced/ContactDescription.js +47 -1
- package/dist/nodes/MauticAdvanced/GenericFunctions.js +33 -13
- package/dist/nodes/MauticAdvanced/MauticAdvanced.node.js +192 -55
- package/dist/nodes/MauticAdvanced/MauticAdvanced.svg +10 -1
- package/dist/nodes/MauticAdvanced/SegmentDescription.js +360 -0
- package/package.json +3 -1
|
@@ -31,6 +31,12 @@ exports.contactOperations = [
|
|
|
31
31
|
description: 'Delete a contact',
|
|
32
32
|
action: 'Delete a contact',
|
|
33
33
|
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Delete Batch',
|
|
36
|
+
value: 'deleteBatch',
|
|
37
|
+
description: 'Delete multiple contacts in one operation',
|
|
38
|
+
action: 'Delete multiple contacts',
|
|
39
|
+
},
|
|
34
40
|
{
|
|
35
41
|
name: 'Edit Contact Points',
|
|
36
42
|
value: 'editContactPoint',
|
|
@@ -1315,6 +1321,46 @@ exports.contactFields = [
|
|
|
1315
1321
|
default: '',
|
|
1316
1322
|
},
|
|
1317
1323
|
/* -------------------------------------------------------------------------- */
|
|
1324
|
+
/* contact:deleteBatch */
|
|
1325
|
+
/* -------------------------------------------------------------------------- */
|
|
1326
|
+
{
|
|
1327
|
+
displayName: 'Contact IDs',
|
|
1328
|
+
name: 'contactIds',
|
|
1329
|
+
type: 'string',
|
|
1330
|
+
required: false,
|
|
1331
|
+
displayOptions: {
|
|
1332
|
+
show: {
|
|
1333
|
+
resource: ['contact'],
|
|
1334
|
+
operation: ['deleteBatch'],
|
|
1335
|
+
},
|
|
1336
|
+
},
|
|
1337
|
+
default: '',
|
|
1338
|
+
placeholder: '1,2,3,4,5',
|
|
1339
|
+
description: 'Comma-separated list of contact IDs to delete (e.g., "1,2,3,4,5"). If left empty, all input items\' contactId fields will be used for batch deletion.',
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
displayName: 'Options',
|
|
1343
|
+
name: 'options',
|
|
1344
|
+
type: 'collection',
|
|
1345
|
+
displayOptions: {
|
|
1346
|
+
show: {
|
|
1347
|
+
resource: ['contact'],
|
|
1348
|
+
operation: ['deleteBatch'],
|
|
1349
|
+
},
|
|
1350
|
+
},
|
|
1351
|
+
placeholder: 'Add option',
|
|
1352
|
+
default: {},
|
|
1353
|
+
options: [
|
|
1354
|
+
{
|
|
1355
|
+
displayName: 'RAW Data',
|
|
1356
|
+
name: 'rawData',
|
|
1357
|
+
type: 'boolean',
|
|
1358
|
+
default: true,
|
|
1359
|
+
description: 'Whether to return the raw response data from the API or just a success summary',
|
|
1360
|
+
},
|
|
1361
|
+
],
|
|
1362
|
+
},
|
|
1363
|
+
/* -------------------------------------------------------------------------- */
|
|
1318
1364
|
/* contact:all */
|
|
1319
1365
|
/* -------------------------------------------------------------------------- */
|
|
1320
1366
|
{
|
|
@@ -1326,7 +1372,7 @@ exports.contactFields = [
|
|
|
1326
1372
|
resource: ['contact'],
|
|
1327
1373
|
},
|
|
1328
1374
|
hide: {
|
|
1329
|
-
operation: ['sendEmail', 'editDoNotContactList', 'editContactPoint'],
|
|
1375
|
+
operation: ['sendEmail', 'editDoNotContactList', 'editContactPoint', 'deleteBatch'],
|
|
1330
1376
|
},
|
|
1331
1377
|
},
|
|
1332
1378
|
placeholder: 'Add option',
|
|
@@ -43,26 +43,46 @@ exports.mauticApiRequest = mauticApiRequest;
|
|
|
43
43
|
* Make an API request to paginated mautic endpoint
|
|
44
44
|
* and return all results
|
|
45
45
|
*/
|
|
46
|
+
// Optional: Slightly improved error handling
|
|
46
47
|
async function mauticApiRequestAllItems(propertyName, method, endpoint, body = {}, query = {}, maxResults) {
|
|
47
48
|
const returnData = [];
|
|
48
49
|
let responseData;
|
|
49
50
|
query.limit = 30;
|
|
50
51
|
query.start = 0;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
while (true) {
|
|
53
|
+
try {
|
|
54
|
+
responseData = await mauticApiRequest.call(this, method, endpoint, body, query);
|
|
55
|
+
if (responseData.errors) {
|
|
56
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), responseData);
|
|
57
|
+
}
|
|
58
|
+
const pageItems = responseData[propertyName]
|
|
59
|
+
? Object.values(responseData[propertyName])
|
|
60
|
+
: [];
|
|
61
|
+
if (!pageItems.length) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (maxResults !== undefined && returnData.length + pageItems.length > maxResults) {
|
|
65
|
+
const needed = maxResults - returnData.length;
|
|
66
|
+
returnData.push(...pageItems.slice(0, needed));
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
returnData.push(...pageItems);
|
|
71
|
+
}
|
|
72
|
+
query.start = Number(query.start) + pageItems.length;
|
|
73
|
+
// If less than limit returned, no more data
|
|
74
|
+
if (pageItems.length < Number(query.limit)) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
59
77
|
}
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
catch (error) {
|
|
79
|
+
// Optional: Only wrap non-NodeApiError errors
|
|
80
|
+
if (error instanceof n8n_workflow_1.NodeApiError) {
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
62
84
|
}
|
|
63
|
-
|
|
64
|
-
} while ((responseData.total !== undefined && returnData.length - parseInt(responseData.total, 10) < 0) &&
|
|
65
|
-
(maxResults === undefined || returnData.length < maxResults));
|
|
85
|
+
}
|
|
66
86
|
return returnData;
|
|
67
87
|
}
|
|
68
88
|
exports.mauticApiRequestAllItems = mauticApiRequestAllItems;
|
|
@@ -12,13 +12,14 @@ const ContactDescription_1 = require("./ContactDescription");
|
|
|
12
12
|
const ContactSegmentDescription_1 = require("./ContactSegmentDescription");
|
|
13
13
|
const GenericFunctions_1 = require("./GenericFunctions");
|
|
14
14
|
const SegmentEmailDescription_1 = require("./SegmentEmailDescription");
|
|
15
|
+
const SegmentDescription_1 = require("./SegmentDescription");
|
|
15
16
|
const TagDescription_1 = require("./TagDescription");
|
|
16
17
|
class MauticAdvanced {
|
|
17
18
|
constructor() {
|
|
18
19
|
this.description = {
|
|
19
20
|
displayName: 'Mautic Advanced',
|
|
20
21
|
name: 'mauticAdvanced',
|
|
21
|
-
icon: 'file:
|
|
22
|
+
icon: 'file:mauticadvanced.svg',
|
|
22
23
|
group: ['output'],
|
|
23
24
|
version: 1,
|
|
24
25
|
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
@@ -107,6 +108,11 @@ class MauticAdvanced {
|
|
|
107
108
|
value: 'contactSegment',
|
|
108
109
|
description: 'Add/remove contacts to/from a segment',
|
|
109
110
|
},
|
|
111
|
+
{
|
|
112
|
+
name: 'Segment',
|
|
113
|
+
value: 'segment',
|
|
114
|
+
description: 'Create, update, and retrieve segments',
|
|
115
|
+
},
|
|
110
116
|
{
|
|
111
117
|
name: 'Segment Email',
|
|
112
118
|
value: 'segmentEmail',
|
|
@@ -138,6 +144,8 @@ class MauticAdvanced {
|
|
|
138
144
|
...TagDescription_1.tagFields,
|
|
139
145
|
...CategoryDescription_1.categoryOperations,
|
|
140
146
|
...CategoryDescription_1.categoryFields,
|
|
147
|
+
...SegmentDescription_1.segmentOperations,
|
|
148
|
+
...SegmentDescription_1.segmentFields,
|
|
141
149
|
],
|
|
142
150
|
};
|
|
143
151
|
this.methods = {
|
|
@@ -226,7 +234,7 @@ class MauticAdvanced {
|
|
|
226
234
|
// select them easily
|
|
227
235
|
async getSegments() {
|
|
228
236
|
const returnData = [];
|
|
229
|
-
const segments = await GenericFunctions_1.mauticApiRequestAllItems.call(this, '
|
|
237
|
+
const segments = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'segments', 'GET', '/segments');
|
|
230
238
|
for (const segment of segments) {
|
|
231
239
|
returnData.push({
|
|
232
240
|
name: segment.name,
|
|
@@ -302,6 +310,48 @@ class MauticAdvanced {
|
|
|
302
310
|
let responseData;
|
|
303
311
|
const resource = this.getNodeParameter('resource', 0);
|
|
304
312
|
const operation = this.getNodeParameter('operation', 0);
|
|
313
|
+
// Handle batch operations that process all items together
|
|
314
|
+
if (resource === 'contact' && operation === 'deleteBatch') {
|
|
315
|
+
// Only process once for all items
|
|
316
|
+
const options = this.getNodeParameter('options', 0, {});
|
|
317
|
+
let contactIds = this.getNodeParameter('contactIds', 0, '');
|
|
318
|
+
if (!contactIds) {
|
|
319
|
+
// Fallback: collect from all input items
|
|
320
|
+
const ids = items
|
|
321
|
+
.map((item) => item.json.id)
|
|
322
|
+
.filter((id) => id !== undefined && id !== null && id !== '')
|
|
323
|
+
.map((id) => String(id));
|
|
324
|
+
contactIds = ids.join(',');
|
|
325
|
+
}
|
|
326
|
+
if (!contactIds) {
|
|
327
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No contact IDs provided or found in input items.');
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'DELETE', '/contacts/batch/delete', {}, { ids: contactIds });
|
|
331
|
+
if (options.rawData === false) {
|
|
332
|
+
// Return simplified response
|
|
333
|
+
responseData = {
|
|
334
|
+
success: true,
|
|
335
|
+
deletedIds: contactIds.split(','),
|
|
336
|
+
message: `Successfully deleted ${contactIds.split(',').length} contacts.`,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
if (error instanceof n8n_workflow_1.NodeApiError && error.httpCode === '404') {
|
|
342
|
+
responseData = {
|
|
343
|
+
success: true,
|
|
344
|
+
deletedIds: contactIds.split(','),
|
|
345
|
+
message: 'Some contacts were already deleted or not found.',
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Return as a single output item
|
|
353
|
+
return [this.helpers.returnJsonArray([responseData])];
|
|
354
|
+
}
|
|
305
355
|
for (let i = 0; i < length; i++) {
|
|
306
356
|
qs = {};
|
|
307
357
|
try {
|
|
@@ -339,6 +389,13 @@ class MauticAdvanced {
|
|
|
339
389
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
340
390
|
const options = this.getNodeParameter('options', i);
|
|
341
391
|
qs = { ...options };
|
|
392
|
+
// Patch: enforce default sort order by id ascending if not set by user
|
|
393
|
+
if (!qs.orderBy) {
|
|
394
|
+
qs.orderBy = 'id';
|
|
395
|
+
}
|
|
396
|
+
if (!qs.orderByDir) {
|
|
397
|
+
qs.orderByDir = 'asc';
|
|
398
|
+
}
|
|
342
399
|
if (returnAll) {
|
|
343
400
|
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'campaigns', 'GET', '/campaigns', {}, qs);
|
|
344
401
|
}
|
|
@@ -368,6 +425,86 @@ class MauticAdvanced {
|
|
|
368
425
|
responseData = responseData.campaign;
|
|
369
426
|
}
|
|
370
427
|
}
|
|
428
|
+
if (resource === 'segment') {
|
|
429
|
+
//https://developer.mautic.org/#segments
|
|
430
|
+
if (operation === 'create') {
|
|
431
|
+
const name = this.getNodeParameter('name', i);
|
|
432
|
+
const additionalFields = this.getNodeParameter('additionalFields', i);
|
|
433
|
+
const body = {
|
|
434
|
+
name,
|
|
435
|
+
...additionalFields,
|
|
436
|
+
};
|
|
437
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'POST', '/segments/new', body);
|
|
438
|
+
responseData = responseData.list; // Changed from .segment to .list
|
|
439
|
+
}
|
|
440
|
+
if (operation === 'update') {
|
|
441
|
+
const segmentId = this.getNodeParameter('segmentId', i);
|
|
442
|
+
const createIfNotFound = this.getNodeParameter('createIfNotFound', i);
|
|
443
|
+
const name = this.getNodeParameter('name', i);
|
|
444
|
+
const { ...additionalFields } = this.getNodeParameter('additionalFields', i);
|
|
445
|
+
const body = {
|
|
446
|
+
name,
|
|
447
|
+
...additionalFields,
|
|
448
|
+
};
|
|
449
|
+
const method = createIfNotFound ? 'PUT' : 'PATCH';
|
|
450
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, method, `/segments/${segmentId}/edit`, body);
|
|
451
|
+
responseData = responseData.list; // Changed from .segment to .list
|
|
452
|
+
}
|
|
453
|
+
if (operation === 'get') {
|
|
454
|
+
const segmentId = this.getNodeParameter('segmentId', i);
|
|
455
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'GET', `/segments/${segmentId}`);
|
|
456
|
+
responseData = responseData.list; // Changed from .segment to .list
|
|
457
|
+
}
|
|
458
|
+
if (operation === 'getAll') {
|
|
459
|
+
const returnAll = this.getNodeParameter('returnAll', i);
|
|
460
|
+
const options = this.getNodeParameter('options', i);
|
|
461
|
+
qs = { ...options };
|
|
462
|
+
if (returnAll) {
|
|
463
|
+
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'lists', // Using 'lists' property name
|
|
464
|
+
'GET', '/segments', {}, qs);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
const limit = this.getNodeParameter('limit', i);
|
|
468
|
+
qs.limit = limit;
|
|
469
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'GET', '/segments', {}, qs);
|
|
470
|
+
responseData = responseData.lists ? Object.values(responseData.lists) : []; // Convert object to array
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (operation === 'delete') {
|
|
474
|
+
const segmentId = this.getNodeParameter('segmentId', i);
|
|
475
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'DELETE', `/segments/${segmentId}/delete`);
|
|
476
|
+
responseData = responseData.list; // Changed from .segment to .list
|
|
477
|
+
}
|
|
478
|
+
if (operation === 'addContact') {
|
|
479
|
+
const segmentId = this.getNodeParameter('segmentId', i);
|
|
480
|
+
const contactId = this.getNodeParameter('contactId', i);
|
|
481
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'POST', `/segments/${segmentId}/contact/${contactId}/add`);
|
|
482
|
+
}
|
|
483
|
+
if (operation === 'removeContact') {
|
|
484
|
+
const segmentId = this.getNodeParameter('segmentId', i);
|
|
485
|
+
const contactId = this.getNodeParameter('contactId', i);
|
|
486
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'POST', `/segments/${segmentId}/contact/${contactId}/remove`);
|
|
487
|
+
}
|
|
488
|
+
if (operation === 'addContacts') {
|
|
489
|
+
const segmentId = this.getNodeParameter('segmentId', i);
|
|
490
|
+
let contactIds = this.getNodeParameter('contactIds', i, '');
|
|
491
|
+
if (!contactIds) {
|
|
492
|
+
// Fallback: collect from all input items
|
|
493
|
+
const ids = items
|
|
494
|
+
.map((item) => item.json.contactId || item.json.id)
|
|
495
|
+
.filter((id) => id !== undefined && id !== null && id !== '')
|
|
496
|
+
.map((id) => String(id));
|
|
497
|
+
contactIds = ids.join(',');
|
|
498
|
+
}
|
|
499
|
+
if (!contactIds) {
|
|
500
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No contact IDs provided or found in input items.');
|
|
501
|
+
}
|
|
502
|
+
const body = {
|
|
503
|
+
ids: contactIds.split(','),
|
|
504
|
+
};
|
|
505
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'POST', `/segments/${segmentId}/contacts/add`, body);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
371
508
|
if (resource === 'company') {
|
|
372
509
|
//https://developer.mautic.org/#create-company
|
|
373
510
|
if (operation === 'create') {
|
|
@@ -498,21 +635,19 @@ class MauticAdvanced {
|
|
|
498
635
|
const simple = this.getNodeParameter('simple', i);
|
|
499
636
|
const additionalFields = this.getNodeParameter('additionalFields', i);
|
|
500
637
|
qs = Object.assign(qs, additionalFields);
|
|
501
|
-
if
|
|
502
|
-
|
|
638
|
+
// Patch: enforce default sort order by id ascending if not set by user
|
|
639
|
+
if (!qs.orderBy) {
|
|
640
|
+
qs.orderBy = 'id';
|
|
503
641
|
}
|
|
504
|
-
|
|
505
|
-
qs.
|
|
506
|
-
qs.start = 0;
|
|
507
|
-
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'GET', '/companies', {}, qs);
|
|
508
|
-
if (responseData.errors) {
|
|
509
|
-
throw new n8n_workflow_1.NodeApiError(this.getNode(), responseData);
|
|
510
|
-
}
|
|
511
|
-
responseData = responseData.companies;
|
|
512
|
-
responseData = Object.values(responseData);
|
|
642
|
+
if (!qs.orderByDir) {
|
|
643
|
+
qs.orderByDir = 'asc';
|
|
513
644
|
}
|
|
645
|
+
let limit = undefined;
|
|
646
|
+
if (!returnAll) {
|
|
647
|
+
limit = this.getNodeParameter('limit', i);
|
|
648
|
+
}
|
|
649
|
+
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'companies', 'GET', '/companies', {}, qs, limit);
|
|
514
650
|
if (simple) {
|
|
515
|
-
//@ts-ignore
|
|
516
651
|
responseData = responseData.map((item) => item.fields.all);
|
|
517
652
|
}
|
|
518
653
|
}
|
|
@@ -555,14 +690,18 @@ class MauticAdvanced {
|
|
|
555
690
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
556
691
|
const options = this.getNodeParameter('options', i);
|
|
557
692
|
Object.assign(qs, options);
|
|
558
|
-
if
|
|
559
|
-
|
|
693
|
+
// Patch: enforce default sort order by id ascending if not set by user
|
|
694
|
+
if (!qs.orderBy) {
|
|
695
|
+
qs.orderBy = 'id';
|
|
560
696
|
}
|
|
561
|
-
|
|
562
|
-
qs.
|
|
563
|
-
|
|
564
|
-
|
|
697
|
+
if (!qs.orderByDir) {
|
|
698
|
+
qs.orderByDir = 'asc';
|
|
699
|
+
}
|
|
700
|
+
let limit = undefined;
|
|
701
|
+
if (!returnAll) {
|
|
702
|
+
limit = this.getNodeParameter('limit', i);
|
|
565
703
|
}
|
|
704
|
+
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'tags', 'GET', '/tags', {}, qs, limit);
|
|
566
705
|
}
|
|
567
706
|
if (operation === 'delete') {
|
|
568
707
|
const tagId = this.getNodeParameter('tagId', i);
|
|
@@ -802,30 +941,22 @@ class MauticAdvanced {
|
|
|
802
941
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
803
942
|
const options = this.getNodeParameter('options', i);
|
|
804
943
|
qs = Object.assign(qs, options);
|
|
944
|
+
// Patch: enforce default sort order by id ascending if not set by user
|
|
945
|
+
if (!qs.orderBy) {
|
|
946
|
+
qs.orderBy = 'id';
|
|
947
|
+
}
|
|
948
|
+
if (!qs.orderByDir) {
|
|
949
|
+
qs.orderByDir = 'asc';
|
|
950
|
+
}
|
|
805
951
|
if (qs.orderBy) {
|
|
806
952
|
qs.orderBy = (0, change_case_1.snakeCase)(qs.orderBy);
|
|
807
953
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
else {
|
|
812
|
-
const limit = this.getNodeParameter('limit', i);
|
|
813
|
-
if (limit > 30) {
|
|
814
|
-
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'contacts', 'GET', '/contacts', {}, qs, limit);
|
|
815
|
-
}
|
|
816
|
-
else {
|
|
817
|
-
qs.limit = limit;
|
|
818
|
-
qs.start = 0;
|
|
819
|
-
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'GET', '/contacts', {}, qs);
|
|
820
|
-
if (responseData.errors) {
|
|
821
|
-
throw new n8n_workflow_1.NodeApiError(this.getNode(), responseData);
|
|
822
|
-
}
|
|
823
|
-
responseData = responseData.contacts;
|
|
824
|
-
responseData = Object.values(responseData);
|
|
825
|
-
}
|
|
954
|
+
let limit = undefined;
|
|
955
|
+
if (!returnAll) {
|
|
956
|
+
limit = this.getNodeParameter('limit', i);
|
|
826
957
|
}
|
|
958
|
+
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'contacts', 'GET', '/contacts', {}, qs, limit);
|
|
827
959
|
if (options.rawData === false) {
|
|
828
|
-
//@ts-ignore
|
|
829
960
|
responseData = responseData.map((item) => item.fields.all);
|
|
830
961
|
}
|
|
831
962
|
}
|
|
@@ -847,7 +978,9 @@ class MauticAdvanced {
|
|
|
847
978
|
catch (error) {
|
|
848
979
|
// If the error is a 404 (not found), treat as successful delete (idempotent)
|
|
849
980
|
if (error instanceof n8n_workflow_1.NodeApiError && error.httpCode === '404') {
|
|
850
|
-
responseData = [
|
|
981
|
+
responseData = [
|
|
982
|
+
{ success: true, message: 'Contact already deleted or not found.' },
|
|
983
|
+
];
|
|
851
984
|
}
|
|
852
985
|
else {
|
|
853
986
|
throw error;
|
|
@@ -1039,19 +1172,15 @@ class MauticAdvanced {
|
|
|
1039
1172
|
}
|
|
1040
1173
|
if (operation === 'update') {
|
|
1041
1174
|
const categoryId = this.getNodeParameter('categoryId', i);
|
|
1042
|
-
const
|
|
1043
|
-
const { title, bundle, description, color } = this.getNodeParameter('updateFields', i);
|
|
1175
|
+
const { title, description, color } = this.getNodeParameter('updateFields', i);
|
|
1044
1176
|
const body = {};
|
|
1045
1177
|
if (title)
|
|
1046
1178
|
body.title = title;
|
|
1047
|
-
if (bundle)
|
|
1048
|
-
body.bundle = bundle;
|
|
1049
1179
|
if (description)
|
|
1050
1180
|
body.description = description;
|
|
1051
1181
|
if (color)
|
|
1052
1182
|
body.color = color;
|
|
1053
|
-
|
|
1054
|
-
responseData = await GenericFunctions_1.mauticApiRequest.call(this, method, `/categories/${categoryId}/edit`, body);
|
|
1183
|
+
responseData = await GenericFunctions_1.mauticApiRequest.call(this, 'PATCH', `/categories/${categoryId}/edit`, body);
|
|
1055
1184
|
responseData = responseData.category;
|
|
1056
1185
|
}
|
|
1057
1186
|
if (operation === 'get') {
|
|
@@ -1063,14 +1192,18 @@ class MauticAdvanced {
|
|
|
1063
1192
|
const returnAll = this.getNodeParameter('returnAll', i);
|
|
1064
1193
|
const options = this.getNodeParameter('options', i);
|
|
1065
1194
|
Object.assign(qs, options);
|
|
1066
|
-
if
|
|
1067
|
-
|
|
1195
|
+
// Patch: enforce default sort order by id ascending if not set by user
|
|
1196
|
+
if (!qs.orderBy) {
|
|
1197
|
+
qs.orderBy = 'id';
|
|
1068
1198
|
}
|
|
1069
|
-
|
|
1070
|
-
qs.
|
|
1071
|
-
|
|
1072
|
-
|
|
1199
|
+
if (!qs.orderByDir) {
|
|
1200
|
+
qs.orderByDir = 'asc';
|
|
1201
|
+
}
|
|
1202
|
+
let limit = undefined;
|
|
1203
|
+
if (!returnAll) {
|
|
1204
|
+
limit = this.getNodeParameter('limit', i);
|
|
1073
1205
|
}
|
|
1206
|
+
responseData = await GenericFunctions_1.mauticApiRequestAllItems.call(this, 'categories', 'GET', '/categories', {}, qs, limit);
|
|
1074
1207
|
}
|
|
1075
1208
|
if (operation === 'delete') {
|
|
1076
1209
|
const categoryId = this.getNodeParameter('categoryId', i);
|
|
@@ -1078,12 +1211,16 @@ class MauticAdvanced {
|
|
|
1078
1211
|
responseData = responseData.category;
|
|
1079
1212
|
}
|
|
1080
1213
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1214
|
+
if (Array.isArray(responseData)) {
|
|
1215
|
+
returnData.push(...this.helpers.returnJsonArray(responseData));
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
returnData.push(...this.helpers.returnJsonArray([responseData]));
|
|
1219
|
+
}
|
|
1083
1220
|
}
|
|
1084
1221
|
catch (error) {
|
|
1085
1222
|
if (this.continueOnFail()) {
|
|
1086
|
-
returnData.push({
|
|
1223
|
+
returnData.push(...this.helpers.returnJsonArray([{ error: error.message }]));
|
|
1087
1224
|
continue;
|
|
1088
1225
|
}
|
|
1089
1226
|
throw error;
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="349.779" height="349.779"
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="349.779" height="349.779">
|
|
2
|
+
<path
|
|
3
|
+
fill="#FFF"
|
|
4
|
+
d="M174.89 349.779C78.612 349.779 0 271.462 0 174.89S78.612 0 174.89 0c23.26 0 45.931 4.417 67.129 13.543 5.889 2.65 8.833 9.422 6.478 15.605-2.649 5.888-9.421 8.833-15.604 6.477-18.549-7.655-37.98-11.482-58.002-11.482-83.323 0-151.041 67.718-151.041 151.041s67.717 151.041 151.04 151.041 151.041-67.718 151.041-151.041c0-17.96-2.944-35.332-9.127-51.819-2.355-6.183.883-12.955 7.066-15.31s12.954.883 15.31 7.066c7.066 19.138 10.6 39.453 10.6 60.063-.001 95.983-78.318 174.595-174.89 174.595"
|
|
5
|
+
/>
|
|
6
|
+
<path
|
|
7
|
+
fill="#FDB933"
|
|
8
|
+
d="m251.44 156.93-27.086 28.264 15.015 63.302h34.153zm-11.187-83.618 9.421 9.422-74.784 79.201-63.891-65.658-36.803 152.219h34.154l20.315-84.5 46.225 50.347 98.927-107.76 9.422 9.716 9.421-53.292z"
|
|
9
|
+
/>
|
|
10
|
+
</svg>
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.segmentFields = exports.segmentOperations = void 0;
|
|
4
|
+
exports.segmentOperations = [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Operation',
|
|
7
|
+
name: 'operation',
|
|
8
|
+
type: 'options',
|
|
9
|
+
noDataExpression: true,
|
|
10
|
+
displayOptions: {
|
|
11
|
+
show: {
|
|
12
|
+
resource: ['segment'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
options: [
|
|
16
|
+
{
|
|
17
|
+
name: 'Add Contact',
|
|
18
|
+
value: 'addContact',
|
|
19
|
+
description: 'Add a contact to a segment',
|
|
20
|
+
action: 'Add a contact to a segment',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Add Contacts',
|
|
24
|
+
value: 'addContacts',
|
|
25
|
+
description: 'Add contacts to a segment',
|
|
26
|
+
action: 'Add contacts to a segment',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Create',
|
|
30
|
+
value: 'create',
|
|
31
|
+
description: 'Create a new segment',
|
|
32
|
+
action: 'Create a segment',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Delete',
|
|
36
|
+
value: 'delete',
|
|
37
|
+
description: 'Delete a segment',
|
|
38
|
+
action: 'Delete a segment',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Get',
|
|
42
|
+
value: 'get',
|
|
43
|
+
description: 'Get data of a segment',
|
|
44
|
+
action: 'Get a segment',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Get Many',
|
|
48
|
+
value: 'getAll',
|
|
49
|
+
description: 'Get data of many segments',
|
|
50
|
+
action: 'Get many segments',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Remove Contact',
|
|
54
|
+
value: 'removeContact',
|
|
55
|
+
description: 'Remove a contact from a segment',
|
|
56
|
+
action: 'Remove a contact from a segment',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'Update',
|
|
60
|
+
value: 'update',
|
|
61
|
+
description: 'Update a segment',
|
|
62
|
+
action: 'Update a segment',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
default: 'create',
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
exports.segmentFields = [
|
|
69
|
+
/* -------------------------------------------------------------------------- */
|
|
70
|
+
/* segment:create */
|
|
71
|
+
/* -------------------------------------------------------------------------- */
|
|
72
|
+
{
|
|
73
|
+
displayName: 'Name',
|
|
74
|
+
name: 'name',
|
|
75
|
+
type: 'string',
|
|
76
|
+
required: true,
|
|
77
|
+
displayOptions: {
|
|
78
|
+
show: {
|
|
79
|
+
resource: ['segment'],
|
|
80
|
+
operation: ['create', 'update'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
default: '',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
displayName: 'Additional Fields',
|
|
87
|
+
name: 'additionalFields',
|
|
88
|
+
type: 'collection',
|
|
89
|
+
placeholder: 'Add Field',
|
|
90
|
+
default: {},
|
|
91
|
+
displayOptions: {
|
|
92
|
+
show: {
|
|
93
|
+
resource: ['segment'],
|
|
94
|
+
operation: ['create', 'update'],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
options: [
|
|
98
|
+
{
|
|
99
|
+
displayName: 'Alias',
|
|
100
|
+
name: 'alias',
|
|
101
|
+
type: 'string',
|
|
102
|
+
default: '',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
displayName: 'Description',
|
|
106
|
+
name: 'description',
|
|
107
|
+
type: 'string',
|
|
108
|
+
default: '',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
displayName: 'Is Published',
|
|
112
|
+
name: 'isPublished',
|
|
113
|
+
type: 'boolean',
|
|
114
|
+
default: true,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
displayName: 'Is Global',
|
|
118
|
+
name: 'isGlobal',
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
default: false,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
displayName: 'Filters',
|
|
124
|
+
name: 'filters',
|
|
125
|
+
type: 'fixedCollection',
|
|
126
|
+
placeholder: 'Add Filter',
|
|
127
|
+
typeOptions: {
|
|
128
|
+
multiple: true,
|
|
129
|
+
},
|
|
130
|
+
default: {},
|
|
131
|
+
options: [
|
|
132
|
+
{
|
|
133
|
+
displayName: 'Filter',
|
|
134
|
+
name: 'filter',
|
|
135
|
+
values: [
|
|
136
|
+
{
|
|
137
|
+
displayName: 'Glue',
|
|
138
|
+
name: 'glue',
|
|
139
|
+
type: 'options',
|
|
140
|
+
options: [
|
|
141
|
+
{ name: 'And', value: 'and' },
|
|
142
|
+
{ name: 'Or', value: 'or' },
|
|
143
|
+
],
|
|
144
|
+
default: 'and',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
displayName: 'Field',
|
|
148
|
+
name: 'field',
|
|
149
|
+
type: 'string',
|
|
150
|
+
default: 'email',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
displayName: 'Object',
|
|
154
|
+
name: 'object',
|
|
155
|
+
type: 'options',
|
|
156
|
+
options: [
|
|
157
|
+
{ name: 'Contact', value: 'lead' },
|
|
158
|
+
{ name: 'Company', value: 'company' },
|
|
159
|
+
],
|
|
160
|
+
default: 'lead',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
displayName: 'Type',
|
|
164
|
+
name: 'type',
|
|
165
|
+
type: 'string',
|
|
166
|
+
default: 'email',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
displayName: 'Filter',
|
|
170
|
+
name: 'filter',
|
|
171
|
+
type: 'string',
|
|
172
|
+
default: '',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
displayName: 'Operator',
|
|
176
|
+
name: 'operator',
|
|
177
|
+
type: 'options',
|
|
178
|
+
options: [
|
|
179
|
+
{ name: '=', value: '=' },
|
|
180
|
+
{ name: '!=', value: '!=' },
|
|
181
|
+
{ name: 'Empty', value: 'empty' },
|
|
182
|
+
{ name: 'Not Empty', value: '!empty' },
|
|
183
|
+
{ name: 'Like', value: 'like' },
|
|
184
|
+
{ name: 'Not Like', value: '!like' },
|
|
185
|
+
{ name: 'Regexp', value: 'regexp' },
|
|
186
|
+
{ name: 'Not Regexp', value: '!regexp' },
|
|
187
|
+
{ name: 'Starts With', value: 'startsWith' },
|
|
188
|
+
{ name: 'Ends With', value: 'endsWith' },
|
|
189
|
+
{ name: 'Contains', value: 'contains' },
|
|
190
|
+
],
|
|
191
|
+
default: 'like',
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
/* -------------------------------------------------------------------------- */
|
|
200
|
+
/* segment:update */
|
|
201
|
+
/* -------------------------------------------------------------------------- */
|
|
202
|
+
{
|
|
203
|
+
displayName: 'Segment ID',
|
|
204
|
+
name: 'segmentId',
|
|
205
|
+
type: 'string',
|
|
206
|
+
required: true,
|
|
207
|
+
displayOptions: {
|
|
208
|
+
show: {
|
|
209
|
+
resource: ['segment'],
|
|
210
|
+
operation: ['update', 'addContact', 'addContacts', 'removeContact'],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
default: '',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
displayName: 'Create If Not Found',
|
|
217
|
+
name: 'createIfNotFound',
|
|
218
|
+
type: 'boolean',
|
|
219
|
+
displayOptions: {
|
|
220
|
+
show: {
|
|
221
|
+
resource: ['segment'],
|
|
222
|
+
operation: ['update'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
default: false,
|
|
226
|
+
description: 'Whether to create a segment if the given ID is not found',
|
|
227
|
+
},
|
|
228
|
+
/* -------------------------------------------------------------------------- */
|
|
229
|
+
/* segment:get */
|
|
230
|
+
/* -------------------------------------------------------------------------- */
|
|
231
|
+
{
|
|
232
|
+
displayName: 'Segment ID',
|
|
233
|
+
name: 'segmentId',
|
|
234
|
+
type: 'string',
|
|
235
|
+
required: true,
|
|
236
|
+
displayOptions: {
|
|
237
|
+
show: {
|
|
238
|
+
resource: ['segment'],
|
|
239
|
+
operation: ['get', 'delete'],
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
default: '',
|
|
243
|
+
},
|
|
244
|
+
/* -------------------------------------------------------------------------- */
|
|
245
|
+
/* segment:getAll */
|
|
246
|
+
/* -------------------------------------------------------------------------- */
|
|
247
|
+
{
|
|
248
|
+
displayName: 'Return All',
|
|
249
|
+
name: 'returnAll',
|
|
250
|
+
type: 'boolean',
|
|
251
|
+
displayOptions: {
|
|
252
|
+
show: {
|
|
253
|
+
resource: ['segment'],
|
|
254
|
+
operation: ['getAll'],
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
default: false,
|
|
258
|
+
description: 'Whether to return all results or only up to a given limit',
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
displayName: 'Limit',
|
|
262
|
+
name: 'limit',
|
|
263
|
+
type: 'number',
|
|
264
|
+
displayOptions: {
|
|
265
|
+
show: {
|
|
266
|
+
resource: ['segment'],
|
|
267
|
+
operation: ['getAll'],
|
|
268
|
+
returnAll: [false],
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
typeOptions: {
|
|
272
|
+
minValue: 1,
|
|
273
|
+
},
|
|
274
|
+
default: 30,
|
|
275
|
+
description: 'Max number of results to return',
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
displayName: 'Options',
|
|
279
|
+
name: 'options',
|
|
280
|
+
type: 'collection',
|
|
281
|
+
placeholder: 'Add Option',
|
|
282
|
+
default: {},
|
|
283
|
+
displayOptions: {
|
|
284
|
+
show: {
|
|
285
|
+
resource: ['segment'],
|
|
286
|
+
operation: ['getAll'],
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
options: [
|
|
290
|
+
{
|
|
291
|
+
displayName: 'Search',
|
|
292
|
+
name: 'search',
|
|
293
|
+
type: 'string',
|
|
294
|
+
default: '',
|
|
295
|
+
description: 'String or search command to filter entities by',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
displayName: 'Order By',
|
|
299
|
+
name: 'orderBy',
|
|
300
|
+
type: 'string',
|
|
301
|
+
default: '',
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
displayName: 'Order By Direction',
|
|
305
|
+
name: 'orderByDir',
|
|
306
|
+
type: 'options',
|
|
307
|
+
options: [
|
|
308
|
+
{ name: 'ASC', value: 'asc' },
|
|
309
|
+
{ name: 'DESC', value: 'desc' },
|
|
310
|
+
],
|
|
311
|
+
default: 'asc',
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
displayName: 'Published Only',
|
|
315
|
+
name: 'publishedOnly',
|
|
316
|
+
type: 'boolean',
|
|
317
|
+
default: false,
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
displayName: 'Minimal',
|
|
321
|
+
name: 'minimal',
|
|
322
|
+
type: 'boolean',
|
|
323
|
+
default: false,
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
/* -------------------------------------------------------------------------- */
|
|
328
|
+
/* segment:addContact */
|
|
329
|
+
/* -------------------------------------------------------------------------- */
|
|
330
|
+
{
|
|
331
|
+
displayName: 'Contact ID',
|
|
332
|
+
name: 'contactId',
|
|
333
|
+
type: 'string',
|
|
334
|
+
required: true,
|
|
335
|
+
displayOptions: {
|
|
336
|
+
show: {
|
|
337
|
+
resource: ['segment'],
|
|
338
|
+
operation: ['addContact', 'removeContact'],
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
default: '',
|
|
342
|
+
},
|
|
343
|
+
/* -------------------------------------------------------------------------- */
|
|
344
|
+
/* segment:addContacts */
|
|
345
|
+
/* -------------------------------------------------------------------------- */
|
|
346
|
+
{
|
|
347
|
+
displayName: 'Contact IDs',
|
|
348
|
+
name: 'contactIds',
|
|
349
|
+
type: 'string',
|
|
350
|
+
required: false,
|
|
351
|
+
displayOptions: {
|
|
352
|
+
show: {
|
|
353
|
+
resource: ['segment'],
|
|
354
|
+
operation: ['addContacts'],
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
default: '',
|
|
358
|
+
description: "Comma-separated list of contact IDs to add. If left empty, all input items' contactId or id fields will be used for batch adding.",
|
|
359
|
+
},
|
|
360
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-mautic-advanced",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Enhanced n8n node for Mautic with comprehensive API coverage including tags, campaigns, categories, and advanced contact management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n",
|
|
@@ -54,7 +54,9 @@
|
|
|
54
54
|
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
55
55
|
"@typescript-eslint/parser": "^7.7.0",
|
|
56
56
|
"eslint": "^8.57.0",
|
|
57
|
+
"eslint-config-prettier": "^10.1.5",
|
|
57
58
|
"eslint-plugin-n8n-nodes-base": "^1.16.3",
|
|
59
|
+
"eslint-plugin-prettier": "^5.5.1",
|
|
58
60
|
"gulp": "^4.0.2",
|
|
59
61
|
"n8n-workflow": "^1.70.0",
|
|
60
62
|
"prettier": "^3.2.5",
|