n8n-nodes-mautic-advanced 0.3.7 → 0.3.8
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.
|
@@ -30,11 +30,19 @@ async function mauticApiRequest(method, endpoint, body = {}, query, uri) {
|
|
|
30
30
|
}
|
|
31
31
|
if (returnData.errors) {
|
|
32
32
|
// They seem to sometimes return 200 status but still error.
|
|
33
|
-
|
|
33
|
+
// Preserve the full error object including details for better error handling
|
|
34
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), returnData, {
|
|
35
|
+
httpCode: '400',
|
|
36
|
+
description: returnData,
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
return returnData;
|
|
36
40
|
}
|
|
37
41
|
catch (error) {
|
|
42
|
+
// Preserve error details when available for better error handling
|
|
43
|
+
if (error instanceof n8n_workflow_1.NodeApiError) {
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
38
46
|
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
39
47
|
}
|
|
40
48
|
}
|
|
@@ -99,7 +99,26 @@ async function createContact(context, itemIndex) {
|
|
|
99
99
|
body = (0, DataHelpers_1.validateJsonParameter)(context, 'bodyJson', itemIndex);
|
|
100
100
|
}
|
|
101
101
|
addContactFields(body, additionalFields);
|
|
102
|
-
|
|
102
|
+
// Data sanitization: Remove empty string values and validate email format
|
|
103
|
+
const sanitizedBody = {};
|
|
104
|
+
Object.entries(body).forEach(([key, value]) => {
|
|
105
|
+
// Skip empty strings as Mautic sometimes rejects them
|
|
106
|
+
if (value !== '' && value !== null && value !== undefined) {
|
|
107
|
+
sanitizedBody[key] = value;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Basic email validation if email is provided
|
|
111
|
+
if (sanitizedBody.email && typeof sanitizedBody.email === 'string') {
|
|
112
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
113
|
+
if (!emailRegex.test(sanitizedBody.email)) {
|
|
114
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Invalid email format: ${sanitizedBody.email}`, { itemIndex });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Log the sanitized body for debugging (only in development)
|
|
118
|
+
if (process.env.NODE_ENV === 'development') {
|
|
119
|
+
console.log('Mautic Contact Creation - Sanitized Body:', JSON.stringify(sanitizedBody, null, 2));
|
|
120
|
+
}
|
|
121
|
+
const response = await (0, ApiHelpers_1.makeApiRequest)(context, 'POST', '/contacts/new', sanitizedBody);
|
|
103
122
|
const contactData = [response.contact];
|
|
104
123
|
return (0, DataHelpers_1.processContactFields)(contactData, options);
|
|
105
124
|
}
|
|
@@ -39,7 +39,67 @@ function handleApiError(context, error, operation, resource) {
|
|
|
39
39
|
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Permission denied for ${operation} ${resource}. Please check your API credentials.`, { itemIndex: 0 });
|
|
40
40
|
}
|
|
41
41
|
if (error.httpCode === '400') {
|
|
42
|
-
|
|
42
|
+
// Extract detailed validation errors from Mautic API response
|
|
43
|
+
let errorMessage = `Invalid data provided for ${operation} ${resource}.`;
|
|
44
|
+
try {
|
|
45
|
+
const errorData = error.description;
|
|
46
|
+
// Check if we have a direct error message from Mautic API
|
|
47
|
+
if (typeof errorData === 'string' && errorData.trim()) {
|
|
48
|
+
// Parse field-specific error messages like "field_name: error message"
|
|
49
|
+
const fieldErrorMatch = errorData.match(/^([^:]+):\s*(.+)$/);
|
|
50
|
+
if (fieldErrorMatch) {
|
|
51
|
+
const fieldName = fieldErrorMatch[1].trim();
|
|
52
|
+
const errorMsg = fieldErrorMatch[2].trim();
|
|
53
|
+
errorMessage += ` Validation error:\n- ${fieldName}: ${errorMsg}\n`;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// If it doesn't match the field:message pattern, show the raw message
|
|
57
|
+
errorMessage += ` Error: ${errorData}\n`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Check for errors array (current Mautic API format)
|
|
61
|
+
else if (errorData?.errors && Array.isArray(errorData.errors) && errorData.errors.length > 0) {
|
|
62
|
+
const validationErrors = [];
|
|
63
|
+
errorData.errors.forEach((err) => {
|
|
64
|
+
if (err.details && typeof err.details === 'object') {
|
|
65
|
+
// Extract field-specific validation messages
|
|
66
|
+
Object.entries(err.details).forEach(([field, messages]) => {
|
|
67
|
+
if (Array.isArray(messages)) {
|
|
68
|
+
messages.forEach((msg) => {
|
|
69
|
+
validationErrors.push(`- ${field}: ${msg}`);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (err.message) {
|
|
75
|
+
// Fallback to error message if no details
|
|
76
|
+
validationErrors.push(`- ${err.message}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
if (validationErrors.length > 0) {
|
|
80
|
+
errorMessage += ` Validation errors:\n${validationErrors.join('\n')}\n`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Check for deprecated error format (Mautic < 2.6.0)
|
|
84
|
+
else if (errorData?.error?.details && typeof errorData.error.details === 'object') {
|
|
85
|
+
const validationErrors = [];
|
|
86
|
+
Object.entries(errorData.error.details).forEach(([field, messages]) => {
|
|
87
|
+
if (Array.isArray(messages)) {
|
|
88
|
+
messages.forEach((msg) => {
|
|
89
|
+
validationErrors.push(`- ${field}: ${msg}`);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (validationErrors.length > 0) {
|
|
94
|
+
errorMessage += ` Validation errors:\n${validationErrors.join('\n')}\n`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (parseError) {
|
|
99
|
+
// If we can't parse the error details, just use the generic message
|
|
100
|
+
}
|
|
101
|
+
errorMessage += ' Please check your input parameters.';
|
|
102
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), errorMessage, { itemIndex: 0 });
|
|
43
103
|
}
|
|
44
104
|
throw error;
|
|
45
105
|
}
|
package/package.json
CHANGED