@dereekb/zoho 13.0.0 → 13.0.2
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/index.cjs.default.js +1 -0
- package/index.cjs.js +1187 -1353
- package/index.cjs.mjs +2 -0
- package/index.esm.js +1187 -1353
- package/nestjs/index.cjs.default.js +1 -0
- package/nestjs/index.cjs.js +435 -420
- package/nestjs/index.cjs.mjs +2 -0
- package/nestjs/index.esm.js +435 -420
- package/nestjs/package.json +18 -15
- package/package.json +19 -24
package/index.cjs.js
CHANGED
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('core-js/modules/es.iterator.constructor.js');
|
|
4
|
-
require('core-js/modules/es.iterator.filter.js');
|
|
5
|
-
require('core-js/modules/es.iterator.for-each.js');
|
|
6
3
|
var util = require('@dereekb/util');
|
|
7
4
|
var fetch = require('@dereekb/util/fetch');
|
|
8
|
-
require('core-js/modules/es.iterator.flat-map.js');
|
|
9
|
-
require('core-js/modules/es.iterator.map.js');
|
|
10
5
|
var makeError = require('make-error');
|
|
11
|
-
require('core-js/modules/es.set.difference.v2.js');
|
|
12
|
-
require('core-js/modules/es.set.symmetric-difference.v2.js');
|
|
13
|
-
require('core-js/modules/es.set.union.v2.js');
|
|
14
6
|
|
|
15
7
|
/**
|
|
16
8
|
* Returns an empty ZohoPageResult that is typed to R and has no more records/results.
|
|
17
9
|
*/
|
|
18
10
|
function emptyZohoPageResult() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
};
|
|
11
|
+
return {
|
|
12
|
+
data: [],
|
|
13
|
+
info: {
|
|
14
|
+
page: 1,
|
|
15
|
+
per_page: 100, // default value
|
|
16
|
+
count: 0,
|
|
17
|
+
more_records: false
|
|
18
|
+
}
|
|
19
|
+
};
|
|
29
20
|
}
|
|
30
21
|
/**
|
|
31
22
|
* Creates a FetchPageFactory using the input ZohoFetchPageFetchFunction.
|
|
@@ -35,34 +26,30 @@ function emptyZohoPageResult() {
|
|
|
35
26
|
* @returns
|
|
36
27
|
*/
|
|
37
28
|
function zohoFetchPageFactory(fetch$1, defaults) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
per_page: options.maxItemsPerPage ?? input.per_page
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
});
|
|
29
|
+
return fetch.fetchPageFactory({
|
|
30
|
+
...defaults,
|
|
31
|
+
fetch: fetch$1,
|
|
32
|
+
readFetchPageResultInfo: function (result) {
|
|
33
|
+
return {
|
|
34
|
+
hasNext: result.info?.more_records ?? false // if no info is returned, assume something wrong and there are no more records
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
buildInputForNextPage: function (pageResult, input, options) {
|
|
38
|
+
return { ...input, page: util.getNextPageNumber(pageResult), per_page: options.maxItemsPerPage ?? input.per_page };
|
|
39
|
+
}
|
|
40
|
+
});
|
|
54
41
|
}
|
|
55
42
|
|
|
56
43
|
const ZOHO_RECRUIT_SERVICE_NAME = 'recruit';
|
|
57
44
|
function zohoRecruitConfigApiUrl(input) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
45
|
+
switch (input) {
|
|
46
|
+
case 'sandbox':
|
|
47
|
+
return 'https://recruitsandbox.zoho.com/recruit';
|
|
48
|
+
case 'production':
|
|
49
|
+
return 'https://recruit.zoho.com/recruit';
|
|
50
|
+
default:
|
|
51
|
+
return input;
|
|
52
|
+
}
|
|
66
53
|
}
|
|
67
54
|
|
|
68
55
|
/**
|
|
@@ -106,66 +93,67 @@ const MAX_ZOHO_SEARCH_MODULE_RECORDS_CRITERIA = 10;
|
|
|
106
93
|
* If the input tree is empty, returns undefined.
|
|
107
94
|
*/
|
|
108
95
|
function zohoSearchRecordsCriteriaString(input) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
96
|
+
let result;
|
|
97
|
+
if (input != null) {
|
|
98
|
+
switch (typeof input) {
|
|
99
|
+
case 'string':
|
|
100
|
+
result = input;
|
|
101
|
+
break;
|
|
102
|
+
case 'object':
|
|
103
|
+
let tree;
|
|
104
|
+
if (Array.isArray(input)) {
|
|
105
|
+
tree = { and: [input] };
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
tree = input;
|
|
109
|
+
}
|
|
110
|
+
result = zohoSearchRecordsCriteriaStringForTree(tree);
|
|
111
|
+
break;
|
|
123
112
|
}
|
|
124
|
-
result = zohoSearchRecordsCriteriaStringForTree(tree);
|
|
125
|
-
break;
|
|
126
113
|
}
|
|
127
|
-
|
|
128
|
-
return result;
|
|
114
|
+
return result;
|
|
129
115
|
}
|
|
130
116
|
function zohoSearchRecordsCriteriaStringForTree(tree) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
117
|
+
function convertToString(value) {
|
|
118
|
+
let result;
|
|
119
|
+
if (typeof value === 'object') {
|
|
120
|
+
// array of criteria entries
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
result = value.map(zohoSearchRecordsCriteriaEntryToCriteriaString);
|
|
123
|
+
}
|
|
124
|
+
else if (value) {
|
|
125
|
+
// criteria tree that first needs to be converted to a string
|
|
126
|
+
result = zohoSearchRecordsCriteriaStringForTree(value);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
result = value;
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
function mergeStringValues(values, type) {
|
|
135
|
+
return values.length > 1 ? `(${values.join(type)})` : values[0]; // wrap in and values
|
|
136
|
+
}
|
|
137
|
+
function mergeValues(values, type) {
|
|
138
|
+
const allStrings = util.filterMaybeArrayValues(values.map(convertToString)).flatMap(util.asArray);
|
|
139
|
+
return mergeStringValues(allStrings, type);
|
|
140
|
+
}
|
|
141
|
+
const orValues = tree.or ? mergeValues(tree.or, 'or') : undefined;
|
|
142
|
+
let result = orValues;
|
|
143
|
+
if (tree.and) {
|
|
144
|
+
result = mergeValues([mergeValues(tree.and, 'and'), orValues], 'and');
|
|
143
145
|
}
|
|
144
146
|
return result;
|
|
145
|
-
}
|
|
146
|
-
function mergeStringValues(values, type) {
|
|
147
|
-
return values.length > 1 ? `(${values.join(type)})` : values[0]; // wrap in and values
|
|
148
|
-
}
|
|
149
|
-
function mergeValues(values, type) {
|
|
150
|
-
const allStrings = util.filterMaybeArrayValues(values.map(convertToString)).flatMap(util.asArray);
|
|
151
|
-
return mergeStringValues(allStrings, type);
|
|
152
|
-
}
|
|
153
|
-
const orValues = tree.or ? mergeValues(tree.or, 'or') : undefined;
|
|
154
|
-
let result = orValues;
|
|
155
|
-
if (tree.and) {
|
|
156
|
-
result = mergeValues([mergeValues(tree.and, 'and'), orValues], 'and');
|
|
157
|
-
}
|
|
158
|
-
return result;
|
|
159
147
|
}
|
|
160
148
|
/**
|
|
161
149
|
* Escape used for ZohoSearchRecordsCriteriaString
|
|
162
150
|
*/
|
|
163
151
|
const escapeZohoFieldValueForCriteriaString = util.escapeStringCharactersFunction({
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Parenthesis and commas must be escaped using a backslash
|
|
154
|
+
*/
|
|
155
|
+
escapeTargets: ['(', ')', ','],
|
|
156
|
+
escapeCharacter: (char) => `\\\\${char}`
|
|
169
157
|
});
|
|
170
158
|
/**
|
|
171
159
|
* Converts the input entry to a ZohoSearchRecordsCriteriaString. Properly escapes any parenthesis or commas.
|
|
@@ -174,8 +162,8 @@ const escapeZohoFieldValueForCriteriaString = util.escapeStringCharactersFunctio
|
|
|
174
162
|
* @returns
|
|
175
163
|
*/
|
|
176
164
|
function zohoSearchRecordsCriteriaEntryToCriteriaString(entry) {
|
|
177
|
-
|
|
178
|
-
|
|
165
|
+
const escapedValue = escapeZohoFieldValueForCriteriaString(entry.value);
|
|
166
|
+
return `(${entry.field}:${entry.filter}:${escapedValue})`;
|
|
179
167
|
}
|
|
180
168
|
|
|
181
169
|
/**
|
|
@@ -201,7 +189,7 @@ const ZOHO_DATA_ARRAY_BLANK_ERROR_CODE = '__internal_data_array_blank_error';
|
|
|
201
189
|
* @returns
|
|
202
190
|
*/
|
|
203
191
|
function isZohoServerErrorResponseDataArrayRef(value) {
|
|
204
|
-
|
|
192
|
+
return Array.isArray(value?.data);
|
|
205
193
|
}
|
|
206
194
|
/**
|
|
207
195
|
* A code used in some cases to denote success.
|
|
@@ -216,44 +204,45 @@ const ZOHO_SUCCESS_STATUS = 'success';
|
|
|
216
204
|
*/
|
|
217
205
|
const ZOHO_ERROR_STATUS = 'error';
|
|
218
206
|
function zohoServerErrorData(error) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
207
|
+
const errorType = typeof error;
|
|
208
|
+
let errorData;
|
|
209
|
+
if (errorType === 'object') {
|
|
210
|
+
errorData = error;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
errorData = {
|
|
214
|
+
code: error,
|
|
215
|
+
message: ''
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return errorData;
|
|
230
219
|
}
|
|
231
220
|
/**
|
|
232
221
|
* Zoho Server Error
|
|
233
222
|
*/
|
|
234
223
|
class ZohoServerError extends makeError.BaseError {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
224
|
+
error;
|
|
225
|
+
get code() {
|
|
226
|
+
return this.error.code;
|
|
227
|
+
}
|
|
228
|
+
constructor(error) {
|
|
229
|
+
super(error.message);
|
|
230
|
+
this.error = error;
|
|
231
|
+
}
|
|
243
232
|
}
|
|
244
233
|
/**
|
|
245
234
|
* Zoho Server Error that includes the FetchResponseError
|
|
246
235
|
*/
|
|
247
236
|
class ZohoServerFetchResponseError extends ZohoServerError {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
237
|
+
data;
|
|
238
|
+
errorResponseData;
|
|
239
|
+
responseError;
|
|
240
|
+
constructor(data, errorResponseData, responseError) {
|
|
241
|
+
super(data);
|
|
242
|
+
this.data = data;
|
|
243
|
+
this.errorResponseData = errorResponseData;
|
|
244
|
+
this.responseError = responseError;
|
|
245
|
+
}
|
|
257
246
|
}
|
|
258
247
|
/**
|
|
259
248
|
* Used as a transient error for situations where there are potentially multiple errors within the data array returned.
|
|
@@ -262,15 +251,12 @@ class ZohoServerFetchResponseError extends ZohoServerError {
|
|
|
262
251
|
* the successful and errored results returned within the data.
|
|
263
252
|
*/
|
|
264
253
|
class ZohoServerFetchResponseDataArrayError extends ZohoServerFetchResponseError {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
get errorDataArray() {
|
|
272
|
-
return this.errorResponseData.data;
|
|
273
|
-
}
|
|
254
|
+
constructor(errorResponseData, responseError) {
|
|
255
|
+
super({ code: ZOHO_DATA_ARRAY_BLANK_ERROR_CODE, message: 'Check data for individual errors.' }, errorResponseData, responseError);
|
|
256
|
+
}
|
|
257
|
+
get errorDataArray() {
|
|
258
|
+
return this.errorResponseData.data;
|
|
259
|
+
}
|
|
274
260
|
}
|
|
275
261
|
/**
|
|
276
262
|
* Creates a logZohoServerErrorFunction that logs the error to console.
|
|
@@ -279,25 +265,19 @@ class ZohoServerFetchResponseDataArrayError extends ZohoServerFetchResponseError
|
|
|
279
265
|
* @returns
|
|
280
266
|
*/
|
|
281
267
|
function logZohoServerErrorFunction(zohoApiNamePrefix, options) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
error
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
} else {
|
|
296
|
-
console.log(`${zohoApiNamePrefix}Error(name:${error.name}): `, {
|
|
297
|
-
error
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
};
|
|
268
|
+
const { logDataArrayErrors = false } = options ?? {};
|
|
269
|
+
return (error) => {
|
|
270
|
+
if (error instanceof ZohoServerFetchResponseDataArrayError && !logDataArrayErrors) ;
|
|
271
|
+
else if (error instanceof ZohoServerFetchResponseError) {
|
|
272
|
+
console.log(`${zohoApiNamePrefix}Error(${error.responseError.response.status}): `, { error, errorData: error.data });
|
|
273
|
+
}
|
|
274
|
+
else if (error instanceof ZohoServerError) {
|
|
275
|
+
console.log(`${zohoApiNamePrefix}Error(code:${error.code}): `, { error });
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
console.log(`${zohoApiNamePrefix}Error(name:${error.name}): `, { error });
|
|
279
|
+
}
|
|
280
|
+
};
|
|
301
281
|
}
|
|
302
282
|
/**
|
|
303
283
|
* Wraps a ConfiguredFetch to support handling errors returned by fetch.
|
|
@@ -306,41 +286,42 @@ function logZohoServerErrorFunction(zohoApiNamePrefix, options) {
|
|
|
306
286
|
* @returns
|
|
307
287
|
*/
|
|
308
288
|
function handleZohoErrorFetchFactory(parseZohoError, defaultLogError) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
289
|
+
return (fetch$1, logError = defaultLogError, onError) => {
|
|
290
|
+
return async (x, y) => {
|
|
291
|
+
try {
|
|
292
|
+
return await fetch$1(x, y); // await to catch thrown errors
|
|
293
|
+
}
|
|
294
|
+
catch (e) {
|
|
295
|
+
if (e instanceof fetch.FetchResponseError) {
|
|
296
|
+
const error = await parseZohoError(e);
|
|
297
|
+
if (error) {
|
|
298
|
+
logError(error); // log before throwing.
|
|
299
|
+
onError?.(error); // perform a task
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
throw e;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
324
306
|
};
|
|
325
|
-
};
|
|
326
307
|
}
|
|
327
308
|
/**
|
|
328
309
|
* FetchJsonInterceptJsonResponseFunction that intercepts a 200 response that actually contains a ZohoServerError and throws a ZohoServerError for the error handling to catch.
|
|
329
310
|
*/
|
|
330
311
|
function interceptZohoErrorResponseFactory(parseZohoServerErrorResponseData) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
312
|
+
return (json, response) => {
|
|
313
|
+
const error = json?.error;
|
|
314
|
+
if (error != null) {
|
|
315
|
+
const responseError = new fetch.FetchResponseError(response);
|
|
316
|
+
if (responseError) {
|
|
317
|
+
const parsedError = parseZohoServerErrorResponseData(json, responseError);
|
|
318
|
+
if (parsedError) {
|
|
319
|
+
throw parsedError;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
339
322
|
}
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
return json;
|
|
343
|
-
};
|
|
323
|
+
return json;
|
|
324
|
+
};
|
|
344
325
|
}
|
|
345
326
|
// MARK: Parsed Errors
|
|
346
327
|
/**
|
|
@@ -352,7 +333,8 @@ const ZOHO_INTERNAL_ERROR_CODE = 'INTERNAL_ERROR';
|
|
|
352
333
|
* Error code for when an invalid oauth token is provided.
|
|
353
334
|
*/
|
|
354
335
|
const ZOHO_INVALID_TOKEN_ERROR_CODE = 'INVALID_TOKEN';
|
|
355
|
-
class ZohoInvalidTokenError extends ZohoServerFetchResponseError {
|
|
336
|
+
class ZohoInvalidTokenError extends ZohoServerFetchResponseError {
|
|
337
|
+
}
|
|
356
338
|
/**
|
|
357
339
|
* Error code for when a failure occured for the given action
|
|
358
340
|
*/
|
|
@@ -360,7 +342,8 @@ const ZOHO_FAILURE_ERROR_CODE = 'FAILURE';
|
|
|
360
342
|
/**
|
|
361
343
|
* Error when the Zoho API returns an internal error
|
|
362
344
|
*/
|
|
363
|
-
class ZohoInternalError extends ZohoServerFetchResponseError {
|
|
345
|
+
class ZohoInternalError extends ZohoServerFetchResponseError {
|
|
346
|
+
}
|
|
364
347
|
/**
|
|
365
348
|
* Error in the following cases:
|
|
366
349
|
* - Authorization is not properly constructed ("Invalid Ticket Id")
|
|
@@ -370,16 +353,17 @@ const ZOHO_INVALID_AUTHORIZATION_ERROR_CODE = '4834';
|
|
|
370
353
|
/**
|
|
371
354
|
* Error when the Zoho API returns an invalid authorization error code.
|
|
372
355
|
*/
|
|
373
|
-
class ZohoInvalidAuthorizationError extends ZohoServerFetchResponseError {
|
|
356
|
+
class ZohoInvalidAuthorizationError extends ZohoServerFetchResponseError {
|
|
357
|
+
}
|
|
374
358
|
/**
|
|
375
359
|
* Error in the following cases:
|
|
376
360
|
* - Search query is invalid
|
|
377
361
|
*/
|
|
378
362
|
const ZOHO_INVALID_QUERY_ERROR_CODE = 'INVALID_QUERY';
|
|
379
363
|
class ZohoInvalidQueryError extends ZohoServerFetchResponseError {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
364
|
+
get details() {
|
|
365
|
+
return this.error.details;
|
|
366
|
+
}
|
|
383
367
|
}
|
|
384
368
|
/**
|
|
385
369
|
* Error when a mandatory field is missing.
|
|
@@ -407,28 +391,23 @@ const ZOHO_RATE_LIMIT_RESET_HEADER = 'X-RATELIMIT-RESET';
|
|
|
407
391
|
const DEFAULT_ZOHO_API_RATE_LIMIT = 100;
|
|
408
392
|
const DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD = util.MS_IN_MINUTE;
|
|
409
393
|
function zohoRateLimitHeaderDetails(headers) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
reset,
|
|
423
|
-
resetAt
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
return result;
|
|
394
|
+
const limitHeader = headers.get(ZOHO_RATE_LIMIT_LIMIT_HEADER);
|
|
395
|
+
const remainingHeader = headers.get(ZOHO_RATE_LIMIT_REMAINING_HEADER);
|
|
396
|
+
const resetHeader = headers.get(ZOHO_RATE_LIMIT_RESET_HEADER);
|
|
397
|
+
let result = null;
|
|
398
|
+
if (limitHeader != null && remainingHeader != null && resetHeader != null) {
|
|
399
|
+
const limit = Number(limitHeader);
|
|
400
|
+
const remaining = Number(remainingHeader);
|
|
401
|
+
const reset = Number(resetHeader);
|
|
402
|
+
const resetAt = new Date(reset);
|
|
403
|
+
result = { limit, remaining, reset, resetAt };
|
|
404
|
+
}
|
|
405
|
+
return result;
|
|
427
406
|
}
|
|
428
407
|
class ZohoTooManyRequestsError extends ZohoServerFetchResponseError {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
408
|
+
get headerDetails() {
|
|
409
|
+
return zohoRateLimitHeaderDetails(this.responseError.response.headers);
|
|
410
|
+
}
|
|
432
411
|
}
|
|
433
412
|
/**
|
|
434
413
|
* Function that parses/transforms a ZohoServerErrorResponseData into a general ZohoServerError or other known error type.
|
|
@@ -438,36 +417,37 @@ class ZohoTooManyRequestsError extends ZohoServerFetchResponseError {
|
|
|
438
417
|
* @returns
|
|
439
418
|
*/
|
|
440
419
|
function parseZohoServerErrorResponseData(errorResponseData, responseError) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
} else {
|
|
445
|
-
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
446
|
-
if (error) {
|
|
447
|
-
const errorData = zohoServerErrorData(error);
|
|
448
|
-
switch (errorData.code) {
|
|
449
|
-
case ZOHO_INTERNAL_ERROR_CODE:
|
|
450
|
-
result = new ZohoInternalError(errorData, errorResponseData, responseError);
|
|
451
|
-
break;
|
|
452
|
-
case ZOHO_INVALID_TOKEN_ERROR_CODE:
|
|
453
|
-
result = new ZohoInvalidTokenError(errorData, errorResponseData, responseError);
|
|
454
|
-
break;
|
|
455
|
-
case ZOHO_INVALID_AUTHORIZATION_ERROR_CODE:
|
|
456
|
-
result = new ZohoInvalidAuthorizationError(errorData, errorResponseData, responseError);
|
|
457
|
-
break;
|
|
458
|
-
case ZOHO_INVALID_QUERY_ERROR_CODE:
|
|
459
|
-
result = new ZohoInvalidQueryError(errorData, errorResponseData, responseError);
|
|
460
|
-
break;
|
|
461
|
-
case ZOHO_TOO_MANY_REQUESTS_ERROR_CODE:
|
|
462
|
-
result = new ZohoTooManyRequestsError(errorData, errorResponseData, responseError);
|
|
463
|
-
break;
|
|
464
|
-
default:
|
|
465
|
-
result = new ZohoServerFetchResponseError(errorData, errorResponseData, responseError);
|
|
466
|
-
break;
|
|
467
|
-
}
|
|
420
|
+
let result;
|
|
421
|
+
if (isZohoServerErrorResponseDataArrayRef(errorResponseData)) {
|
|
422
|
+
result = new ZohoServerFetchResponseDataArrayError(errorResponseData, responseError);
|
|
468
423
|
}
|
|
469
|
-
|
|
470
|
-
|
|
424
|
+
else {
|
|
425
|
+
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
426
|
+
if (error) {
|
|
427
|
+
const errorData = zohoServerErrorData(error);
|
|
428
|
+
switch (errorData.code) {
|
|
429
|
+
case ZOHO_INTERNAL_ERROR_CODE:
|
|
430
|
+
result = new ZohoInternalError(errorData, errorResponseData, responseError);
|
|
431
|
+
break;
|
|
432
|
+
case ZOHO_INVALID_TOKEN_ERROR_CODE:
|
|
433
|
+
result = new ZohoInvalidTokenError(errorData, errorResponseData, responseError);
|
|
434
|
+
break;
|
|
435
|
+
case ZOHO_INVALID_AUTHORIZATION_ERROR_CODE:
|
|
436
|
+
result = new ZohoInvalidAuthorizationError(errorData, errorResponseData, responseError);
|
|
437
|
+
break;
|
|
438
|
+
case ZOHO_INVALID_QUERY_ERROR_CODE:
|
|
439
|
+
result = new ZohoInvalidQueryError(errorData, errorResponseData, responseError);
|
|
440
|
+
break;
|
|
441
|
+
case ZOHO_TOO_MANY_REQUESTS_ERROR_CODE:
|
|
442
|
+
result = new ZohoTooManyRequestsError(errorData, errorResponseData, responseError);
|
|
443
|
+
break;
|
|
444
|
+
default:
|
|
445
|
+
result = new ZohoServerFetchResponseError(errorData, errorResponseData, responseError);
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return result;
|
|
471
451
|
}
|
|
472
452
|
/**
|
|
473
453
|
* Attempts to retrieve an ZohoServerErrorResponseDataError from the input.
|
|
@@ -480,8 +460,8 @@ function parseZohoServerErrorResponseData(errorResponseData, responseError) {
|
|
|
480
460
|
* @returns
|
|
481
461
|
*/
|
|
482
462
|
function tryFindZohoServerErrorData(errorResponseData, responseError) {
|
|
483
|
-
|
|
484
|
-
|
|
463
|
+
const error = errorResponseData.error ?? errorResponseData.data?.[0] ?? (!responseError.response.ok ? errorResponseData : undefined);
|
|
464
|
+
return error;
|
|
485
465
|
}
|
|
486
466
|
|
|
487
467
|
/**
|
|
@@ -494,77 +474,83 @@ const ZOHO_RECRUIT_ALREADY_ASSOCIATED_ERROR_CODE = 'ALREADY_ASSOCIATED';
|
|
|
494
474
|
* Thrown when a record with the given id has no content. Typically also means it does not exist.
|
|
495
475
|
*/
|
|
496
476
|
class ZohoRecruitRecordNoContentError extends makeError.BaseError {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
505
|
-
class ZohoRecruitRecordCrudError extends ZohoServerError {
|
|
506
|
-
|
|
507
|
-
class
|
|
477
|
+
moduleName;
|
|
478
|
+
recordId;
|
|
479
|
+
constructor(moduleName, recordId) {
|
|
480
|
+
super(`There was no content or matching records for the content. It may not exist.`);
|
|
481
|
+
this.moduleName = moduleName;
|
|
482
|
+
this.recordId = recordId;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
class ZohoRecruitRecordCrudError extends ZohoServerError {
|
|
486
|
+
}
|
|
487
|
+
class ZohoRecruitRecordCrudMandatoryFieldNotFoundError extends ZohoRecruitRecordCrudError {
|
|
488
|
+
}
|
|
489
|
+
class ZohoRecruitRecordCrudDuplicateDataError extends ZohoRecruitRecordCrudError {
|
|
490
|
+
}
|
|
508
491
|
class ZohoRecruitRecordCrudInvalidDataError extends ZohoRecruitRecordCrudError {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
492
|
+
get invalidFieldDetails() {
|
|
493
|
+
return this.error.details;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
class ZohoRecruitRecordCrudNoMatchingRecordError extends ZohoRecruitRecordCrudInvalidDataError {
|
|
512
497
|
}
|
|
513
|
-
class ZohoRecruitRecordCrudNoMatchingRecordError extends ZohoRecruitRecordCrudInvalidDataError {}
|
|
514
498
|
function zohoRecruitRecordCrudError(error) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
499
|
+
let result;
|
|
500
|
+
switch (error.code) {
|
|
501
|
+
case ZOHO_INVALID_DATA_ERROR_CODE:
|
|
502
|
+
const invalidDataError = new ZohoRecruitRecordCrudInvalidDataError(error);
|
|
503
|
+
if (invalidDataError.invalidFieldDetails['id']) {
|
|
504
|
+
result = new ZohoRecruitRecordCrudNoMatchingRecordError(error);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
result = invalidDataError;
|
|
508
|
+
}
|
|
509
|
+
break;
|
|
510
|
+
case ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE:
|
|
511
|
+
result = new ZohoRecruitRecordCrudMandatoryFieldNotFoundError(error);
|
|
512
|
+
break;
|
|
513
|
+
case ZOHO_DUPLICATE_DATA_ERROR_CODE:
|
|
514
|
+
result = new ZohoRecruitRecordCrudDuplicateDataError(error);
|
|
515
|
+
break;
|
|
516
|
+
default:
|
|
517
|
+
result = new ZohoRecruitRecordCrudError(error);
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
return result;
|
|
536
521
|
}
|
|
537
522
|
function assertZohoRecruitRecordDataArrayResultHasContent(moduleName, recordId) {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
523
|
+
return (x) => {
|
|
524
|
+
if (x == null || !x.data?.length) {
|
|
525
|
+
throw new ZohoRecruitRecordNoContentError(moduleName, recordId);
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
return x;
|
|
529
|
+
}
|
|
530
|
+
};
|
|
545
531
|
}
|
|
546
532
|
const logZohoRecruitErrorToConsole = logZohoServerErrorFunction('ZohoRecruit');
|
|
547
533
|
async function parseZohoRecruitError(responseError) {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
534
|
+
const data = await responseError.response.json().catch((x) => undefined);
|
|
535
|
+
let result;
|
|
536
|
+
if (data) {
|
|
537
|
+
result = parseZohoRecruitServerErrorResponseData(data, responseError);
|
|
538
|
+
}
|
|
539
|
+
return result;
|
|
554
540
|
}
|
|
555
541
|
function parseZohoRecruitServerErrorResponseData(errorResponseData, responseError) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
542
|
+
let result;
|
|
543
|
+
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
544
|
+
if (error) {
|
|
545
|
+
const errorData = zohoServerErrorData(error);
|
|
546
|
+
switch (errorData.code) {
|
|
547
|
+
// TODO: Add recruit-specific error codes here.
|
|
548
|
+
default:
|
|
549
|
+
result = parseZohoServerErrorResponseData(errorResponseData, responseError);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
565
552
|
}
|
|
566
|
-
|
|
567
|
-
return result;
|
|
553
|
+
return result;
|
|
568
554
|
}
|
|
569
555
|
const interceptZohoRecruit200StatusWithErrorResponse = interceptZohoErrorResponseFactory(parseZohoRecruitServerErrorResponseData);
|
|
570
556
|
const handleZohoRecruitErrorFetch = handleZohoErrorFetchFactory(parseZohoRecruitError, logZohoRecruitErrorToConsole);
|
|
@@ -587,28 +573,22 @@ const ZOHO_RECRUIT_CRUD_FUNCTION_MAX_RECORDS_LIMIT = 100;
|
|
|
587
573
|
* @returns
|
|
588
574
|
*/
|
|
589
575
|
function updateRecordLikeFunction$1(context, fetchUrlPrefix, fetchMethod) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
throw zohoRecruitRecordCrudError(errorItems[0].result);
|
|
607
|
-
} else {
|
|
608
|
-
return successItems[0].result.details;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
});
|
|
576
|
+
return (({ data, module }) => context.fetchJson(`/v2/${module}${fetchUrlPrefix}`, zohoRecruitApiFetchJsonInput(fetchMethod, { data: util.asArray(data) })).then((x) => {
|
|
577
|
+
const isInputMultipleItems = Array.isArray(data);
|
|
578
|
+
const result = zohoRecruitMultiRecordResult(util.asArray(data), x.data);
|
|
579
|
+
if (isInputMultipleItems) {
|
|
580
|
+
return result;
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
const { successItems, errorItems } = result;
|
|
584
|
+
if (errorItems[0] != null) {
|
|
585
|
+
throw zohoRecruitRecordCrudError(errorItems[0].result);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
return successItems[0].result.details;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}));
|
|
612
592
|
}
|
|
613
593
|
/**
|
|
614
594
|
* Inserts one or more records into Recruit.
|
|
@@ -619,7 +599,7 @@ function updateRecordLikeFunction$1(context, fetchUrlPrefix, fetchMethod) {
|
|
|
619
599
|
* @returns
|
|
620
600
|
*/
|
|
621
601
|
function zohoRecruitInsertRecord(context) {
|
|
622
|
-
|
|
602
|
+
return updateRecordLikeFunction$1(context, '', 'POST');
|
|
623
603
|
}
|
|
624
604
|
/**
|
|
625
605
|
* Updates or inserts one or more records in Recruit.
|
|
@@ -630,7 +610,7 @@ function zohoRecruitInsertRecord(context) {
|
|
|
630
610
|
* @returns
|
|
631
611
|
*/
|
|
632
612
|
function zohoRecruitUpsertRecord(context) {
|
|
633
|
-
|
|
613
|
+
return updateRecordLikeFunction$1(context, '/upsert', 'POST');
|
|
634
614
|
}
|
|
635
615
|
/**
|
|
636
616
|
* Updates one or more records in Recruit.
|
|
@@ -641,7 +621,7 @@ function zohoRecruitUpsertRecord(context) {
|
|
|
641
621
|
* @returns
|
|
642
622
|
*/
|
|
643
623
|
function zohoRecruitUpdateRecord(context) {
|
|
644
|
-
|
|
624
|
+
return updateRecordLikeFunction$1(context, '', 'PUT');
|
|
645
625
|
}
|
|
646
626
|
/**
|
|
647
627
|
* Deletes one or more records from the given module.
|
|
@@ -652,16 +632,9 @@ function zohoRecruitUpdateRecord(context) {
|
|
|
652
632
|
* @returns ZohoRecruitDeleteRecordFunction
|
|
653
633
|
*/
|
|
654
634
|
function zohoRecruitDeleteRecord(context) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
wf_trigger
|
|
659
|
-
}) => {
|
|
660
|
-
return context.fetchJson(`/v2/${module}?${fetch.makeUrlSearchParams({
|
|
661
|
-
ids,
|
|
662
|
-
wf_trigger
|
|
663
|
-
})}`, zohoRecruitApiFetchJsonInput('DELETE')).then(zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs);
|
|
664
|
-
};
|
|
635
|
+
return ({ ids, module, wf_trigger }) => {
|
|
636
|
+
return context.fetchJson(`/v2/${module}?${fetch.makeUrlSearchParams({ ids, wf_trigger })}`, zohoRecruitApiFetchJsonInput('DELETE')).then(zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs);
|
|
637
|
+
};
|
|
665
638
|
}
|
|
666
639
|
/**
|
|
667
640
|
* Retrieves a specific record from the given module.
|
|
@@ -672,7 +645,10 @@ function zohoRecruitDeleteRecord(context) {
|
|
|
672
645
|
* @returns
|
|
673
646
|
*/
|
|
674
647
|
function zohoRecruitGetRecordById(context) {
|
|
675
|
-
|
|
648
|
+
return (input) => context
|
|
649
|
+
.fetchJson(`/v2/${input.module}/${input.id}`, zohoRecruitApiFetchJsonInput('GET'))
|
|
650
|
+
.then(assertZohoRecruitRecordDataArrayResultHasContent(input.module))
|
|
651
|
+
.then((x) => x.data[0]);
|
|
676
652
|
}
|
|
677
653
|
/**
|
|
678
654
|
* Retrieves records from the given module. Used for paginating across all records.
|
|
@@ -683,7 +659,7 @@ function zohoRecruitGetRecordById(context) {
|
|
|
683
659
|
* @returns
|
|
684
660
|
*/
|
|
685
661
|
function zohoRecruitGetRecords(context) {
|
|
686
|
-
|
|
662
|
+
return ((input) => context.fetchJson(`/v2/${input.module}?${zohoRecruitUrlSearchParamsMinusModule(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')));
|
|
687
663
|
}
|
|
688
664
|
/**
|
|
689
665
|
* Searches records from the given module.
|
|
@@ -694,30 +670,23 @@ function zohoRecruitGetRecords(context) {
|
|
|
694
670
|
* @returns
|
|
695
671
|
*/
|
|
696
672
|
function zohoRecruitSearchRecords(context) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const urlParams = zohoRecruitUrlSearchParamsMinusModule(baseInput);
|
|
710
|
-
return urlParams;
|
|
711
|
-
}
|
|
712
|
-
return input => context.fetchJson(`/v2/${input.module}/search?${searchRecordsUrlSearchParams(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then(x => x ?? {
|
|
713
|
-
data: [],
|
|
714
|
-
info: {
|
|
715
|
-
more_records: false
|
|
673
|
+
function searchRecordsUrlSearchParams(input) {
|
|
674
|
+
const baseInput = { ...input };
|
|
675
|
+
delete baseInput.criteria;
|
|
676
|
+
if (input.criteria != null) {
|
|
677
|
+
const criteriaString = zohoRecruitSearchRecordsCriteriaString(input.criteria);
|
|
678
|
+
baseInput.criteria = criteriaString;
|
|
679
|
+
}
|
|
680
|
+
if (!baseInput.word && !input.criteria && !input.email && !input.phone) {
|
|
681
|
+
throw new Error('At least one of word, criteria, email, or phone must be provided');
|
|
682
|
+
}
|
|
683
|
+
const urlParams = zohoRecruitUrlSearchParamsMinusModule(baseInput);
|
|
684
|
+
return urlParams;
|
|
716
685
|
}
|
|
717
|
-
|
|
686
|
+
return ((input) => context.fetchJson(`/v2/${input.module}/search?${searchRecordsUrlSearchParams(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => x ?? { data: [], info: { more_records: false } }));
|
|
718
687
|
}
|
|
719
688
|
function zohoRecruitSearchRecordsPageFactory(context) {
|
|
720
|
-
|
|
689
|
+
return zohoFetchPageFactory(zohoRecruitSearchRecords(context));
|
|
721
690
|
}
|
|
722
691
|
/**
|
|
723
692
|
* Creates a ZohoRecruitGetRelatedRecordsFunctionFactory, which can be used to create ZohoRecruitGetRelatedRecordsFunction<T> that targets retrieving related records of a given type.
|
|
@@ -728,29 +697,22 @@ function zohoRecruitSearchRecordsPageFactory(context) {
|
|
|
728
697
|
* @returns a ZohoRecruitGetRelatedRecordsFunctionFactory
|
|
729
698
|
*/
|
|
730
699
|
function zohoRecruitGetRelatedRecordsFunctionFactory(context) {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
} = config;
|
|
736
|
-
return input => context.fetchJson(`/v2/${input.module}/${input.id}/${targetModule}?${zohoRecruitUrlSearchParamsMinusIdAndModule(input, input.filter).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then(x => x ?? (returnEmptyRecordsInsteadOfNull !== false ? emptyZohoPageResult() : x));
|
|
737
|
-
};
|
|
700
|
+
return (config) => {
|
|
701
|
+
const { targetModule, returnEmptyRecordsInsteadOfNull = true } = config;
|
|
702
|
+
return (input) => context.fetchJson(`/v2/${input.module}/${input.id}/${targetModule}?${zohoRecruitUrlSearchParamsMinusIdAndModule(input, input.filter).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => x ?? (returnEmptyRecordsInsteadOfNull !== false ? emptyZohoPageResult() : x));
|
|
703
|
+
};
|
|
738
704
|
}
|
|
739
705
|
function zohoRecruitGetEmailsForRecord(context) {
|
|
740
|
-
|
|
741
|
-
targetModule: ZOHO_RECRUIT_EMAILS_MODULE
|
|
742
|
-
});
|
|
706
|
+
return zohoRecruitGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_RECRUIT_EMAILS_MODULE });
|
|
743
707
|
}
|
|
744
708
|
function zohoRecruitGetEmailsForRecordPageFactory(context) {
|
|
745
|
-
|
|
709
|
+
return zohoFetchPageFactory(zohoRecruitGetEmailsForRecord(context));
|
|
746
710
|
}
|
|
747
711
|
function zohoRecruitGetAttachmentsForRecord(context) {
|
|
748
|
-
|
|
749
|
-
targetModule: ZOHO_RECRUIT_ATTACHMENTS_MODULE
|
|
750
|
-
});
|
|
712
|
+
return zohoRecruitGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_RECRUIT_ATTACHMENTS_MODULE });
|
|
751
713
|
}
|
|
752
714
|
function zohoRecruitGetAttachmentsForRecordPageFactory(context) {
|
|
753
|
-
|
|
715
|
+
return zohoFetchPageFactory(zohoRecruitGetAttachmentsForRecord(context));
|
|
754
716
|
}
|
|
755
717
|
/**
|
|
756
718
|
* Maximum attachment size allowed by Zoho Recruit.
|
|
@@ -767,59 +729,57 @@ const ZOHO_RECRUIT_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
|
767
729
|
* @returns
|
|
768
730
|
*/
|
|
769
731
|
function zohoRecruitUploadAttachmentForRecord(context) {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
732
|
+
return (input) => {
|
|
733
|
+
const { attachmentCategoryId, attachmentCategoryName, formData } = input;
|
|
734
|
+
const urlParams = {
|
|
735
|
+
attachments_category_id: util.joinStringsWithCommas(attachmentCategoryId),
|
|
736
|
+
attachments_category: util.joinStringsWithCommas(attachmentCategoryName),
|
|
737
|
+
attachment_url: input.attachmentUrl
|
|
738
|
+
};
|
|
739
|
+
if (!urlParams.attachments_category_id?.length && !urlParams.attachments_category?.length) {
|
|
740
|
+
throw new Error('attachmentCategoryId or attachmentCategoryName must be provided and not empty.');
|
|
741
|
+
}
|
|
742
|
+
if (formData != null) {
|
|
743
|
+
delete urlParams.attachment_url;
|
|
744
|
+
}
|
|
745
|
+
const url = `https://recruitsandbox.zoho.com/recruit/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}?${fetch.makeUrlSearchParams(urlParams).toString()}`;
|
|
746
|
+
let response;
|
|
747
|
+
if (urlParams.attachment_url) {
|
|
748
|
+
response = context.fetch(url, { method: 'POST' });
|
|
749
|
+
}
|
|
750
|
+
else if (formData != null) {
|
|
751
|
+
throw new Error('unsupported currently. Use the attachmentUrl parameter instead.');
|
|
752
|
+
// There is something weird going on with sending requests this way and zoho's server is rejecting it.
|
|
753
|
+
/*
|
|
754
|
+
response = context.fetch(url, {
|
|
755
|
+
method: 'POST',
|
|
756
|
+
headers: {
|
|
757
|
+
'Content-Type': 'multipart/form-data',
|
|
758
|
+
'content-length': '210'
|
|
759
|
+
},
|
|
760
|
+
body: formData
|
|
761
|
+
});
|
|
762
|
+
*/
|
|
763
|
+
/*
|
|
764
|
+
const fullUrl = (context.config.apiUrl as string) + url;
|
|
765
|
+
const accessToken = await context.accessTokenStringFactory();
|
|
766
|
+
|
|
767
|
+
response = fetch(fullUrl, {
|
|
768
|
+
headers: {
|
|
769
|
+
Authorization: `Bearer ${accessToken}`
|
|
770
|
+
},
|
|
771
|
+
body: formData,
|
|
772
|
+
method: 'POST'
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
console.log({ response });
|
|
776
|
+
*/
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
throw new Error('body or attachmentUrl must be provided.');
|
|
780
|
+
}
|
|
781
|
+
return response;
|
|
780
782
|
};
|
|
781
|
-
if (!urlParams.attachments_category_id?.length && !urlParams.attachments_category?.length) {
|
|
782
|
-
throw new Error('attachmentCategoryId or attachmentCategoryName must be provided and not empty.');
|
|
783
|
-
}
|
|
784
|
-
if (formData != null) {
|
|
785
|
-
delete urlParams.attachment_url;
|
|
786
|
-
}
|
|
787
|
-
const url = `https://recruitsandbox.zoho.com/recruit/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}?${fetch.makeUrlSearchParams(urlParams).toString()}`;
|
|
788
|
-
let response;
|
|
789
|
-
if (urlParams.attachment_url) {
|
|
790
|
-
response = context.fetch(url, {
|
|
791
|
-
method: 'POST'
|
|
792
|
-
});
|
|
793
|
-
} else if (formData != null) {
|
|
794
|
-
throw new Error('unsupported currently. Use the attachmentUrl parameter instead.');
|
|
795
|
-
// There is something weird going on with sending requests this way and zoho's server is rejecting it.
|
|
796
|
-
/*
|
|
797
|
-
response = context.fetch(url, {
|
|
798
|
-
method: 'POST',
|
|
799
|
-
headers: {
|
|
800
|
-
'Content-Type': 'multipart/form-data',
|
|
801
|
-
'content-length': '210'
|
|
802
|
-
},
|
|
803
|
-
body: formData
|
|
804
|
-
});
|
|
805
|
-
*/
|
|
806
|
-
/*
|
|
807
|
-
const fullUrl = (context.config.apiUrl as string) + url;
|
|
808
|
-
const accessToken = await context.accessTokenStringFactory();
|
|
809
|
-
response = fetch(fullUrl, {
|
|
810
|
-
headers: {
|
|
811
|
-
Authorization: `Bearer ${accessToken}`
|
|
812
|
-
},
|
|
813
|
-
body: formData,
|
|
814
|
-
method: 'POST'
|
|
815
|
-
});
|
|
816
|
-
console.log({ response });
|
|
817
|
-
*/
|
|
818
|
-
} else {
|
|
819
|
-
throw new Error('body or attachmentUrl must be provided.');
|
|
820
|
-
}
|
|
821
|
-
return response;
|
|
822
|
-
};
|
|
823
783
|
}
|
|
824
784
|
/**
|
|
825
785
|
* Downloads an attachment from a record.
|
|
@@ -830,9 +790,7 @@ function zohoRecruitUploadAttachmentForRecord(context) {
|
|
|
830
790
|
* @returns
|
|
831
791
|
*/
|
|
832
792
|
function zohoRecruitDownloadAttachmentForRecord(context) {
|
|
833
|
-
|
|
834
|
-
method: 'GET'
|
|
835
|
-
}).then(fetch.parseFetchFileResponse);
|
|
793
|
+
return (input) => context.fetch(`/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'GET' }).then(fetch.parseFetchFileResponse);
|
|
836
794
|
}
|
|
837
795
|
/**
|
|
838
796
|
* Deletes an attachment from a record.
|
|
@@ -843,16 +801,14 @@ function zohoRecruitDownloadAttachmentForRecord(context) {
|
|
|
843
801
|
* @returns
|
|
844
802
|
*/
|
|
845
803
|
function zohoRecruitDeleteAttachmentFromRecord(context) {
|
|
846
|
-
|
|
847
|
-
method: 'DELETE'
|
|
848
|
-
});
|
|
804
|
+
return (input) => context.fetch(`/v2/${input.module}/${input.id}/${ZOHO_RECRUIT_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'DELETE' });
|
|
849
805
|
}
|
|
850
806
|
class ZohoRecruitExecuteRestApiFunctionError extends makeError.BaseError {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
807
|
+
error;
|
|
808
|
+
constructor(error) {
|
|
809
|
+
super(`An error occured during the execution of the function. Code: ${error.code}, Message: ${error.message}`);
|
|
810
|
+
this.error = error;
|
|
811
|
+
}
|
|
856
812
|
}
|
|
857
813
|
/**
|
|
858
814
|
* Creates a ZohoRecruitExecuteRestApiFunctionFunction
|
|
@@ -866,87 +822,84 @@ class ZohoRecruitExecuteRestApiFunctionError extends makeError.BaseError {
|
|
|
866
822
|
* @returns
|
|
867
823
|
*/
|
|
868
824
|
function zohoRecruitExecuteRestApiFunction(context) {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
825
|
+
return (input) => {
|
|
826
|
+
const inputSearchParams = fetch.makeUrlSearchParams(input.params);
|
|
827
|
+
const inputSearchParamsString = inputSearchParams.toString();
|
|
828
|
+
const isSpecificRequest = Boolean(input.apiKey);
|
|
829
|
+
const urlParams = (isSpecificRequest ? `auth_type=apikey&zapikey=${input.apiKey}` : 'auth_type=oauth') + (inputSearchParamsString ? `&${inputSearchParamsString}` : '');
|
|
830
|
+
const relativeUrl = `/v2/functions/${input.functionName}/actions/execute?${urlParams}`;
|
|
831
|
+
const baseUrl = isSpecificRequest && input.apiUrl != null ? zohoRecruitConfigApiUrl(input.apiUrl) : '';
|
|
832
|
+
const url = `${baseUrl}${relativeUrl}`;
|
|
833
|
+
return context.fetchJson(url, zohoRecruitApiFetchJsonInput('POST')).then((x) => {
|
|
834
|
+
if (x.code === 'success') {
|
|
835
|
+
return x.details;
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
throw new ZohoRecruitExecuteRestApiFunctionError(x);
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
};
|
|
885
842
|
}
|
|
886
843
|
// MARK: Util
|
|
887
844
|
function zohoRecruitUrlSearchParamsMinusModule(...input) {
|
|
888
|
-
|
|
889
|
-
omitKeys: 'module'
|
|
890
|
-
});
|
|
845
|
+
return fetch.makeUrlSearchParams(input, { omitKeys: 'module' });
|
|
891
846
|
}
|
|
892
847
|
function zohoRecruitUrlSearchParamsMinusIdAndModule(...input) {
|
|
893
|
-
|
|
894
|
-
omitKeys: ['id', 'module']
|
|
895
|
-
});
|
|
848
|
+
return fetch.makeUrlSearchParams(input, { omitKeys: ['id', 'module'] });
|
|
896
849
|
}
|
|
897
850
|
/**
|
|
898
851
|
* @deprecated use makeUrlSearchParams instead.
|
|
899
852
|
*/
|
|
900
853
|
const zohoRecruitUrlSearchParams = fetch.makeUrlSearchParams;
|
|
901
854
|
function zohoRecruitApiFetchJsonInput(method, body) {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
855
|
+
const result = {
|
|
856
|
+
method,
|
|
857
|
+
body: body ?? undefined
|
|
858
|
+
};
|
|
859
|
+
return result;
|
|
907
860
|
}
|
|
908
861
|
function zohoRecruitChangeObjectLikeResponseSuccessAndErrorPairs(response) {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
return result;
|
|
862
|
+
const { data } = response;
|
|
863
|
+
const successItems = [];
|
|
864
|
+
const errorItems = [];
|
|
865
|
+
data.forEach((x) => {
|
|
866
|
+
if (x.status === ZOHO_SUCCESS_STATUS) {
|
|
867
|
+
successItems.push(x);
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
errorItems.push(x);
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
const result = {
|
|
874
|
+
...response,
|
|
875
|
+
successItems,
|
|
876
|
+
errorItems
|
|
877
|
+
};
|
|
878
|
+
return result;
|
|
927
879
|
}
|
|
928
880
|
function zohoRecruitMultiRecordResult(input, results) {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
881
|
+
const successItems = [];
|
|
882
|
+
const errorItems = [];
|
|
883
|
+
input.forEach((x, i) => {
|
|
884
|
+
const result = results[i];
|
|
885
|
+
if (result.status === ZOHO_SUCCESS_STATUS) {
|
|
886
|
+
successItems.push({
|
|
887
|
+
input: x,
|
|
888
|
+
result: result
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
errorItems.push({
|
|
893
|
+
input: x,
|
|
894
|
+
result: result
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
const result = {
|
|
899
|
+
successItems,
|
|
900
|
+
errorItems
|
|
901
|
+
};
|
|
902
|
+
return result;
|
|
950
903
|
}
|
|
951
904
|
/**
|
|
952
905
|
* @deprecated Use zohoRecruitInsertRecord instead.
|
|
@@ -1026,97 +979,82 @@ const executeRestApiFunction = zohoRecruitExecuteRestApiFunction;
|
|
|
1026
979
|
* @returns
|
|
1027
980
|
*/
|
|
1028
981
|
function zohoRecruitAssociateCandidateRecordsWithJobOpenings(context) {
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
982
|
+
return (input) => context.fetchJson(`/v2/${ZOHO_RECRUIT_CANDIDATES_MODULE}/actions/associate`, zohoRecruitApiFetchJsonInput('PUT', { data: util.asArray(input) })).then((x) => {
|
|
983
|
+
const resultInputMap = x.data.map(() => input); // assign "input" to each value for now
|
|
984
|
+
const result = zohoRecruitMultiRecordResult(resultInputMap, x.data);
|
|
985
|
+
const { included: alreadyAssociatedErrorItems, excluded: otherErrorItems } = util.separateValues(result.errorItems, (x) => {
|
|
986
|
+
return x.result.code === ZOHO_FAILURE_ERROR_CODE && x.result.details.error[0].code === ZOHO_RECRUIT_ALREADY_ASSOCIATED_ERROR_CODE;
|
|
987
|
+
});
|
|
988
|
+
return {
|
|
989
|
+
...result,
|
|
990
|
+
errorItems: otherErrorItems,
|
|
991
|
+
alreadyAssociatedErrorItems,
|
|
992
|
+
allErrorItems: result.errorItems
|
|
993
|
+
};
|
|
1039
994
|
});
|
|
1040
|
-
return {
|
|
1041
|
-
...result,
|
|
1042
|
-
errorItems: otherErrorItems,
|
|
1043
|
-
alreadyAssociatedErrorItems,
|
|
1044
|
-
allErrorItems: result.errorItems
|
|
1045
|
-
};
|
|
1046
|
-
});
|
|
1047
995
|
}
|
|
1048
996
|
function zohoRecruitSearchAssociatedRecords(context) {
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
997
|
+
return (input) => {
|
|
998
|
+
return context.fetchJson(`/v2/${input.module}/${input.id}/associate?${zohoRecruitUrlSearchParamsMinusIdAndModule(input).toString()}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => {
|
|
999
|
+
const result = x ?? emptyZohoPageResult();
|
|
1000
|
+
return result;
|
|
1001
|
+
});
|
|
1002
|
+
};
|
|
1055
1003
|
}
|
|
1056
1004
|
function zohoRecruitSearchCandidateAssociatedJobOpeningRecords(context) {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1005
|
+
const searchAssociatedRecordsFactory = zohoRecruitSearchAssociatedRecords(context);
|
|
1006
|
+
return (input) => {
|
|
1007
|
+
return searchAssociatedRecordsFactory({
|
|
1008
|
+
...input,
|
|
1009
|
+
module: ZOHO_RECRUIT_CANDIDATES_MODULE
|
|
1010
|
+
});
|
|
1011
|
+
};
|
|
1064
1012
|
}
|
|
1065
1013
|
function zohoRecruitSearchCandidateAssociatedJobOpeningRecordsPageFactory(context) {
|
|
1066
|
-
|
|
1014
|
+
return zohoFetchPageFactory(zohoRecruitSearchCandidateAssociatedJobOpeningRecords(context));
|
|
1067
1015
|
}
|
|
1068
1016
|
function zohoRecruitSearchJobOpeningAssociatedCandidateRecords(context, jobOpeningModuleName = ZOHO_RECRUIT_JOB_OPENINGS_MODULE) {
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1017
|
+
const searchAssociatedRecordsFactory = zohoRecruitSearchAssociatedRecords(context);
|
|
1018
|
+
return (input) => {
|
|
1019
|
+
return searchAssociatedRecordsFactory({
|
|
1020
|
+
...input,
|
|
1021
|
+
module: jobOpeningModuleName
|
|
1022
|
+
});
|
|
1023
|
+
};
|
|
1076
1024
|
}
|
|
1077
1025
|
function zohoRecruitSearchJobOpeningAssociatedCandidateRecordsPageFactory(context) {
|
|
1078
|
-
|
|
1026
|
+
return zohoFetchPageFactory(zohoRecruitSearchJobOpeningAssociatedCandidateRecords(context));
|
|
1079
1027
|
}
|
|
1080
1028
|
|
|
1081
1029
|
function zohoRecruitCreateNotes(context) {
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
return zohoRecruitMultiRecordResult(util.asArray(input.data), x.data);
|
|
1086
|
-
});
|
|
1030
|
+
return (input) => context.fetchJson(`/v2/${ZOHO_RECRUIT_NOTES_MODULE}`, zohoRecruitApiFetchJsonInput('POST', { data: input.data })).then((x) => {
|
|
1031
|
+
return zohoRecruitMultiRecordResult(util.asArray(input.data), x.data);
|
|
1032
|
+
});
|
|
1087
1033
|
}
|
|
1088
1034
|
function zohoRecruitDeleteNotes(context) {
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
return zohoRecruitMultiRecordResult(util.asArray(input.ids), x.data);
|
|
1093
|
-
});
|
|
1035
|
+
return (input) => context.fetchJson(`/v2/${ZOHO_RECRUIT_NOTES_MODULE}?${fetch.makeUrlSearchParams({ ids: input.ids })}`, zohoRecruitApiFetchJsonInput('DELETE')).then((x) => {
|
|
1036
|
+
return zohoRecruitMultiRecordResult(util.asArray(input.ids), x.data);
|
|
1037
|
+
});
|
|
1094
1038
|
}
|
|
1095
1039
|
function zohoRecruitGetNotesForRecord(context) {
|
|
1096
|
-
|
|
1097
|
-
targetModule: ZOHO_RECRUIT_NOTES_MODULE
|
|
1098
|
-
});
|
|
1040
|
+
return zohoRecruitGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_RECRUIT_NOTES_MODULE });
|
|
1099
1041
|
}
|
|
1100
1042
|
function zohoRecruitGetNotesForRecordPageFactory(context) {
|
|
1101
|
-
|
|
1043
|
+
return zohoFetchPageFactory(zohoRecruitGetNotesForRecord(context));
|
|
1102
1044
|
}
|
|
1103
1045
|
function zohoRecruitCreateNotesForRecord(context) {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
Parent_Id
|
|
1116
|
-
}))
|
|
1046
|
+
const createNotesInstance = zohoRecruitCreateNotes(context);
|
|
1047
|
+
return (input) => {
|
|
1048
|
+
const { module: se_module, id: Parent_Id, notes } = input;
|
|
1049
|
+
const createNotesRequest = {
|
|
1050
|
+
data: util.asArray(notes).map((x) => ({
|
|
1051
|
+
...x,
|
|
1052
|
+
se_module,
|
|
1053
|
+
Parent_Id
|
|
1054
|
+
}))
|
|
1055
|
+
};
|
|
1056
|
+
return createNotesInstance(createNotesRequest);
|
|
1117
1057
|
};
|
|
1118
|
-
return createNotesInstance(createNotesRequest);
|
|
1119
|
-
};
|
|
1120
1058
|
}
|
|
1121
1059
|
// MARK: Compat
|
|
1122
1060
|
/**
|
|
@@ -1141,25 +1079,18 @@ const getNotesForRecordPageFactory = zohoRecruitGetNotesForRecordPageFactory;
|
|
|
1141
1079
|
const createNotesForRecord = zohoRecruitCreateNotesForRecord;
|
|
1142
1080
|
|
|
1143
1081
|
function zohoRecruitCreateTagsForModule(context) {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1082
|
+
return (input) => context.fetchJson(`/v2/settings/tags?${fetch.makeUrlSearchParams({ module: input.module })}`, zohoRecruitApiFetchJsonInput('POST', { tags: util.asArray(input.tags) })).then((x) => {
|
|
1083
|
+
const result = zohoRecruitMultiRecordResult(util.asArray(input.tags), x.tags);
|
|
1084
|
+
const { included: duplicateErrorItems, excluded: otherErrorItems } = util.separateValues(result.errorItems, (x) => {
|
|
1085
|
+
return x.result.code === ZOHO_DUPLICATE_DATA_ERROR_CODE;
|
|
1086
|
+
});
|
|
1087
|
+
return {
|
|
1088
|
+
...result,
|
|
1089
|
+
errorItems: otherErrorItems,
|
|
1090
|
+
duplicateErrorItems,
|
|
1091
|
+
allErrorItems: result.errorItems
|
|
1092
|
+
};
|
|
1155
1093
|
});
|
|
1156
|
-
return {
|
|
1157
|
-
...result,
|
|
1158
|
-
errorItems: otherErrorItems,
|
|
1159
|
-
duplicateErrorItems,
|
|
1160
|
-
allErrorItems: result.errorItems
|
|
1161
|
-
};
|
|
1162
|
-
});
|
|
1163
1094
|
}
|
|
1164
1095
|
/**
|
|
1165
1096
|
* Returns the list of tags within a module.
|
|
@@ -1170,19 +1101,16 @@ function zohoRecruitCreateTagsForModule(context) {
|
|
|
1170
1101
|
* @returns
|
|
1171
1102
|
*/
|
|
1172
1103
|
function zohoRecruitGetTagsForModule(context) {
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
data: x.tags
|
|
1181
|
-
};
|
|
1182
|
-
});
|
|
1104
|
+
return (input) => context.fetchJson(`/v2/settings/tags?${fetch.makeUrlSearchParams({ module: input.module, my_tags: input.my_tags })}`, zohoRecruitApiFetchJsonInput('GET')).then((x) => {
|
|
1105
|
+
// NOTE: This doesn't follow the api documentation, and instead is a normal page result except it has "tags" instead of "data".
|
|
1106
|
+
return {
|
|
1107
|
+
...x,
|
|
1108
|
+
data: x.tags
|
|
1109
|
+
};
|
|
1110
|
+
});
|
|
1183
1111
|
}
|
|
1184
1112
|
function zohoRecruitGetTagsForModulePageFactory(context) {
|
|
1185
|
-
|
|
1113
|
+
return zohoFetchPageFactory(zohoRecruitGetTagsForModule(context));
|
|
1186
1114
|
}
|
|
1187
1115
|
// MARK: Add Tag To Record
|
|
1188
1116
|
/**
|
|
@@ -1198,18 +1126,15 @@ const ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
|
1198
1126
|
* @returns
|
|
1199
1127
|
*/
|
|
1200
1128
|
function zohoRecruitAddTagsToRecords(context) {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
return zohoRecruitMultiRecordResult(resultInputMap, x.data);
|
|
1211
|
-
});
|
|
1212
|
-
};
|
|
1129
|
+
return (input) => {
|
|
1130
|
+
if (Array.isArray(input.ids) && input.ids.length > ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED) {
|
|
1131
|
+
throw new Error(`Cannot add tags to more than ${ZOHO_RECRUIT_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED} records at once.`);
|
|
1132
|
+
}
|
|
1133
|
+
return context.fetchJson(`/v2/${ZOHO_RECRUIT_CANDIDATES_MODULE}/actions/add_tags?${fetch.makeUrlSearchParams({ tag_names: input.tag_names, ids: input.ids })}`, zohoRecruitApiFetchJsonInput('POST')).then((x) => {
|
|
1134
|
+
const resultInputMap = x.data.map(() => input); // assign "input" to each value for now
|
|
1135
|
+
return zohoRecruitMultiRecordResult(resultInputMap, x.data);
|
|
1136
|
+
});
|
|
1137
|
+
};
|
|
1213
1138
|
}
|
|
1214
1139
|
// MARK: Remove Tag From Record
|
|
1215
1140
|
/**
|
|
@@ -1225,18 +1150,15 @@ const ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
|
1225
1150
|
* @returns
|
|
1226
1151
|
*/
|
|
1227
1152
|
function zohoRecruitRemoveTagsFromRecords(context) {
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
return zohoRecruitMultiRecordResult(resultInputMap, x.data);
|
|
1238
|
-
});
|
|
1239
|
-
};
|
|
1153
|
+
return (input) => {
|
|
1154
|
+
if (Array.isArray(input.ids) && input.ids.length > ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED) {
|
|
1155
|
+
throw new Error(`Cannot remove tags from more than ${ZOHO_RECRUIT_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED} records at once.`);
|
|
1156
|
+
}
|
|
1157
|
+
return context.fetchJson(`/v2/${ZOHO_RECRUIT_CANDIDATES_MODULE}/actions/remove_tags?${fetch.makeUrlSearchParams({ tag_names: input.tag_names, ids: input.ids })}`, zohoRecruitApiFetchJsonInput('POST')).then((x) => {
|
|
1158
|
+
const resultInputMap = x.data.map(() => input); // assign "input" to each value for now
|
|
1159
|
+
return zohoRecruitMultiRecordResult(resultInputMap, x.data);
|
|
1160
|
+
});
|
|
1161
|
+
};
|
|
1240
1162
|
}
|
|
1241
1163
|
// MARK: Compat
|
|
1242
1164
|
/**
|
|
@@ -1270,47 +1192,47 @@ const ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE = 'invalid_client';
|
|
|
1270
1192
|
* Thrown if the call to the Zoho API creating an access token using a refresh token fails.
|
|
1271
1193
|
*/
|
|
1272
1194
|
class ZohoAccountsAccessTokenError extends fetch.FetchRequestFactoryError {
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1195
|
+
errorCode;
|
|
1196
|
+
constructor(errorCode) {
|
|
1197
|
+
super(`ZohoAccountsAccessTokenError: ${errorCode}`);
|
|
1198
|
+
this.errorCode = errorCode;
|
|
1199
|
+
}
|
|
1278
1200
|
}
|
|
1279
1201
|
/**
|
|
1280
1202
|
* Thrown if a valid ZohoAccessToken cannot be retrieved successfully.
|
|
1281
1203
|
*/
|
|
1282
1204
|
class ZohoAccountsAuthFailureError extends fetch.FetchRequestFactoryError {
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1205
|
+
reason;
|
|
1206
|
+
constructor(reason) {
|
|
1207
|
+
super(`Failed to retrieve proper authentication for the API call. Reason: ${reason}`);
|
|
1208
|
+
this.reason = reason;
|
|
1209
|
+
}
|
|
1288
1210
|
}
|
|
1289
1211
|
const logZohoAccountsErrorToConsole = logZohoServerErrorFunction('ZohoAccounts');
|
|
1290
1212
|
async function parseZohoAccountsError(responseError) {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1213
|
+
const data = await responseError.response.json().catch((x) => undefined);
|
|
1214
|
+
let result;
|
|
1215
|
+
if (data) {
|
|
1216
|
+
result = parseZohoAccountsServerErrorResponseData(data, responseError);
|
|
1217
|
+
}
|
|
1218
|
+
return result;
|
|
1297
1219
|
}
|
|
1298
1220
|
function parseZohoAccountsServerErrorResponseData(errorResponseData, responseError) {
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1221
|
+
let result;
|
|
1222
|
+
const error = errorResponseData.error;
|
|
1223
|
+
if (error) {
|
|
1224
|
+
const errorData = zohoServerErrorData(error);
|
|
1225
|
+
switch (errorData.code) {
|
|
1226
|
+
case ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE:
|
|
1227
|
+
case ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE:
|
|
1228
|
+
result = new ZohoAccountsAccessTokenError(errorData.code);
|
|
1229
|
+
break;
|
|
1230
|
+
default:
|
|
1231
|
+
result = parseZohoServerErrorResponseData(errorResponseData, responseError);
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1311
1234
|
}
|
|
1312
|
-
|
|
1313
|
-
return result;
|
|
1235
|
+
return result;
|
|
1314
1236
|
}
|
|
1315
1237
|
const interceptZohoAccounts200StatusWithErrorResponse = interceptZohoErrorResponseFactory(parseZohoAccountsServerErrorResponseData);
|
|
1316
1238
|
const handleZohoAccountsErrorFetch = handleZohoErrorFetchFactory(parseZohoAccountsError, logZohoAccountsErrorToConsole);
|
|
@@ -1319,129 +1241,115 @@ const handleZohoAccountsErrorFetch = handleZohoErrorFetchFactory(parseZohoAccoun
|
|
|
1319
1241
|
* Generates a new ZohoAccessTokenStringFactory.
|
|
1320
1242
|
*/
|
|
1321
1243
|
function zohoAccessTokenStringFactory(zohoAccessTokenFactory) {
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1244
|
+
return async () => {
|
|
1245
|
+
const token = await zohoAccessTokenFactory();
|
|
1246
|
+
if (!token?.accessToken) {
|
|
1247
|
+
throw new ZohoAccountsAuthFailureError();
|
|
1248
|
+
}
|
|
1249
|
+
return token.accessToken;
|
|
1250
|
+
};
|
|
1329
1251
|
}
|
|
1330
1252
|
|
|
1331
|
-
const DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION = headers => {
|
|
1332
|
-
|
|
1253
|
+
const DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION = (headers) => {
|
|
1254
|
+
console.warn(`zohoRateLimitedFetchHandler(): Too many requests made. The limit is ${headers.limit} requests per reset period. Will be reset at ${headers.resetAt}.`);
|
|
1333
1255
|
};
|
|
1334
1256
|
function zohoRateLimitedFetchHandler(config) {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
};
|
|
1349
|
-
}
|
|
1350
|
-
const defaultConfig = configForLimit(defaultLimit);
|
|
1351
|
-
const rateLimiter = util.resetPeriodPromiseRateLimiter(defaultConfig);
|
|
1352
|
-
return fetch.rateLimitedFetchHandler({
|
|
1353
|
-
rateLimiter,
|
|
1354
|
-
updateWithResponse: function (response, fetchResponseError) {
|
|
1355
|
-
const hasLimitHeader = response.headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
|
|
1356
|
-
let shouldRetry = false;
|
|
1357
|
-
let enabled = false;
|
|
1358
|
-
if (hasLimitHeader) {
|
|
1359
|
-
const headerDetails = zohoRateLimitHeaderDetails(response.headers);
|
|
1360
|
-
if (headerDetails) {
|
|
1361
|
-
const {
|
|
1362
|
-
limit,
|
|
1363
|
-
resetAt,
|
|
1364
|
-
remaining
|
|
1365
|
-
} = headerDetails;
|
|
1366
|
-
if (limit !== defaultLimit) {
|
|
1367
|
-
const newConfig = configForLimit(limit, resetAt);
|
|
1368
|
-
rateLimiter.setConfig(newConfig, false);
|
|
1369
|
-
}
|
|
1370
|
-
rateLimiter.setRemainingLimit(remaining);
|
|
1371
|
-
rateLimiter.setNextResetAt(resetAt);
|
|
1372
|
-
enabled = true;
|
|
1373
|
-
// only retry if it's a TOO MANY REQUESTS error
|
|
1374
|
-
if (response.status === ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE) {
|
|
1375
|
-
shouldRetry = true;
|
|
1376
|
-
try {
|
|
1377
|
-
onTooManyRequests?.(headerDetails, response, fetchResponseError);
|
|
1378
|
-
} catch (e) {}
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
rateLimiter.setEnabled(enabled);
|
|
1383
|
-
return shouldRetry;
|
|
1257
|
+
const onTooManyRequests = config?.onTooManyRequests !== false ? (config?.onTooManyRequests ?? DEFAULT_ZOHO_RATE_LIMITED_TOO_MANY_REQUETS_LOG_FUNCTION) : undefined;
|
|
1258
|
+
const defaultLimit = config?.maxRateLimit ?? DEFAULT_ZOHO_API_RATE_LIMIT;
|
|
1259
|
+
const defaultResetPeriod = config?.resetPeriod ?? DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD;
|
|
1260
|
+
function configForLimit(limit, resetAt) {
|
|
1261
|
+
return {
|
|
1262
|
+
limit: defaultLimit,
|
|
1263
|
+
startLimitAt: Math.ceil(limit / 10), // can do 10% of the requests of the limit before rate limiting begins
|
|
1264
|
+
cooldownRate: 1.2 * (limit / (defaultResetPeriod / util.MS_IN_SECOND)),
|
|
1265
|
+
exponentRate: 1.08,
|
|
1266
|
+
maxWaitTime: util.MS_IN_SECOND * 10,
|
|
1267
|
+
resetPeriod: defaultResetPeriod,
|
|
1268
|
+
resetAt
|
|
1269
|
+
};
|
|
1384
1270
|
}
|
|
1385
|
-
|
|
1271
|
+
const defaultConfig = configForLimit(defaultLimit);
|
|
1272
|
+
const rateLimiter = util.resetPeriodPromiseRateLimiter(defaultConfig);
|
|
1273
|
+
return fetch.rateLimitedFetchHandler({
|
|
1274
|
+
rateLimiter,
|
|
1275
|
+
updateWithResponse: function (response, fetchResponseError) {
|
|
1276
|
+
const hasLimitHeader = response.headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
|
|
1277
|
+
let shouldRetry = false;
|
|
1278
|
+
let enabled = false;
|
|
1279
|
+
if (hasLimitHeader) {
|
|
1280
|
+
const headerDetails = zohoRateLimitHeaderDetails(response.headers);
|
|
1281
|
+
if (headerDetails) {
|
|
1282
|
+
const { limit, resetAt, remaining } = headerDetails;
|
|
1283
|
+
if (limit !== defaultLimit) {
|
|
1284
|
+
const newConfig = configForLimit(limit, resetAt);
|
|
1285
|
+
rateLimiter.setConfig(newConfig, false);
|
|
1286
|
+
}
|
|
1287
|
+
rateLimiter.setRemainingLimit(remaining);
|
|
1288
|
+
rateLimiter.setNextResetAt(resetAt);
|
|
1289
|
+
enabled = true;
|
|
1290
|
+
// only retry if it's a TOO MANY REQUESTS error
|
|
1291
|
+
if (response.status === ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE) {
|
|
1292
|
+
shouldRetry = true;
|
|
1293
|
+
try {
|
|
1294
|
+
onTooManyRequests?.(headerDetails, response, fetchResponseError);
|
|
1295
|
+
}
|
|
1296
|
+
catch (e) { }
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
rateLimiter.setEnabled(enabled);
|
|
1301
|
+
return shouldRetry;
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1386
1304
|
}
|
|
1387
1305
|
|
|
1388
1306
|
function zohoRecruitFactory(factoryConfig) {
|
|
1389
|
-
|
|
1390
|
-
accountsContext
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1307
|
+
const { accountsContext } = factoryConfig;
|
|
1308
|
+
const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
|
|
1309
|
+
const fetchHandler = zohoRateLimitedFetchHandler(factoryConfig.rateLimiterConfig);
|
|
1310
|
+
const { logZohoServerErrorFunction, fetchFactory = (input) => fetch.fetchApiFetchService.makeFetch({
|
|
1311
|
+
baseUrl: input.apiUrl,
|
|
1312
|
+
baseRequest: async () => ({
|
|
1313
|
+
headers: {
|
|
1314
|
+
'Content-Type': 'application/json',
|
|
1315
|
+
Authorization: `Bearer ${await accessTokenStringFactory()}`
|
|
1316
|
+
}
|
|
1317
|
+
}),
|
|
1318
|
+
fetchHandler,
|
|
1319
|
+
timeout: 20 * 1000, // 20 second timeout
|
|
1320
|
+
requireOkResponse: true, // enforce ok response
|
|
1321
|
+
useTimeout: true // use timeout
|
|
1322
|
+
}) } = factoryConfig;
|
|
1323
|
+
return (config) => {
|
|
1324
|
+
if (!config.apiUrl) {
|
|
1325
|
+
throw new Error('ZohoConfig missing api url.');
|
|
1402
1326
|
}
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
handleFetchJsonParseErrorFunction: fetch.returnNullHandleFetchJsonParseErrorFunction
|
|
1429
|
-
});
|
|
1430
|
-
const recruitContext = {
|
|
1431
|
-
fetch: fetch$1,
|
|
1432
|
-
fetchJson,
|
|
1433
|
-
accessTokenStringFactory,
|
|
1434
|
-
config: {
|
|
1435
|
-
...config,
|
|
1436
|
-
apiUrl
|
|
1437
|
-
},
|
|
1438
|
-
zohoRateLimiter: fetchHandler._rateLimiter
|
|
1439
|
-
};
|
|
1440
|
-
const zohoRecruit = {
|
|
1441
|
-
recruitContext
|
|
1327
|
+
const apiUrl = zohoRecruitConfigApiUrl(config.apiUrl);
|
|
1328
|
+
const baseFetch = fetchFactory({ apiUrl });
|
|
1329
|
+
const fetch$1 = handleZohoRecruitErrorFetch(baseFetch, logZohoServerErrorFunction, (x) => {
|
|
1330
|
+
if (x instanceof ZohoInvalidTokenError) {
|
|
1331
|
+
accountsContext.loadAccessToken.resetAccessToken();
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
const fetchJson = fetch.fetchJsonFunction(fetch$1, {
|
|
1335
|
+
interceptJsonResponse: interceptZohoRecruit200StatusWithErrorResponse, // intercept errors that return status 200
|
|
1336
|
+
handleFetchJsonParseErrorFunction: fetch.returnNullHandleFetchJsonParseErrorFunction
|
|
1337
|
+
});
|
|
1338
|
+
const recruitContext = {
|
|
1339
|
+
fetch: fetch$1,
|
|
1340
|
+
fetchJson,
|
|
1341
|
+
accessTokenStringFactory,
|
|
1342
|
+
config: {
|
|
1343
|
+
...config,
|
|
1344
|
+
apiUrl
|
|
1345
|
+
},
|
|
1346
|
+
zohoRateLimiter: fetchHandler._rateLimiter
|
|
1347
|
+
};
|
|
1348
|
+
const zohoRecruit = {
|
|
1349
|
+
recruitContext
|
|
1350
|
+
};
|
|
1351
|
+
return zohoRecruit;
|
|
1442
1352
|
};
|
|
1443
|
-
return zohoRecruit;
|
|
1444
|
-
};
|
|
1445
1353
|
}
|
|
1446
1354
|
|
|
1447
1355
|
/**
|
|
@@ -1451,14 +1359,14 @@ const ZOHO_RECRUIT_TAG_NAME_MAX_LENGTH = 25;
|
|
|
1451
1359
|
|
|
1452
1360
|
const ZOHO_CRM_SERVICE_NAME = 'crm';
|
|
1453
1361
|
function zohoCrmConfigApiUrl(input) {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1362
|
+
switch (input) {
|
|
1363
|
+
case 'sandbox':
|
|
1364
|
+
return 'https://crmsandbox.zoho.com/crm';
|
|
1365
|
+
case 'production':
|
|
1366
|
+
return 'https://www.zohoapis.com/crm';
|
|
1367
|
+
default:
|
|
1368
|
+
return input;
|
|
1369
|
+
}
|
|
1462
1370
|
}
|
|
1463
1371
|
|
|
1464
1372
|
/**
|
|
@@ -1514,79 +1422,83 @@ const ZOHO_CRM_ALREADY_ASSOCIATED_ERROR_CODE = 'ALREADY_ASSOCIATED';
|
|
|
1514
1422
|
* Thrown when a record with the given id has no content. Typically also means it does not exist.
|
|
1515
1423
|
*/
|
|
1516
1424
|
class ZohoCrmRecordNoContentError extends makeError.BaseError {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
}
|
|
1525
|
-
class ZohoCrmRecordCrudError extends ZohoServerError {
|
|
1526
|
-
|
|
1527
|
-
class
|
|
1425
|
+
moduleName;
|
|
1426
|
+
recordId;
|
|
1427
|
+
constructor(moduleName, recordId) {
|
|
1428
|
+
super(`There was no content or matching records for the content. It may not exist.`);
|
|
1429
|
+
this.moduleName = moduleName;
|
|
1430
|
+
this.recordId = recordId;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
class ZohoCrmRecordCrudError extends ZohoServerError {
|
|
1434
|
+
}
|
|
1435
|
+
class ZohoCrmRecordCrudMandatoryFieldNotFoundError extends ZohoCrmRecordCrudError {
|
|
1436
|
+
}
|
|
1437
|
+
class ZohoCrmRecordCrudDuplicateDataError extends ZohoCrmRecordCrudError {
|
|
1438
|
+
}
|
|
1528
1439
|
class ZohoCrmRecordCrudInvalidDataError extends ZohoCrmRecordCrudError {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1440
|
+
get invalidFieldDetails() {
|
|
1441
|
+
return this.error.details;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
class ZohoCrmRecordCrudNoMatchingRecordError extends ZohoCrmRecordCrudInvalidDataError {
|
|
1532
1445
|
}
|
|
1533
|
-
class ZohoCrmRecordCrudNoMatchingRecordError extends ZohoCrmRecordCrudInvalidDataError {}
|
|
1534
1446
|
function zohoCrmRecordCrudError(error) {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1447
|
+
let result;
|
|
1448
|
+
switch (error.code) {
|
|
1449
|
+
case ZOHO_INVALID_DATA_ERROR_CODE:
|
|
1450
|
+
const invalidDataError = new ZohoCrmRecordCrudInvalidDataError(error);
|
|
1451
|
+
if (invalidDataError.invalidFieldDetails.api_name === 'id') {
|
|
1452
|
+
result = new ZohoCrmRecordCrudNoMatchingRecordError(error);
|
|
1453
|
+
}
|
|
1454
|
+
else {
|
|
1455
|
+
result = invalidDataError;
|
|
1456
|
+
}
|
|
1457
|
+
break;
|
|
1458
|
+
case ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE:
|
|
1459
|
+
result = new ZohoCrmRecordCrudMandatoryFieldNotFoundError(error);
|
|
1460
|
+
break;
|
|
1461
|
+
case ZOHO_DUPLICATE_DATA_ERROR_CODE:
|
|
1462
|
+
result = new ZohoCrmRecordCrudDuplicateDataError(error);
|
|
1463
|
+
break;
|
|
1464
|
+
default:
|
|
1465
|
+
result = new ZohoCrmRecordCrudError(error);
|
|
1466
|
+
break;
|
|
1467
|
+
}
|
|
1468
|
+
return result;
|
|
1556
1469
|
}
|
|
1557
1470
|
function assertZohoCrmRecordDataArrayResultHasContent(moduleName, recordId) {
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1471
|
+
return (x) => {
|
|
1472
|
+
if (x == null || !x.data?.length) {
|
|
1473
|
+
throw new ZohoCrmRecordNoContentError(moduleName, recordId);
|
|
1474
|
+
}
|
|
1475
|
+
else {
|
|
1476
|
+
return x;
|
|
1477
|
+
}
|
|
1478
|
+
};
|
|
1565
1479
|
}
|
|
1566
|
-
const logZohoCrmErrorToConsole = logZohoServerErrorFunction('ZohoCrm', {
|
|
1567
|
-
logDataArrayErrors: false
|
|
1568
|
-
});
|
|
1480
|
+
const logZohoCrmErrorToConsole = logZohoServerErrorFunction('ZohoCrm', { logDataArrayErrors: false });
|
|
1569
1481
|
async function parseZohoCrmError(responseError) {
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1482
|
+
const data = await responseError.response.json().catch((x) => undefined);
|
|
1483
|
+
let result;
|
|
1484
|
+
if (data) {
|
|
1485
|
+
result = parseZohoCrmServerErrorResponseData(data, responseError);
|
|
1486
|
+
}
|
|
1487
|
+
return result;
|
|
1576
1488
|
}
|
|
1577
1489
|
function parseZohoCrmServerErrorResponseData(errorResponseData, responseError) {
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1490
|
+
let result;
|
|
1491
|
+
const error = tryFindZohoServerErrorData(errorResponseData, responseError);
|
|
1492
|
+
if (error) {
|
|
1493
|
+
const errorData = zohoServerErrorData(error);
|
|
1494
|
+
switch (errorData.code) {
|
|
1495
|
+
// TODO: Add crm-specific error codes here.
|
|
1496
|
+
default:
|
|
1497
|
+
result = parseZohoServerErrorResponseData(errorResponseData, responseError);
|
|
1498
|
+
break;
|
|
1499
|
+
}
|
|
1587
1500
|
}
|
|
1588
|
-
|
|
1589
|
-
return result;
|
|
1501
|
+
return result;
|
|
1590
1502
|
}
|
|
1591
1503
|
const interceptZohoCrm200StatusWithErrorResponse = interceptZohoErrorResponseFactory(parseZohoCrmServerErrorResponseData);
|
|
1592
1504
|
const handleZohoCrmErrorFetch = handleZohoErrorFetchFactory(parseZohoCrmError, logZohoCrmErrorToConsole);
|
|
@@ -1604,28 +1516,25 @@ const ZOHO_CRM_CRUD_FUNCTION_MAX_RECORDS_LIMIT = 100;
|
|
|
1604
1516
|
* @returns
|
|
1605
1517
|
*/
|
|
1606
1518
|
function updateRecordLikeFunction(context, fetchUrlPrefix, fetchMethod) {
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
});
|
|
1519
|
+
return (({ data, module }) => context
|
|
1520
|
+
.fetchJson(`/v8/${module}${fetchUrlPrefix}`, zohoCrmApiFetchJsonInput(fetchMethod, { data: util.asArray(data) }))
|
|
1521
|
+
.catch(zohoCrmCatchZohoCrmChangeObjectLikeResponseError)
|
|
1522
|
+
.then((x) => {
|
|
1523
|
+
const isInputMultipleItems = Array.isArray(data);
|
|
1524
|
+
const result = zohoCrmMultiRecordResult(util.asArray(data), x.data);
|
|
1525
|
+
if (isInputMultipleItems) {
|
|
1526
|
+
return result;
|
|
1527
|
+
}
|
|
1528
|
+
else {
|
|
1529
|
+
const { successItems, errorItems } = result;
|
|
1530
|
+
if (errorItems[0] != null) {
|
|
1531
|
+
throw zohoCrmRecordCrudError(errorItems[0].result);
|
|
1532
|
+
}
|
|
1533
|
+
else {
|
|
1534
|
+
return successItems[0].result.details;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
}));
|
|
1629
1538
|
}
|
|
1630
1539
|
/**
|
|
1631
1540
|
* Inserts one or more records into Crm.
|
|
@@ -1636,7 +1545,7 @@ function updateRecordLikeFunction(context, fetchUrlPrefix, fetchMethod) {
|
|
|
1636
1545
|
* @returns
|
|
1637
1546
|
*/
|
|
1638
1547
|
function zohoCrmInsertRecord(context) {
|
|
1639
|
-
|
|
1548
|
+
return updateRecordLikeFunction(context, '', 'POST');
|
|
1640
1549
|
}
|
|
1641
1550
|
/**
|
|
1642
1551
|
* Updates or inserts one or more records in Crm.
|
|
@@ -1647,7 +1556,7 @@ function zohoCrmInsertRecord(context) {
|
|
|
1647
1556
|
* @returns
|
|
1648
1557
|
*/
|
|
1649
1558
|
function zohoCrmUpsertRecord(context) {
|
|
1650
|
-
|
|
1559
|
+
return updateRecordLikeFunction(context, '/upsert', 'POST');
|
|
1651
1560
|
}
|
|
1652
1561
|
/**
|
|
1653
1562
|
* Updates one or more records in Crm.
|
|
@@ -1658,7 +1567,7 @@ function zohoCrmUpsertRecord(context) {
|
|
|
1658
1567
|
* @returns
|
|
1659
1568
|
*/
|
|
1660
1569
|
function zohoCrmUpdateRecord(context) {
|
|
1661
|
-
|
|
1570
|
+
return updateRecordLikeFunction(context, '', 'PUT');
|
|
1662
1571
|
}
|
|
1663
1572
|
/**
|
|
1664
1573
|
* Deletes one or more records from the given module.
|
|
@@ -1669,16 +1578,12 @@ function zohoCrmUpdateRecord(context) {
|
|
|
1669
1578
|
* @returns ZohoCrmDeleteRecordFunction
|
|
1670
1579
|
*/
|
|
1671
1580
|
function zohoCrmDeleteRecord(context) {
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
ids,
|
|
1679
|
-
wf_trigger
|
|
1680
|
-
})}`, zohoCrmApiFetchJsonInput('DELETE')).catch(zohoCrmCatchZohoCrmChangeObjectLikeResponseError).then(zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs);
|
|
1681
|
-
};
|
|
1581
|
+
return ({ ids, module, wf_trigger }) => {
|
|
1582
|
+
return context
|
|
1583
|
+
.fetchJson(`/v8/${module}?${fetch.makeUrlSearchParams({ ids, wf_trigger })}`, zohoCrmApiFetchJsonInput('DELETE'))
|
|
1584
|
+
.catch(zohoCrmCatchZohoCrmChangeObjectLikeResponseError)
|
|
1585
|
+
.then(zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs);
|
|
1586
|
+
};
|
|
1682
1587
|
}
|
|
1683
1588
|
/**
|
|
1684
1589
|
* Retrieves a specific record from the given module.
|
|
@@ -1689,7 +1594,10 @@ function zohoCrmDeleteRecord(context) {
|
|
|
1689
1594
|
* @returns
|
|
1690
1595
|
*/
|
|
1691
1596
|
function zohoCrmGetRecordById(context) {
|
|
1692
|
-
|
|
1597
|
+
return (input) => context
|
|
1598
|
+
.fetchJson(`/v8/${input.module}/${input.id}`, zohoCrmApiFetchJsonInput('GET'))
|
|
1599
|
+
.then(assertZohoCrmRecordDataArrayResultHasContent(input.module))
|
|
1600
|
+
.then((x) => x.data[0]);
|
|
1693
1601
|
}
|
|
1694
1602
|
/**
|
|
1695
1603
|
* Retrieves records from the given module. Used for paginating across all records.
|
|
@@ -1700,7 +1608,7 @@ function zohoCrmGetRecordById(context) {
|
|
|
1700
1608
|
* @returns
|
|
1701
1609
|
*/
|
|
1702
1610
|
function zohoCrmGetRecords(context) {
|
|
1703
|
-
|
|
1611
|
+
return ((input) => context.fetchJson(`/v8/${input.module}?${zohoCrmUrlSearchParamsMinusModule(input).toString()}`, zohoCrmApiFetchJsonInput('GET')));
|
|
1704
1612
|
}
|
|
1705
1613
|
/**
|
|
1706
1614
|
* Searches records from the given module.
|
|
@@ -1711,30 +1619,23 @@ function zohoCrmGetRecords(context) {
|
|
|
1711
1619
|
* @returns
|
|
1712
1620
|
*/
|
|
1713
1621
|
function zohoCrmSearchRecords(context) {
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
const urlParams = zohoCrmUrlSearchParamsMinusModule(baseInput);
|
|
1727
|
-
return urlParams;
|
|
1728
|
-
}
|
|
1729
|
-
return input => context.fetchJson(`/v8/${input.module}/search?${searchRecordsUrlSearchParams(input).toString()}`, zohoCrmApiFetchJsonInput('GET')).then(x => x ?? {
|
|
1730
|
-
data: [],
|
|
1731
|
-
info: {
|
|
1732
|
-
more_records: false
|
|
1622
|
+
function searchRecordsUrlSearchParams(input) {
|
|
1623
|
+
const baseInput = { ...input };
|
|
1624
|
+
delete baseInput.criteria;
|
|
1625
|
+
if (input.criteria != null) {
|
|
1626
|
+
const criteriaString = zohoCrmSearchRecordsCriteriaString(input.criteria);
|
|
1627
|
+
baseInput.criteria = criteriaString;
|
|
1628
|
+
}
|
|
1629
|
+
if (!baseInput.word && !input.cvid && !input.criteria && !input.email && !input.phone) {
|
|
1630
|
+
throw new Error('At least one of word, cvid, criteria, email, or phone must be provided');
|
|
1631
|
+
}
|
|
1632
|
+
const urlParams = zohoCrmUrlSearchParamsMinusModule(baseInput);
|
|
1633
|
+
return urlParams;
|
|
1733
1634
|
}
|
|
1734
|
-
|
|
1635
|
+
return ((input) => context.fetchJson(`/v8/${input.module}/search?${searchRecordsUrlSearchParams(input).toString()}`, zohoCrmApiFetchJsonInput('GET')).then((x) => x ?? { data: [], info: { more_records: false } }));
|
|
1735
1636
|
}
|
|
1736
1637
|
function zohoCrmSearchRecordsPageFactory(context) {
|
|
1737
|
-
|
|
1638
|
+
return zohoFetchPageFactory(zohoCrmSearchRecords(context));
|
|
1738
1639
|
}
|
|
1739
1640
|
/**
|
|
1740
1641
|
* Creates a ZohoCrmGetRelatedRecordsFunctionFactory, which can be used to create ZohoCrmGetRelatedRecordsFunction<T> that targets retrieving related records of a given type.
|
|
@@ -1745,36 +1646,26 @@ function zohoCrmSearchRecordsPageFactory(context) {
|
|
|
1745
1646
|
* @returns a ZohoCrmGetRelatedRecordsFunctionFactory
|
|
1746
1647
|
*/
|
|
1747
1648
|
function zohoCrmGetRelatedRecordsFunctionFactory(context) {
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
} = config;
|
|
1753
|
-
return input => context.fetchJson(`/v8/${input.module}/${input.id}/${targetModule}?${zohoCrmUrlSearchParamsMinusIdAndModule(input, input.filter).toString()}`, zohoCrmApiFetchJsonInput('GET')).then(x => x ?? (returnEmptyRecordsInsteadOfNull !== false ? emptyZohoPageResult() : x));
|
|
1754
|
-
};
|
|
1649
|
+
return (config) => {
|
|
1650
|
+
const { targetModule, returnEmptyRecordsInsteadOfNull = true } = config;
|
|
1651
|
+
return (input) => context.fetchJson(`/v8/${input.module}/${input.id}/${targetModule}?${zohoCrmUrlSearchParamsMinusIdAndModule(input, input.filter).toString()}`, zohoCrmApiFetchJsonInput('GET')).then((x) => x ?? (returnEmptyRecordsInsteadOfNull !== false ? emptyZohoPageResult() : x));
|
|
1652
|
+
};
|
|
1755
1653
|
}
|
|
1756
1654
|
function zohoCrmGetEmailsForRecord(context) {
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
return {
|
|
1763
|
-
...x,
|
|
1764
|
-
data
|
|
1765
|
-
};
|
|
1766
|
-
});
|
|
1655
|
+
const getEmailsFactory = zohoCrmGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_CRM_EMAILS_MODULE });
|
|
1656
|
+
return (input) => getEmailsFactory(input).then((x) => {
|
|
1657
|
+
const data = x.data ?? x.Emails;
|
|
1658
|
+
return { ...x, data };
|
|
1659
|
+
});
|
|
1767
1660
|
}
|
|
1768
1661
|
function zohoCrmGetEmailsForRecordPageFactory(context) {
|
|
1769
|
-
|
|
1662
|
+
return zohoFetchPageFactory(zohoCrmGetEmailsForRecord(context));
|
|
1770
1663
|
}
|
|
1771
1664
|
function zohoCrmGetAttachmentsForRecord(context) {
|
|
1772
|
-
|
|
1773
|
-
targetModule: ZOHO_CRM_ATTACHMENTS_MODULE
|
|
1774
|
-
});
|
|
1665
|
+
return zohoCrmGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_CRM_ATTACHMENTS_MODULE });
|
|
1775
1666
|
}
|
|
1776
1667
|
function zohoCrmGetAttachmentsForRecordPageFactory(context) {
|
|
1777
|
-
|
|
1668
|
+
return zohoFetchPageFactory(zohoCrmGetAttachmentsForRecord(context));
|
|
1778
1669
|
}
|
|
1779
1670
|
/**
|
|
1780
1671
|
* Maximum attachment size allowed by Zoho Crm.
|
|
@@ -1791,59 +1682,57 @@ const ZOHO_CRM_ATTACHMENT_MAX_SIZE = 20 * 1024 * 1024;
|
|
|
1791
1682
|
* @returns
|
|
1792
1683
|
*/
|
|
1793
1684
|
function zohoCrmUploadAttachmentForRecord(context) {
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1685
|
+
return (input) => {
|
|
1686
|
+
const { attachmentCategoryId, attachmentCategoryName, formData } = input;
|
|
1687
|
+
const urlParams = {
|
|
1688
|
+
attachments_category_id: util.joinStringsWithCommas(attachmentCategoryId),
|
|
1689
|
+
attachments_category: util.joinStringsWithCommas(attachmentCategoryName),
|
|
1690
|
+
attachment_url: input.attachmentUrl
|
|
1691
|
+
};
|
|
1692
|
+
if (!urlParams.attachments_category_id?.length && !urlParams.attachments_category?.length) {
|
|
1693
|
+
throw new Error('attachmentCategoryId or attachmentCategoryName must be provided and not empty.');
|
|
1694
|
+
}
|
|
1695
|
+
if (formData != null) {
|
|
1696
|
+
delete urlParams.attachment_url;
|
|
1697
|
+
}
|
|
1698
|
+
const url = `https://crmsandbox.zoho.com/crm/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}?${fetch.makeUrlSearchParams(urlParams).toString()}`;
|
|
1699
|
+
let response;
|
|
1700
|
+
if (urlParams.attachment_url) {
|
|
1701
|
+
response = context.fetch(url, { method: 'POST' });
|
|
1702
|
+
}
|
|
1703
|
+
else if (formData != null) {
|
|
1704
|
+
throw new Error('unsupported currently. Use the attachmentUrl parameter instead.');
|
|
1705
|
+
// There is something weird going on with sending requests this way and zoho's server is rejecting it.
|
|
1706
|
+
/*
|
|
1707
|
+
response = context.fetch(url, {
|
|
1708
|
+
method: 'POST',
|
|
1709
|
+
headers: {
|
|
1710
|
+
'Content-Type': 'multipart/form-data',
|
|
1711
|
+
'content-length': '210'
|
|
1712
|
+
},
|
|
1713
|
+
body: formData
|
|
1714
|
+
});
|
|
1715
|
+
*/
|
|
1716
|
+
/*
|
|
1717
|
+
const fullUrl = (context.config.apiUrl as string) + url;
|
|
1718
|
+
const accessToken = await context.accessTokenStringFactory();
|
|
1719
|
+
|
|
1720
|
+
response = fetch(fullUrl, {
|
|
1721
|
+
headers: {
|
|
1722
|
+
Authorization: `Bearer ${accessToken}`
|
|
1723
|
+
},
|
|
1724
|
+
body: formData,
|
|
1725
|
+
method: 'POST'
|
|
1726
|
+
});
|
|
1727
|
+
|
|
1728
|
+
console.log({ response });
|
|
1729
|
+
*/
|
|
1730
|
+
}
|
|
1731
|
+
else {
|
|
1732
|
+
throw new Error('body or attachmentUrl must be provided.');
|
|
1733
|
+
}
|
|
1734
|
+
return response;
|
|
1804
1735
|
};
|
|
1805
|
-
if (!urlParams.attachments_category_id?.length && !urlParams.attachments_category?.length) {
|
|
1806
|
-
throw new Error('attachmentCategoryId or attachmentCategoryName must be provided and not empty.');
|
|
1807
|
-
}
|
|
1808
|
-
if (formData != null) {
|
|
1809
|
-
delete urlParams.attachment_url;
|
|
1810
|
-
}
|
|
1811
|
-
const url = `https://crmsandbox.zoho.com/crm/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}?${fetch.makeUrlSearchParams(urlParams).toString()}`;
|
|
1812
|
-
let response;
|
|
1813
|
-
if (urlParams.attachment_url) {
|
|
1814
|
-
response = context.fetch(url, {
|
|
1815
|
-
method: 'POST'
|
|
1816
|
-
});
|
|
1817
|
-
} else if (formData != null) {
|
|
1818
|
-
throw new Error('unsupported currently. Use the attachmentUrl parameter instead.');
|
|
1819
|
-
// There is something weird going on with sending requests this way and zoho's server is rejecting it.
|
|
1820
|
-
/*
|
|
1821
|
-
response = context.fetch(url, {
|
|
1822
|
-
method: 'POST',
|
|
1823
|
-
headers: {
|
|
1824
|
-
'Content-Type': 'multipart/form-data',
|
|
1825
|
-
'content-length': '210'
|
|
1826
|
-
},
|
|
1827
|
-
body: formData
|
|
1828
|
-
});
|
|
1829
|
-
*/
|
|
1830
|
-
/*
|
|
1831
|
-
const fullUrl = (context.config.apiUrl as string) + url;
|
|
1832
|
-
const accessToken = await context.accessTokenStringFactory();
|
|
1833
|
-
response = fetch(fullUrl, {
|
|
1834
|
-
headers: {
|
|
1835
|
-
Authorization: `Bearer ${accessToken}`
|
|
1836
|
-
},
|
|
1837
|
-
body: formData,
|
|
1838
|
-
method: 'POST'
|
|
1839
|
-
});
|
|
1840
|
-
console.log({ response });
|
|
1841
|
-
*/
|
|
1842
|
-
} else {
|
|
1843
|
-
throw new Error('body or attachmentUrl must be provided.');
|
|
1844
|
-
}
|
|
1845
|
-
return response;
|
|
1846
|
-
};
|
|
1847
1736
|
}
|
|
1848
1737
|
/**
|
|
1849
1738
|
* Downloads an attachment from a record.
|
|
@@ -1854,9 +1743,7 @@ function zohoCrmUploadAttachmentForRecord(context) {
|
|
|
1854
1743
|
* @returns
|
|
1855
1744
|
*/
|
|
1856
1745
|
function zohoCrmDownloadAttachmentForRecord(context) {
|
|
1857
|
-
|
|
1858
|
-
method: 'GET'
|
|
1859
|
-
}).then(fetch.parseFetchFileResponse);
|
|
1746
|
+
return (input) => context.fetch(`/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'GET' }).then(fetch.parseFetchFileResponse);
|
|
1860
1747
|
}
|
|
1861
1748
|
/**
|
|
1862
1749
|
* Deletes an attachment from a record.
|
|
@@ -1867,16 +1754,14 @@ function zohoCrmDownloadAttachmentForRecord(context) {
|
|
|
1867
1754
|
* @returns
|
|
1868
1755
|
*/
|
|
1869
1756
|
function zohoCrmDeleteAttachmentFromRecord(context) {
|
|
1870
|
-
|
|
1871
|
-
method: 'DELETE'
|
|
1872
|
-
});
|
|
1757
|
+
return (input) => context.fetch(`/v8/${input.module}/${input.id}/${ZOHO_CRM_ATTACHMENTS_MODULE}/${input.attachment_id}`, { method: 'DELETE' });
|
|
1873
1758
|
}
|
|
1874
1759
|
class ZohoCrmExecuteRestApiFunctionError extends makeError.BaseError {
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1760
|
+
error;
|
|
1761
|
+
constructor(error) {
|
|
1762
|
+
super(`An error occured during the execution of the function. Code: ${error.code}, Message: ${error.message}`);
|
|
1763
|
+
this.error = error;
|
|
1764
|
+
}
|
|
1880
1765
|
}
|
|
1881
1766
|
/**
|
|
1882
1767
|
* Creates a ZohoCrmExecuteRestApiFunctionFunction
|
|
@@ -1890,44 +1775,41 @@ class ZohoCrmExecuteRestApiFunctionError extends makeError.BaseError {
|
|
|
1890
1775
|
* @returns
|
|
1891
1776
|
*/
|
|
1892
1777
|
function zohoCrmExecuteRestApiFunction(context) {
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1778
|
+
return (input) => {
|
|
1779
|
+
const inputSearchParams = fetch.makeUrlSearchParams(input.params);
|
|
1780
|
+
const inputSearchParamsString = inputSearchParams.toString();
|
|
1781
|
+
const isSpecificRequest = Boolean(input.apiKey);
|
|
1782
|
+
const urlParams = (isSpecificRequest ? `auth_type=apikey&zapikey=${input.apiKey}` : 'auth_type=oauth') + (inputSearchParamsString ? `&${inputSearchParamsString}` : '');
|
|
1783
|
+
const relativeUrl = `/v8/functions/${input.functionName}/actions/execute?${urlParams}`;
|
|
1784
|
+
const baseUrl = isSpecificRequest && input.apiUrl != null ? zohoCrmConfigApiUrl(input.apiUrl) : '';
|
|
1785
|
+
const url = `${baseUrl}${relativeUrl}`;
|
|
1786
|
+
return context.fetchJson(url, zohoCrmApiFetchJsonInput('POST')).then((x) => {
|
|
1787
|
+
if (x.code === 'success') {
|
|
1788
|
+
return x.details;
|
|
1789
|
+
}
|
|
1790
|
+
else {
|
|
1791
|
+
throw new ZohoCrmExecuteRestApiFunctionError(x);
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1794
|
+
};
|
|
1909
1795
|
}
|
|
1910
1796
|
// MARK: Util
|
|
1911
1797
|
function zohoCrmUrlSearchParamsMinusModule(...input) {
|
|
1912
|
-
|
|
1913
|
-
omitKeys: 'module'
|
|
1914
|
-
});
|
|
1798
|
+
return fetch.makeUrlSearchParams(input, { omitKeys: 'module' });
|
|
1915
1799
|
}
|
|
1916
1800
|
function zohoCrmUrlSearchParamsMinusIdAndModule(...input) {
|
|
1917
|
-
|
|
1918
|
-
omitKeys: ['id', 'module']
|
|
1919
|
-
});
|
|
1801
|
+
return fetch.makeUrlSearchParams(input, { omitKeys: ['id', 'module'] });
|
|
1920
1802
|
}
|
|
1921
1803
|
/**
|
|
1922
1804
|
* @deprecated use makeUrlSearchParams instead.
|
|
1923
1805
|
*/
|
|
1924
1806
|
const zohoCrmUrlSearchParams = fetch.makeUrlSearchParams;
|
|
1925
1807
|
function zohoCrmApiFetchJsonInput(method, body) {
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1808
|
+
const result = {
|
|
1809
|
+
method,
|
|
1810
|
+
body: body ?? undefined
|
|
1811
|
+
};
|
|
1812
|
+
return result;
|
|
1931
1813
|
}
|
|
1932
1814
|
// MARK: Results
|
|
1933
1815
|
/**
|
|
@@ -1936,81 +1818,76 @@ function zohoCrmApiFetchJsonInput(method, body) {
|
|
|
1936
1818
|
* Use to catch errors from functions that return ZohoCrmChangeObjectLikeResponse and pass the result to zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs.
|
|
1937
1819
|
*/
|
|
1938
1820
|
function zohoCrmCatchZohoCrmChangeObjectLikeResponseError(e) {
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1821
|
+
let result;
|
|
1822
|
+
if (e instanceof ZohoServerFetchResponseDataArrayError) {
|
|
1823
|
+
result = {
|
|
1824
|
+
data: e.errorDataArray
|
|
1825
|
+
};
|
|
1826
|
+
}
|
|
1827
|
+
else {
|
|
1828
|
+
throw e;
|
|
1829
|
+
}
|
|
1830
|
+
return result;
|
|
1948
1831
|
}
|
|
1949
1832
|
function zohoCrmChangeObjectLikeResponseSuccessAndErrorPairs(response) {
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
return result;
|
|
1833
|
+
const { data } = response;
|
|
1834
|
+
const successItems = [];
|
|
1835
|
+
const errorItems = [];
|
|
1836
|
+
data.forEach((x) => {
|
|
1837
|
+
if (x.status === ZOHO_SUCCESS_STATUS) {
|
|
1838
|
+
successItems.push(x);
|
|
1839
|
+
}
|
|
1840
|
+
else {
|
|
1841
|
+
errorItems.push(x);
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
const result = {
|
|
1845
|
+
...response,
|
|
1846
|
+
successItems,
|
|
1847
|
+
errorItems
|
|
1848
|
+
};
|
|
1849
|
+
return result;
|
|
1968
1850
|
}
|
|
1969
1851
|
function zohoCrmMultiRecordResult(input, results) {
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1852
|
+
const successItems = [];
|
|
1853
|
+
const errorItems = [];
|
|
1854
|
+
input.forEach((x, i) => {
|
|
1855
|
+
const result = results[i];
|
|
1856
|
+
if (result.status === ZOHO_SUCCESS_STATUS) {
|
|
1857
|
+
successItems.push({
|
|
1858
|
+
input: x,
|
|
1859
|
+
result: result
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
else {
|
|
1863
|
+
errorItems.push({
|
|
1864
|
+
input: x,
|
|
1865
|
+
result: result
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1869
|
+
const result = {
|
|
1870
|
+
successItems,
|
|
1871
|
+
errorItems
|
|
1872
|
+
};
|
|
1873
|
+
return result;
|
|
1991
1874
|
}
|
|
1992
1875
|
|
|
1993
1876
|
function zohoCrmCreateNotes(context) {
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
return zohoCrmMultiRecordResult(util.asArray(input.data), x.data);
|
|
1998
|
-
});
|
|
1877
|
+
return (input) => context.fetchJson(`/v2/${ZOHO_CRM_NOTES_MODULE}`, zohoCrmApiFetchJsonInput('POST', { data: input.data })).then((x) => {
|
|
1878
|
+
return zohoCrmMultiRecordResult(util.asArray(input.data), x.data);
|
|
1879
|
+
});
|
|
1999
1880
|
}
|
|
2000
1881
|
function zohoCrmDeleteNotes(context) {
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
return zohoCrmMultiRecordResult(util.asArray(input.ids), x.data);
|
|
2005
|
-
});
|
|
1882
|
+
return (input) => context.fetchJson(`/v2/${ZOHO_CRM_NOTES_MODULE}?${fetch.makeUrlSearchParams({ ids: input.ids })}`, zohoCrmApiFetchJsonInput('DELETE')).then((x) => {
|
|
1883
|
+
return zohoCrmMultiRecordResult(util.asArray(input.ids), x.data);
|
|
1884
|
+
});
|
|
2006
1885
|
}
|
|
2007
1886
|
function zohoCrmGetNotesForRecord(context) {
|
|
2008
|
-
|
|
2009
|
-
targetModule: ZOHO_CRM_NOTES_MODULE
|
|
2010
|
-
});
|
|
1887
|
+
return zohoCrmGetRelatedRecordsFunctionFactory(context)({ targetModule: ZOHO_CRM_NOTES_MODULE });
|
|
2011
1888
|
}
|
|
2012
1889
|
function zohoCrmGetNotesForRecordPageFactory(context) {
|
|
2013
|
-
|
|
1890
|
+
return zohoFetchPageFactory(zohoCrmGetNotesForRecord(context));
|
|
2014
1891
|
}
|
|
2015
1892
|
/**
|
|
2016
1893
|
* https://www.zoho.com/crm/developer/docs/api/v8/create-notes.html
|
|
@@ -2019,58 +1896,50 @@ function zohoCrmGetNotesForRecordPageFactory(context) {
|
|
|
2019
1896
|
* @returns
|
|
2020
1897
|
*/
|
|
2021
1898
|
function zohoCrmCreateNotesForRecord(context) {
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
Parent_Id
|
|
2034
|
-
}))
|
|
1899
|
+
const createNotesInstance = zohoCrmCreateNotes(context);
|
|
1900
|
+
return (input) => {
|
|
1901
|
+
const { module: se_module, id: Parent_Id, notes } = input;
|
|
1902
|
+
const createNotesRequest = {
|
|
1903
|
+
data: util.asArray(notes).map((x) => ({
|
|
1904
|
+
...x,
|
|
1905
|
+
se_module,
|
|
1906
|
+
Parent_Id
|
|
1907
|
+
}))
|
|
1908
|
+
};
|
|
1909
|
+
return createNotesInstance(createNotesRequest);
|
|
2035
1910
|
};
|
|
2036
|
-
return createNotesInstance(createNotesRequest);
|
|
2037
|
-
};
|
|
2038
1911
|
}
|
|
2039
1912
|
|
|
2040
1913
|
function zohoCrmCreateTagsForModule(context) {
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
1914
|
+
return (input) => context
|
|
1915
|
+
.fetchJson(`/v8/settings/tags?${fetch.makeUrlSearchParams({ module: input.module })}`, zohoCrmApiFetchJsonInput('POST', { tags: util.asArray(input.tags) }))
|
|
1916
|
+
.catch((e) => {
|
|
1917
|
+
let result;
|
|
1918
|
+
if (e instanceof ZohoServerFetchResponseError) {
|
|
1919
|
+
const tags = e.data?.tags;
|
|
1920
|
+
if (Array.isArray(tags)) {
|
|
1921
|
+
result = {
|
|
1922
|
+
tags
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
if (!result) {
|
|
1927
|
+
throw e;
|
|
1928
|
+
}
|
|
1929
|
+
return result;
|
|
1930
|
+
})
|
|
1931
|
+
.then((x) => {
|
|
1932
|
+
const result = zohoCrmMultiRecordResult(util.asArray(input.tags), x.tags);
|
|
1933
|
+
const { included: duplicateErrorItems, excluded: otherErrorItems } = util.separateValues(result.errorItems, (x) => {
|
|
1934
|
+
return x.result.code === ZOHO_DUPLICATE_DATA_ERROR_CODE;
|
|
1935
|
+
});
|
|
1936
|
+
return {
|
|
1937
|
+
...result,
|
|
1938
|
+
errorItems: otherErrorItems,
|
|
1939
|
+
duplicateErrorItems,
|
|
1940
|
+
allErrorItems: result.errorItems
|
|
2052
1941
|
};
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
if (!result) {
|
|
2056
|
-
throw e;
|
|
2057
|
-
}
|
|
2058
|
-
return result;
|
|
2059
|
-
}).then(x => {
|
|
2060
|
-
const result = zohoCrmMultiRecordResult(util.asArray(input.tags), x.tags);
|
|
2061
|
-
const {
|
|
2062
|
-
included: duplicateErrorItems,
|
|
2063
|
-
excluded: otherErrorItems
|
|
2064
|
-
} = util.separateValues(result.errorItems, x => {
|
|
2065
|
-
return x.result.code === ZOHO_DUPLICATE_DATA_ERROR_CODE;
|
|
2066
1942
|
});
|
|
2067
|
-
return {
|
|
2068
|
-
...result,
|
|
2069
|
-
errorItems: otherErrorItems,
|
|
2070
|
-
duplicateErrorItems,
|
|
2071
|
-
allErrorItems: result.errorItems
|
|
2072
|
-
};
|
|
2073
|
-
});
|
|
2074
1943
|
}
|
|
2075
1944
|
/**
|
|
2076
1945
|
* Deletes a single tag by ID.
|
|
@@ -2083,7 +1952,7 @@ function zohoCrmCreateTagsForModule(context) {
|
|
|
2083
1952
|
* @returns
|
|
2084
1953
|
*/
|
|
2085
1954
|
function zohoCrmDeleteTag(context) {
|
|
2086
|
-
|
|
1955
|
+
return (input) => context.fetchJson(`/v8/settings/tags/${input.id}`, zohoCrmApiFetchJsonInput('DELETE')).then((x) => x.tags);
|
|
2087
1956
|
}
|
|
2088
1957
|
/**
|
|
2089
1958
|
* Returns the list of tags within a module.
|
|
@@ -2094,19 +1963,16 @@ function zohoCrmDeleteTag(context) {
|
|
|
2094
1963
|
* @returns
|
|
2095
1964
|
*/
|
|
2096
1965
|
function zohoCrmGetTagsForModule(context) {
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
data: x.tags
|
|
2105
|
-
};
|
|
2106
|
-
});
|
|
1966
|
+
return (input) => context.fetchJson(`/v8/settings/tags?${fetch.makeUrlSearchParams({ module: input.module, my_tags: input.my_tags })}`, zohoCrmApiFetchJsonInput('GET')).then((x) => {
|
|
1967
|
+
// NOTE: This doesn't follow the api documentation, and instead is a normal page result except it has "tags" instead of "data".
|
|
1968
|
+
return {
|
|
1969
|
+
...x,
|
|
1970
|
+
data: x.tags
|
|
1971
|
+
};
|
|
1972
|
+
});
|
|
2107
1973
|
}
|
|
2108
1974
|
function zohoCrmGetTagsForModulePageFactory(context) {
|
|
2109
|
-
|
|
1975
|
+
return zohoFetchPageFactory(zohoCrmGetTagsForModule(context));
|
|
2110
1976
|
}
|
|
2111
1977
|
// MARK: Add Tag To Record
|
|
2112
1978
|
/**
|
|
@@ -2122,33 +1988,31 @@ const ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
|
2122
1988
|
* @returns
|
|
2123
1989
|
*/
|
|
2124
1990
|
function zohoCrmAddTagsToRecords(context) {
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
1991
|
+
return (input) => {
|
|
1992
|
+
return context.fetchJson(`/v8/${input.module}/actions/add_tags`, zohoCrmApiFetchJsonInput('POST', zohoCrmAddTagsToRecordsRequestBody(input))).then((x) => {
|
|
1993
|
+
const resultInputMap = x.data.map(() => input); // assign "input" to each value for now
|
|
1994
|
+
return zohoCrmMultiRecordResult(resultInputMap, x.data);
|
|
1995
|
+
});
|
|
1996
|
+
};
|
|
2131
1997
|
}
|
|
2132
1998
|
function zohoCrmAddTagsToRecordsRequestBody(input) {
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
1999
|
+
if (Array.isArray(input.ids) && input.ids.length > ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED) {
|
|
2000
|
+
throw new Error(`Cannot add/remove tags from more than ${ZOHO_CRM_ADD_TAGS_TO_RECORDS_MAX_IDS_ALLOWED} records at once.`);
|
|
2001
|
+
}
|
|
2002
|
+
const tags = [...util.asArray(input.tags)];
|
|
2003
|
+
const tagNames = new Set(tags.map((x) => x.name));
|
|
2004
|
+
if (input.tag_names) {
|
|
2005
|
+
util.asArray(input.tag_names).forEach((x) => {
|
|
2006
|
+
if (!tagNames.has(x)) {
|
|
2007
|
+
tags.push({ name: x });
|
|
2008
|
+
tagNames.add(x);
|
|
2009
|
+
}
|
|
2143
2010
|
});
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
tags,
|
|
2150
|
-
ids: util.asArray(input.ids)
|
|
2151
|
-
};
|
|
2011
|
+
}
|
|
2012
|
+
return {
|
|
2013
|
+
tags,
|
|
2014
|
+
ids: util.asArray(input.ids)
|
|
2015
|
+
};
|
|
2152
2016
|
}
|
|
2153
2017
|
// MARK: Remove Tag From Record
|
|
2154
2018
|
/**
|
|
@@ -2164,71 +2028,61 @@ const ZOHO_CRM_REMOVE_TAGS_FROM_RECORDS_MAX_IDS_ALLOWED = 100;
|
|
|
2164
2028
|
* @returns
|
|
2165
2029
|
*/
|
|
2166
2030
|
function zohoCrmRemoveTagsFromRecords(context) {
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2031
|
+
return (input) => {
|
|
2032
|
+
return context.fetchJson(`/v8/${input.module}/actions/remove_tags`, zohoCrmApiFetchJsonInput('POST', zohoCrmAddTagsToRecordsRequestBody(input))).then((x) => {
|
|
2033
|
+
const resultInputMap = x.data.map(() => input); // assign "input" to each value for now
|
|
2034
|
+
return zohoCrmMultiRecordResult(resultInputMap, x.data);
|
|
2035
|
+
});
|
|
2036
|
+
};
|
|
2173
2037
|
}
|
|
2174
2038
|
|
|
2175
2039
|
function zohoCrmFactory(factoryConfig) {
|
|
2176
|
-
|
|
2177
|
-
accountsContext
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2040
|
+
const { accountsContext } = factoryConfig;
|
|
2041
|
+
const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
|
|
2042
|
+
const fetchHandler = zohoRateLimitedFetchHandler(factoryConfig.rateLimiterConfig);
|
|
2043
|
+
const { logZohoServerErrorFunction, fetchFactory = (input) => fetch.fetchApiFetchService.makeFetch({
|
|
2044
|
+
baseUrl: input.apiUrl,
|
|
2045
|
+
baseRequest: async () => ({
|
|
2046
|
+
headers: {
|
|
2047
|
+
'Content-Type': 'application/json',
|
|
2048
|
+
Authorization: `Bearer ${await accessTokenStringFactory()}`
|
|
2049
|
+
}
|
|
2050
|
+
}),
|
|
2051
|
+
fetchHandler,
|
|
2052
|
+
timeout: 20 * 1000, // 20 second timeout
|
|
2053
|
+
requireOkResponse: true, // enforce ok response
|
|
2054
|
+
useTimeout: true // use timeout
|
|
2055
|
+
}) } = factoryConfig;
|
|
2056
|
+
return (config) => {
|
|
2057
|
+
if (!config.apiUrl) {
|
|
2058
|
+
throw new Error('ZohoConfig missing api url.');
|
|
2189
2059
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
handleFetchJsonParseErrorFunction: fetch.returnNullHandleFetchJsonParseErrorFunction
|
|
2216
|
-
});
|
|
2217
|
-
const crmContext = {
|
|
2218
|
-
fetch: fetch$1,
|
|
2219
|
-
fetchJson,
|
|
2220
|
-
accessTokenStringFactory,
|
|
2221
|
-
config: {
|
|
2222
|
-
...config,
|
|
2223
|
-
apiUrl
|
|
2224
|
-
},
|
|
2225
|
-
zohoRateLimiter: fetchHandler._rateLimiter
|
|
2226
|
-
};
|
|
2227
|
-
const zohoCrm = {
|
|
2228
|
-
crmContext
|
|
2060
|
+
const apiUrl = zohoCrmConfigApiUrl(config.apiUrl);
|
|
2061
|
+
const baseFetch = fetchFactory({ apiUrl });
|
|
2062
|
+
const fetch$1 = handleZohoCrmErrorFetch(baseFetch, logZohoServerErrorFunction, (x) => {
|
|
2063
|
+
if (x instanceof ZohoInvalidTokenError) {
|
|
2064
|
+
accountsContext.loadAccessToken.resetAccessToken();
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
2067
|
+
const fetchJson = fetch.fetchJsonFunction(fetch$1, {
|
|
2068
|
+
interceptJsonResponse: interceptZohoCrm200StatusWithErrorResponse, // intercept errors that return status 200
|
|
2069
|
+
handleFetchJsonParseErrorFunction: fetch.returnNullHandleFetchJsonParseErrorFunction
|
|
2070
|
+
});
|
|
2071
|
+
const crmContext = {
|
|
2072
|
+
fetch: fetch$1,
|
|
2073
|
+
fetchJson,
|
|
2074
|
+
accessTokenStringFactory,
|
|
2075
|
+
config: {
|
|
2076
|
+
...config,
|
|
2077
|
+
apiUrl
|
|
2078
|
+
},
|
|
2079
|
+
zohoRateLimiter: fetchHandler._rateLimiter
|
|
2080
|
+
};
|
|
2081
|
+
const zohoCrm = {
|
|
2082
|
+
crmContext
|
|
2083
|
+
};
|
|
2084
|
+
return zohoCrm;
|
|
2229
2085
|
};
|
|
2230
|
-
return zohoCrm;
|
|
2231
|
-
};
|
|
2232
2086
|
}
|
|
2233
2087
|
|
|
2234
2088
|
/**
|
|
@@ -2242,28 +2096,21 @@ const ZOHO_CRM_TAG_NAME_MAX_LENGTH = 25;
|
|
|
2242
2096
|
* @returns
|
|
2243
2097
|
*/
|
|
2244
2098
|
function zohoAccountsAccessToken(context) {
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
refreshToken: inputRefreshToken
|
|
2254
|
-
} = input ?? {};
|
|
2255
|
-
const clientId = client?.clientId ?? configClientId;
|
|
2256
|
-
const clientSecret = client?.clientSecret ?? configClientSecret;
|
|
2257
|
-
const refreshToken = inputRefreshToken ?? configRefreshToken;
|
|
2258
|
-
return context.fetchJson(`/oauth/v2/token?grant_type=refresh_token&client_id=${clientId}&client_secret=${clientSecret}&refresh_token=${refreshToken}`, zohoAccountsApiFetchJsonInput('POST'));
|
|
2259
|
-
};
|
|
2099
|
+
return (input) => {
|
|
2100
|
+
const { clientId: configClientId, clientSecret: configClientSecret, refreshToken: configRefreshToken } = context.config;
|
|
2101
|
+
const { client, refreshToken: inputRefreshToken } = input ?? {};
|
|
2102
|
+
const clientId = client?.clientId ?? configClientId;
|
|
2103
|
+
const clientSecret = client?.clientSecret ?? configClientSecret;
|
|
2104
|
+
const refreshToken = inputRefreshToken ?? configRefreshToken;
|
|
2105
|
+
return context.fetchJson(`/oauth/v2/token?grant_type=refresh_token&client_id=${clientId}&client_secret=${clientSecret}&refresh_token=${refreshToken}`, zohoAccountsApiFetchJsonInput('POST'));
|
|
2106
|
+
};
|
|
2260
2107
|
}
|
|
2261
2108
|
function zohoAccountsApiFetchJsonInput(method, body) {
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2109
|
+
const result = {
|
|
2110
|
+
method,
|
|
2111
|
+
body
|
|
2112
|
+
};
|
|
2113
|
+
return result;
|
|
2267
2114
|
}
|
|
2268
2115
|
|
|
2269
2116
|
/**
|
|
@@ -2271,89 +2118,78 @@ function zohoAccountsApiFetchJsonInput(method, body) {
|
|
|
2271
2118
|
*/
|
|
2272
2119
|
const ZOHO_ACCOUNTS_US_API_URL = 'https://accounts.zoho.com';
|
|
2273
2120
|
function zohoAccountsConfigApiUrl(input) {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2121
|
+
switch (input) {
|
|
2122
|
+
case 'us':
|
|
2123
|
+
return ZOHO_ACCOUNTS_US_API_URL;
|
|
2124
|
+
default:
|
|
2125
|
+
return input;
|
|
2126
|
+
}
|
|
2280
2127
|
}
|
|
2281
2128
|
|
|
2282
2129
|
function zohoAccountsFactory(factoryConfig) {
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2130
|
+
const fetchHandler = zohoRateLimitedFetchHandler();
|
|
2131
|
+
const { logZohoServerErrorFunction, fetchFactory = (input) => fetch.fetchApiFetchService.makeFetch({
|
|
2132
|
+
baseUrl: input.apiUrl,
|
|
2133
|
+
baseRequest: {
|
|
2134
|
+
headers: {
|
|
2135
|
+
'Content-Type': 'application/json'
|
|
2136
|
+
}
|
|
2137
|
+
},
|
|
2138
|
+
fetchHandler,
|
|
2139
|
+
timeout: 20 * 1000, // 20 second timeout
|
|
2140
|
+
requireOkResponse: true, // enforce ok response
|
|
2141
|
+
useTimeout: true // use timeout
|
|
2142
|
+
}) } = factoryConfig;
|
|
2143
|
+
return (config) => {
|
|
2144
|
+
if (!config.refreshToken) {
|
|
2145
|
+
throw new Error('ZohoAccountsConfig missing refreshToken.');
|
|
2291
2146
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
return config.accessTokenCache?.clearCachedToken();
|
|
2338
|
-
};
|
|
2339
|
-
const loadAccessToken = zohoAccountsZohoAccessTokenFactory({
|
|
2340
|
-
tokenRefresher,
|
|
2341
|
-
accessTokenCache: config.accessTokenCache
|
|
2342
|
-
});
|
|
2343
|
-
const accountsContext = {
|
|
2344
|
-
fetch: fetch$1,
|
|
2345
|
-
fetchJson,
|
|
2346
|
-
loadAccessToken,
|
|
2347
|
-
config: {
|
|
2348
|
-
...config,
|
|
2349
|
-
apiUrl
|
|
2350
|
-
}
|
|
2351
|
-
};
|
|
2352
|
-
const zohoAccounts = {
|
|
2353
|
-
accountsContext
|
|
2147
|
+
else if (!config.clientId) {
|
|
2148
|
+
throw new Error('ZohoAccountsConfig missing clientId.');
|
|
2149
|
+
}
|
|
2150
|
+
else if (!config.clientSecret) {
|
|
2151
|
+
throw new Error('ZohoAccountsConfig missing clientSecret.');
|
|
2152
|
+
}
|
|
2153
|
+
const apiUrl = zohoAccountsConfigApiUrl(config.apiUrl ?? 'us');
|
|
2154
|
+
const baseFetch = fetchFactory({ apiUrl });
|
|
2155
|
+
const fetch$1 = handleZohoAccountsErrorFetch(baseFetch, logZohoServerErrorFunction);
|
|
2156
|
+
const fetchJson = fetch.fetchJsonFunction(fetch$1, {
|
|
2157
|
+
interceptJsonResponse: interceptZohoAccounts200StatusWithErrorResponse, // intercept errors that return status 200
|
|
2158
|
+
handleFetchJsonParseErrorFunction: fetch.returnNullHandleFetchJsonParseErrorFunction
|
|
2159
|
+
});
|
|
2160
|
+
const tokenRefresher = async () => {
|
|
2161
|
+
const createdAt = new Date().getTime();
|
|
2162
|
+
const { access_token, api_domain, scope, expires_in } = await zohoAccountsAccessToken(accountsContext)();
|
|
2163
|
+
const result = {
|
|
2164
|
+
accessToken: access_token,
|
|
2165
|
+
apiDomain: api_domain,
|
|
2166
|
+
expiresIn: expires_in,
|
|
2167
|
+
expiresAt: new Date(createdAt + expires_in * util.MS_IN_SECOND),
|
|
2168
|
+
scope
|
|
2169
|
+
};
|
|
2170
|
+
return result;
|
|
2171
|
+
};
|
|
2172
|
+
tokenRefresher.resetAccessToken = async () => {
|
|
2173
|
+
return config.accessTokenCache?.clearCachedToken();
|
|
2174
|
+
};
|
|
2175
|
+
const loadAccessToken = zohoAccountsZohoAccessTokenFactory({
|
|
2176
|
+
tokenRefresher,
|
|
2177
|
+
accessTokenCache: config.accessTokenCache
|
|
2178
|
+
});
|
|
2179
|
+
const accountsContext = {
|
|
2180
|
+
fetch: fetch$1,
|
|
2181
|
+
fetchJson,
|
|
2182
|
+
loadAccessToken,
|
|
2183
|
+
config: {
|
|
2184
|
+
...config,
|
|
2185
|
+
apiUrl
|
|
2186
|
+
}
|
|
2187
|
+
};
|
|
2188
|
+
const zohoAccounts = {
|
|
2189
|
+
accountsContext
|
|
2190
|
+
};
|
|
2191
|
+
return zohoAccounts;
|
|
2354
2192
|
};
|
|
2355
|
-
return zohoAccounts;
|
|
2356
|
-
};
|
|
2357
2193
|
}
|
|
2358
2194
|
/**
|
|
2359
2195
|
* Creates a ZohoAccountsZohoAccessTokenFactoryConfig
|
|
@@ -2362,58 +2198,56 @@ function zohoAccountsFactory(factoryConfig) {
|
|
|
2362
2198
|
* @returns
|
|
2363
2199
|
*/
|
|
2364
2200
|
function zohoAccountsZohoAccessTokenFactory(config) {
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
* Caches the token internally here until it expires.
|
|
2373
|
-
*/
|
|
2374
|
-
let currentToken = null;
|
|
2375
|
-
const resetAccessToken = async () => {
|
|
2376
|
-
currentToken = null;
|
|
2377
|
-
};
|
|
2378
|
-
const fn = async () => {
|
|
2379
|
-
// load from cache
|
|
2380
|
-
if (!currentToken) {
|
|
2381
|
-
const cachedToken = await accessTokenCache?.loadCachedToken();
|
|
2382
|
-
if (cachedToken) {
|
|
2383
|
-
currentToken = cachedToken;
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
// check expiration
|
|
2387
|
-
if (currentToken != null) {
|
|
2388
|
-
const isExpired = new Date().getTime() + tokenExpirationBuffer >= currentToken.expiresAt.getTime();
|
|
2389
|
-
if (isExpired) {
|
|
2201
|
+
const { tokenRefresher, accessTokenCache, tokenExpirationBuffer: inputTokenExpirationBuffer } = config;
|
|
2202
|
+
const tokenExpirationBuffer = inputTokenExpirationBuffer ?? util.MS_IN_MINUTE;
|
|
2203
|
+
/**
|
|
2204
|
+
* Caches the token internally here until it expires.
|
|
2205
|
+
*/
|
|
2206
|
+
let currentToken = null;
|
|
2207
|
+
const resetAccessToken = async () => {
|
|
2390
2208
|
currentToken = null;
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
throw new ZohoAccountsAuthFailureError('Token Refresh Failed');
|
|
2400
|
-
}
|
|
2401
|
-
if (currentToken) {
|
|
2402
|
-
try {
|
|
2403
|
-
await accessTokenCache?.updateCachedToken(currentToken);
|
|
2404
|
-
} catch (e) {
|
|
2405
|
-
// do nothing
|
|
2209
|
+
};
|
|
2210
|
+
const fn = async () => {
|
|
2211
|
+
// load from cache
|
|
2212
|
+
if (!currentToken) {
|
|
2213
|
+
const cachedToken = await accessTokenCache?.loadCachedToken();
|
|
2214
|
+
if (cachedToken) {
|
|
2215
|
+
currentToken = cachedToken;
|
|
2216
|
+
}
|
|
2406
2217
|
}
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2218
|
+
// check expiration
|
|
2219
|
+
if (currentToken != null) {
|
|
2220
|
+
const isExpired = new Date().getTime() + tokenExpirationBuffer >= currentToken.expiresAt.getTime();
|
|
2221
|
+
if (isExpired) {
|
|
2222
|
+
currentToken = null;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
// load from source
|
|
2226
|
+
if (!currentToken) {
|
|
2227
|
+
try {
|
|
2228
|
+
currentToken = await tokenRefresher();
|
|
2229
|
+
}
|
|
2230
|
+
catch (e) {
|
|
2231
|
+
console.error(`zohoAccountsZohoAccessTokenFactory(): Failed retrieving new token from tokenRefresher: `, e);
|
|
2232
|
+
throw new ZohoAccountsAuthFailureError('Token Refresh Failed');
|
|
2233
|
+
}
|
|
2234
|
+
if (currentToken) {
|
|
2235
|
+
try {
|
|
2236
|
+
await accessTokenCache?.updateCachedToken(currentToken);
|
|
2237
|
+
}
|
|
2238
|
+
catch (e) {
|
|
2239
|
+
// do nothing
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
return currentToken;
|
|
2244
|
+
};
|
|
2245
|
+
fn.resetAccessToken = resetAccessToken;
|
|
2246
|
+
return fn;
|
|
2413
2247
|
}
|
|
2414
2248
|
|
|
2415
2249
|
function safeZohoDateTimeString(date) {
|
|
2416
|
-
|
|
2250
|
+
return date != null ? zohoDateTimeString(date) : date;
|
|
2417
2251
|
}
|
|
2418
2252
|
/**
|
|
2419
2253
|
* Converts the input date to a Zoho date.
|
|
@@ -2422,8 +2256,8 @@ function safeZohoDateTimeString(date) {
|
|
|
2422
2256
|
* @returns
|
|
2423
2257
|
*/
|
|
2424
2258
|
function zohoDateTimeString(date) {
|
|
2425
|
-
|
|
2426
|
-
|
|
2259
|
+
const isoDate = date.toISOString();
|
|
2260
|
+
return isoDate.substring(0, isoDate.length - 5) + 'Z';
|
|
2427
2261
|
}
|
|
2428
2262
|
|
|
2429
2263
|
exports.DEFAULT_ZOHO_API_RATE_LIMIT = DEFAULT_ZOHO_API_RATE_LIMIT;
|