@limetech/n8n-nodes-lime 0.4.0 → 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.
Files changed (64) hide show
  1. package/.prettierignore +3 -1
  2. package/CHANGELOG.md +93 -0
  3. package/README.md +1 -8
  4. package/credentials/LimeCrmApi.credentials.ts +6 -6
  5. package/docker-compose.yml +9 -3
  6. package/nodes/fortnox/Fortnox.node.ts +3 -3
  7. package/nodes/fortnox/FortnoxTrigger.node.ts +2 -2
  8. package/nodes/lime-crm/LimeCrmNode.node.ts +54 -67
  9. package/nodes/lime-crm/LimeCrmTrigger.node.ts +17 -24
  10. package/nodes/lime-crm/commons/constants.ts +2 -3
  11. package/nodes/lime-crm/commons/files.ts +162 -0
  12. package/nodes/lime-crm/commons/index.ts +4 -4
  13. package/nodes/lime-crm/commons/webhook.ts +15 -3
  14. package/nodes/lime-crm/methods/getLimetypeProperties.ts +67 -0
  15. package/nodes/lime-crm/methods/getLimetypes.ts +21 -0
  16. package/nodes/lime-crm/methods/index.ts +6 -2
  17. package/nodes/lime-crm/model.ts +22 -0
  18. package/nodes/lime-crm/resources/data/index.ts +80 -0
  19. package/nodes/lime-crm/resources/{limeObject/operations/create.operation.ts → data/operations/createSingleObject.ts} +53 -30
  20. package/nodes/lime-crm/resources/{limeObject/operations/delete.operation.ts → data/operations/deleteSingleObject.ts} +15 -15
  21. package/nodes/lime-crm/resources/data/operations/getManyObjects.ts +356 -0
  22. package/nodes/lime-crm/resources/data/operations/getSingleFile.ts +138 -0
  23. package/nodes/lime-crm/resources/data/operations/getSingleObject.ts +83 -0
  24. package/nodes/lime-crm/resources/{limeObject/operations/update.operation.ts → data/operations/updateSingleObject.operation.ts} +51 -23
  25. package/nodes/lime-crm/resources/erpConnector/index.ts +3 -3
  26. package/nodes/lime-crm/resources/erpConnector/operations/transform.operation.ts +14 -14
  27. package/nodes/lime-crm/resources/erpConnector/transform.ts +3 -3
  28. package/nodes/lime-crm/resources/erpConnector/transformers/baseTransformer.ts +2 -2
  29. package/nodes/lime-crm/resources/erpConnector/transformers/fortnox.ts +8 -8
  30. package/nodes/lime-crm/resources/metadata/index.ts +57 -0
  31. package/nodes/lime-crm/resources/metadata/operations/getAllLimetypes.operation.ts +18 -0
  32. package/nodes/lime-crm/resources/metadata/operations/getSingleFileMetadata.ts +130 -0
  33. package/nodes/lime-crm/resources/metadata/operations/getSingleLimetype.ts +36 -0
  34. package/nodes/lime-crm/transport/commons.ts +14 -2
  35. package/nodes/lime-crm/transport/files.ts +155 -0
  36. package/nodes/lime-crm/transport/index.ts +14 -7
  37. package/nodes/lime-crm/transport/limeQuery.ts +2 -4
  38. package/nodes/lime-crm/transport/limeobjects.ts +79 -44
  39. package/nodes/lime-crm/transport/limetypes.ts +80 -24
  40. package/package.json +4 -3
  41. package/restore_script/README +42 -0
  42. package/restore_script/api_key_download.txt +0 -0
  43. package/restore_script/api_key_upload.txt +0 -0
  44. package/restore_script/cli.py +73 -0
  45. package/restore_script/download.py +73 -0
  46. package/restore_script/main.py +19 -0
  47. package/restore_script/poetry.lock +162 -0
  48. package/restore_script/pyproject.toml +15 -0
  49. package/restore_script/transfer.py +41 -0
  50. package/restore_script/upload.py +66 -0
  51. package/restore_script/utils.py +42 -0
  52. package/tests/transform.spec.ts +6 -6
  53. package/nodes/lime-crm/commons/limetype.ts +0 -11
  54. package/nodes/lime-crm/methods/getLimeTypeProperties.ts +0 -27
  55. package/nodes/lime-crm/methods/getLimeTypes.ts +0 -23
  56. package/nodes/lime-crm/resources/limeObject/index.ts +0 -64
  57. package/nodes/lime-crm/resources/limeObject/operations/fetchMany.operation.ts +0 -112
  58. package/nodes/lime-crm/resources/limeObject/operations/get.operation.ts +0 -54
  59. package/nodes/lime-crm/resources/limeQuery/index.ts +0 -40
  60. package/nodes/lime-crm/resources/limeQuery/operations/query.operation.ts +0 -222
  61. package/nodes/lime-crm/resources/limeType/index.ts +0 -58
  62. package/nodes/lime-crm/resources/limeType/operations/getProperties.operation.ts +0 -42
  63. package/nodes/lime-crm/resources/limeType/operations/getType.operation.ts +0 -36
  64. package/nodes/lime-crm/resources/limeType/operations/listTypes.operation.ts +0 -18
@@ -0,0 +1,356 @@
1
+ import { IExecuteFunctions, INodeProperties } from 'n8n-workflow';
2
+
3
+ import { queryLimeobjects } from '../../../transport';
4
+ import { DATA_RESOURCE } from '../../../commons';
5
+
6
+ export const description = {
7
+ name: 'Get Many Objects',
8
+ value: 'getManyObjects',
9
+ description: 'Get a list of many objects',
10
+ action: 'Get many objects',
11
+ };
12
+
13
+ const BATCHSIZE = 50;
14
+
15
+ interface ResponseFormat {
16
+ object: {
17
+ [key: string]: string;
18
+ };
19
+ }
20
+
21
+ interface OrderByCollection {
22
+ orderByFields: {
23
+ propertyName: string;
24
+ sortDirection: 'ASC' | 'DESC';
25
+ }[];
26
+ }
27
+
28
+ export const properties: INodeProperties[] = [
29
+ {
30
+ displayName: 'Limetype',
31
+ name: 'limetype',
32
+ type: 'options',
33
+ typeOptions: {
34
+ loadOptionsMethod: 'getLimetypes',
35
+ },
36
+ required: true,
37
+ default: '',
38
+ description: 'The type of entity to query',
39
+ displayOptions: {
40
+ show: {
41
+ resource: [DATA_RESOURCE],
42
+ operation: ['getManyObjects'],
43
+ },
44
+ },
45
+ },
46
+ {
47
+ displayName: 'Response Format',
48
+ name: 'responseFormatInputMethod',
49
+ type: 'options',
50
+ required: true,
51
+ default: 'fields',
52
+ description: 'Select how the response should be formatted',
53
+ displayOptions: {
54
+ show: {
55
+ resource: [DATA_RESOURCE],
56
+ operation: ['getManyObjects'],
57
+ },
58
+ },
59
+ options: [
60
+ {
61
+ name: 'Properties',
62
+ value: 'fields',
63
+ },
64
+ {
65
+ name: 'JSON',
66
+ value: 'json',
67
+ },
68
+ ],
69
+ },
70
+ {
71
+ displayName: 'Response Format (Form Fields)',
72
+ name: 'responseFormatProperties',
73
+ type: 'fixedCollection',
74
+ placeholder: 'Add Property',
75
+ typeOptions: {
76
+ multipleValues: true,
77
+ },
78
+ default: {},
79
+ displayOptions: {
80
+ show: {
81
+ resource: [DATA_RESOURCE],
82
+ operation: ['getManyObjects'],
83
+ responseFormatInputMethod: ['fields'],
84
+ },
85
+ },
86
+ options: [
87
+ {
88
+ displayName: 'Property',
89
+ name: 'property',
90
+ values: [
91
+ {
92
+ displayName: 'Property Name',
93
+ name: 'name',
94
+ type: 'options',
95
+ typeOptions: {
96
+ sortable: true,
97
+ loadOptionsMethod: 'getNoHasManyProperties',
98
+ loadOptionsDependsOn: ['limetype'],
99
+ },
100
+ default: '',
101
+ description: 'Name of the property',
102
+ },
103
+ ],
104
+ },
105
+ ],
106
+ },
107
+ {
108
+ displayName: 'Response Format (JSON)',
109
+ name: 'responseFormatJson',
110
+ type: 'json',
111
+ required: true,
112
+ default: '{\n\t"object": {\n\t\t"_id": ""\n\t}\n}',
113
+ description:
114
+ 'Information included in the response when using JSON format',
115
+ displayOptions: {
116
+ show: {
117
+ resource: [DATA_RESOURCE],
118
+ operation: ['getManyObjects'],
119
+ responseFormatInputMethod: ['json'],
120
+ },
121
+ },
122
+ },
123
+ {
124
+ displayName: 'Filter (JSON)',
125
+ name: 'filter',
126
+ type: 'json',
127
+ default: '{}',
128
+ description: "The filter DSL defining the query's conditions",
129
+ displayOptions: {
130
+ show: {
131
+ resource: [DATA_RESOURCE],
132
+ operation: ['getManyObjects'],
133
+ },
134
+ },
135
+ },
136
+ {
137
+ displayName: 'Limit',
138
+ name: 'limit',
139
+ type: 'number',
140
+ default: 50,
141
+ description: 'The maximum number of records to return',
142
+ displayOptions: {
143
+ show: {
144
+ resource: [DATA_RESOURCE],
145
+ operation: ['getManyObjects'],
146
+ },
147
+ },
148
+ },
149
+ {
150
+ displayName: 'Order By',
151
+ name: 'orderByInputMethod',
152
+ type: 'options',
153
+ required: true,
154
+ default: 'fields',
155
+ description: 'Select how the response should be ordered',
156
+ displayOptions: {
157
+ show: {
158
+ resource: [DATA_RESOURCE],
159
+ operation: ['getManyObjects'],
160
+ },
161
+ },
162
+ options: [
163
+ {
164
+ name: 'Form Fields',
165
+ value: 'fields',
166
+ },
167
+ {
168
+ name: 'JSON',
169
+ value: 'json',
170
+ },
171
+ ],
172
+ },
173
+ {
174
+ displayName: 'Order By (Form Fields)',
175
+ name: 'orderByProperties',
176
+ type: 'fixedCollection',
177
+ placeholder: 'Add Property',
178
+ typeOptions: {
179
+ multipleValues: true,
180
+ },
181
+ default: {},
182
+ description:
183
+ 'The list of properties by which to order the query results',
184
+ displayOptions: {
185
+ show: {
186
+ resource: [DATA_RESOURCE],
187
+ operation: ['getManyObjects'],
188
+ orderByInputMethod: ['fields'],
189
+ },
190
+ },
191
+ options: [
192
+ {
193
+ name: 'orderByFields',
194
+ displayName: 'Order By Fields',
195
+ values: [
196
+ {
197
+ displayName: 'Property Name',
198
+ name: 'propertyName',
199
+ type: 'options',
200
+ required: true,
201
+ typeOptions: {
202
+ sortable: true,
203
+ loadOptionsMethod: 'getNoHasManyProperties',
204
+ loadOptionsDependsOn: ['limetype'],
205
+ },
206
+ default: '',
207
+ description: 'Name of the property to order by',
208
+ },
209
+ {
210
+ displayName: 'Sort Direction',
211
+ name: 'sortDirection',
212
+ type: 'options',
213
+ default: 'ASC',
214
+ description: 'Ordering direction',
215
+ options: [
216
+ { name: 'Ascending', value: 'ASC' },
217
+ { name: 'Descending', value: 'DESC' },
218
+ ],
219
+ },
220
+ ],
221
+ },
222
+ ],
223
+ },
224
+ {
225
+ displayName: 'Order By (JSON)',
226
+ name: 'orderByJson',
227
+ type: 'json',
228
+ required: true,
229
+ default: '[\n\t{\n\t\t"_id": "ASC"\n\t}\n]',
230
+ description: 'Provide ordering in JSON',
231
+ displayOptions: {
232
+ show: {
233
+ resource: [DATA_RESOURCE],
234
+ operation: ['getManyObjects'],
235
+ orderByInputMethod: ['json'],
236
+ },
237
+ },
238
+ },
239
+ ];
240
+
241
+ function _createResponseFormatObject(
242
+ properties: { name: string }[] = []
243
+ ): ResponseFormat {
244
+ const object: Record<string, string> = { _id: '' };
245
+ for (const { name } of properties) {
246
+ if (name) object[name] = '';
247
+ }
248
+ return { object };
249
+ }
250
+
251
+ function _getOrderBy(orderByCollection: OrderByCollection) {
252
+ const orderBy =
253
+ orderByCollection.orderByFields &&
254
+ orderByCollection.orderByFields.map((field) => ({
255
+ [field.propertyName]: field.sortDirection,
256
+ }));
257
+ return orderBy || [{ _id: 'ASC' }];
258
+ }
259
+
260
+ async function _fetchLimeObjectsInBatches(
261
+ this: IExecuteFunctions,
262
+ limetype: string,
263
+ responseFormat: ResponseFormat,
264
+ filter: string,
265
+ limit: number,
266
+ orderBy: Array<{ [key: string]: 'ASC' | 'DESC' }>
267
+ ) {
268
+ if (limit <= BATCHSIZE) {
269
+ const q = JSON.stringify({
270
+ limetype,
271
+ responseFormat: responseFormat,
272
+ filter: JSON.parse(filter),
273
+ limit: limit,
274
+ offset: 0,
275
+ orderBy: orderBy,
276
+ });
277
+ return queryLimeobjects(this, q);
278
+ } else {
279
+ let allResults: unknown[] = [];
280
+ let fetched = 0;
281
+ let currentOffset = 0;
282
+ while (fetched < limit) {
283
+ const currentLimit = Math.min(BATCHSIZE, limit - fetched);
284
+ const q = JSON.stringify({
285
+ limetype,
286
+ responseFormat: responseFormat,
287
+ filter: JSON.parse(filter),
288
+ limit: currentLimit,
289
+ offset: currentOffset,
290
+ orderBy,
291
+ });
292
+ const batch = await queryLimeobjects(this, q);
293
+ if (!batch.success) {
294
+ return batch;
295
+ }
296
+ const collected = batch.data.objects.length;
297
+ if (!batch || collected === 0) break;
298
+ allResults = [...allResults, ...batch.data.objects];
299
+ fetched += collected;
300
+ currentOffset += collected;
301
+
302
+ if (collected < currentLimit) break;
303
+ }
304
+ return {
305
+ success: true,
306
+ data: allResults,
307
+ };
308
+ }
309
+ }
310
+
311
+ export async function execute(this: IExecuteFunctions, i: number) {
312
+ const limetype = this.getNodeParameter('limetype', i) as string;
313
+ const responseFormatInputMethod = this.getNodeParameter(
314
+ 'responseFormatInputMethod',
315
+ i
316
+ ) as string;
317
+ const orderByInputMethod = this.getNodeParameter(
318
+ 'orderByInputMethod',
319
+ i
320
+ ) as string;
321
+ const filter = this.getNodeParameter('filter', i) as string;
322
+ const limit = this.getNodeParameter('limit', i, 50) as number;
323
+
324
+ let response;
325
+ if (responseFormatInputMethod === 'fields') {
326
+ const properties = this.getNodeParameter(
327
+ 'responseFormatProperties',
328
+ i
329
+ ) as { property: [{ name: string }] };
330
+ response = _createResponseFormatObject(properties.property);
331
+ } else if (responseFormatInputMethod === 'json') {
332
+ response = this.getNodeParameter('responseFormatJson', i) as string;
333
+ response = JSON.parse(response);
334
+ }
335
+
336
+ let orderBy;
337
+ if (orderByInputMethod === 'fields') {
338
+ const orderByCollection = this.getNodeParameter(
339
+ 'orderByProperties',
340
+ i
341
+ ) as OrderByCollection;
342
+ orderBy = _getOrderBy(orderByCollection);
343
+ } else if (orderByInputMethod === 'json') {
344
+ orderBy = this.getNodeParameter('orderByJson', i) as string;
345
+ orderBy = JSON.parse(orderBy);
346
+ }
347
+
348
+ return await _fetchLimeObjectsInBatches.call(
349
+ this,
350
+ limetype,
351
+ response,
352
+ filter,
353
+ limit,
354
+ orderBy
355
+ );
356
+ }
@@ -0,0 +1,138 @@
1
+ import {
2
+ IExecuteFunctions,
3
+ INodeProperties,
4
+ NodeOperationError,
5
+ } from 'n8n-workflow';
6
+ import { getFileContent, getFileContentByLimetype } from '../../../transport';
7
+ import { DATA_RESOURCE } from '../../../commons';
8
+
9
+ export const description = {
10
+ name: 'Get Single File',
11
+ value: 'getSingleFile',
12
+ description: 'Get the file data for one specific file',
13
+ action: 'Get single file',
14
+ };
15
+
16
+ export const properties: INodeProperties[] = [
17
+ {
18
+ displayName: 'Get by',
19
+ name: 'source',
20
+ type: 'options',
21
+ required: true,
22
+ placeholder: 'Add Source',
23
+ displayOptions: {
24
+ show: {
25
+ resource: [DATA_RESOURCE],
26
+ operation: ['getSingleFile'],
27
+ },
28
+ },
29
+ options: [
30
+ {
31
+ name: 'File ID',
32
+ value: 'byFile',
33
+ description: 'Get file by its ID',
34
+ },
35
+ {
36
+ name: 'Limeobject ID',
37
+ value: 'byLimeobject',
38
+ description: "Get file by it's associated Limeobject ID",
39
+ },
40
+ ],
41
+ default: 'byFile',
42
+ },
43
+ {
44
+ displayName: 'Limetype',
45
+ name: 'limetype',
46
+ type: 'options',
47
+ typeOptions: {
48
+ loadOptionsMethod: 'getLimetypes',
49
+ },
50
+ required: true,
51
+ default: '',
52
+ description: 'The type of entity associated with the file',
53
+ displayOptions: {
54
+ show: {
55
+ resource: [DATA_RESOURCE],
56
+ operation: ['getSingleFile'],
57
+ source: ['byLimeobject'],
58
+ },
59
+ },
60
+ },
61
+ {
62
+ displayName: 'Identifier',
63
+ name: 'identifier',
64
+ type: 'string',
65
+ required: true,
66
+ default: '',
67
+ description: 'The ID of the file or Limeobject to retrieve',
68
+ displayOptions: {
69
+ show: {
70
+ resource: [DATA_RESOURCE],
71
+ operation: ['getSingleFile'],
72
+ },
73
+ },
74
+ placeholder: 'e.g., 12345',
75
+ },
76
+ {
77
+ displayName: 'File type property',
78
+ name: 'property',
79
+ type: 'options',
80
+ typeOptions: {
81
+ loadOptionsMethod: 'getFileProperties',
82
+ loadOptionsDependsOn: ['limetype'],
83
+ },
84
+ required: true,
85
+ default: '',
86
+ description: 'The type of entity associated with the file',
87
+ displayOptions: {
88
+ show: {
89
+ resource: [DATA_RESOURCE],
90
+ operation: ['getSingleFile'],
91
+ source: ['byLimeobject'],
92
+ },
93
+ },
94
+ },
95
+ ];
96
+
97
+ export async function execute(this: IExecuteFunctions, i: number) {
98
+ const source = this.getNodeParameter('source', i) as string;
99
+ const id = this.getNodeParameter('identifier', i) as string;
100
+
101
+ if (source == 'byFile') {
102
+ const fileResponse = await getFileContent(this, id);
103
+ if (!fileResponse.success) {
104
+ return { json: fileResponse };
105
+ }
106
+
107
+ return {
108
+ json: { success: fileResponse.success },
109
+ binary: { data: fileResponse.data },
110
+ };
111
+ }
112
+ if (source == 'byLimeobject') {
113
+ const limetype = this.getNodeParameter('limetype', i) as string;
114
+ const property = this.getNodeParameter('property', i) as string;
115
+
116
+ const fileResponse = await getFileContentByLimetype(
117
+ this,
118
+ limetype,
119
+ id,
120
+ property
121
+ );
122
+ if (!fileResponse.success) {
123
+ return { json: fileResponse };
124
+ }
125
+
126
+ return {
127
+ json: { success: fileResponse.success },
128
+ binary: {
129
+ data: fileResponse.data,
130
+ },
131
+ };
132
+ }
133
+
134
+ throw new NodeOperationError(
135
+ this.getNode(),
136
+ `The source "${source}" is not supported!`
137
+ );
138
+ }
@@ -0,0 +1,83 @@
1
+ import { IExecuteFunctions, INodeProperties } from 'n8n-workflow';
2
+
3
+ import { getLimeobject } from '../../../transport';
4
+ import { DATA_RESOURCE } from '../../../commons';
5
+ import { getFileProperties, processFileResponse } from '../../../commons/files';
6
+
7
+ export const description = {
8
+ name: 'Get Single Object',
9
+ value: 'getSingleObject',
10
+ description: 'Get one specific object',
11
+ action: 'Get single object',
12
+ };
13
+
14
+ export const properties: INodeProperties[] = [
15
+ {
16
+ displayName: 'Limetype',
17
+ name: 'limetype',
18
+ type: 'options',
19
+ typeOptions: {
20
+ loadOptionsMethod: 'getLimetypes',
21
+ },
22
+ required: true,
23
+ default: '',
24
+ description: 'The type of entity to retrieve',
25
+ displayOptions: {
26
+ show: {
27
+ resource: [DATA_RESOURCE],
28
+ operation: ['getSingleObject'],
29
+ },
30
+ },
31
+ },
32
+
33
+ {
34
+ displayName: 'Object ID',
35
+ name: 'objectId',
36
+ type: 'string',
37
+ required: true,
38
+ default: '',
39
+ description: 'The ID of the object to retrieve',
40
+ displayOptions: {
41
+ show: {
42
+ resource: [DATA_RESOURCE],
43
+ operation: ['getSingleObject'],
44
+ },
45
+ },
46
+ },
47
+ {
48
+ displayName: 'Include file content',
49
+ name: 'includeFileContent',
50
+ type: 'boolean',
51
+ default: false,
52
+ description:
53
+ 'Include file binary data if the Limetype has any file properties. ' +
54
+ 'Keep performance in mind before activating this. ' +
55
+ 'For Limetypes without any file properties, this setting is ignored.',
56
+ displayOptions: {
57
+ show: {
58
+ resource: [DATA_RESOURCE],
59
+ operation: ['getSingleObject'],
60
+ },
61
+ },
62
+ },
63
+ ];
64
+
65
+ export async function execute(this: IExecuteFunctions, i: number) {
66
+ const limetype = this.getNodeParameter('limetype', i) as string;
67
+ const objectId = this.getNodeParameter('objectId', i) as string;
68
+ const includeFileContent = this.getNodeParameter(
69
+ 'includeFileContent',
70
+ i
71
+ ) as boolean;
72
+
73
+ const limeObjectResponse = await getLimeobject(this, limetype, objectId);
74
+ if (!limeObjectResponse.success) return { json: limeObjectResponse };
75
+
76
+ const fileProperties = await getFileProperties(this, limetype);
77
+ return processFileResponse(
78
+ this,
79
+ fileProperties,
80
+ limeObjectResponse.data,
81
+ includeFileContent
82
+ );
83
+ }