@itentialopensource/adapter-utils 4.44.9 → 4.45.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/CHANGELOG.md CHANGED
@@ -1,4 +1,54 @@
1
1
 
2
+ ## 4.45.2 [12-09-2021]
3
+
4
+ * change for sending content-length with empty token body
5
+
6
+ Closes ADAPT-1889
7
+
8
+ See merge request itentialopensource/adapter-utils!228
9
+
10
+ ---
11
+
12
+ ## 4.45.1 [12-08-2021]
13
+
14
+ * Modified response handling on error to use the translator
15
+
16
+ Closes ADAPT-1876
17
+
18
+ See merge request itentialopensource/adapter-utils!225
19
+
20
+ ---
21
+
22
+ ## 4.45.0 [12-08-2021]
23
+
24
+ * changes for uriOptions and not encoding query params
25
+
26
+ Closes ADAPT-1866
27
+
28
+ See merge request itentialopensource/adapter-utils!227
29
+
30
+ ---
31
+
32
+ ## 4.44.11 [10-25-2021]
33
+
34
+ * change to the npm registry url
35
+
36
+ Closes ADAPT-1793
37
+
38
+ See merge request itentialopensource/adapter-utils!224
39
+
40
+ ---
41
+
42
+ ## 4.44.10 [10-25-2021]
43
+
44
+ * fixes for dbUtils, proxy, misspelling
45
+
46
+ Closes ADAPT-1019
47
+
48
+ See merge request itentialopensource/adapter-utils!223
49
+
50
+ ---
51
+
2
52
  ## 4.44.9 [09-14-2021]
3
53
 
4
54
  * Refactor storage handling
@@ -640,7 +640,7 @@ function makeRequest(request, entitySchema, callProperties, startTrip, attempt,
640
640
  } else if (proxyEnabled) {
641
641
  let proxy = `${proxyProtocol}://${proxyHost}:${proxyPort}`;
642
642
  if (proxyUser && proxyPassword) {
643
- proxy = `${callProperties.proxy.protocol}://${proxyUser}:${proxyPassword}@${callProperties.proxy.host}:${callProperties.proxy.port}`;
643
+ proxy = `${proxyProtocol}://${proxyUser}:${proxyPassword}@${proxyHost}:${proxyPort}`;
644
644
  }
645
645
  request.header.agent = new HttpsProxyAgent(proxy);
646
646
 
@@ -1760,6 +1760,20 @@ function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
1760
1760
  }
1761
1761
  }
1762
1762
 
1763
+ // only add global options if there are global options to add
1764
+ if (globalRequest && globalRequest.uriOptions
1765
+ && Object.keys(globalRequest.uriOptions).length > 0) {
1766
+ const optionString = querystring.stringify(globalRequest.uriOptions);
1767
+
1768
+ // if no query paramters yet - start with ?
1769
+ if (options.path.indexOf('?') < 0) {
1770
+ options.path += `?${optionString}`;
1771
+ } else {
1772
+ // if already have query parameters, add on to end
1773
+ options.path += `&${optionString}`;
1774
+ }
1775
+ }
1776
+
1763
1777
  // remove the path vars from the reqBody
1764
1778
  const actReqBody = Object.assign({}, reqBody);
1765
1779
  if (actReqBody && actReqBody.uriPathVars) {
@@ -1917,7 +1931,7 @@ function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
1917
1931
 
1918
1932
  // if there is a body, set the content length of the body and add it to
1919
1933
  // the header
1920
- if (Object.keys(tokenEntity).length > 0) {
1934
+ if (Object.keys(tokenEntity).length > 0 || tokenSchema.sendEmpty) {
1921
1935
  options.headers['Content-length'] = Buffer.byteLength(bodyString);
1922
1936
  }
1923
1937
 
package/lib/dbUtil.js CHANGED
@@ -14,6 +14,7 @@ const { MongoClient } = require('mongodb');
14
14
  let adapterDir = '';
15
15
  let saveFS = false;
16
16
  let storDir = `${adapterDir}/storage`;
17
+ let entityDir = `${adapterDir}/entities`;
17
18
  let id = null;
18
19
 
19
20
  const Storage = {
@@ -60,6 +61,55 @@ function getFromJson(fileName, filter) {
60
61
  }
61
62
 
62
63
  try {
64
+ if (fileName === 'adapter_configs') {
65
+ const retEntity = filter.entity;
66
+ if (!retEntity || !fs.existsSync(`${entityDir}`) || !fs.existsSync(`${entityDir}/${retEntity}`)) {
67
+ log.warn(`${origin}: Could not find adapter entity directory ${retEntity} - nothing to retrieve`);
68
+ return null;
69
+ }
70
+ if (!fs.existsSync(`${entityDir}/${retEntity}/action.json`)) {
71
+ log.warn(`${origin}: Could not find action.json for entity ${retEntity} - nothing to retrieve`);
72
+ return null;
73
+ }
74
+
75
+ // load the mockdatafiles
76
+ let files = fs.readdirSync(`${entityDir}/${retEntity}`);
77
+ const mockdatafiles = {};
78
+ if (files.includes('mockdatafiles') && fs.lstatSync(`${entityDir}/${retEntity}/mockdatafiles`).isDirectory()) {
79
+ fs.readdirSync(`${entityDir}/${retEntity}/mockdatafiles`).forEach((file) => {
80
+ if (file.split('.').pop() === 'json') {
81
+ const mockpath = `${entityDir}/${retEntity}/mockdatafiles/${file}`;
82
+ const data = JSON.parse(fs.readFileSync(mockpath));
83
+ mockdatafiles[mockpath.split('/').pop()] = data;
84
+ }
85
+ });
86
+ }
87
+
88
+ // load the action data
89
+ let actions;
90
+ if (files.includes('action.json')) {
91
+ actions = JSON.parse(fs.readFileSync(`${entityDir}/${retEntity}/action.json`));
92
+ }
93
+
94
+ // Load schema.json and other schemas in remaining json files
95
+ files = files.filter((f) => (f !== 'action.json') && f.endsWith('.json'));
96
+ const schema = [];
97
+ files.forEach((file) => {
98
+ const data = JSON.parse(fs.readFileSync(`${entityDir}/${retEntity}/${file}`));
99
+ schema.push({
100
+ name: file,
101
+ schema: data
102
+ });
103
+ });
104
+
105
+ // return the data
106
+ return {
107
+ actions: actions.actions,
108
+ schema,
109
+ mockdatafiles
110
+ };
111
+ }
112
+
63
113
  // make sure what we need exists and has been provided
64
114
  if (!fs.existsSync(`${storDir}`)) {
65
115
  log.warn(`${origin}: Could not find adapter storage directory - nothing to retrieve`);
@@ -80,21 +130,29 @@ function getFromJson(fileName, filter) {
80
130
  });
81
131
  } else {
82
132
  // if not metric must match the items in the filter
83
- const key = Object.keys(useFilter);
133
+ // if no filter, match everything
134
+ let key = [];
135
+ if (useFilter && useFilter.length > 0) {
136
+ key = Object.keys(useFilter);
137
+ }
84
138
  content.table.forEach((item) => {
85
139
  let push = true;
140
+ // check each key - if it does not match a key do not add to return data
86
141
  key.forEach((fil) => {
87
142
  if (useFilter[fil] !== item[fil]) push = false;
88
143
  });
89
144
  if (push) toReturn.push(item);
90
145
  });
91
146
  }
147
+ // not sure why we do this - a little different than above.
92
148
  const filtered = content.table.filter((el) => {
93
- Object.keys(useFilter).forEach((obj) => {
94
- if (el[obj] !== useFilter[obj]) {
95
- return false;
96
- }
97
- });
149
+ if (useFilter) {
150
+ Object.keys(useFilter).forEach((obj) => {
151
+ if (el[obj] !== useFilter[obj]) {
152
+ return false;
153
+ }
154
+ });
155
+ }
98
156
  return true;
99
157
  });
100
158
  return toReturn;
@@ -401,6 +459,7 @@ class DBUtil {
401
459
  this.baseDir = directory;
402
460
  adapterDir = this.baseDir;
403
461
  storDir = `${adapterDir}/storage`;
462
+ entityDir = `${adapterDir}/entities`;
404
463
  this.props = properties;
405
464
  this.adapterMongoClient = null;
406
465
 
@@ -1190,7 +1249,11 @@ class DBUtil {
1190
1249
  // if using file storage
1191
1250
  if (storage === Storage.FILESYSTEM) {
1192
1251
  // Find it from file in the adapter
1193
- let toReturn = getFromJson(collectionName, filter);
1252
+ let toReturn = getFromJson(collectionName, options);
1253
+ if (collectionName === 'adapter_configs') {
1254
+ log.debug(`${origin}: Data retrieved from file storage`);
1255
+ return callback(null, [toReturn]);
1256
+ }
1194
1257
  if (toReturn && toReturn.length > limit) {
1195
1258
  let curEnd = start + limit;
1196
1259
  if (curEnd < toReturn.length) {
@@ -1198,7 +1261,7 @@ class DBUtil {
1198
1261
  }
1199
1262
  toReturn = toReturn.slice(start, curEnd);
1200
1263
  }
1201
- log.trace(`${origin}: Data retrieved from file storage`);
1264
+ log.debug(`${origin}: Data retrieved from file storage`);
1202
1265
  return callback(null, toReturn);
1203
1266
  }
1204
1267
 
@@ -187,6 +187,7 @@ class AdapterPropertyUtil {
187
187
  // get the path for the specific schema file
188
188
  const reqSchemaFile = path.join(this.baseDir, `/entities/${entityName}/${reqSchemaName}`);
189
189
  const respSchemaFile = path.join(this.baseDir, `/entities/${entityName}/${respSchemaName}`);
190
+ const errorSchemaFile = path.join(this.baseDir, '/entities/.system/errorSchema');
190
191
 
191
192
  // if the file does not exist - error
192
193
  if (!fs.existsSync(reqSchemaFile)) {
@@ -244,6 +245,16 @@ class AdapterPropertyUtil {
244
245
  throw new Error(JSON.stringify(errorObj));
245
246
  }
246
247
 
248
+ // if the error schema file exist - read it in
249
+ if (fs.existsSync(errorSchemaFile)) {
250
+ entitySchema.errorSchema = JSON.parse(fs.readFileSync(errorSchemaFile, 'utf-8'));
251
+
252
+ // if the error schema file is bad, warn about it but continue and use the global on!
253
+ if (entitySchema.errorSchema && typeof entitySchema.errorSchema !== 'object') {
254
+ log.warn(`${origin}: Invalid error schema, please verify file: ${errorSchemaFile}`);
255
+ }
256
+ }
257
+
247
258
  // Merge the information into the entity schema
248
259
  entitySchema.protocol = actionInfo.protocol;
249
260
  entitySchema.method = actionInfo.method;
@@ -428,7 +439,8 @@ class AdapterPropertyUtil {
428
439
  filter: {
429
440
  id: this.myid,
430
441
  entity: entityName
431
- }
442
+ },
443
+ entity: entityName
432
444
  };
433
445
 
434
446
  // call to get the adapter schema from the database
@@ -51,7 +51,7 @@ function validateProperties(properties) {
51
51
 
52
52
  try {
53
53
  // get the path for the specific action file
54
- const propertyFile = path.join(__dirname, '/../propertiesSchema.json');
54
+ const propertyFile = path.join(__dirname, '/../schemas/propertiesSchema.json');
55
55
 
56
56
  // Read the action from the file system
57
57
  const propertySchema = JSON.parse(fs.readFileSync(propertyFile, 'utf-8'));
@@ -113,7 +113,7 @@ function walkThroughActionFiles(directory) {
113
113
 
114
114
  try {
115
115
  // Read the action schema from the file system
116
- const actionSchemaFile = path.join(__dirname, '/../actionSchema.json');
116
+ const actionSchemaFile = path.join(__dirname, '/../schemas/actionSchema.json');
117
117
  const actionSchema = JSON.parse(fs.readFileSync(actionSchemaFile, 'utf-8'));
118
118
  const entitydir = `${directory}/entities`;
119
119
 
@@ -9,6 +9,8 @@ const jsonQuery = require('json-query');
9
9
  const jsonxml = require('jsontoxml');
10
10
  const xml2js = require('xml2js');
11
11
 
12
+ const globalSchema = JSON.parse(require('fs').readFileSync(require('path').join(__dirname, '/../schemas/globalSchema.json')));
13
+
12
14
  let transUtilInst = null;
13
15
  let connectorInst = null;
14
16
 
@@ -19,6 +21,7 @@ let basepathGl = null;
19
21
  let globalRequestGl = null;
20
22
  let returnRawGl = false;
21
23
  let encodePath = true;
24
+ let encodeUri = true;
22
25
 
23
26
  // INTERNAL FUNCTIONS
24
27
  /*
@@ -178,7 +181,13 @@ function handleRestRequest(request, entityId, entitySchema, callProperties, filt
178
181
 
179
182
  // if the return error message was JSON then return the parsed object
180
183
  if (retError !== null) {
181
- retErrorObj.response = retError;
184
+ // if there is a local error schema in the entity use that one
185
+ if (Object.hasOwnProperty.call(entitySchema, 'errorSchema')) {
186
+ retErrorObj.response = transUtilInst.mapFromOutboundEntity(retError, entitySchema.errorSchema);
187
+ } else {
188
+ // if there is a no local error schema in the entity use that one
189
+ retErrorObj.response = transUtilInst.mapFromOutboundEntity(retError, globalSchema);
190
+ }
182
191
  }
183
192
 
184
193
  // return the error response
@@ -460,6 +469,9 @@ function handleRestRequest(request, entityId, entitySchema, callProperties, filt
460
469
  return callback(retObject);
461
470
  }
462
471
 
472
+ // Apply global schema
473
+ // retResponse = transUtilInst.mapFromOutboundEntity(retResponse, globalSchema);
474
+
463
475
  // added the translated response to the return Object
464
476
  retObject.response = transUtilInst.mapFromOutboundEntity(retResponse, entitySchema.responseSchema);
465
477
 
@@ -677,7 +689,23 @@ function buildRequestPath(entity, action, entitySchema, reqPath, uriPathVars, ur
677
689
  addquery = entitySchema.querykey;
678
690
  }
679
691
  if (systemQuery !== null) {
680
- addquery += querystring.stringify(systemQuery);
692
+ // if we are encoding - use querystring since it does it all!
693
+ if (encodeUri === true) {
694
+ addquery += querystring.stringify(systemQuery);
695
+ } else {
696
+ // if not encoding we need to build
697
+ const qkeys = Object.keys(systemQuery);
698
+
699
+ // add each query parameter and its value
700
+ for (let k = 0; k < qkeys.length; k += 1) {
701
+ // need to add separator for everything after the first one
702
+ if (k > 0) {
703
+ addquery += '&';
704
+ }
705
+ // adds key=value
706
+ addquery += `${qkeys[k]}=${systemQuery[qkeys[k]]}`;
707
+ }
708
+ }
681
709
  }
682
710
  }
683
711
 
@@ -897,7 +925,7 @@ function buildPayload(entity, action, entitySchema, payload) {
897
925
  }
898
926
  }
899
927
  } else {
900
- log.warn(`${origin}: Payload and Gloabl Payload can not be merged!`);
928
+ log.warn(`${origin}: Payload and Global Payload can not be merged!`);
901
929
  }
902
930
  }
903
931
 
@@ -988,6 +1016,8 @@ class RestHandler {
988
1016
  this.globalRequest = null;
989
1017
  this.encode = properties.encode_pathvars;
990
1018
  encodePath = this.encode;
1019
+ this.encodeQ = properties.encode_queryvars;
1020
+ encodeUri = this.encodeQ;
991
1021
 
992
1022
  // only need to set returnRaw if the property is true - defaults to false
993
1023
  if (properties.request && properties.request.return_raw) {
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@itentialopensource/adapter-utils",
3
- "version": "4.44.9",
3
+ "version": "4.45.2",
4
4
  "description": "Itential Adapter Utility Libraries",
5
5
  "scripts": {
6
6
  "preinstall": "node utils/setup.js",
7
7
  "lint": "eslint . --ext .json --ext .js",
8
8
  "lint:errors": "eslint --quiet . --ext .json --ext .js",
9
- "test:unit": "mocha test/unit/lib/requestHandlerTest.js --LOG=error && mocha test/unit/lib/restHandlerTest.js --LOG=error && mocha test/unit/lib/propertyUtilTest.js --LOG=error && mocha test/unit/lib/translatorUtilTest.js --LOG=error && mocha test/unit/lib/dbUtilTest.js --LOG=error",
9
+ "test:unit": "mocha test/unit/lib/requestHandlerTest.js --LOG=error && mocha test/unit/lib/restHandlerTest.js --LOG=error && mocha test/unit/lib/propertyUtilTest.js --LOG=error && mocha test/unit/lib/translatorUtilTest.js --LOG=error && mocha test/unit/lib/dbUtilTest.js --LOG=debug",
10
10
  "test:integration": "mocha test/integration/lib/requestHandlerTest.js --LOG=error && mocha test/integration/lib/restHandlerTest.js --LOG=error",
11
11
  "test:cover": "nyc --reporter html --reporter text mocha --recursive --reporter dot test/*",
12
12
  "test": "npm run test:unit && npm run test:integration",
13
- "deploy": "npm publish --registry=http://registry.npmjs.org --access=public",
13
+ "deploy": "npm publish --registry=https://registry.npmjs.org --access=public",
14
14
  "build": "npm run deploy"
15
15
  },
16
16
  "license": "Apache-2.0",
@@ -51,7 +51,7 @@
51
51
  "eslint-plugin-json": "^3.0.0",
52
52
  "mocha": "^9.0.1",
53
53
  "nyc": "^15.1.0",
54
- "strip-ansi": "^7.0.0",
54
+ "strip-ansi": "^7.0.1",
55
55
  "strip-ansi-cli": "^3.0.1",
56
56
  "testdouble": "^3.16.1",
57
57
  "winston": "^3.3.3"
File without changes
@@ -0,0 +1,19 @@
1
+ {
2
+ "$id": "schema.json",
3
+ "type": "object",
4
+ "schema": "http://json-schema.org/draft-07/schema#",
5
+ "translate": true,
6
+ "dynamicfields": true,
7
+ "properties": {
8
+ "id": {
9
+ "type": "string",
10
+ "description": "Restricted for: special use within mongo",
11
+ "encrypt": {
12
+ "type": "AES",
13
+ "key": ""
14
+ },
15
+ "external_name": "$id"
16
+ }
17
+ },
18
+ "definitions": {}
19
+ }
@@ -51,6 +51,11 @@
51
51
  "description": "When true the path variables are encoded in the url",
52
52
  "default": true
53
53
  },
54
+ "encode_queryvars": {
55
+ "type": "boolean",
56
+ "description": "When true the query variables are encoded in the url",
57
+ "default": true
58
+ },
54
59
  "save_metric": {
55
60
  "type": [
56
61
  "boolean",