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.
Files changed (209) hide show
  1. package/.circleci/config.yml +11 -0
  2. package/.ncurc.yaml +6 -0
  3. package/.nvmrc +1 -0
  4. package/.nycrc.yml +20 -0
  5. package/.versionrc +15 -0
  6. package/CHANGELOG.md +330 -0
  7. package/CODEOWNERS +38 -0
  8. package/Dockerfile +45 -0
  9. package/LICENSE.md +10 -0
  10. package/README.md +252 -0
  11. package/audit-ci.jsonc +32 -0
  12. package/audit-resolve.json +161 -0
  13. package/config/default.json +109 -0
  14. package/config/knexfile.js +21 -0
  15. package/docker/account-lookup-service/default.json +106 -0
  16. package/docker/account-lookup-service/make-default-json.sh +5 -0
  17. package/docker/account-lookup-service/override.json +15 -0
  18. package/docker/central-ledger/default.json +458 -0
  19. package/docker/config-modifier/account-lookup-service.js +31 -0
  20. package/docker/kafka/consumer.properties +26 -0
  21. package/docker/kafka/producer.properties +45 -0
  22. package/docker/kafka/server.properties +143 -0
  23. package/docker/kafka/tools-log4j.properties +21 -0
  24. package/docker/mock-proxy/Dockerfile +15 -0
  25. package/docker/mock-proxy/package-lock.json +4986 -0
  26. package/docker/mock-proxy/package.json +24 -0
  27. package/docker/mock-proxy/src/config.ts +14 -0
  28. package/docker/mock-proxy/src/server.ts +94 -0
  29. package/docker/mock-proxy/src/utils.ts +29 -0
  30. package/docker/mock-proxy/tsconfig.json +24 -0
  31. package/docker/sql-init/01_permissions.sql +2 -0
  32. package/docker/sql-init-central-ledger/01_permissions.sql +2 -0
  33. package/docker/wait-for/wait-for-account-lookup-service.sh +10 -0
  34. package/docker/wait-for/wait-for-central-ledger.sh +11 -0
  35. package/docker/wait-for/wait-for-kafka.sh +7 -0
  36. package/docker/wait-for/wait-for-ml-api-adapter.sh +9 -0
  37. package/docker/wait-for/wait-for-mockserver.sh +20 -0
  38. package/docker/wait-for/wait-for-mysql-als.sh +14 -0
  39. package/docker/wait-for/wait-for-mysql-central-ledger.sh +11 -0
  40. package/docker/wait-for/wait-for-mysql.sh +11 -0
  41. package/docker/wait-for/wait-for-objstore.sh +12 -0
  42. package/docker/wait-for/wait-for.env +18 -0
  43. package/docker/wait-for/wait-for.sh +81 -0
  44. package/docker-compose.integration.yml +29 -0
  45. package/docker-compose.yml +243 -0
  46. package/jest-int.config.js +8 -0
  47. package/jest.config.js +16 -0
  48. package/jsdoc.json +38 -0
  49. package/migrations/01_currency.js +42 -0
  50. package/migrations/02_endpointType.js +43 -0
  51. package/migrations/03_endpointType-indexes.js +37 -0
  52. package/migrations/04_partyIdType.js +43 -0
  53. package/migrations/05_partyIdType-indexes.js +38 -0
  54. package/migrations/08_oracleEndpoint.js +51 -0
  55. package/migrations/09_oracleEndpoint-indexes.js +41 -0
  56. package/migrations/10_oracleEndpoint-remove-constraints.js +38 -0
  57. package/package.json +180 -0
  58. package/scripts/_wait4_all.js +143 -0
  59. package/scripts/test-functional.sh +76 -0
  60. package/secrets/jwsSigningKey.key +27 -0
  61. package/seeds/currency.js +765 -0
  62. package/seeds/endpointType.js +65 -0
  63. package/seeds/partyIdType.js +79 -0
  64. package/src/api/endpointcache.js +67 -0
  65. package/src/api/health.js +66 -0
  66. package/src/api/index.js +85 -0
  67. package/src/api/oracles/{ID}.js +100 -0
  68. package/src/api/oracles.js +96 -0
  69. package/src/api/participants/{ID}/error.js +44 -0
  70. package/src/api/participants/{ID}.js +44 -0
  71. package/src/api/participants/{Type}/{ID}/error.js +74 -0
  72. package/src/api/participants/{Type}/{ID}/{SubId}/error.js +68 -0
  73. package/src/api/participants/{Type}/{ID}/{SubId}.js +113 -0
  74. package/src/api/participants/{Type}/{ID}.js +133 -0
  75. package/src/api/participants.js +63 -0
  76. package/src/api/parties/{Type}/{ID}/error.js +66 -0
  77. package/src/api/parties/{Type}/{ID}/{SubId}/error.js +56 -0
  78. package/src/api/parties/{Type}/{ID}/{SubId}.js +77 -0
  79. package/src/api/parties/{Type}/{ID}.js +98 -0
  80. package/src/api/routes.js +294 -0
  81. package/src/constants.js +16 -0
  82. package/src/domain/oracle/index.js +33 -0
  83. package/src/domain/oracle/oracle.js +234 -0
  84. package/src/domain/participants/index.js +35 -0
  85. package/src/domain/participants/participants.js +560 -0
  86. package/src/domain/parties/getPartiesByTypeAndID.js +239 -0
  87. package/src/domain/parties/index.js +32 -0
  88. package/src/domain/parties/parties.js +215 -0
  89. package/src/domain/parties/utils.js +84 -0
  90. package/src/domain/timeout/dto.js +48 -0
  91. package/src/domain/timeout/index.js +104 -0
  92. package/src/handlers/TimeoutHandler.js +94 -0
  93. package/src/handlers/index.js +70 -0
  94. package/src/handlers/monitoring/index.js +51 -0
  95. package/src/handlers/monitoring/plugins/health.js +61 -0
  96. package/src/handlers/monitoring/plugins/metrics.js +48 -0
  97. package/src/handlers/register.js +102 -0
  98. package/src/index.js +66 -0
  99. package/src/interface/admin-swagger.yaml +804 -0
  100. package/src/interface/admin_swagger.json +959 -0
  101. package/src/interface/api-swagger-iso20022-parties.yaml +1734 -0
  102. package/src/interface/api-swagger.yaml +1733 -0
  103. package/src/interface/api_swagger.json +3046 -0
  104. package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2256 -0
  105. package/src/interface/thirdparty/admin-swagger.yaml +808 -0
  106. package/src/interface/thirdparty/admin_swagger.json +961 -0
  107. package/src/interface/thirdparty/api-swagger.yaml +1739 -0
  108. package/src/interface/thirdparty/api_swagger.json +3142 -0
  109. package/src/lib/argv.js +39 -0
  110. package/src/lib/cache.js +126 -0
  111. package/src/lib/config.js +183 -0
  112. package/src/lib/db.js +26 -0
  113. package/src/lib/headers.js +53 -0
  114. package/src/lib/healthCheck/subServiceHealth.js +84 -0
  115. package/src/lib/index.js +11 -0
  116. package/src/lib/migrator.js +17 -0
  117. package/src/lib/requestLogger.js +54 -0
  118. package/src/lib/util.js +66 -0
  119. package/src/metrics/handler.js +33 -0
  120. package/src/metrics/plugin.js +52 -0
  121. package/src/metrics/routes.js +43 -0
  122. package/src/models/currency/currency.js +48 -0
  123. package/src/models/currency/index.js +32 -0
  124. package/src/models/endpointType/endpointType.js +48 -0
  125. package/src/models/endpointType/index.js +32 -0
  126. package/src/models/misc/migrationLock.js +49 -0
  127. package/src/models/oracle/facade.js +341 -0
  128. package/src/models/oracle/index.js +41 -0
  129. package/src/models/oracle/oracleEndpoint.js +192 -0
  130. package/src/models/oracle/oracleEndpointCached.js +108 -0
  131. package/src/models/participantEndpoint/facade.js +238 -0
  132. package/src/models/partyIdType/index.js +32 -0
  133. package/src/models/partyIdType/partyIdType.js +41 -0
  134. package/src/plugins.js +139 -0
  135. package/src/server.js +199 -0
  136. package/test/fixtures/index.js +131 -0
  137. package/test/fixtures/iso.js +110 -0
  138. package/test/integration/.env +8 -0
  139. package/test/integration/api/parties.test.js +137 -0
  140. package/test/integration/constants.js +20 -0
  141. package/test/integration/domain/oracle/index.test.js +324 -0
  142. package/test/integration/domain/timeout/index.test.js +75 -0
  143. package/test/integration/env.sh +15 -0
  144. package/test/integration/example.test.js +12 -0
  145. package/test/integration/models/currency/currency.test.js +68 -0
  146. package/test/integration/plugins.test.js +62 -0
  147. package/test/integration/prepareTestParticipants.js +30 -0
  148. package/test/integration/setup.js +5 -0
  149. package/test/integration-config.json +81 -0
  150. package/test/integration-runner.sh +108 -0
  151. package/test/unit/api/health.test.js +142 -0
  152. package/test/unit/api/oracles/{ID}.test.js +264 -0
  153. package/test/unit/api/oracles.test.js +173 -0
  154. package/test/unit/api/participants/participants.test.js +117 -0
  155. package/test/unit/api/participants/{Type}/{ID}/error.test.js +155 -0
  156. package/test/unit/api/participants/{Type}/{ID}/{SubId}/error.test.js +131 -0
  157. package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +377 -0
  158. package/test/unit/api/participants/{Type}/{ID}.test.js +383 -0
  159. package/test/unit/api/participants.test.js +108 -0
  160. package/test/unit/api/parties/endpointcache.test.js +83 -0
  161. package/test/unit/api/parties/parties.test.js +102 -0
  162. package/test/unit/api/parties/{Type}/{ID}/error.test.js +145 -0
  163. package/test/unit/api/parties/{Type}/{ID}/{SubId}/error.test.js +141 -0
  164. package/test/unit/api/parties/{Type}/{ID}/{SubId}.test.js +241 -0
  165. package/test/unit/api/parties/{Type}/{ID}.test.js +240 -0
  166. package/test/unit/domain/oracle/oracle.test.js +505 -0
  167. package/test/unit/domain/participants/participants.test.js +1724 -0
  168. package/test/unit/domain/parties/parties.test.js +940 -0
  169. package/test/unit/domain/timeout/dto.test.js +28 -0
  170. package/test/unit/domain/timeout/index.test.js +81 -0
  171. package/test/unit/handlers/TimeoutHandler.test.js +125 -0
  172. package/test/unit/handlers/index.test.js +56 -0
  173. package/test/unit/handlers/register.test.js +90 -0
  174. package/test/unit/index.test.js +139 -0
  175. package/test/unit/iso20022/partiesValidation.test.js +129 -0
  176. package/test/unit/lib/TransformFacades.test.js +18 -0
  177. package/test/unit/lib/argv.test.js +40 -0
  178. package/test/unit/lib/cache.test.js +172 -0
  179. package/test/unit/lib/config.test.js +108 -0
  180. package/test/unit/lib/healthCheck/subServiceHealth.test.js +89 -0
  181. package/test/unit/lib/migrator.test.js +52 -0
  182. package/test/unit/lib/requestLogger.test.js +115 -0
  183. package/test/unit/lib/util.test.js +68 -0
  184. package/test/unit/mocks.js +66 -0
  185. package/test/unit/models/currency/currency.test.js +91 -0
  186. package/test/unit/models/endpointType/endpointType.test.js +69 -0
  187. package/test/unit/models/misc/migrationLock.test.js +96 -0
  188. package/test/unit/models/oracle/facade.test.js +546 -0
  189. package/test/unit/models/oracle/oracleEndpoint.test.js +409 -0
  190. package/test/unit/models/oracle/oracleEndpointCached.test.js +153 -0
  191. package/test/unit/models/participantEndpoint/facade.test.js +295 -0
  192. package/test/unit/models/partyIdType/partyIdType.test.js +88 -0
  193. package/test/unit/plugins.test.js +89 -0
  194. package/test/unit/setup.js +7 -0
  195. package/test/util/apiClients/AlsApiClient.js +44 -0
  196. package/test/util/apiClients/BasicApiClient.js +34 -0
  197. package/test/util/apiClients/ProxyApiClient.js +25 -0
  198. package/test/util/apiClients/index.js +7 -0
  199. package/test/util/helper.js +332 -0
  200. package/test/util/index.js +11 -0
  201. package/test/util/mockgen.js +43 -0
  202. package/test/util/onboarding.js +132 -0
  203. package/test/util/scripts/addAlsDb.sh +33 -0
  204. package/test/util/scripts/configureMockServer.sh +35 -0
  205. package/test/util/scripts/env.sh +19 -0
  206. package/test/util/scripts/populateTestData.sh +62 -0
  207. package/test/util/scripts/startMockCentralServer.sh +45 -0
  208. package/test/util/scripts/startMockOracleServer.sh +45 -0
  209. 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/&lt;Type&gt;/&lt;ID&gt; (or GET /parties/&lt;Type&gt;/&lt;ID&gt;/&lt;SubId&gt;) is used to lookup information regarding the requested Party, defined by &lt;Type&gt;, &lt;ID&gt; and optionally &lt;SubId&gt; (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/&lt;Type&gt;/&lt;ID&gt; (or PUT /parties/&lt;Type&gt;/&lt;ID&gt;/&lt;SubId&gt;) 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 }
@@ -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
+ }