n8n-nodes-recruspace 0.1.3 → 0.2.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/LICENSE +21 -0
- package/README.md +29 -16
- package/dist/nodes/Recruspace/Recruspace.node.js +403 -166
- package/dist/nodes/Recruspace/Recruspace.node.js.map +1 -1
- package/dist/nodes/Recruspace/RecruspaceTrigger.node.js +25 -3
- package/dist/nodes/Recruspace/RecruspaceTrigger.node.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -25,26 +25,80 @@ class Recruspace {
|
|
|
25
25
|
},
|
|
26
26
|
],
|
|
27
27
|
properties: [
|
|
28
|
+
{
|
|
29
|
+
displayName: 'Resource',
|
|
30
|
+
name: 'resource',
|
|
31
|
+
type: 'options',
|
|
32
|
+
noDataExpression: true,
|
|
33
|
+
options: [
|
|
34
|
+
{
|
|
35
|
+
name: 'Candidate',
|
|
36
|
+
value: 'candidate',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Talent Pool',
|
|
40
|
+
value: 'talentPool',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
default: 'candidate',
|
|
44
|
+
},
|
|
28
45
|
{
|
|
29
46
|
displayName: 'Operation',
|
|
30
47
|
name: 'operation',
|
|
31
48
|
type: 'options',
|
|
32
49
|
noDataExpression: true,
|
|
50
|
+
displayOptions: {
|
|
51
|
+
show: {
|
|
52
|
+
resource: ['candidate'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
33
55
|
options: [
|
|
34
56
|
{
|
|
35
|
-
name: 'Create
|
|
36
|
-
value: '
|
|
57
|
+
name: 'Create',
|
|
58
|
+
value: 'create',
|
|
37
59
|
description: 'Create a new candidate',
|
|
38
60
|
action: 'Create candidate',
|
|
39
61
|
},
|
|
40
62
|
{
|
|
41
|
-
name: 'Add
|
|
42
|
-
value: '
|
|
63
|
+
name: 'Add Note',
|
|
64
|
+
value: 'addNote',
|
|
43
65
|
description: 'Add a note to an existing candidate',
|
|
44
66
|
action: 'Add candidate note',
|
|
45
67
|
},
|
|
68
|
+
{
|
|
69
|
+
name: 'Add Tag',
|
|
70
|
+
value: 'addTag',
|
|
71
|
+
description: 'Add a tag to an existing candidate',
|
|
72
|
+
action: 'Add candidate tag',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Search',
|
|
76
|
+
value: 'search',
|
|
77
|
+
description: 'Search for a candidate by email',
|
|
78
|
+
action: 'Search candidate',
|
|
79
|
+
},
|
|
46
80
|
],
|
|
47
|
-
default: '
|
|
81
|
+
default: 'create',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Operation',
|
|
85
|
+
name: 'operation',
|
|
86
|
+
type: 'options',
|
|
87
|
+
noDataExpression: true,
|
|
88
|
+
displayOptions: {
|
|
89
|
+
show: {
|
|
90
|
+
resource: ['talentPool'],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
options: [
|
|
94
|
+
{
|
|
95
|
+
name: 'Create',
|
|
96
|
+
value: 'create',
|
|
97
|
+
description: 'Create a new talent pool',
|
|
98
|
+
action: 'Create talent pool',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
default: 'create',
|
|
48
102
|
},
|
|
49
103
|
{
|
|
50
104
|
displayName: 'First Name',
|
|
@@ -55,7 +109,8 @@ class Recruspace {
|
|
|
55
109
|
description: 'The first name of the candidate',
|
|
56
110
|
displayOptions: {
|
|
57
111
|
show: {
|
|
58
|
-
|
|
112
|
+
resource: ['candidate'],
|
|
113
|
+
operation: ['create'],
|
|
59
114
|
},
|
|
60
115
|
},
|
|
61
116
|
},
|
|
@@ -68,7 +123,8 @@ class Recruspace {
|
|
|
68
123
|
description: 'The last name of the candidate',
|
|
69
124
|
displayOptions: {
|
|
70
125
|
show: {
|
|
71
|
-
|
|
126
|
+
resource: ['candidate'],
|
|
127
|
+
operation: ['create'],
|
|
72
128
|
},
|
|
73
129
|
},
|
|
74
130
|
},
|
|
@@ -82,7 +138,39 @@ class Recruspace {
|
|
|
82
138
|
description: 'The email of the candidate',
|
|
83
139
|
displayOptions: {
|
|
84
140
|
show: {
|
|
85
|
-
|
|
141
|
+
resource: ['candidate'],
|
|
142
|
+
operation: ['create', 'search'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
displayName: 'If Multiple Results Found',
|
|
148
|
+
name: 'resultStrategy',
|
|
149
|
+
type: 'options',
|
|
150
|
+
noDataExpression: true,
|
|
151
|
+
options: [
|
|
152
|
+
{
|
|
153
|
+
name: 'Return First Result',
|
|
154
|
+
value: 'Select First',
|
|
155
|
+
description: 'Return only the first matching candidate',
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'Stop Execution',
|
|
159
|
+
value: 'Select None',
|
|
160
|
+
description: 'Return empty result if multiple candidates found',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'Return All Results',
|
|
164
|
+
value: 'Select All',
|
|
165
|
+
description: 'Return all matching candidates as separate items',
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
default: 'Select First',
|
|
169
|
+
description: 'How to handle when multiple candidates match the email',
|
|
170
|
+
displayOptions: {
|
|
171
|
+
show: {
|
|
172
|
+
resource: ['candidate'],
|
|
173
|
+
operation: ['search'],
|
|
86
174
|
},
|
|
87
175
|
},
|
|
88
176
|
},
|
|
@@ -101,7 +189,8 @@ class Recruspace {
|
|
|
101
189
|
description: 'Where to get the CV from (only binary data is supported for candidates)',
|
|
102
190
|
displayOptions: {
|
|
103
191
|
show: {
|
|
104
|
-
|
|
192
|
+
resource: ['candidate'],
|
|
193
|
+
operation: ['create'],
|
|
105
194
|
},
|
|
106
195
|
},
|
|
107
196
|
},
|
|
@@ -115,7 +204,8 @@ class Recruspace {
|
|
|
115
204
|
placeholder: 'data',
|
|
116
205
|
displayOptions: {
|
|
117
206
|
show: {
|
|
118
|
-
|
|
207
|
+
resource: ['candidate'],
|
|
208
|
+
operation: ['create'],
|
|
119
209
|
},
|
|
120
210
|
},
|
|
121
211
|
},
|
|
@@ -139,7 +229,8 @@ class Recruspace {
|
|
|
139
229
|
description: 'Where to associate the candidate',
|
|
140
230
|
displayOptions: {
|
|
141
231
|
show: {
|
|
142
|
-
|
|
232
|
+
resource: ['candidate'],
|
|
233
|
+
operation: ['create'],
|
|
143
234
|
},
|
|
144
235
|
},
|
|
145
236
|
},
|
|
@@ -151,7 +242,8 @@ class Recruspace {
|
|
|
151
242
|
required: true,
|
|
152
243
|
displayOptions: {
|
|
153
244
|
show: {
|
|
154
|
-
|
|
245
|
+
resource: ['candidate'],
|
|
246
|
+
operation: ['create'],
|
|
155
247
|
associationType: ['jobPost'],
|
|
156
248
|
},
|
|
157
249
|
},
|
|
@@ -182,7 +274,8 @@ class Recruspace {
|
|
|
182
274
|
required: true,
|
|
183
275
|
displayOptions: {
|
|
184
276
|
show: {
|
|
185
|
-
|
|
277
|
+
resource: ['candidate'],
|
|
278
|
+
operation: ['create'],
|
|
186
279
|
associationType: ['talentPool'],
|
|
187
280
|
},
|
|
188
281
|
},
|
|
@@ -222,7 +315,8 @@ class Recruspace {
|
|
|
222
315
|
default: {},
|
|
223
316
|
displayOptions: {
|
|
224
317
|
show: {
|
|
225
|
-
|
|
318
|
+
resource: ['candidate'],
|
|
319
|
+
operation: ['create'],
|
|
226
320
|
},
|
|
227
321
|
},
|
|
228
322
|
options: [
|
|
@@ -245,7 +339,8 @@ class Recruspace {
|
|
|
245
339
|
placeholder: '12345',
|
|
246
340
|
displayOptions: {
|
|
247
341
|
show: {
|
|
248
|
-
|
|
342
|
+
resource: ['candidate'],
|
|
343
|
+
operation: ['addNote'],
|
|
249
344
|
},
|
|
250
345
|
},
|
|
251
346
|
},
|
|
@@ -261,7 +356,53 @@ class Recruspace {
|
|
|
261
356
|
description: 'The note text to add',
|
|
262
357
|
displayOptions: {
|
|
263
358
|
show: {
|
|
264
|
-
|
|
359
|
+
resource: ['candidate'],
|
|
360
|
+
operation: ['addNote'],
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
displayName: 'Candidate ID',
|
|
366
|
+
name: 'tagCandidateId',
|
|
367
|
+
type: 'number',
|
|
368
|
+
required: true,
|
|
369
|
+
default: 0,
|
|
370
|
+
description: 'The ID of the candidate to add tag to',
|
|
371
|
+
placeholder: '12345',
|
|
372
|
+
displayOptions: {
|
|
373
|
+
show: {
|
|
374
|
+
resource: ['candidate'],
|
|
375
|
+
operation: ['addTag'],
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
displayName: 'Tag Title',
|
|
381
|
+
name: 'tagTitle',
|
|
382
|
+
type: 'string',
|
|
383
|
+
required: true,
|
|
384
|
+
default: '',
|
|
385
|
+
placeholder: 'Important',
|
|
386
|
+
description: 'The title of the tag to add',
|
|
387
|
+
displayOptions: {
|
|
388
|
+
show: {
|
|
389
|
+
resource: ['candidate'],
|
|
390
|
+
operation: ['addTag'],
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
displayName: 'Name',
|
|
396
|
+
name: 'talentPoolName',
|
|
397
|
+
type: 'string',
|
|
398
|
+
required: true,
|
|
399
|
+
default: '',
|
|
400
|
+
placeholder: 'Software Developer Talents',
|
|
401
|
+
description: 'The name of the talent pool',
|
|
402
|
+
displayOptions: {
|
|
403
|
+
show: {
|
|
404
|
+
resource: ['talentPool'],
|
|
405
|
+
operation: ['create'],
|
|
265
406
|
},
|
|
266
407
|
},
|
|
267
408
|
},
|
|
@@ -321,180 +462,276 @@ class Recruspace {
|
|
|
321
462
|
};
|
|
322
463
|
}
|
|
323
464
|
async execute() {
|
|
324
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
465
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
325
466
|
const items = this.getInputData();
|
|
326
467
|
const returnData = [];
|
|
327
468
|
const credentials = await this.getCredentials('recruspaceApi');
|
|
328
469
|
const baseUrl = 'https://n8n.api.recruspace.com';
|
|
329
|
-
const operation = this.getNodeParameter('operation', 0);
|
|
330
470
|
for (let i = 0; i < items.length; i++) {
|
|
331
471
|
try {
|
|
472
|
+
const resource = this.getNodeParameter('resource', i);
|
|
473
|
+
const operation = this.getNodeParameter('operation', i);
|
|
332
474
|
const cleanBaseUrl = baseUrl.replace(/\/$/, '');
|
|
333
|
-
if (
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
else if (associationType === 'talentPool') {
|
|
349
|
-
const talentPoolIdParam = this.getNodeParameter('talentPoolId', i);
|
|
350
|
-
talentPoolId =
|
|
351
|
-
typeof talentPoolIdParam === 'object' && talentPoolIdParam !== null
|
|
352
|
-
? parseInt(String(talentPoolIdParam.value), 10)
|
|
353
|
-
: parseInt(String(talentPoolIdParam || '0'), 10);
|
|
354
|
-
}
|
|
355
|
-
const additionalFields = this.getNodeParameter('additionalFields', i);
|
|
356
|
-
if (cvSource !== 'binaryData') {
|
|
357
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Only "Binary Data" is supported as CV Source for creating candidates. Please provide CV as binary data from a previous node.', { itemIndex: i });
|
|
358
|
-
}
|
|
359
|
-
const associateWithJobPost = associationType === 'jobPost';
|
|
360
|
-
const associateWithTalentPool = associationType === 'talentPool';
|
|
361
|
-
if (associateWithJobPost) {
|
|
362
|
-
if (!jobPost || jobPost.trim() === '') {
|
|
363
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Job Post Hash is required when associating the candidate with a Job Post.', { itemIndex: i });
|
|
475
|
+
if (resource === 'candidate') {
|
|
476
|
+
if (operation === 'create') {
|
|
477
|
+
const firstName = this.getNodeParameter('firstName', i);
|
|
478
|
+
const lastName = this.getNodeParameter('lastName', i);
|
|
479
|
+
const email = this.getNodeParameter('email', i);
|
|
480
|
+
const cvSource = this.getNodeParameter('cvSource', i);
|
|
481
|
+
const associationType = this.getNodeParameter('associationType', i);
|
|
482
|
+
let jobPost = '';
|
|
483
|
+
let talentPoolId = 0;
|
|
484
|
+
if (associationType === 'jobPost') {
|
|
485
|
+
const jobPostParam = this.getNodeParameter('jobPost', i);
|
|
486
|
+
jobPost =
|
|
487
|
+
typeof jobPostParam === 'object' && jobPostParam !== null
|
|
488
|
+
? jobPostParam.value
|
|
489
|
+
: (jobPostParam || '');
|
|
364
490
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
491
|
+
else if (associationType === 'talentPool') {
|
|
492
|
+
const talentPoolIdParam = this.getNodeParameter('talentPoolId', i);
|
|
493
|
+
talentPoolId =
|
|
494
|
+
typeof talentPoolIdParam === 'object' && talentPoolIdParam !== null
|
|
495
|
+
? parseInt(String(talentPoolIdParam.value), 10)
|
|
496
|
+
: parseInt(String(talentPoolIdParam || '0'), 10);
|
|
369
497
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
const apiUrl = `${cleanBaseUrl}/add-candidate`;
|
|
375
|
-
try {
|
|
376
|
-
const binaryProperty = this.getNodeParameter('binaryProperty', i);
|
|
377
|
-
const binaryData = this.helpers.assertBinaryData(i, binaryProperty);
|
|
378
|
-
const cvBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
|
|
379
|
-
const cvFileName = binaryData.fileName || 'cv.pdf';
|
|
380
|
-
const cvMimeType = binaryData.mimeType || 'application/pdf';
|
|
381
|
-
const boundary = `----n8nFormBoundary${Date.now().toString(16)}`;
|
|
382
|
-
const createTextField = (name, value) => {
|
|
383
|
-
return `--${boundary}\r\nContent-Disposition: form-data; name="${name}"\r\n\r\n${value}\r\n`;
|
|
384
|
-
};
|
|
385
|
-
let formBody = '';
|
|
386
|
-
formBody += createTextField('first_name', firstName);
|
|
387
|
-
formBody += createTextField('last_name', lastName);
|
|
388
|
-
formBody += createTextField('email', email);
|
|
389
|
-
if (associateWithJobPost) {
|
|
390
|
-
formBody += createTextField('job_post', jobPost);
|
|
498
|
+
const additionalFields = this.getNodeParameter('additionalFields', i);
|
|
499
|
+
if (cvSource !== 'binaryData') {
|
|
500
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Only "Binary Data" is supported as CV Source for creating candidates. Please provide CV as binary data from a previous node.', { itemIndex: i });
|
|
391
501
|
}
|
|
392
|
-
|
|
393
|
-
|
|
502
|
+
const associateWithJobPost = associationType === 'jobPost';
|
|
503
|
+
const associateWithTalentPool = associationType === 'talentPool';
|
|
504
|
+
if (associateWithJobPost) {
|
|
505
|
+
if (!jobPost || jobPost.trim() === '') {
|
|
506
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Job Post Hash is required when associating the candidate with a Job Post.', { itemIndex: i });
|
|
507
|
+
}
|
|
394
508
|
}
|
|
395
|
-
if (
|
|
396
|
-
|
|
509
|
+
else if (associateWithTalentPool) {
|
|
510
|
+
if (!talentPoolId || talentPoolId <= 0) {
|
|
511
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Talent Pool ID is required when associating the candidate with a Talent Pool.', { itemIndex: i });
|
|
512
|
+
}
|
|
397
513
|
}
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const responseObject = response;
|
|
416
|
-
const responseContent = (_a = responseObject.content) !== null && _a !== void 0 ? _a : responseObject;
|
|
417
|
-
returnData.push({
|
|
418
|
-
json: responseContent,
|
|
419
|
-
pairedItem: { item: i },
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
catch (error) {
|
|
423
|
-
let errorMessage = 'Unknown error occurred';
|
|
424
|
-
let statusCode = 'unknown';
|
|
425
|
-
if (typeof error === 'object' && error !== null) {
|
|
426
|
-
const errorObj = error;
|
|
427
|
-
const responseData = (_b = errorObj.response) === null || _b === void 0 ? void 0 : _b.data;
|
|
428
|
-
if (typeof responseData === 'object' && responseData !== null) {
|
|
429
|
-
const dataObj = responseData;
|
|
430
|
-
errorMessage =
|
|
431
|
-
(_f = (_e = (_d = (_c = dataObj.detail) !== null && _c !== void 0 ? _c : dataObj.message) !== null && _d !== void 0 ? _d : responseData) !== null && _e !== void 0 ? _e : errorObj.message) !== null && _f !== void 0 ? _f : errorMessage;
|
|
514
|
+
const apiUrl = `${cleanBaseUrl}/add-candidate`;
|
|
515
|
+
try {
|
|
516
|
+
const binaryProperty = this.getNodeParameter('binaryProperty', i);
|
|
517
|
+
const binaryData = this.helpers.assertBinaryData(i, binaryProperty);
|
|
518
|
+
const cvBuffer = await this.helpers.getBinaryDataBuffer(i, binaryProperty);
|
|
519
|
+
const cvFileName = binaryData.fileName || 'cv.pdf';
|
|
520
|
+
const cvMimeType = binaryData.mimeType || 'application/pdf';
|
|
521
|
+
const boundary = `----n8nFormBoundary${Date.now().toString(16)}`;
|
|
522
|
+
const createTextField = (name, value) => {
|
|
523
|
+
return `--${boundary}\r\nContent-Disposition: form-data; name="${name}"\r\n\r\n${value}\r\n`;
|
|
524
|
+
};
|
|
525
|
+
let formBody = '';
|
|
526
|
+
formBody += createTextField('first_name', firstName);
|
|
527
|
+
formBody += createTextField('last_name', lastName);
|
|
528
|
+
formBody += createTextField('email', email);
|
|
529
|
+
if (associateWithJobPost) {
|
|
530
|
+
formBody += createTextField('job_post', jobPost);
|
|
432
531
|
}
|
|
433
|
-
|
|
434
|
-
|
|
532
|
+
if (associateWithTalentPool) {
|
|
533
|
+
formBody += createTextField('talent_pool_id', talentPoolId.toString());
|
|
435
534
|
}
|
|
436
|
-
if (
|
|
437
|
-
|
|
535
|
+
if (additionalFields.phone_number) {
|
|
536
|
+
formBody += createTextField('phone_number', additionalFields.phone_number);
|
|
438
537
|
}
|
|
538
|
+
const fileHeader = `--${boundary}\r\nContent-Disposition: form-data; name="cv_file"; filename="${cvFileName}"\r\nContent-Type: ${cvMimeType}\r\n\r\n`;
|
|
539
|
+
const fileFooter = `\r\n--${boundary}--\r\n`;
|
|
540
|
+
const bodyBuffer = Buffer.concat([
|
|
541
|
+
Buffer.from(formBody, 'utf-8'),
|
|
542
|
+
Buffer.from(fileHeader, 'utf-8'),
|
|
543
|
+
cvBuffer,
|
|
544
|
+
Buffer.from(fileFooter, 'utf-8'),
|
|
545
|
+
]);
|
|
546
|
+
const response = await this.helpers.httpRequest({
|
|
547
|
+
method: 'POST',
|
|
548
|
+
url: apiUrl,
|
|
549
|
+
headers: {
|
|
550
|
+
'x-api-key': credentials.apiKey,
|
|
551
|
+
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
552
|
+
},
|
|
553
|
+
body: bodyBuffer,
|
|
554
|
+
});
|
|
555
|
+
const responseObject = response;
|
|
556
|
+
const responseContent = (_a = responseObject.content) !== null && _a !== void 0 ? _a : responseObject;
|
|
557
|
+
returnData.push({
|
|
558
|
+
json: responseContent,
|
|
559
|
+
pairedItem: { item: i },
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
let errorMessage = 'Unknown error occurred';
|
|
564
|
+
let statusCode = 'unknown';
|
|
565
|
+
if (typeof error === 'object' && error !== null) {
|
|
566
|
+
const errorObj = error;
|
|
567
|
+
const responseData = (_b = errorObj.response) === null || _b === void 0 ? void 0 : _b.data;
|
|
568
|
+
if (typeof responseData === 'object' && responseData !== null) {
|
|
569
|
+
const dataObj = responseData;
|
|
570
|
+
errorMessage =
|
|
571
|
+
(_f = (_e = (_d = (_c = dataObj.detail) !== null && _c !== void 0 ? _c : dataObj.message) !== null && _d !== void 0 ? _d : responseData) !== null && _e !== void 0 ? _e : errorObj.message) !== null && _f !== void 0 ? _f : errorMessage;
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
errorMessage = (_g = responseData !== null && responseData !== void 0 ? responseData : errorObj.message) !== null && _g !== void 0 ? _g : errorMessage;
|
|
575
|
+
}
|
|
576
|
+
if ((_h = errorObj.response) === null || _h === void 0 ? void 0 : _h.status) {
|
|
577
|
+
statusCode = errorObj.response.status;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to create candidate (${statusCode}): ${JSON.stringify(errorMessage)}\n\nBase URL: ${baseUrl}\nFull URL: ${apiUrl}`, { itemIndex: i });
|
|
439
581
|
}
|
|
440
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to create candidate (${statusCode}): ${JSON.stringify(errorMessage)}\n\nBase URL: ${baseUrl}\nFull URL: ${apiUrl}`, { itemIndex: i });
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
else if (operation === 'addCandidateNote') {
|
|
444
|
-
const candidateId = this.getNodeParameter('candidateId', i);
|
|
445
|
-
const noteText = this.getNodeParameter('comment', i);
|
|
446
|
-
if (!candidateId || candidateId === 0) {
|
|
447
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Candidate ID is required. Please provide a valid Candidate ID.', { itemIndex: i });
|
|
448
582
|
}
|
|
449
|
-
if (
|
|
450
|
-
|
|
583
|
+
else if (operation === 'addNote') {
|
|
584
|
+
const candidateId = this.getNodeParameter('candidateId', i);
|
|
585
|
+
const noteText = this.getNodeParameter('comment', i);
|
|
586
|
+
if (!candidateId || candidateId === 0) {
|
|
587
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Candidate ID is required. Please provide a valid Candidate ID.', { itemIndex: i });
|
|
588
|
+
}
|
|
589
|
+
if (!noteText || noteText.trim() === '') {
|
|
590
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Note text is required.', { itemIndex: i });
|
|
591
|
+
}
|
|
592
|
+
const apiUrl = `${cleanBaseUrl}/add-note`;
|
|
593
|
+
try {
|
|
594
|
+
const response = await this.helpers.httpRequest({
|
|
595
|
+
method: 'POST',
|
|
596
|
+
url: apiUrl,
|
|
597
|
+
headers: {
|
|
598
|
+
'x-api-key': credentials.apiKey,
|
|
599
|
+
'Content-Type': 'application/json',
|
|
600
|
+
},
|
|
601
|
+
body: {
|
|
602
|
+
candidate_id: candidateId,
|
|
603
|
+
text: noteText,
|
|
604
|
+
},
|
|
605
|
+
json: true,
|
|
606
|
+
});
|
|
607
|
+
returnData.push({
|
|
608
|
+
json: {
|
|
609
|
+
...response,
|
|
610
|
+
candidate_id: candidateId,
|
|
611
|
+
},
|
|
612
|
+
pairedItem: { item: i },
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
let errorMessage = 'Unknown error occurred';
|
|
617
|
+
let statusCode = 'unknown';
|
|
618
|
+
if (typeof error === 'object' && error !== null) {
|
|
619
|
+
const errorObj = error;
|
|
620
|
+
const responseData = (_j = errorObj.response) === null || _j === void 0 ? void 0 : _j.data;
|
|
621
|
+
if (typeof responseData === 'object' && responseData !== null) {
|
|
622
|
+
const dataObj = responseData;
|
|
623
|
+
errorMessage =
|
|
624
|
+
(_o = (_m = (_l = (_k = dataObj.detail) !== null && _k !== void 0 ? _k : dataObj.message) !== null && _l !== void 0 ? _l : responseData) !== null && _m !== void 0 ? _m : errorObj.message) !== null && _o !== void 0 ? _o : errorMessage;
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
errorMessage = (_p = responseData !== null && responseData !== void 0 ? responseData : errorObj.message) !== null && _p !== void 0 ? _p : errorMessage;
|
|
628
|
+
}
|
|
629
|
+
if ((_q = errorObj.response) === null || _q === void 0 ? void 0 : _q.status) {
|
|
630
|
+
statusCode = errorObj.response.status;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to add note (${statusCode}): ${JSON.stringify(errorMessage)}\n\nURL: ${apiUrl}\nRequest body: ${JSON.stringify({ candidate_id: candidateId, text: noteText }, null, 2)}`, { itemIndex: i });
|
|
634
|
+
}
|
|
451
635
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
|
|
636
|
+
else if (operation === 'search') {
|
|
637
|
+
const email = this.getNodeParameter('email', i);
|
|
638
|
+
const resultStrategy = this.getNodeParameter('resultStrategy', i);
|
|
639
|
+
if (!email || email.trim() === '') {
|
|
640
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Email is required to search for a candidate.', { itemIndex: i });
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
const response = await this.helpers.httpRequest({
|
|
644
|
+
method: 'GET',
|
|
645
|
+
url: `${cleanBaseUrl}/actions/candidates/search-by-email`,
|
|
646
|
+
headers: {
|
|
647
|
+
'x-api-key': credentials.apiKey,
|
|
648
|
+
'Content-Type': 'application/json',
|
|
649
|
+
},
|
|
650
|
+
qs: {
|
|
651
|
+
email: email.trim(),
|
|
652
|
+
type: resultStrategy,
|
|
653
|
+
},
|
|
654
|
+
json: true,
|
|
655
|
+
});
|
|
656
|
+
const results = Array.isArray(response) ? response : [response];
|
|
657
|
+
for (const result of results) {
|
|
658
|
+
returnData.push({
|
|
659
|
+
json: result,
|
|
660
|
+
pairedItem: { item: i },
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to search candidate: ${error.message}`, { itemIndex: i });
|
|
666
|
+
}
|
|
474
667
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (
|
|
668
|
+
else if (operation === 'addTag') {
|
|
669
|
+
const candidateId = this.getNodeParameter('tagCandidateId', i);
|
|
670
|
+
const tagTitle = this.getNodeParameter('tagTitle', i);
|
|
671
|
+
if (!candidateId) {
|
|
672
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Candidate ID is required to add a tag.', { itemIndex: i });
|
|
673
|
+
}
|
|
674
|
+
if (!tagTitle || tagTitle.trim() === '') {
|
|
675
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Tag Title is required.', { itemIndex: i });
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
const response = await this.helpers.httpRequest({
|
|
679
|
+
method: 'POST',
|
|
680
|
+
url: `${cleanBaseUrl}/actions/candidates/add-tag`,
|
|
681
|
+
headers: {
|
|
682
|
+
'x-api-key': credentials.apiKey,
|
|
683
|
+
'Content-Type': 'application/json',
|
|
684
|
+
},
|
|
685
|
+
body: {
|
|
686
|
+
candidate_id: candidateId,
|
|
687
|
+
title: tagTitle,
|
|
688
|
+
},
|
|
689
|
+
json: true,
|
|
690
|
+
});
|
|
691
|
+
returnData.push({
|
|
692
|
+
json: response,
|
|
693
|
+
pairedItem: { item: i },
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
catch (error) {
|
|
479
697
|
const errorObj = error;
|
|
480
|
-
|
|
481
|
-
if (
|
|
482
|
-
const
|
|
483
|
-
errorMessage =
|
|
484
|
-
(_o = (_m = (_l = (_k = dataObj.detail) !== null && _k !== void 0 ? _k : dataObj.message) !== null && _l !== void 0 ? _l : responseData) !== null && _m !== void 0 ? _m : errorObj.message) !== null && _o !== void 0 ? _o : errorMessage;
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
errorMessage = (_p = responseData !== null && responseData !== void 0 ? responseData : errorObj.message) !== null && _p !== void 0 ? _p : errorMessage;
|
|
488
|
-
}
|
|
489
|
-
if ((_q = errorObj.response) === null || _q === void 0 ? void 0 : _q.status) {
|
|
490
|
-
statusCode = errorObj.response.status;
|
|
698
|
+
let errorMessage = error.message;
|
|
699
|
+
if ((_r = errorObj.response) === null || _r === void 0 ? void 0 : _r.data) {
|
|
700
|
+
const data = errorObj.response.data;
|
|
701
|
+
errorMessage = String(data.message || data.error || JSON.stringify(data));
|
|
491
702
|
}
|
|
703
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to add tag: ${errorMessage}`, { itemIndex: i });
|
|
492
704
|
}
|
|
493
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to add note (${statusCode}): ${JSON.stringify(errorMessage)}\n\nURL: ${apiUrl}\nRequest body: ${JSON.stringify({ candidate_id: candidateId, text: noteText }, null, 2)}`, { itemIndex: i });
|
|
494
705
|
}
|
|
495
706
|
}
|
|
496
|
-
else {
|
|
497
|
-
|
|
707
|
+
else if (resource === 'talentPool') {
|
|
708
|
+
if (operation === 'create') {
|
|
709
|
+
const talentPoolName = this.getNodeParameter('talentPoolName', i);
|
|
710
|
+
if (!talentPoolName || talentPoolName.trim() === '') {
|
|
711
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Talent Pool Name is required.', { itemIndex: i });
|
|
712
|
+
}
|
|
713
|
+
try {
|
|
714
|
+
const response = await this.helpers.httpRequest({
|
|
715
|
+
method: 'POST',
|
|
716
|
+
url: `${cleanBaseUrl}/create-talent-pool`,
|
|
717
|
+
headers: {
|
|
718
|
+
'x-api-key': credentials.apiKey,
|
|
719
|
+
'Content-Type': 'application/json',
|
|
720
|
+
},
|
|
721
|
+
body: {
|
|
722
|
+
name: talentPoolName,
|
|
723
|
+
},
|
|
724
|
+
json: true,
|
|
725
|
+
});
|
|
726
|
+
returnData.push({
|
|
727
|
+
json: response,
|
|
728
|
+
pairedItem: { item: i },
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
catch (error) {
|
|
732
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to create talent pool: ${error.message}`, { itemIndex: i });
|
|
733
|
+
}
|
|
734
|
+
}
|
|
498
735
|
}
|
|
499
736
|
}
|
|
500
737
|
catch (error) {
|