@limetech/n8n-nodes-lime 0.3.8 → 0.5.0
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/.prettierignore +3 -1
- package/CHANGELOG.md +100 -0
- package/README.md +1 -8
- package/credentials/LimeCrmApi.credentials.ts +6 -6
- package/dist/nodes/lime-crm/LimeCrmNode.node.js +13 -0
- package/dist/nodes/lime-crm/LimeCrmNode.node.js.map +1 -1
- package/dist/nodes/lime-crm/commons/constants.d.ts +1 -0
- package/dist/nodes/lime-crm/commons/constants.js +2 -1
- package/dist/nodes/lime-crm/commons/constants.js.map +1 -1
- package/dist/nodes/lime-crm/commons/index.d.ts +1 -1
- package/dist/nodes/lime-crm/commons/index.js +2 -1
- package/dist/nodes/lime-crm/commons/index.js.map +1 -1
- package/dist/nodes/lime-crm/resources/limeQuery/index.d.ts +6 -0
- package/dist/nodes/lime-crm/resources/limeQuery/index.js +66 -0
- package/dist/nodes/lime-crm/resources/limeQuery/index.js.map +1 -0
- package/dist/nodes/lime-crm/resources/limeQuery/operations/query.operation.d.ts +9 -0
- package/dist/nodes/lime-crm/resources/limeQuery/operations/query.operation.js +191 -0
- package/dist/nodes/lime-crm/resources/limeQuery/operations/query.operation.js.map +1 -0
- package/dist/nodes/lime-crm/resources/limeType/index.d.ts +3 -3
- package/dist/nodes/lime-crm/transport/index.d.ts +1 -0
- package/dist/nodes/lime-crm/transport/index.js +3 -1
- package/dist/nodes/lime-crm/transport/index.js.map +1 -1
- package/dist/nodes/lime-crm/transport/limeQuery.d.ts +10 -0
- package/dist/nodes/lime-crm/transport/limeQuery.js +15 -0
- package/dist/nodes/lime-crm/transport/limeQuery.js.map +1 -0
- package/dist/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docker-compose.yml +9 -3
- package/nodes/fortnox/Fortnox.node.ts +3 -3
- package/nodes/fortnox/FortnoxTrigger.node.ts +2 -2
- package/nodes/lime-crm/LimeCrmNode.node.ts +54 -53
- package/nodes/lime-crm/LimeCrmTrigger.node.ts +17 -24
- package/nodes/lime-crm/commons/constants.ts +2 -2
- package/nodes/lime-crm/commons/files.ts +162 -0
- package/nodes/lime-crm/commons/index.ts +4 -3
- package/nodes/lime-crm/commons/webhook.ts +15 -3
- package/nodes/lime-crm/methods/getLimetypeProperties.ts +67 -0
- package/nodes/lime-crm/methods/getLimetypes.ts +21 -0
- package/nodes/lime-crm/methods/index.ts +6 -2
- package/nodes/lime-crm/model.ts +22 -0
- package/nodes/lime-crm/resources/data/index.ts +80 -0
- package/nodes/lime-crm/resources/{limeObject/operations/create.operation.ts → data/operations/createSingleObject.ts} +53 -30
- package/nodes/lime-crm/resources/{limeObject/operations/delete.operation.ts → data/operations/deleteSingleObject.ts} +15 -15
- package/nodes/lime-crm/resources/data/operations/getManyObjects.ts +356 -0
- package/nodes/lime-crm/resources/data/operations/getSingleFile.ts +138 -0
- package/nodes/lime-crm/resources/data/operations/getSingleObject.ts +83 -0
- package/nodes/lime-crm/resources/{limeObject/operations/update.operation.ts → data/operations/updateSingleObject.operation.ts} +51 -23
- package/nodes/lime-crm/resources/erpConnector/index.ts +3 -3
- package/nodes/lime-crm/resources/erpConnector/operations/transform.operation.ts +14 -14
- package/nodes/lime-crm/resources/erpConnector/transform.ts +3 -3
- package/nodes/lime-crm/resources/erpConnector/transformers/baseTransformer.ts +2 -2
- package/nodes/lime-crm/resources/erpConnector/transformers/fortnox.ts +8 -8
- package/nodes/lime-crm/resources/metadata/index.ts +57 -0
- package/nodes/lime-crm/resources/metadata/operations/getAllLimetypes.operation.ts +18 -0
- package/nodes/lime-crm/resources/metadata/operations/getSingleFileMetadata.ts +130 -0
- package/nodes/lime-crm/resources/metadata/operations/getSingleLimetype.ts +36 -0
- package/nodes/lime-crm/transport/commons.ts +14 -2
- package/nodes/lime-crm/transport/files.ts +155 -0
- package/nodes/lime-crm/transport/index.ts +14 -6
- package/nodes/lime-crm/transport/limeQuery.ts +26 -0
- package/nodes/lime-crm/transport/limeobjects.ts +79 -44
- package/nodes/lime-crm/transport/limetypes.ts +80 -24
- package/package.json +4 -3
- package/restore_script/README +42 -0
- package/restore_script/api_key_download.txt +0 -0
- package/restore_script/api_key_upload.txt +0 -0
- package/restore_script/cli.py +73 -0
- package/restore_script/download.py +73 -0
- package/restore_script/main.py +19 -0
- package/restore_script/poetry.lock +162 -0
- package/restore_script/pyproject.toml +15 -0
- package/restore_script/transfer.py +41 -0
- package/restore_script/upload.py +66 -0
- package/restore_script/utils.py +42 -0
- package/tests/transform.spec.ts +6 -6
- package/nodes/lime-crm/commons/limetype.ts +0 -11
- package/nodes/lime-crm/methods/getLimeTypeProperties.ts +0 -27
- package/nodes/lime-crm/methods/getLimeTypes.ts +0 -23
- package/nodes/lime-crm/resources/limeObject/index.ts +0 -64
- package/nodes/lime-crm/resources/limeObject/operations/fetchMany.operation.ts +0 -112
- package/nodes/lime-crm/resources/limeObject/operations/get.operation.ts +0 -54
- package/nodes/lime-crm/resources/limeType/index.ts +0 -58
- package/nodes/lime-crm/resources/limeType/operations/getProperties.operation.ts +0 -42
- package/nodes/lime-crm/resources/limeType/operations/getType.operation.ts +0 -36
- package/nodes/lime-crm/resources/limeType/operations/listTypes.operation.ts +0 -18
package/docker-compose.yml
CHANGED
|
@@ -16,8 +16,11 @@ services:
|
|
|
16
16
|
- DB_POSTGRESDB_PASSWORD=n8n
|
|
17
17
|
- N8N_SECURE_COOKIE=false
|
|
18
18
|
- N8N_LOG_LEVEL=debug
|
|
19
|
+
- N8N_LOG_OUTPUT=console
|
|
20
|
+
- N8N_LOG_FORMAT=text
|
|
21
|
+
- NODES_EXCLUDE=["n8n-nodes-base.executeCommand", "n8n-nodes-base.readWriteFile", "n8n-nodes-base.n8n", "n8n-nodes-base.ssh"]
|
|
19
22
|
volumes:
|
|
20
|
-
-
|
|
23
|
+
- n8n_dist:/home/node/.n8n/custom
|
|
21
24
|
depends_on:
|
|
22
25
|
- postgres
|
|
23
26
|
|
|
@@ -28,8 +31,10 @@ services:
|
|
|
28
31
|
command: -c "cd /source && tsc --watch"
|
|
29
32
|
entrypoint: /bin/sh
|
|
30
33
|
volumes:
|
|
31
|
-
-
|
|
32
|
-
- ./
|
|
34
|
+
- ./nodes:/source/nodes
|
|
35
|
+
- ./credentials:/source/credentials
|
|
36
|
+
- ./tsconfig.json:/source/tsconfig.json
|
|
37
|
+
- n8n_dist:/source/dist
|
|
33
38
|
|
|
34
39
|
postgres:
|
|
35
40
|
image: postgres:14
|
|
@@ -44,3 +49,4 @@ services:
|
|
|
44
49
|
|
|
45
50
|
volumes:
|
|
46
51
|
postgres_data:
|
|
52
|
+
n8n_dist:
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
INodeProperties,
|
|
6
6
|
INodeType,
|
|
7
7
|
INodeTypeDescription,
|
|
8
|
-
|
|
8
|
+
NodeConnectionTypes,
|
|
9
9
|
NodeOperationError,
|
|
10
10
|
NodePropertyTypes,
|
|
11
11
|
} from 'n8n-workflow';
|
|
@@ -27,8 +27,8 @@ export class Fortnox implements INodeType {
|
|
|
27
27
|
defaults: {
|
|
28
28
|
name: 'Fortnox',
|
|
29
29
|
},
|
|
30
|
-
inputs: [
|
|
31
|
-
outputs: [
|
|
30
|
+
inputs: [NodeConnectionTypes.Main],
|
|
31
|
+
outputs: [NodeConnectionTypes.Main],
|
|
32
32
|
credentials: [
|
|
33
33
|
{
|
|
34
34
|
name: FORTNOX_API_CREDENTIAL_KEY,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
INodeTypeDescription,
|
|
4
4
|
ITriggerFunctions,
|
|
5
5
|
ITriggerResponse,
|
|
6
|
-
|
|
6
|
+
NodeConnectionTypes,
|
|
7
7
|
NodeOperationError,
|
|
8
8
|
} from 'n8n-workflow';
|
|
9
9
|
import WebSocket from 'ws';
|
|
@@ -32,7 +32,7 @@ export class FortnoxTrigger implements INodeType {
|
|
|
32
32
|
name: 'Fortnox Trigger',
|
|
33
33
|
},
|
|
34
34
|
inputs: [],
|
|
35
|
-
outputs: [
|
|
35
|
+
outputs: [NodeConnectionTypes.Main],
|
|
36
36
|
credentials: [
|
|
37
37
|
{
|
|
38
38
|
name: FORTNOX_API_CREDENTIAL_KEY,
|
|
@@ -4,30 +4,32 @@ import {
|
|
|
4
4
|
INodeProperties,
|
|
5
5
|
INodeType,
|
|
6
6
|
INodeTypeDescription,
|
|
7
|
-
|
|
7
|
+
NodeConnectionTypes,
|
|
8
8
|
NodePropertyTypes,
|
|
9
9
|
} from 'n8n-workflow';
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
erpConnectorOperations,
|
|
14
|
-
} from './resources/erpConnector';
|
|
15
|
-
import { limeTypeFields, limeTypeOperations } from './resources/limeType';
|
|
16
|
-
import { limeObjectFields, limeObjectOperations } from './resources/limeObject';
|
|
11
|
+
import { metadataFields, metadataOperations } from './resources/metadata';
|
|
12
|
+
import { dataFields, dataOperations } from './resources/data';
|
|
17
13
|
|
|
18
14
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
DATA_RESOURCE,
|
|
16
|
+
METADATA_RESOURCE,
|
|
21
17
|
LIME_CRM_API_CREDENTIAL_KEY,
|
|
22
|
-
ERP_CONNECTOR_RESOURCE,
|
|
23
18
|
} from './commons';
|
|
24
19
|
|
|
25
20
|
import {
|
|
26
21
|
getEntitiesForErpSystem,
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
getFileProperties,
|
|
23
|
+
getLimetypeProperties,
|
|
24
|
+
getLimetypes,
|
|
25
|
+
getNoHasManyProperties,
|
|
29
26
|
} from './methods';
|
|
30
27
|
|
|
28
|
+
type OperationFn = (
|
|
29
|
+
this: IExecuteFunctions,
|
|
30
|
+
args: { operation: string; i: number }
|
|
31
|
+
) => Promise<unknown>;
|
|
32
|
+
|
|
31
33
|
export class LimeCrmNode implements INodeType {
|
|
32
34
|
description: INodeTypeDescription = {
|
|
33
35
|
displayName: 'Lime CRM',
|
|
@@ -41,8 +43,8 @@ export class LimeCrmNode implements INodeType {
|
|
|
41
43
|
defaults: {
|
|
42
44
|
name: 'Lime CRM',
|
|
43
45
|
},
|
|
44
|
-
inputs: [
|
|
45
|
-
outputs: [
|
|
46
|
+
inputs: [NodeConnectionTypes.Main],
|
|
47
|
+
outputs: [NodeConnectionTypes.Main],
|
|
46
48
|
credentials: [
|
|
47
49
|
{
|
|
48
50
|
name: LIME_CRM_API_CREDENTIAL_KEY,
|
|
@@ -57,35 +59,33 @@ export class LimeCrmNode implements INodeType {
|
|
|
57
59
|
noDataExpression: true,
|
|
58
60
|
options: [
|
|
59
61
|
{
|
|
60
|
-
name: '
|
|
61
|
-
value:
|
|
62
|
-
description:
|
|
62
|
+
name: 'Metadata',
|
|
63
|
+
value: METADATA_RESOURCE,
|
|
64
|
+
description:
|
|
65
|
+
'Work with the structure of available ' +
|
|
66
|
+
'Limetypes and their properties',
|
|
63
67
|
},
|
|
64
68
|
{
|
|
65
|
-
name: '
|
|
66
|
-
value:
|
|
67
|
-
description: 'Work with
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: 'ERP Connector',
|
|
71
|
-
value: ERP_CONNECTOR_RESOURCE,
|
|
72
|
-
description: 'Integrate data between ERP and Lime CRM',
|
|
69
|
+
name: 'Data',
|
|
70
|
+
value: DATA_RESOURCE,
|
|
71
|
+
description: 'Work with CRM data',
|
|
73
72
|
},
|
|
74
73
|
],
|
|
75
|
-
default:
|
|
74
|
+
default: DATA_RESOURCE,
|
|
76
75
|
},
|
|
77
76
|
|
|
78
|
-
...(
|
|
79
|
-
...(
|
|
80
|
-
...(erpConnectorFields as INodeProperties[]),
|
|
77
|
+
...(metadataFields as INodeProperties[]),
|
|
78
|
+
...(dataFields as INodeProperties[]),
|
|
81
79
|
],
|
|
82
80
|
};
|
|
83
81
|
|
|
84
82
|
methods = {
|
|
85
83
|
loadOptions: {
|
|
86
84
|
getEntitiesForErpSystem,
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
getLimetypes,
|
|
86
|
+
getFileProperties,
|
|
87
|
+
getLimetypeProperties,
|
|
88
|
+
getNoHasManyProperties,
|
|
89
89
|
},
|
|
90
90
|
};
|
|
91
91
|
|
|
@@ -96,38 +96,39 @@ export class LimeCrmNode implements INodeType {
|
|
|
96
96
|
const resource = this.getNodeParameter('resource', 0) as string;
|
|
97
97
|
const operation = this.getNodeParameter('operation', 0) as string;
|
|
98
98
|
|
|
99
|
+
let operationFn: OperationFn | undefined;
|
|
100
|
+
switch (resource) {
|
|
101
|
+
case METADATA_RESOURCE: {
|
|
102
|
+
operationFn = metadataOperations;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case DATA_RESOURCE: {
|
|
106
|
+
operationFn = dataOperations;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
99
111
|
for (let i = 0; i < items.length; i++) {
|
|
100
|
-
|
|
112
|
+
if (!operationFn) continue;
|
|
101
113
|
try {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
i,
|
|
111
|
-
});
|
|
112
|
-
} else if (resource === ERP_CONNECTOR_RESOURCE) {
|
|
113
|
-
responseData = await erpConnectorOperations.call(this, {
|
|
114
|
-
operation,
|
|
115
|
-
i,
|
|
116
|
-
});
|
|
114
|
+
const responseData = await operationFn.call(this, {
|
|
115
|
+
operation,
|
|
116
|
+
i,
|
|
117
|
+
});
|
|
118
|
+
if (responseData !== undefined) {
|
|
119
|
+
returnData.push(
|
|
120
|
+
responseData as unknown as INodeExecutionData
|
|
121
|
+
);
|
|
117
122
|
}
|
|
118
|
-
|
|
119
|
-
returnData.push({ json: responseData });
|
|
120
123
|
} catch (error) {
|
|
121
124
|
if (this.continueOnFail()) {
|
|
122
|
-
returnData.push({
|
|
123
|
-
error: error.message,
|
|
124
|
-
json: { error: error.message },
|
|
125
|
-
});
|
|
125
|
+
returnData.push({ error: error.message });
|
|
126
126
|
continue;
|
|
127
127
|
}
|
|
128
128
|
throw error;
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
+
|
|
131
132
|
return [this.helpers.returnJsonArray(returnData)];
|
|
132
133
|
}
|
|
133
134
|
}
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
IWebhookResponseData,
|
|
8
8
|
NodeOperationError,
|
|
9
9
|
LoggerProxy as Logger,
|
|
10
|
-
|
|
10
|
+
NodeConnectionTypes,
|
|
11
11
|
} from 'n8n-workflow';
|
|
12
12
|
|
|
13
13
|
import { getWebhook, LIME_CRM_API_CREDENTIAL_KEY } from './commons';
|
|
14
|
-
import {
|
|
14
|
+
import { getLimetypes } from './methods';
|
|
15
15
|
import {
|
|
16
16
|
createSubscription,
|
|
17
17
|
deleteSubscription,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
listSubscriptionsWithExistingData,
|
|
20
20
|
} from './transport';
|
|
21
21
|
|
|
22
|
-
import { verifyHmac } from './commons
|
|
22
|
+
import { verifyHmac } from './commons';
|
|
23
23
|
|
|
24
24
|
export class LimeCrmTrigger implements INodeType {
|
|
25
25
|
description: INodeTypeDescription = {
|
|
@@ -30,12 +30,12 @@ export class LimeCrmTrigger implements INodeType {
|
|
|
30
30
|
version: 1,
|
|
31
31
|
description:
|
|
32
32
|
'Trigger which handles webhooks coming from Lime, e.g when ' +
|
|
33
|
-
'
|
|
33
|
+
'an object is updated',
|
|
34
34
|
defaults: {
|
|
35
35
|
name: 'Lime CRM Trigger',
|
|
36
36
|
},
|
|
37
37
|
inputs: [],
|
|
38
|
-
outputs: [
|
|
38
|
+
outputs: [NodeConnectionTypes.Main],
|
|
39
39
|
credentials: [
|
|
40
40
|
{
|
|
41
41
|
name: LIME_CRM_API_CREDENTIAL_KEY,
|
|
@@ -68,18 +68,18 @@ export class LimeCrmTrigger implements INodeType {
|
|
|
68
68
|
displayName: 'Event',
|
|
69
69
|
values: [
|
|
70
70
|
{
|
|
71
|
-
displayName: '
|
|
72
|
-
name: '
|
|
71
|
+
displayName: 'Limetype',
|
|
72
|
+
name: 'limetype',
|
|
73
73
|
type: 'options',
|
|
74
74
|
typeOptions: {
|
|
75
|
-
loadOptionsMethod: '
|
|
75
|
+
loadOptionsMethod: 'getLimetypes',
|
|
76
76
|
},
|
|
77
77
|
default: '',
|
|
78
78
|
description:
|
|
79
|
-
'
|
|
79
|
+
'Limetype to subscribe to events for',
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
|
-
displayName: 'Event
|
|
82
|
+
displayName: 'Event',
|
|
83
83
|
name: 'eventType',
|
|
84
84
|
type: 'options',
|
|
85
85
|
options: [
|
|
@@ -87,41 +87,34 @@ export class LimeCrmTrigger implements INodeType {
|
|
|
87
87
|
name: 'New',
|
|
88
88
|
value: 'new',
|
|
89
89
|
description:
|
|
90
|
-
'When a new
|
|
90
|
+
'When a new object is created',
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
name: 'Update',
|
|
94
94
|
value: 'update',
|
|
95
|
-
description:
|
|
95
|
+
description:
|
|
96
|
+
'When an object is updated',
|
|
96
97
|
},
|
|
97
98
|
{
|
|
98
99
|
name: 'Delete',
|
|
99
100
|
value: 'delete',
|
|
100
|
-
description:
|
|
101
|
+
description:
|
|
102
|
+
'When an object is deleted',
|
|
101
103
|
},
|
|
102
104
|
],
|
|
103
105
|
default: 'new',
|
|
104
|
-
description: '
|
|
106
|
+
description: 'Event to subscribe to',
|
|
105
107
|
},
|
|
106
108
|
],
|
|
107
109
|
},
|
|
108
110
|
],
|
|
109
111
|
},
|
|
110
|
-
{
|
|
111
|
-
displayName: 'Name',
|
|
112
|
-
name: 'name',
|
|
113
|
-
type: 'string',
|
|
114
|
-
default: '',
|
|
115
|
-
placeholder: 'my-lime-webhook',
|
|
116
|
-
required: true,
|
|
117
|
-
description: 'Name for this webhook subscription',
|
|
118
|
-
},
|
|
119
112
|
],
|
|
120
113
|
};
|
|
121
114
|
|
|
122
115
|
methods = {
|
|
123
116
|
loadOptions: {
|
|
124
|
-
|
|
117
|
+
getLimetypes,
|
|
125
118
|
},
|
|
126
119
|
};
|
|
127
120
|
|
|
@@ -4,6 +4,6 @@ export const LIME_CRM_API_CREDENTIAL_KEY = 'limeCrmApi';
|
|
|
4
4
|
|
|
5
5
|
// Resources
|
|
6
6
|
|
|
7
|
-
export const
|
|
8
|
-
export const
|
|
7
|
+
export const DATA_RESOURCE = 'data';
|
|
8
|
+
export const METADATA_RESOURCE = 'metadata';
|
|
9
9
|
export const ERP_CONNECTOR_RESOURCE = 'erpConnector';
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IBinaryData,
|
|
3
|
+
IDataObject,
|
|
4
|
+
IExecuteFunctions,
|
|
5
|
+
LoggerProxy as Logger,
|
|
6
|
+
} from 'n8n-workflow';
|
|
7
|
+
import {
|
|
8
|
+
createFile,
|
|
9
|
+
getFileContent,
|
|
10
|
+
getFileMetadata,
|
|
11
|
+
getProperties,
|
|
12
|
+
} from '../transport';
|
|
13
|
+
import { NodeResponse } from '../../nodeResponse';
|
|
14
|
+
|
|
15
|
+
type FileResponse<T> = {
|
|
16
|
+
json: NodeResponse<T>;
|
|
17
|
+
binary?: Record<string, IBinaryData>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const setFilename = (
|
|
21
|
+
preparedBinaryData: IBinaryData,
|
|
22
|
+
responseFileName: string
|
|
23
|
+
) => {
|
|
24
|
+
if (!preparedBinaryData.fileName && preparedBinaryData.fileExtension) {
|
|
25
|
+
return responseFileName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return preparedBinaryData.fileName;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function getFilenameFromHeader(
|
|
32
|
+
headers: Record<string, string | string[] | undefined>
|
|
33
|
+
): string | null {
|
|
34
|
+
let contentDisposition =
|
|
35
|
+
headers['content-disposition'] || headers['Content-Disposition'];
|
|
36
|
+
if (!contentDisposition) return null;
|
|
37
|
+
|
|
38
|
+
if (Array.isArray(contentDisposition)) {
|
|
39
|
+
contentDisposition = contentDisposition[0];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Try RFC 5987 filename* format
|
|
43
|
+
const filenameStarMatch = /filename\*\s*=\s*UTF-8''([^;]+)/i.exec(
|
|
44
|
+
contentDisposition
|
|
45
|
+
);
|
|
46
|
+
if (filenameStarMatch) {
|
|
47
|
+
try {
|
|
48
|
+
return decodeURIComponent(filenameStarMatch[1]);
|
|
49
|
+
} catch {
|
|
50
|
+
return filenameStarMatch[1];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Try regular filename="..." or filename=...
|
|
55
|
+
const filenameMatch =
|
|
56
|
+
/filename\s*=\s*"([^"]+)"|filename\s*=\s*([^;]+)/i.exec(
|
|
57
|
+
contentDisposition
|
|
58
|
+
);
|
|
59
|
+
if (filenameMatch) {
|
|
60
|
+
return filenameMatch[1] || filenameMatch[2];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function getFileProperties(
|
|
67
|
+
nodeContext: IExecuteFunctions,
|
|
68
|
+
limetype: string,
|
|
69
|
+
allowedProperties?: Set<string>
|
|
70
|
+
): Promise<Set<string>> {
|
|
71
|
+
const response = await getProperties(nodeContext, limetype);
|
|
72
|
+
|
|
73
|
+
if (!response.success) return new Set();
|
|
74
|
+
return new Set(
|
|
75
|
+
response.data
|
|
76
|
+
.filter(
|
|
77
|
+
(property) =>
|
|
78
|
+
property.type === 'file' &&
|
|
79
|
+
(!allowedProperties || allowedProperties.has(property.name))
|
|
80
|
+
)
|
|
81
|
+
.map((property) => property.name)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function setFileProperties(
|
|
86
|
+
context: IExecuteFunctions,
|
|
87
|
+
i: number,
|
|
88
|
+
fileProperties: Set<string>,
|
|
89
|
+
definedProperties: IDataObject
|
|
90
|
+
): Promise<NodeResponse<IDataObject>> {
|
|
91
|
+
for (const fileProperty of fileProperties) {
|
|
92
|
+
if (!(fileProperty in definedProperties)) continue;
|
|
93
|
+
let binaryData: IBinaryData;
|
|
94
|
+
try {
|
|
95
|
+
Logger.info(
|
|
96
|
+
`Checking whether "${definedProperties[fileProperty]}" is a valid binary object for property "${fileProperty}"...`
|
|
97
|
+
);
|
|
98
|
+
binaryData = context.helpers.assertBinaryData(
|
|
99
|
+
i,
|
|
100
|
+
definedProperties[fileProperty] as string
|
|
101
|
+
);
|
|
102
|
+
} catch {
|
|
103
|
+
Logger.info(
|
|
104
|
+
`Invalid or missing binary data for "${fileProperty}". Using original value instead.`
|
|
105
|
+
);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const response = await createFile(
|
|
109
|
+
context,
|
|
110
|
+
binaryData,
|
|
111
|
+
definedProperties[fileProperty] as string
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (response.success) {
|
|
115
|
+
definedProperties[fileProperty] = response.data.id;
|
|
116
|
+
} else return response;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
success: true,
|
|
120
|
+
data: definedProperties,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function processFileResponse<T extends Record<string, unknown>>(
|
|
125
|
+
nodeContext: IExecuteFunctions,
|
|
126
|
+
fileProperties: Set<string>,
|
|
127
|
+
data: T,
|
|
128
|
+
includeFileContent: boolean = false
|
|
129
|
+
): Promise<FileResponse<T>> {
|
|
130
|
+
let updatedData = { ...data };
|
|
131
|
+
const binaryData: Record<string, IBinaryData> = {};
|
|
132
|
+
for (const fileProperty of fileProperties) {
|
|
133
|
+
if (!data[fileProperty]) continue;
|
|
134
|
+
const fileMetadataResponse = await getFileMetadata(
|
|
135
|
+
nodeContext,
|
|
136
|
+
data[fileProperty] as string
|
|
137
|
+
);
|
|
138
|
+
if (!fileMetadataResponse.success)
|
|
139
|
+
return { json: fileMetadataResponse };
|
|
140
|
+
|
|
141
|
+
updatedData = {
|
|
142
|
+
...updatedData,
|
|
143
|
+
[fileProperty]: fileMetadataResponse.data,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (includeFileContent) {
|
|
147
|
+
const fileResponse = await getFileContent(
|
|
148
|
+
nodeContext,
|
|
149
|
+
fileMetadataResponse.data.id
|
|
150
|
+
);
|
|
151
|
+
if (!fileResponse.success) return { json: fileResponse };
|
|
152
|
+
binaryData[fileProperty] = fileResponse.data;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
json: {
|
|
157
|
+
success: true,
|
|
158
|
+
data: updatedData,
|
|
159
|
+
},
|
|
160
|
+
binary: binaryData,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export {
|
|
2
2
|
LIME_CRM_API_CREDENTIAL_KEY,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
DATA_RESOURCE,
|
|
4
|
+
METADATA_RESOURCE,
|
|
5
5
|
ERP_CONNECTOR_RESOURCE,
|
|
6
6
|
} from './constants';
|
|
7
7
|
export { Webhook, getWebhook } from './webhook';
|
|
8
8
|
|
|
9
|
-
export {
|
|
9
|
+
export { verifyHmac } from './hmac';
|
|
10
|
+
export { setFilename, getFilenameFromHeader } from './files';
|
|
@@ -24,18 +24,30 @@ export interface CreateWebhook extends Webhook {
|
|
|
24
24
|
function _getEvents(hookData: WebhookFunctions): string[] {
|
|
25
25
|
const eventData = hookData.getNodeParameter('events', []) as {
|
|
26
26
|
event: Array<{
|
|
27
|
-
|
|
27
|
+
limetype: string;
|
|
28
28
|
eventType: string;
|
|
29
29
|
}>;
|
|
30
30
|
};
|
|
31
31
|
const eventItems = eventData.event;
|
|
32
32
|
const events: string[] = [];
|
|
33
33
|
for (const eventItem of eventItems) {
|
|
34
|
-
events.push(`${eventItem.
|
|
34
|
+
events.push(`${eventItem.limetype}.${eventItem.eventType}`);
|
|
35
35
|
}
|
|
36
36
|
return events;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function _createWebhookName(hookData: WebhookFunctions): string {
|
|
40
|
+
interface Events {
|
|
41
|
+
event: Array<{
|
|
42
|
+
limetype: string;
|
|
43
|
+
eventType: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const events = hookData.getNodeParameter('events') as Events;
|
|
48
|
+
return `${events.event[0].limetype}-${events.event[0].eventType}-${Date.now()}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
export function getWebhook(hookData: WebhookFunctions): Webhook {
|
|
40
52
|
const node = hookData.getNode();
|
|
41
53
|
const workflow = hookData.getWorkflow();
|
|
@@ -51,6 +63,6 @@ export function getWebhook(hookData: WebhookFunctions): Webhook {
|
|
|
51
63
|
events: _getEvents(hookData),
|
|
52
64
|
url: hookData.getNodeWebhookUrl('default'),
|
|
53
65
|
context: context,
|
|
54
|
-
name: hookData
|
|
66
|
+
name: _createWebhookName(hookData),
|
|
55
67
|
};
|
|
56
68
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ILoadOptionsFunctions,
|
|
3
|
+
INodePropertyOptions,
|
|
4
|
+
LoggerProxy as Logger,
|
|
5
|
+
} from 'n8n-workflow';
|
|
6
|
+
import { getProperties } from '../transport/';
|
|
7
|
+
|
|
8
|
+
async function _getProperties(nodeContext: ILoadOptionsFunctions) {
|
|
9
|
+
const limetype = nodeContext.getNodeParameter('limetype', '') as string;
|
|
10
|
+
Logger.info(`Fetching file properties for Lime type: ${limetype}`);
|
|
11
|
+
if (!limetype) return [];
|
|
12
|
+
|
|
13
|
+
const response = await getProperties(nodeContext, limetype);
|
|
14
|
+
|
|
15
|
+
return response.success ? response.data : [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Gets property options from a specific Limetype
|
|
20
|
+
*
|
|
21
|
+
* It's not meant to be used directly in 'loadOptionsMethod'
|
|
22
|
+
*
|
|
23
|
+
* This function fetches properties for the specified Limetype and optionally filters them
|
|
24
|
+
* based on allowed types.
|
|
25
|
+
*
|
|
26
|
+
* @param [loader] - The n8n load options context
|
|
27
|
+
* @param [allowedTypes] - Optional set of property types to filter by
|
|
28
|
+
* @param [forbiddenType] - Optional set of property types to exclude
|
|
29
|
+
* @returns Array of formatted property options
|
|
30
|
+
*/
|
|
31
|
+
export async function getFilteredLimetypeProperties(
|
|
32
|
+
loader: ILoadOptionsFunctions,
|
|
33
|
+
allowedTypes?: Set<string>,
|
|
34
|
+
forbiddenType?: Set<string>
|
|
35
|
+
): Promise<INodePropertyOptions[]> {
|
|
36
|
+
const properties = await _getProperties(loader);
|
|
37
|
+
|
|
38
|
+
return properties
|
|
39
|
+
.filter(
|
|
40
|
+
(property) =>
|
|
41
|
+
(!allowedTypes || allowedTypes.has(property.type)) &&
|
|
42
|
+
(!forbiddenType || !forbiddenType.has(property.type))
|
|
43
|
+
)
|
|
44
|
+
.map((property) => ({
|
|
45
|
+
name: (property.localname as string) || (property.name as string),
|
|
46
|
+
value: property.name as string,
|
|
47
|
+
description: `Type: ${property.type as string}${(property.required as boolean) ? ' (Required)' : ''}`,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function getLimetypeProperties(
|
|
52
|
+
this: ILoadOptionsFunctions
|
|
53
|
+
): Promise<INodePropertyOptions[]> {
|
|
54
|
+
return getFilteredLimetypeProperties(this);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function getFileProperties(
|
|
58
|
+
this: ILoadOptionsFunctions
|
|
59
|
+
): Promise<INodePropertyOptions[]> {
|
|
60
|
+
return getFilteredLimetypeProperties(this, new Set(['file']));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function getNoHasManyProperties(
|
|
64
|
+
this: ILoadOptionsFunctions
|
|
65
|
+
): Promise<INodePropertyOptions[]> {
|
|
66
|
+
return getFilteredLimetypeProperties(this, undefined, new Set(['hasmany']));
|
|
67
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
|
2
|
+
import { getLimetypesFromApi } from '../transport';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Load available Lime types from the API
|
|
6
|
+
*/
|
|
7
|
+
export async function getLimetypes(
|
|
8
|
+
this: ILoadOptionsFunctions
|
|
9
|
+
): Promise<INodePropertyOptions[]> {
|
|
10
|
+
const data: INodePropertyOptions[] = [];
|
|
11
|
+
const response = await getLimetypesFromApi(this);
|
|
12
|
+
if (response.success && response.data) {
|
|
13
|
+
for (const limetype of response.data) {
|
|
14
|
+
data.push({
|
|
15
|
+
name: limetype.localname?.singular || limetype.name,
|
|
16
|
+
value: limetype.name,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export { getEntitiesForErpSystem } from './getEntitiesForErpSystem';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { getLimetypes } from './getLimetypes';
|
|
3
|
+
export {
|
|
4
|
+
getFileProperties,
|
|
5
|
+
getLimetypeProperties,
|
|
6
|
+
getNoHasManyProperties,
|
|
7
|
+
} from './getLimetypeProperties';
|