@itentialopensource/adapter-utils 4.45.7 → 4.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,34 @@
1
1
 
2
+ ## 4.48.0 [08-16-2022]
3
+
4
+ * Changes to support entitypath object with multiple paths
5
+
6
+ Closes ADAPT-2331
7
+
8
+ See merge request itentialopensource/adapter-utils!236
9
+
10
+ ---
11
+
12
+ ## 4.47.0 [08-13-2022]
13
+
14
+ * Add SSO capability into service instance config
15
+
16
+ Closes ADAPT-2328
17
+
18
+ See merge request itentialopensource/adapter-utils!235
19
+
20
+ ---
21
+
22
+ ## 4.46.0 [07-27-2022]
23
+
24
+ * Added code to skip split string on dot for special cases
25
+
26
+ Closes ADAPT-2266
27
+
28
+ See merge request itentialopensource/adapter-utils!234
29
+
30
+ ---
31
+
2
32
  ## 4.45.7 [07-25-2022]
3
33
 
4
34
  * Fix issue on no token where it takes exception
@@ -45,6 +45,7 @@ let host = null;
45
45
  let port = null;
46
46
  let basepath = null;
47
47
  let version = null;
48
+ let choosepath = null;
48
49
  let authMethod = null;
49
50
  let authField = null;
50
51
  let authFormat = null;
@@ -62,6 +63,7 @@ let tokenTimeout = -1;
62
63
  let tokenError = 401;
63
64
  let tokenPath = null;
64
65
  let tokenCache = 'local';
66
+ let sso = null;
65
67
  const tokenList = [];
66
68
  const tokenlock = 0;
67
69
  let stub = false;
@@ -1502,7 +1504,7 @@ function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
1502
1504
 
1503
1505
  try {
1504
1506
  // Get the entity schema from the file system
1505
- return propUtilInst.getEntitySchema('.system', 'getToken', this.dbUtil, (tokenSchema, healthError) => {
1507
+ return propUtilInst.getEntitySchema('.system', 'getToken', choosepath, this.dbUtil, (tokenSchema, healthError) => {
1506
1508
  if (healthError || !tokenSchema || Object.keys(tokenSchema).length === 0) {
1507
1509
  log.debug(`${origin}: Using adapter properties for token information`);
1508
1510
  tokenSchema = null;
@@ -1646,6 +1648,28 @@ function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
1646
1648
  }
1647
1649
 
1648
1650
  // specific token properties override everything (Single Sign On System)
1651
+ if (sso && sso.host) {
1652
+ options.hostname = sso.host;
1653
+ }
1654
+ if (sso && sso.port) {
1655
+ options.port = sso.port;
1656
+ }
1657
+ if (sso && sso.protocol) {
1658
+ // need to put protocol in token schema
1659
+ if (!tokenSchema) {
1660
+ tokenSchema = {
1661
+ sso: {
1662
+ protocol: sso.protocol
1663
+ }
1664
+ };
1665
+ } else if (tokenSchema && !tokenSchema.sso) {
1666
+ tokenSchema.sso = {
1667
+ protocol: sso.protocol
1668
+ };
1669
+ } else if (tokenSchema && tokenSchema.sso && !tokenSchema.sso.protocol) {
1670
+ tokenSchema.sso.protocol = sso.protocol;
1671
+ }
1672
+ }
1649
1673
  if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host) {
1650
1674
  options.hostname = tokenSchema.sso.host;
1651
1675
  }
@@ -3294,6 +3318,11 @@ class ConnectorRest {
3294
3318
  version = props.version;
3295
3319
  }
3296
3320
 
3321
+ // set the choosepath (optional - default is null)
3322
+ if (typeof props.choosepath === 'string') {
3323
+ choosepath = props.choosepath;
3324
+ }
3325
+
3297
3326
  if (props.authentication) {
3298
3327
  // set the authentication method (required - default is null)
3299
3328
  if (typeof props.authentication.auth_method === 'string') {
@@ -3347,19 +3376,19 @@ class ConnectorRest {
3347
3376
  tokenTimeout = Number(props.authentication.token_timeout);
3348
3377
  }
3349
3378
 
3350
- // set the token cache (required - default is local)
3379
+ // set the token cache (optional - default is local)
3351
3380
  if (typeof props.authentication.token_cache === 'string') {
3352
3381
  tokenCache = props.authentication.token_cache;
3353
3382
  }
3354
3383
 
3355
- // set the auth field (required - default is null)
3384
+ // set the auth field (optional - default is null)
3356
3385
  if (typeof props.authentication.auth_field === 'string') {
3357
3386
  authField = [props.authentication.auth_field];
3358
3387
  } else if (Array.isArray(props.authentication.auth_field)) {
3359
3388
  authField = props.authentication.auth_field;
3360
3389
  }
3361
3390
 
3362
- // set the auth format (required - default is null)
3391
+ // set the auth format (optional - default is null)
3363
3392
  if (typeof props.authentication.auth_field_format === 'string') {
3364
3393
  authFormat = [props.authentication.auth_field_format];
3365
3394
  } else if (Array.isArray(props.authentication.auth_field_format)) {
@@ -3371,20 +3400,25 @@ class ConnectorRest {
3371
3400
  authLogging = props.authentication.auth_logging;
3372
3401
  }
3373
3402
 
3374
- // set the client id (required - default is null)
3403
+ // set the client id (optional - default is null)
3375
3404
  if (typeof props.authentication.client_id === 'string') {
3376
3405
  clientId = props.authentication.client_id;
3377
3406
  }
3378
3407
 
3379
- // set the client secret (required - default is null)
3408
+ // set the client secret (optional - default is null)
3380
3409
  if (typeof props.authentication.client_secret === 'string') {
3381
3410
  clientSecret = props.authentication.client_secret;
3382
3411
  }
3383
3412
 
3384
- // set the grant type (required - default is null)
3413
+ // set the grant type (optional - default is null)
3385
3414
  if (typeof props.authentication.grant_type === 'string') {
3386
3415
  grantType = props.authentication.grant_type;
3387
3416
  }
3417
+
3418
+ // set the sso (optional - default is null)
3419
+ if (props.authentication.sso && typeof props.authentication.sso === 'object') {
3420
+ sso = props.authentication.sso;
3421
+ }
3388
3422
  }
3389
3423
 
3390
3424
  // set the stub mode (optional - default is false)
@@ -30,7 +30,7 @@ class AdapterPropertyUtil {
30
30
  *
31
31
  * @return {Object} entitySchema - the entity schema object
32
32
  */
33
- getEntitySchemaFromFS(entityName, actionName) {
33
+ getEntitySchemaFromFS(entityName, actionName, choosepath) {
34
34
  const origin = `${this.myid}-propertyUtil-getEntitySchemaFromFS`;
35
35
  log.trace(origin);
36
36
 
@@ -264,6 +264,32 @@ class AdapterPropertyUtil {
264
264
  entitySchema.responseObjects = [];
265
265
  entitySchema.mockresponses = [];
266
266
 
267
+ // if the entitypath is an object instead of a string need to figure out which path to use
268
+ if (actionInfo.entitypath && typeof actionInfo.entitypath === 'object') {
269
+ const ekeys = Object.keys(actionInfo.entitypath);
270
+ if (ekeys.length > 0) {
271
+ // the first one is the default so if we do not have a match that is the one that will be used
272
+ entitySchema.entitypath = actionInfo.entitypath[ekeys[0]];
273
+ for (let ep = 1; ep < ekeys.length; ep += 1) {
274
+ // see if the key matches the choosepath value, if it does set the entitypath
275
+ if (choosepath && ekeys[ep] === choosepath) {
276
+ entitySchema.entitypath = actionInfo.entitypath[ekeys[ep]];
277
+ break;
278
+ }
279
+ }
280
+ } else {
281
+ // add the specific pieces of the error object
282
+ errorObj.type = 'Invalid Action File';
283
+ errorObj.vars = ['missing entity path', actionFile];
284
+
285
+ // log (if not system entity) and throw the error
286
+ if (entityName !== '.system') {
287
+ log.error(`${origin}: Entity ${entityName} action ${actionName} - missing entity path`);
288
+ }
289
+ throw new Error(JSON.stringify(errorObj));
290
+ }
291
+ }
292
+
267
293
  // if info provided, replace the defaults
268
294
  if (actionInfo.querykey) {
269
295
  entitySchema.querykey = actionInfo.querykey;
@@ -399,7 +425,7 @@ class AdapterPropertyUtil {
399
425
  *
400
426
  * @return {Object} entitySchema - the entity schema object
401
427
  */
402
- getEntitySchemaFromDB(dbObj, entityName, actionName, dbUtils, callback) {
428
+ getEntitySchemaFromDB(dbObj, entityName, actionName, choosepath, dbUtils, callback) {
403
429
  const origin = `${this.myid}-propertyUtil-getEntitySchemaFromDB`;
404
430
  log.trace(origin);
405
431
 
@@ -672,6 +698,33 @@ class AdapterPropertyUtil {
672
698
  entitySchema.responseObjects = [];
673
699
  entitySchema.mockresponses = [];
674
700
 
701
+ // if the entitypath is an object instead of a string need to figure out which path to use
702
+ if (actionInfo.entitypath && typeof actionInfo.entitypath === 'object') {
703
+ const ekeys = Object.keys(actionInfo.entitypath);
704
+ if (ekeys.length > 0) {
705
+ // the first one is the default so if we do not have a match that is the one that will be used
706
+ entitySchema.entitypath = actionInfo.entitypath[ekeys[0]];
707
+ for (let ep = 1; ep < ekeys.length; ep += 1) {
708
+ // see if the key matches the choosepath value, if it does set the entitypath
709
+ if (choosepath && ekeys[ep] === choosepath) {
710
+ entitySchema.entitypath = actionInfo.entitypath[ekeys[ep]];
711
+ break;
712
+ }
713
+ }
714
+ } else {
715
+ // add the specific pieces of the error object
716
+ errorObj.type = 'Invalid Action File';
717
+ errorObj.vars = ['missing entity path', entityName];
718
+
719
+ // log (if not system entity) and return the error
720
+ if (entityName !== '.system') {
721
+ log.error(`${origin}: Entity ${entityName} action ${actionName} - missing entity path`);
722
+ errorObj.error = [`${origin}: Entity ${entityName} action ${actionName} - missing entity path`];
723
+ }
724
+ return callback(null, errorObj);
725
+ }
726
+ }
727
+
675
728
  // if info provided, replace the defaults
676
729
  if (actionInfo.querykey) {
677
730
  entitySchema.querykey = actionInfo.querykey;
@@ -796,14 +849,14 @@ class AdapterPropertyUtil {
796
849
  *
797
850
  * @return {Object} entitySchema - the entity schema object
798
851
  */
799
- getEntitySchema(entityName, actionName, dbUtils, callback) {
852
+ getEntitySchema(entityName, actionName, choosepath, dbUtils, callback) {
800
853
  const origin = `${this.myid}-propertyUtil-getEntitySchema`;
801
854
  log.trace(origin);
802
855
 
803
856
  // need to try to get the entity schema from the adapter database
804
857
  try {
805
858
  // call to get the adapter schema from the database
806
- return this.getEntitySchemaFromDB(null, entityName, actionName, dbUtils, (dbresp, dberror) => {
859
+ return this.getEntitySchemaFromDB(null, entityName, actionName, choosepath, dbUtils, (dbresp, dberror) => {
807
860
  // if we got an error back - just means db config not in place
808
861
  if (dberror || !dbresp || (dbresp && Object.keys(dbresp).length === 0)) {
809
862
  log.debug('unable to get adapter config from adapter database');
@@ -816,7 +869,7 @@ class AdapterPropertyUtil {
816
869
  };
817
870
 
818
871
  // need to try to get the entity schema from the iap database
819
- return this.getEntitySchemaFromDB(iapDB, entityName, actionName, dbUtils, (iapdbresp, iapdberror) => {
872
+ return this.getEntitySchemaFromDB(iapDB, entityName, actionName, choosepath, dbUtils, (iapdbresp, iapdberror) => {
820
873
  // if we got an error back - just means db config not in place
821
874
  if (iapdberror || !iapdbresp || (iapdbresp && Object.keys(iapdbresp).length === 0)) {
822
875
  log.debug('unable to get adapter config from iap database');
@@ -824,7 +877,7 @@ class AdapterPropertyUtil {
824
877
  // need to try to get the entity schema from the filesystem
825
878
  log.debug('returning adapter config from file system');
826
879
  try {
827
- return callback(this.getEntitySchemaFromFS(entityName, actionName), null);
880
+ return callback(this.getEntitySchemaFromFS(entityName, actionName, choosepath), null);
828
881
  } catch (exc) {
829
882
  log.error('Exception caught on File System');
830
883
  return callback(null, exc);
@@ -117,6 +117,11 @@ function walkThroughActionFiles(directory) {
117
117
  const actionSchema = JSON.parse(fs.readFileSync(actionSchemaFile, 'utf-8'));
118
118
  const entitydir = `${directory}/entities`;
119
119
 
120
+ // if there is no entity directory - return
121
+ if (!fs.existsSync(directory) || !fs.existsSync(entitydir)) {
122
+ return clean;
123
+ }
124
+
120
125
  // if there is an entity directory
121
126
  if (fs.statSync(directory).isDirectory() && fs.statSync(entitydir).isDirectory()) {
122
127
  const entities = fs.readdirSync(entitydir);
@@ -577,7 +582,7 @@ class RequestHandler {
577
582
  }
578
583
 
579
584
  // Get the entity schema from the file system
580
- return this.propUtil.getEntitySchema(entity, action, this.dbUtil, (entitySchema, entityError) => {
585
+ return this.propUtil.getEntitySchema(entity, action, this.props.choosepath, this.dbUtil, (entitySchema, entityError) => {
581
586
  // verify protocol for call
582
587
  if (entityError) {
583
588
  const errorObj = this.transUtil.checkAndReturn(entityError, origin, 'Issue identifiying request');
@@ -673,7 +678,7 @@ class RequestHandler {
673
678
  let prot = this.props.healthcheck.protocol;
674
679
 
675
680
  // Get the entity schema from the file system
676
- return this.propUtil.getEntitySchema('.system', 'healthcheck', this.dbUtil, (healthSchema, healthError) => {
681
+ return this.propUtil.getEntitySchema('.system', 'healthcheck', this.props.choosepath, this.dbUtil, (healthSchema, healthError) => {
677
682
  if (healthError || !healthSchema || Object.keys(healthSchema).length === 0) {
678
683
  log.debug(`${origin}: Using adapter properties for healthcheck information`);
679
684
  } else {
@@ -247,6 +247,7 @@ function extractObject(dataObj, entitySchema, dynamicFields) {
247
247
  log.trace(origin);
248
248
  const returnObj = {};
249
249
  let addFields = dynamicFields;
250
+ const regex = /(?<!\\)\./gm;
250
251
 
251
252
  // if no translation needed - just return the object
252
253
  if (Object.hasOwnProperty.call(entitySchema, 'translate')
@@ -278,7 +279,7 @@ function extractObject(dataObj, entitySchema, dynamicFields) {
278
279
  // if the external name is something get that field
279
280
  if (field.external_name) {
280
281
  // need to determine the field in the incoming object where the data is
281
- const externalPath = field.external_name.split('.');
282
+ const externalPath = field.external_name.split(regex).map((e) => (e.replace(/\\./g, '.')));
282
283
  let location = dataObj;
283
284
  let inField = null;
284
285
 
@@ -349,7 +350,7 @@ function extractObject(dataObj, entitySchema, dynamicFields) {
349
350
  // if the field is not in the schema - we need to add it
350
351
  // using the field name that came in since no translation
351
352
  if (field.external_name) {
352
- const externalPath = field.external_name.split('.');
353
+ const externalPath = field.external_name.split(regex).map((e) => (e.replace(/\\./g, '.')));
353
354
 
354
355
  if (externalPath[externalPath.length - 1] === objectKeys[o]) {
355
356
  found = true;
@@ -488,7 +489,7 @@ function extractJSONEntity(dataObj, entitySchema) {
488
489
  function buildObject(dataObj, entitySchema, dynamicFields) {
489
490
  const origin = `${id}-translatorUtil-buildObject`;
490
491
  log.trace(origin);
491
-
492
+ const regex = /(?<!\\)\./gm;
492
493
  const returnObj = {};
493
494
  let addFields = dynamicFields;
494
495
 
@@ -531,7 +532,7 @@ function buildObject(dataObj, entitySchema, dynamicFields) {
531
532
  // if in the data object, add to the system entity
532
533
  if (fieldValue !== null) {
533
534
  // need to determine the field in the object where the data should go
534
- const externalPath = field.external_name.split('.');
535
+ const externalPath = field.external_name.split(regex).map((e) => (e.replace(/\\./g, '.')));
535
536
  let location = returnObj;
536
537
 
537
538
  // get to the field in the object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itentialopensource/adapter-utils",
3
- "version": "4.45.7",
3
+ "version": "4.48.0",
4
4
  "description": "Itential Adapter Utility Libraries",
5
5
  "scripts": {
6
6
  "postinstall": "node utils/setup.js",
@@ -32,10 +32,12 @@
32
32
  ]
33
33
  },
34
34
  "entitypath": {
35
- "type": "string",
36
- "description": "the path to use for this action",
37
- "default": "GET",
38
- "pattern": "^({base_path}|\\/)[-a-zA-Z0-9!@$:&%_+.,~#\\/*=:]*({version})?([-a-zA-Z0-9!@$:&%_+.,~#\\/*=:]*({pathv[0-9]+})?)*(\\??[-a-zA-Z0-9!@$:&%_+.,\\(\\)~#\\/*=:]*({username})?[-a-zA-Z0-9!@$:&%_+.,\\(\\)~#\/*=:]*({password})?({query})?)?$",
35
+ "type": [
36
+ "string",
37
+ "object"
38
+ ],
39
+ "description": "the path(s) to use for this action",
40
+ "default": "",
39
41
  "examples": [
40
42
  "/api/devices{pathv1}{query}", "/api/devices{pathv1}/components{pathv2}{query}",
41
43
  "/api/devices", "/api/devices{query}"
@@ -18,6 +18,11 @@
18
18
  "minimum": 1,
19
19
  "maximum": 65535
20
20
  },
21
+ "choosepath": {
22
+ "type": "string",
23
+ "description": "choose the path to use -- requires entityPath choices",
24
+ "default": ""
25
+ },
21
26
  "base_path": {
22
27
  "type": "string",
23
28
  "description": "a base path that is consistent across api calls",
@@ -252,6 +257,34 @@
252
257
  "type": "string",
253
258
  "description": "The grant type for OAuth requests - can also provide in schema",
254
259
  "default": ""
260
+ },
261
+ "sso": {
262
+ "type": "object",
263
+ "properties": {
264
+ "protocol": {
265
+ "type": "string",
266
+ "description": "the protocol to request token from system",
267
+ "default": "",
268
+ "enum": [
269
+ "http", "https", ""
270
+ ]
271
+ },
272
+ "host": {
273
+ "type": "string",
274
+ "description": "hostname of the authentication system",
275
+ "default": "",
276
+ "examples": [
277
+ "systemx.customer.com"
278
+ ]
279
+ },
280
+ "port": {
281
+ "type": "integer",
282
+ "description": "port on which to connect to the authentication system",
283
+ "default": 0,
284
+ "minimum": 0,
285
+ "maximum": 65535
286
+ }
287
+ }
255
288
  }
256
289
  },
257
290
  "required": [
@@ -354,7 +387,8 @@
354
387
  },
355
388
  "query_object": {
356
389
  "type": "object",
357
- "description": "Query object { device: xxxxx } to be placed into the healthcheck, will be converted to query string by the adapter"
390
+ "description": "Query object { device: xxxxx } to be placed into the healthcheck, will be converted to query string by the adapter",
391
+ "default": {}
358
392
  }
359
393
  },
360
394
  "required": [
@@ -434,6 +468,7 @@
434
468
  "priorities": {
435
469
  "type": "array",
436
470
  "description": "define your priorities here",
471
+ "default": [],
437
472
  "items": {
438
473
  "type": "object",
439
474
  "properties": {
@@ -504,6 +539,7 @@
504
539
  "failover_codes": {
505
540
  "type": "array",
506
541
  "description": "An array of codes where it is ok to try another method",
542
+ "default": [],
507
543
  "items": {
508
544
  "type": "integer"
509
545
  }
@@ -521,19 +557,23 @@
521
557
  "properties": {
522
558
  "payload": {
523
559
  "type": "object",
524
- "description": "payload fields that will be appended to the provided payload (excluding GET calls)"
560
+ "description": "payload fields that will be appended to the provided payload (excluding GET calls)",
561
+ "default": {}
525
562
  },
526
563
  "uriOptions": {
527
564
  "type": "object",
528
- "description": "options that will be appended to all GET calls"
565
+ "description": "options that will be appended to all GET calls",
566
+ "default": {}
529
567
  },
530
568
  "addlHeaders": {
531
569
  "type": "object",
532
- "description": "headers that will be appended to the headers for the call"
570
+ "description": "headers that will be appended to the headers for the call",
571
+ "default": {}
533
572
  },
534
573
  "authData": {
535
574
  "type": "object",
536
- "description": "authentication data that will be appended to the payload for authentication calls"
575
+ "description": "authentication data that will be appended to the payload for authentication calls",
576
+ "default": {}
537
577
  }
538
578
  }
539
579
  },