account-lookup-service 15.5.0-iso.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.circleci/config.yml +11 -0
- package/.ncurc.yaml +6 -0
- package/.nvmrc +1 -0
- package/.nycrc.yml +20 -0
- package/.versionrc +15 -0
- package/CHANGELOG.md +330 -0
- package/CODEOWNERS +38 -0
- package/Dockerfile +45 -0
- package/LICENSE.md +10 -0
- package/README.md +252 -0
- package/audit-ci.jsonc +32 -0
- package/audit-resolve.json +161 -0
- package/config/default.json +109 -0
- package/config/knexfile.js +21 -0
- package/docker/account-lookup-service/default.json +106 -0
- package/docker/account-lookup-service/make-default-json.sh +5 -0
- package/docker/account-lookup-service/override.json +15 -0
- package/docker/central-ledger/default.json +458 -0
- package/docker/config-modifier/account-lookup-service.js +31 -0
- package/docker/kafka/consumer.properties +26 -0
- package/docker/kafka/producer.properties +45 -0
- package/docker/kafka/server.properties +143 -0
- package/docker/kafka/tools-log4j.properties +21 -0
- package/docker/mock-proxy/Dockerfile +15 -0
- package/docker/mock-proxy/package-lock.json +4986 -0
- package/docker/mock-proxy/package.json +24 -0
- package/docker/mock-proxy/src/config.ts +14 -0
- package/docker/mock-proxy/src/server.ts +94 -0
- package/docker/mock-proxy/src/utils.ts +29 -0
- package/docker/mock-proxy/tsconfig.json +24 -0
- package/docker/sql-init/01_permissions.sql +2 -0
- package/docker/sql-init-central-ledger/01_permissions.sql +2 -0
- package/docker/wait-for/wait-for-account-lookup-service.sh +10 -0
- package/docker/wait-for/wait-for-central-ledger.sh +11 -0
- package/docker/wait-for/wait-for-kafka.sh +7 -0
- package/docker/wait-for/wait-for-ml-api-adapter.sh +9 -0
- package/docker/wait-for/wait-for-mockserver.sh +20 -0
- package/docker/wait-for/wait-for-mysql-als.sh +14 -0
- package/docker/wait-for/wait-for-mysql-central-ledger.sh +11 -0
- package/docker/wait-for/wait-for-mysql.sh +11 -0
- package/docker/wait-for/wait-for-objstore.sh +12 -0
- package/docker/wait-for/wait-for.env +18 -0
- package/docker/wait-for/wait-for.sh +81 -0
- package/docker-compose.integration.yml +29 -0
- package/docker-compose.yml +243 -0
- package/jest-int.config.js +8 -0
- package/jest.config.js +16 -0
- package/jsdoc.json +38 -0
- package/migrations/01_currency.js +42 -0
- package/migrations/02_endpointType.js +43 -0
- package/migrations/03_endpointType-indexes.js +37 -0
- package/migrations/04_partyIdType.js +43 -0
- package/migrations/05_partyIdType-indexes.js +38 -0
- package/migrations/08_oracleEndpoint.js +51 -0
- package/migrations/09_oracleEndpoint-indexes.js +41 -0
- package/migrations/10_oracleEndpoint-remove-constraints.js +38 -0
- package/package.json +180 -0
- package/scripts/_wait4_all.js +143 -0
- package/scripts/test-functional.sh +76 -0
- package/secrets/jwsSigningKey.key +27 -0
- package/seeds/currency.js +765 -0
- package/seeds/endpointType.js +65 -0
- package/seeds/partyIdType.js +79 -0
- package/src/api/endpointcache.js +67 -0
- package/src/api/health.js +66 -0
- package/src/api/index.js +85 -0
- package/src/api/oracles/{ID}.js +100 -0
- package/src/api/oracles.js +96 -0
- package/src/api/participants/{ID}/error.js +44 -0
- package/src/api/participants/{ID}.js +44 -0
- package/src/api/participants/{Type}/{ID}/error.js +74 -0
- package/src/api/participants/{Type}/{ID}/{SubId}/error.js +68 -0
- package/src/api/participants/{Type}/{ID}/{SubId}.js +113 -0
- package/src/api/participants/{Type}/{ID}.js +133 -0
- package/src/api/participants.js +63 -0
- package/src/api/parties/{Type}/{ID}/error.js +66 -0
- package/src/api/parties/{Type}/{ID}/{SubId}/error.js +56 -0
- package/src/api/parties/{Type}/{ID}/{SubId}.js +77 -0
- package/src/api/parties/{Type}/{ID}.js +98 -0
- package/src/api/routes.js +294 -0
- package/src/constants.js +16 -0
- package/src/domain/oracle/index.js +33 -0
- package/src/domain/oracle/oracle.js +234 -0
- package/src/domain/participants/index.js +35 -0
- package/src/domain/participants/participants.js +560 -0
- package/src/domain/parties/getPartiesByTypeAndID.js +239 -0
- package/src/domain/parties/index.js +32 -0
- package/src/domain/parties/parties.js +215 -0
- package/src/domain/parties/utils.js +84 -0
- package/src/domain/timeout/dto.js +48 -0
- package/src/domain/timeout/index.js +104 -0
- package/src/handlers/TimeoutHandler.js +94 -0
- package/src/handlers/index.js +70 -0
- package/src/handlers/monitoring/index.js +51 -0
- package/src/handlers/monitoring/plugins/health.js +61 -0
- package/src/handlers/monitoring/plugins/metrics.js +48 -0
- package/src/handlers/register.js +102 -0
- package/src/index.js +66 -0
- package/src/interface/admin-swagger.yaml +804 -0
- package/src/interface/admin_swagger.json +959 -0
- package/src/interface/api-swagger-iso20022-parties.yaml +1734 -0
- package/src/interface/api-swagger.yaml +1733 -0
- package/src/interface/api_swagger.json +3046 -0
- package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2256 -0
- package/src/interface/thirdparty/admin-swagger.yaml +808 -0
- package/src/interface/thirdparty/admin_swagger.json +961 -0
- package/src/interface/thirdparty/api-swagger.yaml +1739 -0
- package/src/interface/thirdparty/api_swagger.json +3142 -0
- package/src/lib/argv.js +39 -0
- package/src/lib/cache.js +126 -0
- package/src/lib/config.js +183 -0
- package/src/lib/db.js +26 -0
- package/src/lib/headers.js +53 -0
- package/src/lib/healthCheck/subServiceHealth.js +84 -0
- package/src/lib/index.js +11 -0
- package/src/lib/migrator.js +17 -0
- package/src/lib/requestLogger.js +54 -0
- package/src/lib/util.js +66 -0
- package/src/metrics/handler.js +33 -0
- package/src/metrics/plugin.js +52 -0
- package/src/metrics/routes.js +43 -0
- package/src/models/currency/currency.js +48 -0
- package/src/models/currency/index.js +32 -0
- package/src/models/endpointType/endpointType.js +48 -0
- package/src/models/endpointType/index.js +32 -0
- package/src/models/misc/migrationLock.js +49 -0
- package/src/models/oracle/facade.js +341 -0
- package/src/models/oracle/index.js +41 -0
- package/src/models/oracle/oracleEndpoint.js +192 -0
- package/src/models/oracle/oracleEndpointCached.js +108 -0
- package/src/models/participantEndpoint/facade.js +238 -0
- package/src/models/partyIdType/index.js +32 -0
- package/src/models/partyIdType/partyIdType.js +41 -0
- package/src/plugins.js +139 -0
- package/src/server.js +199 -0
- package/test/fixtures/index.js +131 -0
- package/test/fixtures/iso.js +110 -0
- package/test/integration/.env +8 -0
- package/test/integration/api/parties.test.js +137 -0
- package/test/integration/constants.js +20 -0
- package/test/integration/domain/oracle/index.test.js +324 -0
- package/test/integration/domain/timeout/index.test.js +75 -0
- package/test/integration/env.sh +15 -0
- package/test/integration/example.test.js +12 -0
- package/test/integration/models/currency/currency.test.js +68 -0
- package/test/integration/plugins.test.js +62 -0
- package/test/integration/prepareTestParticipants.js +30 -0
- package/test/integration/setup.js +5 -0
- package/test/integration-config.json +81 -0
- package/test/integration-runner.sh +108 -0
- package/test/unit/api/health.test.js +142 -0
- package/test/unit/api/oracles/{ID}.test.js +264 -0
- package/test/unit/api/oracles.test.js +173 -0
- package/test/unit/api/participants/participants.test.js +117 -0
- package/test/unit/api/participants/{Type}/{ID}/error.test.js +155 -0
- package/test/unit/api/participants/{Type}/{ID}/{SubId}/error.test.js +131 -0
- package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +377 -0
- package/test/unit/api/participants/{Type}/{ID}.test.js +383 -0
- package/test/unit/api/participants.test.js +108 -0
- package/test/unit/api/parties/endpointcache.test.js +83 -0
- package/test/unit/api/parties/parties.test.js +102 -0
- package/test/unit/api/parties/{Type}/{ID}/error.test.js +145 -0
- package/test/unit/api/parties/{Type}/{ID}/{SubId}/error.test.js +141 -0
- package/test/unit/api/parties/{Type}/{ID}/{SubId}.test.js +241 -0
- package/test/unit/api/parties/{Type}/{ID}.test.js +240 -0
- package/test/unit/domain/oracle/oracle.test.js +505 -0
- package/test/unit/domain/participants/participants.test.js +1724 -0
- package/test/unit/domain/parties/parties.test.js +940 -0
- package/test/unit/domain/timeout/dto.test.js +28 -0
- package/test/unit/domain/timeout/index.test.js +81 -0
- package/test/unit/handlers/TimeoutHandler.test.js +125 -0
- package/test/unit/handlers/index.test.js +56 -0
- package/test/unit/handlers/register.test.js +90 -0
- package/test/unit/index.test.js +139 -0
- package/test/unit/iso20022/partiesValidation.test.js +129 -0
- package/test/unit/lib/TransformFacades.test.js +18 -0
- package/test/unit/lib/argv.test.js +40 -0
- package/test/unit/lib/cache.test.js +172 -0
- package/test/unit/lib/config.test.js +108 -0
- package/test/unit/lib/healthCheck/subServiceHealth.test.js +89 -0
- package/test/unit/lib/migrator.test.js +52 -0
- package/test/unit/lib/requestLogger.test.js +115 -0
- package/test/unit/lib/util.test.js +68 -0
- package/test/unit/mocks.js +66 -0
- package/test/unit/models/currency/currency.test.js +91 -0
- package/test/unit/models/endpointType/endpointType.test.js +69 -0
- package/test/unit/models/misc/migrationLock.test.js +96 -0
- package/test/unit/models/oracle/facade.test.js +546 -0
- package/test/unit/models/oracle/oracleEndpoint.test.js +409 -0
- package/test/unit/models/oracle/oracleEndpointCached.test.js +153 -0
- package/test/unit/models/participantEndpoint/facade.test.js +295 -0
- package/test/unit/models/partyIdType/partyIdType.test.js +88 -0
- package/test/unit/plugins.test.js +89 -0
- package/test/unit/setup.js +7 -0
- package/test/util/apiClients/AlsApiClient.js +44 -0
- package/test/util/apiClients/BasicApiClient.js +34 -0
- package/test/util/apiClients/ProxyApiClient.js +25 -0
- package/test/util/apiClients/index.js +7 -0
- package/test/util/helper.js +332 -0
- package/test/util/index.js +11 -0
- package/test/util/mockgen.js +43 -0
- package/test/util/onboarding.js +132 -0
- package/test/util/scripts/addAlsDb.sh +33 -0
- package/test/util/scripts/configureMockServer.sh +35 -0
- package/test/util/scripts/env.sh +19 -0
- package/test/util/scripts/populateTestData.sh +62 -0
- package/test/util/scripts/startMockCentralServer.sh +45 -0
- package/test/util/scripts/startMockOracleServer.sh +45 -0
- package/test/util/testConfig.js +44 -0
@@ -0,0 +1,98 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
+
Contributors
|
9
|
+
--------------
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
12
|
+
should be listed with a '*' in the first column. People who have
|
13
|
+
contributed from an organization can be listed under the organization
|
14
|
+
that actually holds the copyright for their contributions (see the
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
17
|
+
optionally within square brackets <email>.
|
18
|
+
* Gates Foundation
|
19
|
+
* Name Surname <name.surname@gatesfoundation.com>
|
20
|
+
|
21
|
+
* Rajiv Mothilal <rajiv.mothilal@modusbox.com>
|
22
|
+
|
23
|
+
--------------
|
24
|
+
******/
|
25
|
+
'use strict'
|
26
|
+
|
27
|
+
const { Action, Type } = require('@mojaloop/central-services-shared').Enum.Events.Event
|
28
|
+
const EventSdk = require('@mojaloop/event-sdk')
|
29
|
+
const Metrics = require('@mojaloop/central-services-metrics')
|
30
|
+
const parties = require('../../../domain/parties')
|
31
|
+
const LibUtil = require('../../../lib/util')
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Operations on /parties/{Type}/{ID}
|
35
|
+
*/
|
36
|
+
module.exports = {
|
37
|
+
/**
|
38
|
+
* summary: getPartiesByTypeAndID
|
39
|
+
* description: The HTTP request GET /parties/<Type>/<ID> (or GET /parties/<Type>/<ID>/<SubId>) is used to lookup information regarding the requested Party, defined by <Type>, <ID> and optionally <SubId> (for example, GET /parties/MSISDN/123456789, or GET /parties/BUSINESS/shoecompany/employee1).
|
40
|
+
* parameters: Accept
|
41
|
+
* produces: application/json
|
42
|
+
* responses: 202, 400, 401, 403, 404, 405, 406, 501, 503
|
43
|
+
*/
|
44
|
+
get: async function (context, request, h) {
|
45
|
+
const histTimerEnd = Metrics.getHistogram(
|
46
|
+
'ing_getPartiesByTypeAndID',
|
47
|
+
'Ingress - Get party by Type and Id',
|
48
|
+
['success']
|
49
|
+
).startTimer()
|
50
|
+
const { headers, payload, params, method, query, span } = request
|
51
|
+
const { cache, proxyCache } = request.server.app
|
52
|
+
|
53
|
+
const spanTags = LibUtil.getSpanTags({ headers }, Type.PARTY, Action.LOOKUP)
|
54
|
+
span.setTags(spanTags)
|
55
|
+
await span.audit({
|
56
|
+
headers,
|
57
|
+
payload
|
58
|
+
}, EventSdk.AuditEventAction.start)
|
59
|
+
// Here we call an async function- but as we send an immediate sync response, _all_ errors
|
60
|
+
// _must_ be handled by getPartiesByTypeAndID.
|
61
|
+
parties.getPartiesByTypeAndID(headers, params, method, query, span, cache, proxyCache).catch(err => {
|
62
|
+
request.server.log(['error'], `ERROR - getPartiesByTypeAndID: ${LibUtil.getStackOrInspect(err)}`)
|
63
|
+
})
|
64
|
+
histTimerEnd({ success: true })
|
65
|
+
return h.response().code(202)
|
66
|
+
},
|
67
|
+
|
68
|
+
/**
|
69
|
+
* summary: putPartiesByTypeAndID
|
70
|
+
* description: The callback PUT /parties/<Type>/<ID> (or PUT /parties/<Type>/<ID>/<SubId>) is used to inform the client of a successful result of the Party information lookup.
|
71
|
+
* parameters: body, Content-Length
|
72
|
+
* produces: application/json
|
73
|
+
* responses: 200, 400, 401, 403, 404, 405, 406, 501, 503
|
74
|
+
*/
|
75
|
+
put: async function (context, request, h) {
|
76
|
+
const histTimerEnd = Metrics.getHistogram(
|
77
|
+
'ing_putPartiesByTypeAndID',
|
78
|
+
'Ingress - Put party by Type and Id',
|
79
|
+
['success']
|
80
|
+
).startTimer()
|
81
|
+
const { headers, payload, params, method, dataUri, span } = request
|
82
|
+
const { cache, proxyCache } = request.server.app
|
83
|
+
|
84
|
+
const spanTags = LibUtil.getSpanTags({ headers }, Type.PARTY, Action.PUT)
|
85
|
+
span.setTags(spanTags)
|
86
|
+
await span.audit({
|
87
|
+
headers,
|
88
|
+
payload
|
89
|
+
}, EventSdk.AuditEventAction.start)
|
90
|
+
// Here we call an async function- but as we send an immediate sync response, _all_ errors
|
91
|
+
// _must_ be handled by putPartiesByTypeAndID.
|
92
|
+
parties.putPartiesByTypeAndID(headers, params, method, payload, dataUri, cache, proxyCache).catch(err => {
|
93
|
+
request.server.log(['error'], `ERROR - putPartiesByTypeAndID: ${LibUtil.getStackOrInspect(err)}`)
|
94
|
+
})
|
95
|
+
histTimerEnd({ success: true })
|
96
|
+
return h.response().code(200)
|
97
|
+
}
|
98
|
+
}
|
@@ -0,0 +1,294 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
+
Contributors
|
9
|
+
--------------
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
12
|
+
should be listed with a '*' in the first column. People who have
|
13
|
+
contributed from an organization can be listed under the organization
|
14
|
+
that actually holds the copyright for their contributions (see the
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
17
|
+
optionally within square brackets <email>.
|
18
|
+
* Gates Foundation
|
19
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
20
|
+
|
21
|
+
* ModusBox
|
22
|
+
- Steven Oderayi <steven.oderayi@modusbox.com>
|
23
|
+
--------------
|
24
|
+
******/
|
25
|
+
|
26
|
+
'use strict'
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Request handler
|
30
|
+
*
|
31
|
+
* @param {object} api OpenAPIBackend instance
|
32
|
+
* @param {object} req Request
|
33
|
+
* @param {object} h Response handle
|
34
|
+
*/
|
35
|
+
const handleRequest = (api, req, h) => api.handleRequest(
|
36
|
+
{
|
37
|
+
method: req.method,
|
38
|
+
path: req.path,
|
39
|
+
body: req.payload,
|
40
|
+
query: req.query,
|
41
|
+
headers: req.headers
|
42
|
+
}, req, h)
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Core API Routes
|
46
|
+
*
|
47
|
+
* @param {object} api OpenAPIBackend instance
|
48
|
+
*/
|
49
|
+
const APIRoutes = (api) => [
|
50
|
+
{
|
51
|
+
method: 'GET',
|
52
|
+
path: '/health',
|
53
|
+
handler: (req, h) => handleRequest(api, req, h),
|
54
|
+
config: {
|
55
|
+
tags: ['api', 'health'],
|
56
|
+
description: 'GET health'
|
57
|
+
}
|
58
|
+
},
|
59
|
+
{
|
60
|
+
method: 'PUT',
|
61
|
+
path: '/participants/{ID}/error',
|
62
|
+
handler: (req, h) => handleRequest(api, req, h),
|
63
|
+
config: {
|
64
|
+
tags: ['api', 'participants', 'sampled'],
|
65
|
+
description: 'PUT Participant error by ID'
|
66
|
+
}
|
67
|
+
},
|
68
|
+
{
|
69
|
+
method: 'PUT',
|
70
|
+
path: '/participants/{ID}',
|
71
|
+
handler: (req, h) => handleRequest(api, req, h),
|
72
|
+
config: {
|
73
|
+
tags: ['api', 'participants', 'sampled'],
|
74
|
+
description: 'PUT Participant by ID'
|
75
|
+
}
|
76
|
+
},
|
77
|
+
{
|
78
|
+
method: 'PUT',
|
79
|
+
path: '/participants/{Type}/{ID}/error',
|
80
|
+
handler: (req, h) => handleRequest(api, req, h),
|
81
|
+
config: {
|
82
|
+
tags: ['api', 'participants', 'sampled'],
|
83
|
+
description: 'PUT Participant error by Type & ID'
|
84
|
+
}
|
85
|
+
},
|
86
|
+
{
|
87
|
+
method: 'PUT',
|
88
|
+
path: '/participants/{Type}/{ID}/{SubId}/error',
|
89
|
+
handler: (req, h) => handleRequest(api, req, h),
|
90
|
+
config: {
|
91
|
+
tags: ['api', 'participants', 'sampled'],
|
92
|
+
description: 'PUT Participant error by Type, ID & SubId'
|
93
|
+
}
|
94
|
+
},
|
95
|
+
{
|
96
|
+
method: 'GET',
|
97
|
+
path: '/participants/{Type}/{ID}/{SubId}',
|
98
|
+
handler: (req, h) => handleRequest(api, req, h),
|
99
|
+
config: {
|
100
|
+
tags: ['api', 'participants', 'sampled'],
|
101
|
+
description: 'GET Participants by Type, ID & SubId'
|
102
|
+
}
|
103
|
+
},
|
104
|
+
{
|
105
|
+
method: 'PUT',
|
106
|
+
path: '/participants/{Type}/{ID}/{SubId}',
|
107
|
+
handler: (req, h) => handleRequest(api, req, h),
|
108
|
+
config: {
|
109
|
+
tags: ['api', 'participants', 'sampled'],
|
110
|
+
description: 'PUT Participant by Type, ID & SubId'
|
111
|
+
}
|
112
|
+
},
|
113
|
+
{
|
114
|
+
method: 'POST',
|
115
|
+
path: '/participants/{Type}/{ID}/{SubId}',
|
116
|
+
handler: (req, h) => handleRequest(api, req, h),
|
117
|
+
config: {
|
118
|
+
tags: ['api', 'participants', 'sampled'],
|
119
|
+
description: 'POST Participant by Type, ID & SubId'
|
120
|
+
}
|
121
|
+
},
|
122
|
+
{
|
123
|
+
method: 'DELETE',
|
124
|
+
path: '/participants/{Type}/{ID}/{SubId}',
|
125
|
+
handler: (req, h) => handleRequest(api, req, h),
|
126
|
+
config: {
|
127
|
+
tags: ['api', 'participants', 'sampled'],
|
128
|
+
description: 'DELETE Participant by Type, ID, & SubId'
|
129
|
+
}
|
130
|
+
},
|
131
|
+
{
|
132
|
+
method: 'GET',
|
133
|
+
path: '/participants/{Type}/{ID}',
|
134
|
+
handler: (req, h) => handleRequest(api, req, h),
|
135
|
+
config: {
|
136
|
+
tags: ['api', 'participants', 'sampled'],
|
137
|
+
description: 'GET Participant by Type & ID'
|
138
|
+
}
|
139
|
+
},
|
140
|
+
{
|
141
|
+
method: 'PUT',
|
142
|
+
path: '/participants/{Type}/{ID}',
|
143
|
+
handler: (req, h) => handleRequest(api, req, h),
|
144
|
+
config: {
|
145
|
+
tags: ['api', 'participants', 'sampled'],
|
146
|
+
description: 'PUT Participant by Type & ID'
|
147
|
+
}
|
148
|
+
},
|
149
|
+
{
|
150
|
+
method: 'POST',
|
151
|
+
path: '/participants/{Type}/{ID}',
|
152
|
+
handler: (req, h) => handleRequest(api, req, h),
|
153
|
+
config: {
|
154
|
+
tags: ['api', 'participants', 'sampled'],
|
155
|
+
description: 'POST Participant by Type & ID'
|
156
|
+
}
|
157
|
+
},
|
158
|
+
{
|
159
|
+
method: 'DELETE',
|
160
|
+
path: '/participants/{Type}/{ID}',
|
161
|
+
handler: (req, h) => handleRequest(api, req, h),
|
162
|
+
config: {
|
163
|
+
tags: ['api', 'participants', 'sampled'],
|
164
|
+
description: 'DELETE Participant by Type & ID'
|
165
|
+
}
|
166
|
+
},
|
167
|
+
{
|
168
|
+
method: 'POST',
|
169
|
+
path: '/participants',
|
170
|
+
handler: (req, h) => handleRequest(api, req, h),
|
171
|
+
config: {
|
172
|
+
tags: ['api', 'participants', 'sampled'],
|
173
|
+
description: 'POST Participants'
|
174
|
+
}
|
175
|
+
},
|
176
|
+
{
|
177
|
+
method: 'GET',
|
178
|
+
path: '/parties/{Type}/{ID}',
|
179
|
+
handler: (req, h) => handleRequest(api, req, h),
|
180
|
+
config: {
|
181
|
+
tags: ['api', 'parties', 'sampled'],
|
182
|
+
description: 'GET Parties by Type & ID'
|
183
|
+
}
|
184
|
+
},
|
185
|
+
{
|
186
|
+
method: 'PUT',
|
187
|
+
path: '/parties/{Type}/{ID}',
|
188
|
+
handler: (req, h) => handleRequest(api, req, h),
|
189
|
+
config: {
|
190
|
+
tags: ['api', 'parties', 'sampled'],
|
191
|
+
description: 'PUT Parties by Type & ID'
|
192
|
+
}
|
193
|
+
},
|
194
|
+
{
|
195
|
+
method: 'PUT',
|
196
|
+
path: '/parties/{Type}/{ID}/error',
|
197
|
+
handler: (req, h) => handleRequest(api, req, h),
|
198
|
+
config: {
|
199
|
+
tags: ['api', 'parties', 'sampled'],
|
200
|
+
description: 'PUT Parties error by Type & ID'
|
201
|
+
}
|
202
|
+
},
|
203
|
+
{
|
204
|
+
method: 'GET',
|
205
|
+
path: '/parties/{Type}/{ID}/{SubId}',
|
206
|
+
handler: (req, h) => handleRequest(api, req, h),
|
207
|
+
config: {
|
208
|
+
tags: ['api', 'parties', 'sampled'],
|
209
|
+
description: 'GET Parties by Type, ID & SubId'
|
210
|
+
}
|
211
|
+
},
|
212
|
+
{
|
213
|
+
method: 'PUT',
|
214
|
+
path: '/parties/{Type}/{ID}/{SubId}',
|
215
|
+
handler: (req, h) => handleRequest(api, req, h),
|
216
|
+
config: {
|
217
|
+
tags: ['api', 'parties', 'sampled'],
|
218
|
+
description: 'PUT Parties by Type, ID & SubId'
|
219
|
+
}
|
220
|
+
},
|
221
|
+
{
|
222
|
+
method: 'PUT',
|
223
|
+
path: '/parties/{Type}/{ID}/{SubId}/error',
|
224
|
+
handler: (req, h) => handleRequest(api, req, h),
|
225
|
+
config: {
|
226
|
+
tags: ['api', 'parties', 'sampled'],
|
227
|
+
description: 'PUT Parties error by Type, ID & SubId'
|
228
|
+
}
|
229
|
+
},
|
230
|
+
{
|
231
|
+
method: 'DELETE',
|
232
|
+
path: '/endpointcache',
|
233
|
+
handler: (req, h) => handleRequest(api, req, h),
|
234
|
+
config: {
|
235
|
+
tags: ['api', 'sampled'],
|
236
|
+
description: 'DELETE Participants Endpoint Cache'
|
237
|
+
}
|
238
|
+
}
|
239
|
+
]
|
240
|
+
|
241
|
+
/**
|
242
|
+
* Admin API Routes
|
243
|
+
*
|
244
|
+
* @param {object} api OpenAPIBackend instance
|
245
|
+
*/
|
246
|
+
const AdminRoutes = (api) => [
|
247
|
+
{
|
248
|
+
method: 'GET',
|
249
|
+
path: '/health',
|
250
|
+
handler: (req, h) => handleRequest(api, req, h),
|
251
|
+
config: {
|
252
|
+
tags: ['api', 'health'],
|
253
|
+
description: 'GET health'
|
254
|
+
}
|
255
|
+
},
|
256
|
+
{
|
257
|
+
method: 'GET',
|
258
|
+
path: '/oracles',
|
259
|
+
handler: (req, h) => handleRequest(api, req, h),
|
260
|
+
config: {
|
261
|
+
tags: ['api', 'admin', 'sampled'],
|
262
|
+
description: 'GET Oracles'
|
263
|
+
}
|
264
|
+
},
|
265
|
+
{
|
266
|
+
method: 'POST',
|
267
|
+
path: '/oracles',
|
268
|
+
handler: (req, h) => handleRequest(api, req, h),
|
269
|
+
config: {
|
270
|
+
tags: ['api', 'admin', 'sampled'],
|
271
|
+
description: 'Create Oracles'
|
272
|
+
}
|
273
|
+
},
|
274
|
+
{
|
275
|
+
method: 'PUT',
|
276
|
+
path: '/oracles/{ID}',
|
277
|
+
handler: (req, h) => handleRequest(api, req, h),
|
278
|
+
config: {
|
279
|
+
tags: ['api', 'admin', 'sampled'],
|
280
|
+
description: 'Update Oracle'
|
281
|
+
}
|
282
|
+
},
|
283
|
+
{
|
284
|
+
method: 'DELETE',
|
285
|
+
path: '/oracles/{ID}',
|
286
|
+
handler: (req, h) => handleRequest(api, req, h),
|
287
|
+
config: {
|
288
|
+
tags: ['api', 'admin', 'sampled'],
|
289
|
+
description: 'Delete Oracle by ID'
|
290
|
+
}
|
291
|
+
}
|
292
|
+
]
|
293
|
+
|
294
|
+
module.exports = { APIRoutes, AdminRoutes }
|
package/src/constants.js
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
const ERROR_MESSAGES = Object.freeze({
|
2
|
+
partySourceFspNotFound: 'Requester FSP not found',
|
3
|
+
partyDestinationFspNotFound: 'Destination FSP not found',
|
4
|
+
partyProxyNotFound: 'Proxy not found',
|
5
|
+
proxyConnectionError: 'Proxy connection error',
|
6
|
+
failedToCacheSendToProxiesList: 'Failed to cache sendToProxiesList'
|
7
|
+
})
|
8
|
+
|
9
|
+
const HANDLER_TYPES = Object.freeze({
|
10
|
+
TIMEOUT: 'timeout'
|
11
|
+
})
|
12
|
+
|
13
|
+
module.exports = {
|
14
|
+
ERROR_MESSAGES,
|
15
|
+
HANDLER_TYPES
|
16
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
+
Contributors
|
9
|
+
--------------
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
12
|
+
should be listed with a '*' in the first column. People who have
|
13
|
+
contributed from an organization can be listed under the organization
|
14
|
+
that actually holds the copyright for their contributions (see the
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
17
|
+
optionally within square brackets <email>.
|
18
|
+
* Gates Foundation
|
19
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
20
|
+
|
21
|
+
- Rajiv Mothilal <rajiv.mothilal@modusbox.com>
|
22
|
+
|
23
|
+
--------------
|
24
|
+
******/
|
25
|
+
|
26
|
+
'use strict'
|
27
|
+
|
28
|
+
const oracle = require('./oracle')
|
29
|
+
|
30
|
+
exports.createOracle = oracle.createOracle
|
31
|
+
exports.getOracle = oracle.getOracle
|
32
|
+
exports.deleteOracle = oracle.deleteOracle
|
33
|
+
exports.updateOracle = oracle.updateOracle
|
@@ -0,0 +1,234 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
8
|
+
Contributors
|
9
|
+
--------------
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
12
|
+
should be listed with a '*' in the first column. People who have
|
13
|
+
contributed from an organization can be listed under the organization
|
14
|
+
that actually holds the copyright for their contributions (see the
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
17
|
+
optionally within square brackets <email>.
|
18
|
+
* Gates Foundation
|
19
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
20
|
+
|
21
|
+
- Rajiv Mothilal <rajiv.mothilal@modusbox.com>
|
22
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
23
|
+
|
24
|
+
--------------
|
25
|
+
******/
|
26
|
+
'use strict'
|
27
|
+
|
28
|
+
const Logger = require('@mojaloop/central-services-logger')
|
29
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
30
|
+
const Metrics = require('@mojaloop/central-services-metrics')
|
31
|
+
|
32
|
+
const Config = require('../../lib/config')
|
33
|
+
const oracleEndpoint = require('../../models/oracle')
|
34
|
+
const cachedOracleEndpoint = require('../../models/oracle/oracleEndpointCached')
|
35
|
+
const partyIdType = require('../../models/partyIdType')
|
36
|
+
const endpointType = require('../../models/endpointType')
|
37
|
+
const currency = require('../../models/currency')
|
38
|
+
|
39
|
+
/**
|
40
|
+
* @function createOracle
|
41
|
+
*
|
42
|
+
* @description This creates and entry in the oracleEndpoint table
|
43
|
+
*
|
44
|
+
* @param {object} payload The payload from the Hapi server request
|
45
|
+
*/
|
46
|
+
exports.createOracle = async (payload) => {
|
47
|
+
const histTimerEnd = Metrics.getHistogram(
|
48
|
+
'createOracle',
|
49
|
+
'Create Oracle',
|
50
|
+
['success']
|
51
|
+
).startTimer()
|
52
|
+
try {
|
53
|
+
const partyIdTypeModel = await partyIdType.getPartyIdTypeByName(payload.oracleIdType)
|
54
|
+
const endpointTypeModel = await endpointType.getEndpointTypeByType(payload.endpoint.endpointType)
|
55
|
+
const existingActiveOracle = await oracleEndpoint.getAllOracleEndpointsByMatchCondition(
|
56
|
+
payload,
|
57
|
+
partyIdTypeModel.partyIdTypeId,
|
58
|
+
endpointTypeModel.endpointTypeId
|
59
|
+
)
|
60
|
+
|
61
|
+
if (existingActiveOracle.length > 0 && existingActiveOracle[0].isActive === 1) {
|
62
|
+
const err = new Error('Active oracle with matching partyIdTypeId, endpointTypeId, currencyId already exists')
|
63
|
+
Logger.isErrorEnabled && Logger.error(err)
|
64
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
65
|
+
}
|
66
|
+
|
67
|
+
const oracleEntity = {}
|
68
|
+
if (payload.isDefault) {
|
69
|
+
oracleEntity.isDefault = payload.isDefault
|
70
|
+
} else {
|
71
|
+
oracleEntity.isDefault = false
|
72
|
+
}
|
73
|
+
if (payload.currency) {
|
74
|
+
oracleEntity.currencyId = payload.currency
|
75
|
+
}
|
76
|
+
oracleEntity.value = payload.endpoint.value
|
77
|
+
oracleEntity.createdBy = 'Admin'
|
78
|
+
oracleEntity.partyIdTypeId = partyIdTypeModel.partyIdTypeId
|
79
|
+
oracleEntity.endpointTypeId = endpointTypeModel.endpointTypeId
|
80
|
+
await oracleEndpoint.createOracleEndpoint(oracleEntity)
|
81
|
+
histTimerEnd({ success: true })
|
82
|
+
return true
|
83
|
+
} catch (err) {
|
84
|
+
histTimerEnd({ success: false })
|
85
|
+
Logger.isErrorEnabled && Logger.error(err)
|
86
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* @function getOracle
|
92
|
+
*
|
93
|
+
* @description Retrieves list of oracles may accept query parameters
|
94
|
+
*
|
95
|
+
* @param {object} query The query parameters from the Hapi server request
|
96
|
+
*/
|
97
|
+
exports.getOracle = async (query) => {
|
98
|
+
const histTimerEnd = Metrics.getHistogram(
|
99
|
+
'getOracle',
|
100
|
+
'Get Oracle',
|
101
|
+
['success']
|
102
|
+
).startTimer()
|
103
|
+
try {
|
104
|
+
let oracleEndpointModelList
|
105
|
+
let isCurrency; let isType = false
|
106
|
+
const oracleList = []
|
107
|
+
if (query.currency) {
|
108
|
+
isCurrency = true
|
109
|
+
}
|
110
|
+
if (query.type) {
|
111
|
+
isType = true
|
112
|
+
}
|
113
|
+
if (isCurrency && isType) {
|
114
|
+
oracleEndpointModelList = await cachedOracleEndpoint.getOracleEndpointByTypeAndCurrency(query.type, query.currency)
|
115
|
+
} else if (isCurrency && !isType) {
|
116
|
+
oracleEndpointModelList = await cachedOracleEndpoint.getOracleEndpointByCurrency(query.currency)
|
117
|
+
} else if (isType && !isCurrency) {
|
118
|
+
oracleEndpointModelList = await cachedOracleEndpoint.getOracleEndpointByType(query.type)
|
119
|
+
} else {
|
120
|
+
oracleEndpointModelList = await oracleEndpoint.getAllOracleEndpoint()
|
121
|
+
}
|
122
|
+
for (const oracleEndpointModel of oracleEndpointModelList) {
|
123
|
+
const oracle = {
|
124
|
+
oracleId: oracleEndpointModel.oracleEndpointId,
|
125
|
+
oracleIdType: oracleEndpointModel.idType,
|
126
|
+
endpoint: {
|
127
|
+
value: oracleEndpointModel.value,
|
128
|
+
endpointType: oracleEndpointModel.endpointType
|
129
|
+
},
|
130
|
+
currency: oracleEndpointModel.currency || undefined,
|
131
|
+
isDefault: oracleEndpointModel.isDefault
|
132
|
+
}
|
133
|
+
oracleList.push(oracle)
|
134
|
+
}
|
135
|
+
histTimerEnd({ success: true })
|
136
|
+
return oracleList
|
137
|
+
} catch (err) {
|
138
|
+
histTimerEnd({ success: false })
|
139
|
+
Logger.isErrorEnabled && Logger.error(err)
|
140
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
/**
|
145
|
+
* @function updateOracle
|
146
|
+
*
|
147
|
+
* @description This process updates properties of oracle entries
|
148
|
+
*
|
149
|
+
* @param {object} params The parameters from the Hapi server request
|
150
|
+
* @param {object} payload The payload from the Hapi server request
|
151
|
+
*/
|
152
|
+
exports.updateOracle = async (params, payload) => {
|
153
|
+
const histTimerEnd = Metrics.getHistogram(
|
154
|
+
'updateOracle',
|
155
|
+
'Update Oracle',
|
156
|
+
['success']
|
157
|
+
).startTimer()
|
158
|
+
try {
|
159
|
+
const currentOracleEndpointList = await oracleEndpoint.getOracleEndpointById(params.ID)
|
160
|
+
if (currentOracleEndpointList.length > 0) {
|
161
|
+
const partyIdTypeModel = await partyIdType.getPartyIdTypeByName(payload.oracleIdType)
|
162
|
+
const endpointTypeModel = await endpointType.getEndpointTypeByType(payload.endpoint.endpointType)
|
163
|
+
const existingActiveOracle = await oracleEndpoint.getAllOracleEndpointsByMatchCondition(
|
164
|
+
payload,
|
165
|
+
partyIdTypeModel.partyIdTypeId,
|
166
|
+
endpointTypeModel.endpointTypeId
|
167
|
+
)
|
168
|
+
|
169
|
+
if (existingActiveOracle.length > 0 && existingActiveOracle[0].isActive === 1) {
|
170
|
+
const err = new Error('Active oracle with matching partyIdTypeId, endpointTypeId, currencyId already exists')
|
171
|
+
Logger.isErrorEnabled && Logger.error(err)
|
172
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
173
|
+
}
|
174
|
+
|
175
|
+
const currentOracleEndpoint = currentOracleEndpointList[0]
|
176
|
+
const newOracleEntry = {}
|
177
|
+
if (payload.oracleIdType && payload.oracleIdType !== currentOracleEndpoint.idType) {
|
178
|
+
const partyTypeModel = await partyIdType.getPartyIdTypeByName(payload.oracleIdType)
|
179
|
+
newOracleEntry.partyIdTypeId = partyTypeModel.partyIdTypeId
|
180
|
+
}
|
181
|
+
if (payload.endpoint && payload.endpoint.value && payload.endpoint.value !== currentOracleEndpoint.value) {
|
182
|
+
newOracleEntry.value = payload.endpoint.value
|
183
|
+
}
|
184
|
+
if (payload.endpoint && payload.endpoint.endpointType && payload.endpoint.endpointType !== currentOracleEndpoint.endpointType) {
|
185
|
+
const endpointTypeModel = await endpointType.getEndpointTypeByType(payload.endpoint.endpointType)
|
186
|
+
newOracleEntry.endpointTypeId = endpointTypeModel.endpointTypeId
|
187
|
+
}
|
188
|
+
if (payload.currency && payload.currency !== currentOracleEndpoint.currency) {
|
189
|
+
const currencyModel = await currency.getCurrencyById(payload.currency)
|
190
|
+
if (currencyModel) {
|
191
|
+
newOracleEntry.currencyId = payload.currency
|
192
|
+
} else {
|
193
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, 'Invalid currency code').toApiErrorObject(Config.ERROR_HANDLING)
|
194
|
+
}
|
195
|
+
}
|
196
|
+
if (payload.isDefault && payload.isDefault !== currentOracleEndpoint.isDefault) {
|
197
|
+
newOracleEntry.isDefault = payload.isDefault
|
198
|
+
}
|
199
|
+
await oracleEndpoint.updateOracleEndpointById(params.ID, newOracleEntry)
|
200
|
+
histTimerEnd({ success: true })
|
201
|
+
return true
|
202
|
+
} else {
|
203
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Oracle not found')
|
204
|
+
}
|
205
|
+
} catch (err) {
|
206
|
+
histTimerEnd({ success: false })
|
207
|
+
Logger.isErrorEnabled && Logger.error(err)
|
208
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
/**
|
213
|
+
* @function deleteOracle
|
214
|
+
*
|
215
|
+
* @description This process deletes an oracle endpoint by setting
|
216
|
+
*
|
217
|
+
* @param {object} params The parameters from the Hapi server request
|
218
|
+
*/
|
219
|
+
exports.deleteOracle = async (params) => {
|
220
|
+
const histTimerEnd = Metrics.getHistogram(
|
221
|
+
'deleteOracle',
|
222
|
+
'Delete Oracle',
|
223
|
+
['success']
|
224
|
+
).startTimer()
|
225
|
+
try {
|
226
|
+
await oracleEndpoint.destroyOracleEndpointById(params.ID)
|
227
|
+
histTimerEnd({ success: true })
|
228
|
+
return true
|
229
|
+
} catch (err) {
|
230
|
+
histTimerEnd({ success: false })
|
231
|
+
Logger.isErrorEnabled && Logger.error(err)
|
232
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
233
|
+
}
|
234
|
+
}
|