@w3-commons/js-build-resources 0.0.1-security → 1.0.4

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.

Potentially problematic release.


This version of @w3-commons/js-build-resources might be problematic. Click here for more details.

Files changed (98) hide show
  1. package/package.json +9 -3
  2. package/settings-service/.eslintrc.js +4 -0
  3. package/settings-service/.node-version +1 -0
  4. package/settings-service/.prettierrc +6 -0
  5. package/settings-service/.whitesource +15 -0
  6. package/settings-service/LICENSE +4 -0
  7. package/settings-service/README.md +50 -0
  8. package/settings-service/build.yml +56 -0
  9. package/settings-service/collectCodeCoverage.js +9 -0
  10. package/settings-service/db/cassandra/Dockerfile +3 -0
  11. package/settings-service/db/cassandra/createkeyspace.dev.cql +4 -0
  12. package/settings-service/db/cassandra/createkeyspace.dev.sh +3 -0
  13. package/settings-service/db/cassandra/schema_001.cql +15 -0
  14. package/settings-service/db/cassandra/schema_002.cql +8 -0
  15. package/settings-service/db/cassandra/schema_003.cql +10 -0
  16. package/settings-service/db/cassandra/schema_004.cql +1 -0
  17. package/settings-service/db/cassandra/schema_005.cql +39 -0
  18. package/settings-service/db/cassandra/schema_006.cql +255 -0
  19. package/settings-service/db/cassandra/schema_007.cql +40 -0
  20. package/settings-service/db/cassandra/schema_008.cql +2 -0
  21. package/settings-service/db/cassandra/schema_009.cql +143 -0
  22. package/settings-service/db/cassandra/schema_010.cql +143 -0
  23. package/settings-service/db/cassandra/schema_011.cql +2 -0
  24. package/settings-service/db/cassandra/schema_012.cql +8 -0
  25. package/settings-service/jest.config.fn.js +3 -0
  26. package/settings-service/jest.config.it.js +3 -0
  27. package/settings-service/jest.config.js +14 -0
  28. package/settings-service/jest.config.unit.js +19 -0
  29. package/settings-service/jest.setup.js +11 -0
  30. package/settings-service/package-lock.json +11772 -0
  31. package/settings-service/package.json +101 -0
  32. package/settings-service/scripts/run-fn-tests.sh +3 -0
  33. package/settings-service/sonar-project.properties +3 -0
  34. package/settings-service/src/__tests__/functional/controller/ApiKeyController.fn.ts +132 -0
  35. package/settings-service/src/__tests__/functional/middleware/AuthMiddlewareNextGenSSO.fn.ts +82 -0
  36. package/settings-service/src/__tests__/functional/repo/settingsRepo.fn.ts +302 -0
  37. package/settings-service/src/__tests__/functional/unified-profile/unified-profile.fn.ts +66 -0
  38. package/settings-service/src/__tests__/integration/repo/ApiKeyRepo.it.ts +43 -0
  39. package/settings-service/src/__tests__/integration/repo/settingsRepo.it.ts +142 -0
  40. package/settings-service/src/__tests__/integration/unified-profile/unified-profile.it.ts +31 -0
  41. package/settings-service/src/__tests__/unit/ErrResponse.ts +4 -0
  42. package/settings-service/src/__tests__/unit/JWTResponse.ts +18 -0
  43. package/settings-service/src/__tests__/unit/bluepagesResponse.ts +25 -0
  44. package/settings-service/src/__tests__/unit/controller/ApiKeyController.spec.ts +217 -0
  45. package/settings-service/src/__tests__/unit/controller/AppSettingsController.spec.ts +133 -0
  46. package/settings-service/src/__tests__/unit/controller/UserSettingsController.spec.ts +328 -0
  47. package/settings-service/src/__tests__/unit/controller/getAllSettings.spec.ts +83 -0
  48. package/settings-service/src/__tests__/unit/middleware/AuthMiddlewareNextGenSSO.spec.ts +282 -0
  49. package/settings-service/src/__tests__/unit/middleware/AuthenticationMiddleware.spec.ts +494 -0
  50. package/settings-service/src/__tests__/unit/repo/ApiKeyRepo.spec.ts +194 -0
  51. package/settings-service/src/__tests__/unit/repo/getAllSettings.spec.ts +100 -0
  52. package/settings-service/src/__tests__/unit/repo/getUserSettingsRepo.spec.ts +249 -0
  53. package/settings-service/src/__tests__/unit/repo/settingsRepo.spec.ts +614 -0
  54. package/settings-service/src/__tests__/unit/unified-profile/UnifiedProfileClient.spec.ts +31 -0
  55. package/settings-service/src/__tests__/unit/unified-profile/unifiedProfileUtils.spec.ts +36 -0
  56. package/settings-service/src/__tests__/utils/test-utils.ts +41 -0
  57. package/settings-service/src/config/config.ts +190 -0
  58. package/settings-service/src/controller/ApiKeyController.ts +114 -0
  59. package/settings-service/src/controller/AppSettingsController.ts +137 -0
  60. package/settings-service/src/controller/UserSettingsController.ts +202 -0
  61. package/settings-service/src/helpers/commons.ts +69 -0
  62. package/settings-service/src/logger/logger.ts +17 -0
  63. package/settings-service/src/middleware/AuthenticationMiddleware.ts +486 -0
  64. package/settings-service/src/middleware/AuthenticationMiddlewareFactory.ts +10 -0
  65. package/settings-service/src/repo/ApiKeyRepo.ts +135 -0
  66. package/settings-service/src/repo/ApiKeyRepoFactory.ts +10 -0
  67. package/settings-service/src/repo/CassandraClient.ts +33 -0
  68. package/settings-service/src/repo/CassandraClientFactory.ts +11 -0
  69. package/settings-service/src/repo/apiKeyQueries.ts +64 -0
  70. package/settings-service/src/repo/cassandraDBHelpers.ts +119 -0
  71. package/settings-service/src/repo/settingsRepo.ts +388 -0
  72. package/settings-service/src/repo/settingsRepoFactory.ts +10 -0
  73. package/settings-service/src/repo/settingsRepoQueries.ts +62 -0
  74. package/settings-service/src/routes/apiKeyRoutes.ts +27 -0
  75. package/settings-service/src/routes/appSettingsRoutes.ts +30 -0
  76. package/settings-service/src/routes/healthCheck.ts +10 -0
  77. package/settings-service/src/routes/swagger.ts +8 -0
  78. package/settings-service/src/routes/userSettingsRoutes.ts +30 -0
  79. package/settings-service/src/server.ts +77 -0
  80. package/settings-service/src/swagger.json +732 -0
  81. package/settings-service/src/types/ApiKey.ts +19 -0
  82. package/settings-service/src/types/IRequest.ts +9 -0
  83. package/settings-service/src/types/IRequestAuthorization.ts +5 -0
  84. package/settings-service/src/types/IRouteOptions.ts +5 -0
  85. package/settings-service/src/types/QueryResultsTypes.ts +6 -0
  86. package/settings-service/src/types/UserSettingsControllerTypes.ts +5 -0
  87. package/settings-service/src/types/W3IdUser.ts +36 -0
  88. package/settings-service/src/types/settingsRepoTypes.ts +61 -0
  89. package/settings-service/src/types/unifiedProfileTypes.ts +10 -0
  90. package/settings-service/src/unified-profile/UnifiedProfileClient.ts +29 -0
  91. package/settings-service/src/unified-profile/UnifiedProfileClientFactory.ts +10 -0
  92. package/settings-service/src/unified-profile/unifiedProfileUtils.ts +22 -0
  93. package/settings-service/src/util/downloadCassandra.ts +34 -0
  94. package/settings-service/src/util/isocodeMapper.ts +22 -0
  95. package/settings-service/src/util/languages.ts +1457 -0
  96. package/settings-service/test_resources/mockApiKeyDBResult.json +8 -0
  97. package/settings-service/tsconfig.json +40 -0
  98. package/README.md +0 -5
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "settings-service",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "local": "nodemon --watch src/ -e ts --exec \"npm run build-quick\"",
8
+ "build": "npm run compile && npm run package && npm run analyze",
9
+ "build-quick": "npm run compile && npm run package && node ./build/server.js ",
10
+ "compile": "npm run clean && tsc -p tsconfig.json",
11
+ "analyze": "npm run unit-test",
12
+ "clean": "rm -rf build",
13
+ "test:functional": "sh ./scripts/run-fn-tests.sh",
14
+ "smoke-test": "npm run --silent",
15
+ "unit-test": "jest --forceExit -c jest.config.unit.js --coverage && node collectCodeCoverage",
16
+ "integration-test": "jest -i --forceExit -c jest.config.it.js",
17
+ "package": "cp jest.config* build && cp -r scripts build",
18
+ "lint": "eslint \"src/**/*.ts\" --fix"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.ibm.com/w3-profile/settings-service.git"
23
+ },
24
+ "author": "",
25
+ "license": "ISC",
26
+ "dependencies": {
27
+ "app-root-path": "^2.2.1",
28
+ "axios": "^0.19.0",
29
+ "cors": "^2.8.5",
30
+ "dotenv": "^6.2.0",
31
+ "dse-driver": "^2.3.1",
32
+ "eslint-plugin-import": "^2.25.4",
33
+ "lodash": "^4.17.21",
34
+ "npm-run": "^5.0.1",
35
+ "randomstring": "^1.1.5",
36
+ "request-promise": "^4.2.6",
37
+ "restify": "^8.1.0",
38
+ "restify-cors-middleware": "^1.1.1",
39
+ "restify-errors": "^8.0.2",
40
+ "swagger-ui-restify": "^3.0.8",
41
+ "ts-node": "^10.7.0",
42
+ "winston": "^3.2.1"
43
+ },
44
+ "devDependencies": {
45
+ "@types/app-root-path": "^1.2.4",
46
+ "@types/cors": "^2.8.4",
47
+ "@types/eslint": "^7.29.0",
48
+ "@types/jest": "^24.0.11",
49
+ "@types/lodash": "^4.14.123",
50
+ "@types/node": "^11.9.4",
51
+ "@types/node-fetch": "^2.1.6",
52
+ "@types/node-schedule": "^1.2.4",
53
+ "@types/request": "^2.0.12",
54
+ "@types/request-promise": "^4.1.42",
55
+ "@types/restify": "^7.2.5",
56
+ "@types/restify-errors": "^4.3.3",
57
+ "@typescript-eslint/eslint-plugin": "^4.6.1",
58
+ "@typescript-eslint/parser": "^4.6.1",
59
+ "@w3-commons/js-build-resources": "^1.0.3",
60
+ "eslint": "^7.27.0",
61
+ "eslint-config-airbnb-base": "^14.2.1",
62
+ "eslint-config-prettier": "^6.15.0",
63
+ "eslint-import-resolver-typescript": "^2.5.0",
64
+ "eslint-plugin-prettier": "^3.4.1",
65
+ "jest": "^26.6.3",
66
+ "nodemon": "^1.18.10",
67
+ "prettier": "^2.5.1",
68
+ "request": "^2.88.2",
69
+ "ts-jest": "^26.5.6",
70
+ "typescript": "^4.5.4",
71
+ "typescript-eslint-parser": "^22.0.0"
72
+ },
73
+ "jest": {
74
+ "verbose": false,
75
+ "transform": {
76
+ "^.+\\.tsx?$": "ts-jest"
77
+ },
78
+ "testRegex": "(/__tests__/unit/.*)spec.ts$",
79
+ "moduleFileExtensions": [
80
+ "ts",
81
+ "tsx",
82
+ "js",
83
+ "json"
84
+ ],
85
+ "coverageDirectory": "test/coverage",
86
+ "collectCoverageFrom": [
87
+ "**/src/**/*.{ts,tsx}"
88
+ ],
89
+ "coveragePathIgnorePatterns": [
90
+ "(/__tests__/unit/.*)"
91
+ ],
92
+ "coverageThreshold": {
93
+ "global": {
94
+ "branches": 70,
95
+ "functions": 80,
96
+ "lines": 80,
97
+ "statements": 80
98
+ }
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,3 @@
1
+ if [ "${APP_ENVIRONMENT}" = "test" -o "${APP_ENVIRONMENT}" = "dev" ]; then
2
+ jest -i --forceExit -c jest.config.fn.js
3
+ fi
@@ -0,0 +1,3 @@
1
+ sonar.sources=src
2
+ sonar.typescript.lcov.reportPaths=coverage/lcov.info
3
+ sonar.exclusions=src/__tests__/**/*,src/index.ts,src/server.ts,src/logger/logger.ts
@@ -0,0 +1,132 @@
1
+ import axios from 'axios';
2
+ import http from 'axios/lib/adapters/http';
3
+ import { downloadCassandra } from '../../../util/downloadCassandra';
4
+ import { cassandraDBHelpers } from '../../../repo/cassandraDBHelpers';
5
+ import { settings } from '../../../config/config';
6
+ import { deleteApiKeyQuery } from '../../../repo/apiKeyQueries';
7
+ import { sampleAuthorization, TEST_APP_ID, TEST_USER_ID } from '../../utils/test-utils';
8
+
9
+ axios.defaults.adapter = http;
10
+
11
+ const apiKeyAuthorizedIds: string = settings.apiKeyAuthorizedUserIds;
12
+ settings.apiKeyAuthorizedUserIds = TEST_USER_ID;
13
+
14
+ const urlprefix =
15
+ process.env.INGRESS_HOSTNAME !== undefined
16
+ ? `https://${process.env.INGRESS_HOSTNAME}`
17
+ : 'http://localhost:8000';
18
+
19
+ let createdApiKey = '';
20
+
21
+ const TEST_HEADER = { Authorization: `Bearer ${JSON.stringify(sampleAuthorization)}` };
22
+
23
+ beforeAll(async () => {
24
+ await downloadCassandra();
25
+ await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
26
+ });
27
+
28
+ afterAll(async () => {
29
+ await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
30
+ await cassandraDBHelpers.shutdown();
31
+ settings.apiKeyAuthorizedUserIds = apiKeyAuthorizedIds;
32
+ });
33
+
34
+ afterEach(() => {
35
+ jest.clearAllMocks();
36
+ });
37
+
38
+ describe('create api key', () => {
39
+ it('should allow an authorized user to create an api key', async () => {
40
+ const data = await axios({
41
+ method: 'post',
42
+ url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
43
+ headers: TEST_HEADER,
44
+ }).then((res) => res.data);
45
+ createdApiKey = data.key;
46
+
47
+ expect(data).toBeDefined();
48
+ expect(data.key).toHaveLength(48);
49
+ expect(typeof data.key).toBe('string');
50
+ });
51
+
52
+ it('should not allow an unauthorized user to create an api key', async () => {
53
+ expect.assertions(3);
54
+ try {
55
+ await axios({
56
+ method: 'post',
57
+ url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
58
+ headers: {
59
+ Authorization: `Bearer ${JSON.stringify({ email: 'invalidEmail@ibm.com', id: 'INVALIDID' })}`,
60
+ },
61
+ }).then((res) => res.data);
62
+ } catch (err) {
63
+ expect(err).toBeDefined();
64
+ expect(err).toBeInstanceOf(Error);
65
+ expect(err.message).toBe('Request failed with status code 403');
66
+ }
67
+ });
68
+ });
69
+
70
+ describe('get api key', () => {
71
+ it('should allow an authorized user to create an api key', async () => {
72
+ const data = await axios({
73
+ method: 'get',
74
+ url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
75
+ headers: TEST_HEADER,
76
+ }).then((res) => res.data);
77
+
78
+ expect(data).toBeDefined();
79
+ expect(data.key).toHaveLength(48);
80
+ expect(typeof data.key).toBe('string');
81
+ expect(data.key).toEqual(createdApiKey);
82
+ });
83
+
84
+ it('should not allow an unauthorized user to retrive an api key', async () => {
85
+ expect.assertions(3);
86
+ try {
87
+ await axios({
88
+ method: 'get',
89
+ url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
90
+ headers: {
91
+ Authorization: `Bearer ${JSON.stringify({ email: 'invalidEmail@ibm.com', id: 'INVALIDID' })}`,
92
+ },
93
+ }).then((res) => res.data);
94
+ } catch (err) {
95
+ expect(err).toBeDefined();
96
+ expect(err).toBeInstanceOf(Error);
97
+ expect(err.message).toBe('Request failed with status code 403');
98
+ }
99
+ });
100
+
101
+ describe('update api key', () => {
102
+ it('should allow an authorized user to update an api key', async () => {
103
+ const data = await axios({
104
+ method: 'put',
105
+ url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
106
+ headers: TEST_HEADER,
107
+ }).then((res) => res.data);
108
+
109
+ expect(data).toBeDefined();
110
+ expect(data.key).toHaveLength(48);
111
+ expect(typeof data.key).toBe('string');
112
+ expect(data.key).not.toEqual(createdApiKey);
113
+ });
114
+
115
+ it('should not allow an unauthorized user to update an api key', async () => {
116
+ expect.assertions(3);
117
+ try {
118
+ await axios({
119
+ method: 'put',
120
+ url: `${urlprefix}/v1/settings/apiKey/app/${TEST_APP_ID}`,
121
+ headers: {
122
+ Authorization: `Bearer ${JSON.stringify({ email: 'invalidEmail@ibm.com', id: 'INVALIDID' })}`,
123
+ },
124
+ }).then((res) => res.data);
125
+ } catch (err) {
126
+ expect(err).toBeDefined();
127
+ expect(err).toBeInstanceOf(Error);
128
+ expect(err.message).toBe('Request failed with status code 403');
129
+ }
130
+ });
131
+ });
132
+ });
@@ -0,0 +1,82 @@
1
+ import axios from 'axios';
2
+ import http from 'axios/lib/adapters/http';
3
+ import { ApiKeyRepoFactory } from '../../../repo/ApiKeyRepoFactory';
4
+ import { deleteApiKeyQuery } from '../../../repo/apiKeyQueries';
5
+ import { ApiKeyRepo } from '../../../repo/ApiKeyRepo';
6
+ import { cassandraDBHelpers } from '../../../repo/cassandraDBHelpers';
7
+ import { SettingsRepo } from '../../../repo/settingsRepo';
8
+ import { TEST_APP_ID, TEST_USER_ID } from '../../utils/test-utils';
9
+ import { SettingsRepoFactory } from '../../../repo/settingsRepoFactory';
10
+ import { downloadCassandra } from '../../../util/downloadCassandra';
11
+
12
+ axios.defaults.adapter = http;
13
+
14
+ const TEST_SETTING = 'test';
15
+ const W3ID_TOKEN = `Bearer Q3ccWQ4TZxK3bm6vnuOk5kQ9JApv7PCr8aLFxtKf`;
16
+
17
+ async function apiKeySetup(): Promise<string> {
18
+ const apiKeyRepo: ApiKeyRepo = ApiKeyRepoFactory.accessOrCreateSingleton();
19
+ const createdApiKey = await apiKeyRepo.createApiKey(TEST_APP_ID, 'TEST_USER_ID');
20
+ return Buffer.from(`w3notifications-test:${createdApiKey}`).toString('base64');
21
+ }
22
+
23
+ const TEST_HEADER = { headers: { Authorization: `${W3ID_TOKEN}` } };
24
+ let TEST_HEADER_API: any = {};
25
+
26
+ const urlprefix =
27
+ process.env.INGRESS_HOSTNAME !== undefined
28
+ ? `https://${process.env.INGRESS_HOSTNAME}`
29
+ : 'http://localhost:8000';
30
+
31
+ const settingsRepo: SettingsRepo = SettingsRepoFactory.accessOrCreateSingleton();
32
+
33
+ /**
34
+ * Below are functional tests for Authentication Middleware NextGen SSO (ISV)
35
+ */
36
+ describe('Authentication fails with invalid token', () => {
37
+ const TEST_RESP = { general: {} };
38
+ TEST_RESP[TEST_APP_ID] = {};
39
+
40
+ beforeAll(async () => {
41
+ await downloadCassandra();
42
+ await settingsRepo.deleteUserSettings(TEST_USER_ID);
43
+ await settingsRepo.deleteAppSettings(TEST_APP_ID, TEST_SETTING);
44
+ TEST_HEADER_API = { headers: { Authorization: `apiKey ${await apiKeySetup()}`, nextgen_sso: true } };
45
+ });
46
+
47
+ afterAll(async () => {
48
+ await settingsRepo.deleteUserSettings(TEST_USER_ID);
49
+ await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
50
+ await cassandraDBHelpers.shutdown();
51
+ });
52
+
53
+ it('will not authenticate invalid token', async () => {
54
+ let caughtError;
55
+ try {
56
+ await axios.post(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, {}, TEST_HEADER);
57
+ expect(false).toBeTruthy();
58
+ } catch (err) {
59
+ caughtError = err;
60
+ }
61
+ expect(caughtError.response.data.code).toBe(401);
62
+ expect(caughtError.response.data.message).toBe('User token is expired or is invalid');
63
+ });
64
+
65
+ it('will authenticate API key with nextgen_sso true', async () => {
66
+ let data = await axios
67
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
68
+ .then((res) => res.data);
69
+ expect(data).toEqual({});
70
+
71
+ data = await axios
72
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
73
+ .then((res) => res.data);
74
+ expect(data).toEqual({});
75
+ });
76
+
77
+ it('does not need authentication for user get request', async () => {
78
+ const resp = await axios.get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`);
79
+ expect(resp.status).toBe(200);
80
+ expect(resp.data).toBeDefined();
81
+ });
82
+ });
@@ -0,0 +1,302 @@
1
+ import axios from 'axios';
2
+ import http from 'axios/lib/adapters/http';
3
+ import { ApiKeyRepoFactory } from '../../../repo/ApiKeyRepoFactory';
4
+ import { deleteApiKeyQuery } from '../../../repo/apiKeyQueries';
5
+ import { ApiKeyRepo } from '../../../repo/ApiKeyRepo';
6
+ import { cassandraDBHelpers } from '../../../repo/cassandraDBHelpers';
7
+ import { SettingsRepo } from '../../../repo/settingsRepo';
8
+ import { INVALID_APP_ID, sampleAuthorization, TEST_APP_ID, TEST_USER_ID } from '../../utils/test-utils';
9
+ import { SettingsRepoFactory } from '../../../repo/settingsRepoFactory';
10
+ import { downloadCassandra } from '../../../util/downloadCassandra';
11
+
12
+ axios.defaults.adapter = http;
13
+
14
+ const TEST_SETTING = 'test';
15
+ const TEST_SETTING_OPTIONS_DEFAULT = { default: 'false', options: ['true', 'false'], setting_type: null };
16
+ const TEST_SETTING_OPTIONS_DEFAULT_NO_TYPE = { default: 'false', options: ['true', 'false'] };
17
+
18
+ async function apiKeySetup(): Promise<string> {
19
+ const apiKeyRepo: ApiKeyRepo = ApiKeyRepoFactory.accessOrCreateSingleton();
20
+ const createdApiKey = await apiKeyRepo.createApiKey(TEST_APP_ID, 'TEST_USER_ID');
21
+ return Buffer.from(`w3notifications-test:${createdApiKey}`).toString('base64');
22
+ }
23
+
24
+ const TEST_HEADER = { headers: { Authorization: `Bearer ${JSON.stringify(sampleAuthorization)}` } };
25
+ let TEST_HEADER_API: any = {};
26
+
27
+ const urlprefix =
28
+ process.env.INGRESS_HOSTNAME !== undefined
29
+ ? `https://${process.env.INGRESS_HOSTNAME}`
30
+ : 'http://localhost:8000';
31
+
32
+ const settingsRepo: SettingsRepo = SettingsRepoFactory.accessOrCreateSingleton();
33
+
34
+ const secondaryLanguageSetting = { options: ['sk', 'en', 'fr'], setting_type: 'array' };
35
+
36
+ describe('get/update user and app settings', () => {
37
+ const TEST_RESP = { general: {} };
38
+ TEST_RESP[TEST_APP_ID] = {};
39
+
40
+ beforeAll(async () => {
41
+ await downloadCassandra();
42
+ await settingsRepo.deleteUserSettings(TEST_USER_ID);
43
+ await settingsRepo.deleteAppSettings(TEST_APP_ID, TEST_SETTING);
44
+ await settingsRepo.deleteAppSettings(TEST_APP_ID, 'secondaryLanguages');
45
+ TEST_HEADER_API = { headers: { Authorization: `apiKey ${await apiKeySetup()}` } };
46
+ });
47
+
48
+ afterAll(async () => {
49
+ await settingsRepo.deleteUserSettings(TEST_USER_ID);
50
+ await cassandraDBHelpers.execute(deleteApiKeyQuery, [TEST_APP_ID]);
51
+ await settingsRepo.deleteAppSettings(TEST_APP_ID, 'secondaryLanguages');
52
+ await cassandraDBHelpers.shutdown();
53
+ });
54
+
55
+ it('reads empty user settings', async () => {
56
+ const data = await axios
57
+ .get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
58
+ .then((res) => res.data);
59
+ data.general = {};
60
+ expect(data).toEqual(TEST_RESP);
61
+ });
62
+
63
+ it('reads empty app settings', async () => {
64
+ let data = await axios
65
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
66
+ .then((res) => res.data);
67
+ expect(data).toEqual({});
68
+
69
+ data = await axios
70
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
71
+ .then((res) => res.data);
72
+ expect(data).toEqual({});
73
+ });
74
+
75
+ it('updates app data', async () => {
76
+ const data = await axios
77
+ .post(
78
+ `${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
79
+ TEST_SETTING_OPTIONS_DEFAULT,
80
+ TEST_HEADER_API,
81
+ )
82
+ .then((res) => res.data);
83
+ expect(data).toEqual('Success');
84
+ });
85
+
86
+ it('reads updated app settings', async () => {
87
+ let data = await axios
88
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
89
+ .then((res) => res.data);
90
+ expect(data[TEST_SETTING]).toEqual(TEST_SETTING_OPTIONS_DEFAULT_NO_TYPE);
91
+ data = await axios
92
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
93
+ .then((res) => res.data);
94
+ expect(data[TEST_SETTING]).toEqual(TEST_SETTING_OPTIONS_DEFAULT_NO_TYPE);
95
+ });
96
+
97
+ it('updates app data with default', async () => {
98
+ const data = await axios
99
+ .post(
100
+ `${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
101
+ TEST_SETTING_OPTIONS_DEFAULT,
102
+ TEST_HEADER_API,
103
+ )
104
+ .then((res) => res.data);
105
+ expect(data).toEqual('Success');
106
+ });
107
+
108
+ it('reads default user settings', async () => {
109
+ TEST_RESP[TEST_APP_ID] = {};
110
+ TEST_RESP[TEST_APP_ID][TEST_SETTING] = 'false';
111
+ const data = await axios
112
+ .get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
113
+ .then((res) => res.data);
114
+ data.general = {};
115
+ expect(data).toEqual(TEST_RESP);
116
+ });
117
+
118
+ it('updates user data', async () => {
119
+ TEST_RESP[TEST_APP_ID] = {};
120
+ TEST_RESP[TEST_APP_ID][TEST_SETTING] = 'true';
121
+ const data = await axios
122
+ .post(
123
+ `${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`,
124
+ TEST_RESP[TEST_APP_ID],
125
+ TEST_HEADER,
126
+ )
127
+ .then((res) => res.data);
128
+ expect(data).toEqual(TEST_RESP[TEST_APP_ID]);
129
+ });
130
+
131
+ it('reads updated user settings', async () => {
132
+ const data = await axios
133
+ .get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
134
+ .then((res) => res.data);
135
+ data.general = {};
136
+ expect(data).toEqual(TEST_RESP);
137
+ });
138
+
139
+ it('throws error for invalid app', async () => {
140
+ await axios
141
+ .get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
142
+ .catch((error) => expect(error.response.status).toEqual(400));
143
+ });
144
+
145
+ it('deletes app data', async () => {
146
+ const data = await axios
147
+ .delete(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
148
+ .then((res) => res.data);
149
+ expect(data).toEqual('Success');
150
+ });
151
+
152
+ it('reads empty app settings', async () => {
153
+ let data = await axios
154
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
155
+ .then((res) => res.data);
156
+ expect(data).toEqual({});
157
+
158
+ data = await axios
159
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
160
+ .then((res) => res.data);
161
+ expect(data).toEqual({});
162
+ });
163
+
164
+ it('throws error for invalid app', async () => {
165
+ await axios
166
+ .get(`${urlprefix}/v1/settings/app/${INVALID_APP_ID}`, TEST_HEADER_API)
167
+ .catch((error) => expect(error.response.status).toEqual(400));
168
+ await axios
169
+ .get(`${urlprefix}/v1/settings/app/${INVALID_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
170
+ .catch((error) => expect(error.response.status).toEqual(400));
171
+ });
172
+
173
+ it('updates user setting with array value', async () => {
174
+ await axios.post(
175
+ `${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/secondaryLanguages`,
176
+ secondaryLanguageSetting,
177
+ TEST_HEADER_API,
178
+ );
179
+
180
+ const updatedSetting = { secondaryLanguages: ['en', 'fr'] };
181
+ const data = await axios
182
+ .post(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, updatedSetting, TEST_HEADER)
183
+ .then((res) => res.data);
184
+ expect(data).toEqual({ secondaryLanguages: ['en', 'fr'] });
185
+ });
186
+
187
+ it('reads user settings with array value', async () => {
188
+ const data = await axios
189
+ .get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`, TEST_HEADER)
190
+ .then((res) => res.data);
191
+ expect(data[TEST_APP_ID].secondaryLanguages).toEqual(['en', 'fr']);
192
+ });
193
+
194
+ it('updates user setting with null value', async () => {
195
+ const data = await axios
196
+ .post(
197
+ `${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/${TEST_APP_ID}`,
198
+ { secondaryLanguages: null },
199
+ TEST_HEADER,
200
+ )
201
+ .then((res) => res.data);
202
+ expect(data).toEqual({ secondaryLanguages: null });
203
+ });
204
+
205
+ it('update general settings', async () => {
206
+ const data = await axios
207
+ .post(
208
+ `${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/general`,
209
+ { primaryLanguage: 'pt', secondaryLanguages: ['fr', 'es'], secondaryLocationIds: ['US', 'CH'] },
210
+ TEST_HEADER,
211
+ )
212
+ .then((res) => res.data);
213
+ expect(data.primaryLanguage).toEqual('pt');
214
+ expect(data.secondaryLanguages).toStrictEqual(['fr', 'es']);
215
+ expect(data.secondaryLocationIds).toStrictEqual(['US', 'CH']);
216
+ });
217
+
218
+ it('get general settings', async () => {
219
+ const data = await axios
220
+ .get(`${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/general`, TEST_HEADER)
221
+ .then((res) => res.data);
222
+ expect(data.general.primaryLanguage).toEqual('pt');
223
+ expect(data.general.secondaryLanguages).toStrictEqual(['fr', 'es']);
224
+ expect(data.general.secondaryLocationIds).toStrictEqual(['US', 'CH']);
225
+ });
226
+
227
+ it('update general settings with nulls and empty arrays', async () => {
228
+ const data = await axios
229
+ .post(
230
+ `${urlprefix}/v1/settings/users/${TEST_USER_ID}/apps/general`,
231
+ { primaryLanguage: null, secondaryLanguages: null, secondaryLocationIds: [] },
232
+ TEST_HEADER,
233
+ )
234
+ .then((res) => res.data);
235
+ expect(data.primaryLanguage).toEqual(null);
236
+ expect(data.secondaryLanguages).toStrictEqual(null);
237
+ expect(data.secondaryLocationIds).toStrictEqual([]);
238
+ });
239
+
240
+ it('get default general settings', async () => {
241
+ const badUserId = 'ABCDEFGHI'; // uses an invalid userId so it will always return defaults
242
+ const data = await axios
243
+ .get(`${urlprefix}/v1/settings/users/${badUserId}/apps/general`, TEST_HEADER)
244
+ .then((res) => res.data);
245
+ expect(data.general.primaryLanguage).toEqual('en');
246
+ expect(data.general.secondaryLanguages).toStrictEqual([]);
247
+ expect(data.general.secondaryLocationIds).toStrictEqual([]);
248
+ });
249
+
250
+ describe('deprecated_values tests', () => {
251
+ const settingConfigWithDeprecatedValues = {
252
+ default: 'false',
253
+ options: ['true', 'false'],
254
+ setting_type: null,
255
+ deprecated_values: { false: 'updatedFalse' },
256
+ };
257
+ const settingConfigWithDeprecatedValuesNull = {
258
+ default: 'false',
259
+ options: ['true', 'false'],
260
+ setting_type: null,
261
+ deprecated_values: null,
262
+ };
263
+ it('updates app data with deprecated_values', async () => {
264
+ const data = await axios
265
+ .post(
266
+ `${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
267
+ settingConfigWithDeprecatedValues,
268
+ TEST_HEADER_API,
269
+ )
270
+ .then((res) => res.data);
271
+ expect(data).toEqual('Success');
272
+ });
273
+ it('reads updated app settings with deprecated_values', async () => {
274
+ let data = await axios
275
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}`, TEST_HEADER_API)
276
+ .then((res) => res.data);
277
+ expect(data[TEST_SETTING].deprecated_values).toEqual(
278
+ settingConfigWithDeprecatedValues.deprecated_values,
279
+ );
280
+ data = await axios
281
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
282
+ .then((res) => res.data);
283
+ expect(data[TEST_SETTING].deprecated_values).toEqual(
284
+ settingConfigWithDeprecatedValues.deprecated_values,
285
+ );
286
+ });
287
+ it('updates app data with deprecated_values as null', async () => {
288
+ const data = await axios
289
+ .post(
290
+ `${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`,
291
+ settingConfigWithDeprecatedValuesNull,
292
+ TEST_HEADER_API,
293
+ )
294
+ .then((res) => res.data);
295
+ expect(data).toEqual('Success');
296
+ const getData = await axios
297
+ .get(`${urlprefix}/v1/settings/app/${TEST_APP_ID}/setting/${TEST_SETTING}`, TEST_HEADER_API)
298
+ .then((res) => res.data);
299
+ expect(getData.deprecated_values).toBeUndefined();
300
+ });
301
+ });
302
+ });