From 13292cab3de6a85ec3417bfe8a3388098c72c411 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 24 May 2024 07:00:40 -0500 Subject: [PATCH 1/7] feat: extend admin api to support proxy participants --- migrations/950108_participantProxy.js | 18 ++ package-lock.json | 195 +++++++++++------- package.json | 10 +- src/api/interface/swagger.json | 4 + src/api/participants/handler.js | 8 +- src/domain/participant/index.js | 17 +- src/models/participant/participantProxy.js | 34 +++ .../domain/participant/index.test.js | 31 ++- test/unit/api/participants/handler.test.js | 27 ++- test/unit/domain/participant/index.test.js | 16 +- .../participant/participantProxy.test.js | 132 ++++++++++++ 11 files changed, 390 insertions(+), 102 deletions(-) create mode 100644 migrations/950108_participantProxy.js create mode 100644 src/models/participant/participantProxy.js create mode 100644 test/unit/models/participant/participantProxy.test.js diff --git a/migrations/950108_participantProxy.js b/migrations/950108_participantProxy.js new file mode 100644 index 000000000..ac1306313 --- /dev/null +++ b/migrations/950108_participantProxy.js @@ -0,0 +1,18 @@ +'use strict' + +exports.up = async (knex) => { + return await knex.schema.hasTable('participantProxy').then(function(exists) { + if (!exists) { + return knex.schema.createTable('participantProxy', (t) => { + t.increments('participantProxyId').primary().notNullable() + t.integer('participantId').unsigned().notNullable() + t.foreign('participantId').references('participantId').inTable('participant') + t.boolean('isProxy').defaultTo(false).notNullable() + }) + } + }) +} + +exports.down = function (knex) { + return knex.schema.dropTableIfExists('participantProxy') +} diff --git a/package-lock.json b/package-lock.json index e62dea689..f7b715351 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,8 @@ "@mojaloop/central-services-health": "15.0.0", "@mojaloop/central-services-logger": "11.3.1", "@mojaloop/central-services-metrics": "12.0.8", - "@mojaloop/central-services-shared": "18.3.5", - "@mojaloop/central-services-stream": "11.2.5", + "@mojaloop/central-services-shared": "18.3.6", + "@mojaloop/central-services-stream": "11.3.0", "@mojaloop/database-lib": "11.0.5", "@mojaloop/event-sdk": "14.0.2", "@mojaloop/ml-number": "11.2.4", @@ -30,13 +30,13 @@ "ajv-keywords": "5.1.0", "base64url": "3.0.1", "blipp": "4.0.2", - "commander": "12.0.0", + "commander": "12.1.0", "cron": "3.1.7", "decimal.js": "10.4.3", "docdash": "2.0.2", "event-stream": "4.0.1", "five-bells-condition": "5.0.1", - "glob": "10.3.12", + "glob": "10.4.1", "hapi-auth-basic": "5.0.0", "hapi-auth-bearer-token": "8.0.0", "hapi-swagger": "17.2.1", @@ -52,7 +52,7 @@ "async-retry": "1.3.3", "audit-ci": "^6.6.1", "get-port": "5.1.1", - "jsdoc": "4.0.2", + "jsdoc": "4.0.3", "jsonpath": "1.1.1", "nodemon": "3.1.0", "npm-check-updates": "16.14.20", @@ -1680,18 +1680,18 @@ } }, "node_modules/@mojaloop/central-services-shared": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-18.3.5.tgz", - "integrity": "sha512-OVOEvGRjRZKCjty1ILNEA7hUGIKCL746BNZ60h86+PsJx8/YmnuJpGMuq8z6/M6Iu2vIm1qvulfo1H6PvpxLAA==", + "version": "18.3.6", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-shared/-/central-services-shared-18.3.6.tgz", + "integrity": "sha512-yjKThlivUp5c7HacP1s7mwcoI0Nfw7DfoNWInIkbxnyL/pKOzyyBRjhkMMgZRPQfTT+lDGFRNRE07TWgIM4zLg==", "dependencies": { "@hapi/catbox": "12.1.1", "@hapi/catbox-memory": "5.0.1", - "axios": "1.6.8", + "axios": "1.7.2", "clone": "2.1.2", "dotenv": "16.4.5", - "env-var": "7.4.1", + "env-var": "7.5.0", "event-stream": "4.0.1", - "immutable": "4.3.5", + "immutable": "4.3.6", "lodash": "4.17.21", "mustache": "4.2.0", "openapi-backend": "5.10.6", @@ -1700,7 +1700,7 @@ "shins": "2.6.0", "uuid4": "2.0.3", "widdershins": "^4.0.1", - "yaml": "2.4.1" + "yaml": "2.4.2" }, "peerDependencies": { "@mojaloop/central-services-error-handling": ">=13.x.x", @@ -1754,9 +1754,9 @@ "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" }, "node_modules/@mojaloop/central-services-stream": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/@mojaloop/central-services-stream/-/central-services-stream-11.2.5.tgz", - "integrity": "sha512-7OfOvXBtBOE2zBLhkIv5gR4BN72sdVEWDyit9uT01pu/1KjNstn3nopErBhjTo2ANgdB4Jx74UMhLlokwl24IQ==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@mojaloop/central-services-stream/-/central-services-stream-11.3.0.tgz", + "integrity": "sha512-Yg50/pg6Jk3h8qJHuIkOlN1ZzZkMreEP5ukl6IDNJ758bpr+0sME0JGL5DwbwHCXTD0T/vemMrxIr5igtobq1Q==", "dependencies": { "async": "3.2.5", "async-exit-hook": "2.0.1", @@ -2467,9 +2467,9 @@ "dev": true }, "node_modules/@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true }, "node_modules/@types/lodash": { @@ -2491,19 +2491,19 @@ "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" }, "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", "dev": true, "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" + "@types/linkify-it": "^5", + "@types/mdurl": "^2" } }, "node_modules/@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true }, "node_modules/@types/minimist": { @@ -3066,9 +3066,9 @@ } }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3893,9 +3893,9 @@ } }, "node_modules/commander": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", - "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "engines": { "node": ">=18" } @@ -5187,9 +5187,9 @@ } }, "node_modules/env-var": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.4.1.tgz", - "integrity": "sha512-H8Ga2SbXTQwt6MKEawWSvmxoH1+J6bnAXkuyE7eDvbGmrhIL2i+XGjzGM3DFHcJu8GY1zY9/AnBJY8uGQYPHiw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/env-var/-/env-var-7.5.0.tgz", + "integrity": "sha512-mKZOzLRN0ETzau2W2QXefbFjo5EF4yWq28OyKb9ICdeNhHJlOE/pHHnz4hdYJ9cNZXcJHo5xN4OT4pzuSHSNvA==", "engines": { "node": ">=10" } @@ -7241,21 +7241,21 @@ "dev": true }, "node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -8234,9 +8234,9 @@ } }, "node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", + "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -9090,9 +9090,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", + "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -9173,21 +9173,21 @@ } }, "node_modules/jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz", + "integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==", "dev": true, "dependencies": { "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", + "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", @@ -9616,13 +9616,18 @@ "dev": true }, "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, + "node_modules/linkify-it/node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "node_modules/load-json-file": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", @@ -9914,18 +9919,19 @@ "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==" }, "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dependencies": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdown-it-anchor": { @@ -9959,6 +9965,27 @@ "resolved": "https://registry.npmjs.org/markdown-it-lazy-headers/-/markdown-it-lazy-headers-0.1.3.tgz", "integrity": "sha512-65BxqvmYLpVifv6MvTElthY8zvZ/TpZBCdshr/mTpsFkqwcwWtfD3YoSE7RYSn7ugnEAAaj2gywszq+hI/Pxgg==" }, + "node_modules/markdown-it/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/markdown-it/node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, + "node_modules/markdown-it/node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -10330,9 +10357,9 @@ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10366,9 +10393,9 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } @@ -12576,15 +12603,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -13115,6 +13142,14 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" + } + }, "node_modules/pupa": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", @@ -17734,9 +17769,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", - "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 584bc299e..0c4a3df98 100644 --- a/package.json +++ b/package.json @@ -90,8 +90,8 @@ "@mojaloop/central-services-health": "15.0.0", "@mojaloop/central-services-logger": "11.3.1", "@mojaloop/central-services-metrics": "12.0.8", - "@mojaloop/central-services-shared": "18.3.5", - "@mojaloop/central-services-stream": "11.2.5", + "@mojaloop/central-services-shared": "18.3.6", + "@mojaloop/central-services-stream": "11.3.0", "@mojaloop/event-sdk": "14.0.2", "@mojaloop/ml-number": "11.2.4", "@mojaloop/object-store-lib": "12.0.3", @@ -100,13 +100,13 @@ "ajv-keywords": "5.1.0", "base64url": "3.0.1", "blipp": "4.0.2", - "commander": "12.0.0", + "commander": "12.1.0", "cron": "3.1.7", "decimal.js": "10.4.3", "docdash": "2.0.2", "event-stream": "4.0.1", "five-bells-condition": "5.0.1", - "glob": "10.3.12", + "glob": "10.4.1", "hapi-auth-basic": "5.0.0", "hapi-auth-bearer-token": "8.0.0", "hapi-swagger": "17.2.1", @@ -125,7 +125,7 @@ "async-retry": "1.3.3", "audit-ci": "^6.6.1", "get-port": "5.1.1", - "jsdoc": "4.0.2", + "jsdoc": "4.0.3", "jsonpath": "1.1.1", "nodemon": "3.1.0", "npm-check-updates": "16.14.20", diff --git a/src/api/interface/swagger.json b/src/api/interface/swagger.json index cb4616082..848a82b0b 100644 --- a/src/api/interface/swagger.json +++ b/src/api/interface/swagger.json @@ -1326,6 +1326,10 @@ "description": "Currency code", "$ref" : "#/definitions/Currency" + }, + "isProxy": { + "type": "boolean", + "description": "Is the participant a proxy" } }, "required": [ diff --git a/src/api/participants/handler.js b/src/api/participants/handler.js index ad79e5ee2..912a7353e 100644 --- a/src/api/participants/handler.js +++ b/src/api/participants/handler.js @@ -38,7 +38,7 @@ const LocalEnum = { disabled: 'disabled' } -const entityItem = ({ name, createdDate, isActive, currencyList }, ledgerAccountIds) => { +const entityItem = ({ name, createdDate, isActive, currencyList, isProxy }, ledgerAccountIds) => { const link = UrlParser.toParticipantUri(name) const accounts = currencyList.map((currentValue) => { return { @@ -58,7 +58,8 @@ const entityItem = ({ name, createdDate, isActive, currencyList }, ledgerAccount links: { self: link }, - accounts + accounts, + isProxy } } @@ -104,6 +105,9 @@ const create = async function (request, h) { participant.currencyList = await Promise.all([ParticipantService.getParticipantCurrencyById(participantCurrencyId1), ParticipantService.getParticipantCurrencyById(participantCurrencyId2)]) } } + if (request.payload.isProxy) { + await ParticipantService.createParticipantProxy(participant.participantId, request.payload.isProxy) + } return h.response(entityItem(participant, ledgerAccountIds)).code(201) } catch (err) { Logger.isErrorEnabled && Logger.error(err) diff --git a/src/domain/participant/index.js b/src/domain/participant/index.js index bbeb0cd39..49db0eec4 100644 --- a/src/domain/participant/index.js +++ b/src/domain/participant/index.js @@ -33,6 +33,7 @@ const ParticipantCurrencyModel = require('../../models/participant/participantCu const ParticipantPositionModel = require('../../models/participant/participantPosition') const ParticipantPositionChangeModel = require('../../models/participant/participantPositionChange') const ParticipantLimitModel = require('../../models/participant/participantLimit') +const ParticipantProxyModel = require('../../models/participant/participantProxy') const LedgerAccountTypeModel = require('../../models/ledgerAccountType/ledgerAccountType') const ParticipantFacade = require('../../models/participant/facade') const PositionFacade = require('../../models/position/facade') @@ -70,6 +71,7 @@ const getAll = async () => { const all = await ParticipantModel.getAll() await Promise.all(all.map(async (participant) => { participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId) + participant.isProxy = await ParticipantProxyModel.checkParticipantProxy(participant.participantId) })) return all } catch (err) { @@ -81,6 +83,7 @@ const getById = async (id) => { const participant = await ParticipantModel.getById(id) if (participant) { participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId) + participant.isProxy = await ParticipantProxyModel.checkParticipantProxy(participant.participantId) } return participant } @@ -89,6 +92,7 @@ const getByName = async (name) => { const participant = await ParticipantModel.getByName(name) if (participant) { participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId) + participant.isProxy = await ParticipantProxyModel.checkParticipantProxy(participant.participantId) } return participant } @@ -148,6 +152,7 @@ const destroyByName = async (name) => { await ParticipantLimitModel.destroyByParticipantId(participant.participantId) await ParticipantPositionModel.destroyByParticipantId(participant.participantId) await ParticipantCurrencyModel.destroyByParticipantId(participant.participantId) + await ParticipantProxyModel.destroyByParticipantId(participant.participantId) await destroyParticipantEndpointByParticipantId(participant.participantId) return await ParticipantModel.destroyByName(name) } catch (err) { @@ -764,6 +769,15 @@ const createAssociatedParticipantAccounts = async (currency, ledgerAccountTypeId } } +const createParticipantProxy = async (participantId, isProxy) => { + try { + const participantProxy = await ParticipantProxyModel.create(participantId, isProxy) + return participantProxy + } catch (err) { + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } +} + module.exports = { create, getAll, @@ -795,5 +809,6 @@ module.exports = { hubAccountExists: ParticipantCurrencyModel.hubAccountExists, getLimitsForAllParticipants, validateHubAccounts, - createAssociatedParticipantAccounts + createAssociatedParticipantAccounts, + createParticipantProxy } diff --git a/src/models/participant/participantProxy.js b/src/models/participant/participantProxy.js new file mode 100644 index 000000000..92468b9c7 --- /dev/null +++ b/src/models/participant/participantProxy.js @@ -0,0 +1,34 @@ +'use strict' + +const Db = require('../../lib/db') +const ErrorHandler = require('@mojaloop/central-services-error-handling') + +exports.create = async (participantId, isProxy) => { + try { + const result = await Db.from('participantProxy').insert({ + participantId, + isProxy + }) + return result + } catch (err) { + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } +} + +exports.checkParticipantProxy = async (id) => { + try { + const params = { participantId: id, isProxy: 1 } + const participantProxy = await Db.from('participantProxy').findOne(params) + return participantProxy ? 1 : 0 + } catch (err) { + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } +} + +exports.destroyByParticipantId = async (id) => { + try { + return await Db.from('participantProxy').destroy({ participantId: id }) + } catch (err) { + throw ErrorHandler.Factory.reformatFSPIOPError(err) + } +} diff --git a/test/integration/domain/participant/index.test.js b/test/integration/domain/participant/index.test.js index 4dbdf976c..bf957c748 100644 --- a/test/integration/domain/participant/index.test.js +++ b/test/integration/domain/participant/index.test.js @@ -38,6 +38,7 @@ const ParticipantService = require('../../../../src/domain/participant') const ParticipantCached = require('../../../../src/models/participant/participantCached') const ParticipantCurrencyCached = require('../../../../src/models/participant/participantCurrencyCached') const ParticipantLimitCached = require('../../../../src/models/participant/participantLimitCached') +const ParticipantProxy = require('../../../../src/models/participant/participantProxy') const ParticipantHelper = require('../../helpers/participant') const ParticipantEndpointHelper = require('../../helpers/participantEndpoint') const ParticipantLimitHelper = require('../../helpers/participantLimit') @@ -49,6 +50,7 @@ Test('Participant service', async (participantTest) => { let sandbox const participantFixtures = [] const endpointsFixtures = [] + const participantProxyFixtures = [] const participantMap = new Map() const testData = { @@ -59,7 +61,8 @@ Test('Participant service', async (participantTest) => { fsp3Name: 'payerfsp', fsp4Name: 'payeefsp', simulatorBase: 'http://localhost:8444', - notificationEmail: 'test@example.com' + notificationEmail: 'test@example.com', + proxyParticipant: 'xnProxy' } await participantTest.test('setup', async (test) => { @@ -172,6 +175,7 @@ Test('Participant service', async (participantTest) => { for (const participantId of participantMap.keys()) { const participant = await ParticipantService.getById(participantId) assert.equal(JSON.stringify(participant), JSON.stringify(participantMap.get(participantId))) + assert.equal(participant.isProxy, 0, 'isProxy flag set to false') } assert.end() } catch (err) { @@ -411,6 +415,31 @@ Test('Participant service', async (participantTest) => { } }) + await participantTest.test('create participant with proxy', async (assert) => { + try { + const getByNameResult = await ParticipantService.getByName(testData.proxyParticipant) + const result = await ParticipantHelper.prepareData(testData.proxyParticipant, testData.currency, undefined, !!getByNameResult) + await ParticipantProxy.create(result.participant.participantId, true) + participantProxyFixtures.push(result.participant) + + for (const participant of participantProxyFixtures) { + const read = await ParticipantService.getById(participant.participantId) + participantMap.set(participant.participantId, read) + if (debug) assert.comment(`Testing with participant \n ${JSON.stringify(participant, null, 2)}`) + assert.equal(read.name, participant.name, 'names are equal') + assert.deepEqual(read.currencyList, participant.currencyList, 'currency match') + assert.equal(read.isActive, participant.isActive, 'isActive flag matches') + assert.equal(read.createdDate.toString(), participant.createdDate.toString(), 'created date matches') + assert.equal(read.isProxy, 1, 'isProxy flag set to true') + } + assert.end() + } catch (err) { + Logger.error(`create participant failed with error - ${err}`) + assert.fail() + assert.end() + } + }) + await participantTest.test('teardown', async (assert) => { try { for (const participant of participantFixtures) { diff --git a/test/unit/api/participants/handler.test.js b/test/unit/api/participants/handler.test.js index 0fa165d07..6f0e33aa7 100644 --- a/test/unit/api/participants/handler.test.js +++ b/test/unit/api/participants/handler.test.js @@ -43,7 +43,8 @@ Test('Participant', participantHandlerTest => { currencyList: [ { participantCurrencyId: 1, currencyId: 'USD', ledgerAccountTypeId: 1, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' }, { participantCurrencyId: 2, currencyId: 'USD', ledgerAccountTypeId: 2, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' } - ] + ], + isProxy: 0 }, { participantId: 2, @@ -54,7 +55,8 @@ Test('Participant', participantHandlerTest => { currencyList: [ { participantCurrencyId: 3, currencyId: 'EUR', ledgerAccountTypeId: 1, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' }, { participantCurrencyId: 4, currencyId: 'EUR', ledgerAccountTypeId: 2, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' } - ] + ], + isProxy: 0 }, { participantId: 3, @@ -64,7 +66,8 @@ Test('Participant', participantHandlerTest => { createdDate: '2018-07-17T16:04:24.185Z', currencyList: [ { participantCurrencyId: 5, currencyId: 'USD', ledgerAccountTypeId: 5, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' } - ] + ], + isProxy: 0 } ] @@ -80,7 +83,8 @@ Test('Participant', participantHandlerTest => { accounts: [ { id: 1, currency: 'USD', ledgerAccountType: 'POSITION', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') }, { id: 2, currency: 'USD', ledgerAccountType: 'SETTLEMENT', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') } - ] + ], + isProxy: 0 }, { name: 'fsp2', @@ -93,7 +97,8 @@ Test('Participant', participantHandlerTest => { accounts: [ { id: 3, currency: 'EUR', ledgerAccountType: 'POSITION', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') }, { id: 4, currency: 'EUR', ledgerAccountType: 'SETTLEMENT', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') } - ] + ], + isProxy: 0 }, { name: 'Hub', @@ -105,7 +110,8 @@ Test('Participant', participantHandlerTest => { }, accounts: [ { id: 5, currency: 'USD', ledgerAccountType: 'HUB_FEE', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') } - ] + ], + isProxy: 0 } ] const settlementModelFixtures = [ @@ -236,7 +242,8 @@ Test('Participant', participantHandlerTest => { name: 'fsp1', currency: 'USD', isActive: 1, - createdDate: '2018-07-17T16:04:24.185Z' + createdDate: '2018-07-17T16:04:24.185Z', + isProxy: 0 } const participantCurrencyId1 = 1 @@ -327,7 +334,8 @@ Test('Participant', participantHandlerTest => { currency: 'USD', isActive: 1, createdDate: '2018-07-17T16:04:24.185Z', - currencyList: [] + currencyList: [], + isProxy: 0 } const participantCurrencyId1 = 1 @@ -1231,7 +1239,8 @@ Test('Participant', participantHandlerTest => { isActive: 1, createdDate: '2018-07-17T16:04:24.185Z', createdBy: 'unknown', - currencyList: [] + currencyList: [], + isProxy: 0 } const ledgerAccountType = { ledgerAccountTypeId: 5, diff --git a/test/unit/domain/participant/index.test.js b/test/unit/domain/participant/index.test.js index 5f8ceca27..df8bd694d 100644 --- a/test/unit/domain/participant/index.test.js +++ b/test/unit/domain/participant/index.test.js @@ -34,6 +34,7 @@ const ParticipantModelCached = require('../../../../src/models/participant/parti const ParticipantCurrencyModel = require('../../../../src/models/participant/participantCurrencyCached') const ParticipantPositionModel = require('../../../../src/models/participant/participantPosition') const ParticipantLimitModel = require('../../../../src/models/participant/participantLimit') +const ParticipantProxyModel = require('../../../../src/models/participant/participantProxy') const ParticipantFacade = require('../../../../src/models/participant/facade') const PositionFacade = require('../../../../src/models/position/facade') const ParticipantPositionChangeModel = require('../../../../src/models/participant/participantPositionChange') @@ -52,14 +53,16 @@ Test('Participant service', async (participantTest) => { name: 'fsp1', currency: 'USD', isActive: 1, - createdDate: new Date() + createdDate: new Date(), + isProxy: 0 }, { participantId: 1, name: 'fsp2', currency: 'EUR', isActive: 1, - createdDate: new Date() + createdDate: new Date(), + isProxy: 0 } ] @@ -70,7 +73,8 @@ Test('Participant service', async (participantTest) => { currency: 'USD', isActive: 1, createdDate: new Date(), - currencyList: ['USD'] + currencyList: ['USD'], + isProxy: 0 }, { participantId: 1, @@ -78,7 +82,8 @@ Test('Participant service', async (participantTest) => { currency: 'EUR', isActive: 1, createdDate: new Date(), - currencyList: ['EUR'] + currencyList: ['EUR'], + isProxy: 0 } ] const participantCurrencyResult = [ @@ -164,6 +169,8 @@ Test('Participant service', async (participantTest) => { sandbox.stub(ParticipantPositionChangeModel, 'getByParticipantPositionId') + sandbox.stub(ParticipantProxyModel, 'checkParticipantProxy') + sandbox.stub(PositionFacade, 'getByNameAndCurrency') sandbox.stub(PositionFacade, 'getAllByNameAndCurrency') @@ -210,6 +217,7 @@ Test('Participant service', async (participantTest) => { isActive: 1 }) ParticipantCurrencyModel.getByParticipantId.withArgs(participant.participantId, 1).returns(participant.currency) + ParticipantProxyModel.checkParticipantProxy.withArgs(participant.participantId).returns(0) ParticipantModelCached.destroyByName.withArgs(participant.name).returns(Promise.resolve(true)) ParticipantCurrencyModel.destroyByParticipantId.withArgs(participant.participantId).returns(Promise.resolve(true)) Db.participant.destroy.withArgs({ name: participant.name }).returns(Promise.resolve(true)) diff --git a/test/unit/models/participant/participantProxy.test.js b/test/unit/models/participant/participantProxy.test.js new file mode 100644 index 000000000..5145a5c26 --- /dev/null +++ b/test/unit/models/participant/participantProxy.test.js @@ -0,0 +1,132 @@ +'use strict' + +const Test = require('tapes')(require('tape')) +const Sinon = require('sinon') +const Db = require('../../../../src/lib/db') +const Logger = require('@mojaloop/central-services-logger') +const Model = require('../../../../src/models/participant/participantProxy') + +Test('Participant Proxy model', async (participantProxyTest) => { + let sandbox + + participantProxyTest.beforeEach(t => { + sandbox = Sinon.createSandbox() + Db.participantProxy = { + insert: sandbox.stub(), + findOne: sandbox.stub(), + find: sandbox.stub(), + destroy: sandbox.stub(), + update: sandbox.stub() + } + Db.from = (table) => { + return Db[table] + } + t.end() + }) + + participantProxyTest.afterEach(t => { + sandbox.restore() + t.end() + }) + + await participantProxyTest.test('create participant Proxy', async (assert) => { + try { + const participantId = 1 + const isProxy = true + Db.participantProxy.insert.withArgs({ participantId, isProxy }).returns(1) + const result = await Model.create(participantId, isProxy) + assert.equal(result, 1, `returns ${result}`) + assert.end() + } catch (err) { + Logger.error(`create participant proxy failed with error - ${err}`) + assert.fail() + assert.end() + } + }) + + await participantProxyTest.test('create participant proxy should throw an error', async (assert) => { + Db.participantProxy.insert.throws(new Error('message')) + try { + const result = await Model.create({ participantId: 1, proxyId: 'USD', createdBy: 'unknown' }) + assert.comment(result) + assert.fail(' should throw') + } catch (err) { + assert.assert(err instanceof Error) + Logger.error(`create participant proxy failed with error - ${err}`) + assert.pass('Error thrown') + } + assert.end() + }) + + await participantProxyTest.test('checkParticipantProxy', async (assert) => { + try { + Db.participantProxy.findOne.withArgs({ participantId: 5, isProxy: 1 }).returns(1) + const result = await Model.checkParticipantProxy(5) + assert.equal(result, 1) + assert.end() + } catch (err) { + Logger.error(`get participant proxy by Id failed with error - ${err}`) + assert.fail() + assert.end() + } + }) + + await participantProxyTest.test('checkParticipantProxy returns falsy on no record', async (assert) => { + try { + Db.participantProxy.findOne.withArgs({ participantId: 5, isProxy: 1 }).returns(null) + const result = await Model.checkParticipantProxy(5) + assert.equal(result, 0) + assert.end() + } catch (err) { + Logger.error(`get participant proxy by Id failed with error - ${err}`) + assert.fail() + assert.end() + } + }) + + await participantProxyTest.test('getById should fail', async (test) => { + try { + Db.participantProxy.findOne.withArgs({ participantId: 5, isProxy: 1 }).throws(new Error()) + await Model.checkParticipantProxy(5) + test.fail('Error not thrown') + test.end() + } catch (err) { + Logger.error(`get participant proxy by Id failed with error - ${err}`) + test.pass('Error thrown') + test.end() + } + }) + + await participantProxyTest.test('destroyByParticipantId', async (assert) => { + try { + Db.participantProxy.destroy.withArgs({ participantId: 1 }).returns(Promise.resolve(true)) + const result = await Model.destroyByParticipantId(1) + assert.equal(result, true) + sandbox.restore() + assert.end() + } catch (err) { + Logger.error(`destroy participant failed with error - ${err}`) + sandbox.restore() + assert.fail() + assert.end() + } + }) + + await participantProxyTest.test('destroyByParticipantId should throw an error', async (test) => { + try { + Db.participantProxy.destroy.withArgs({ participantId: 1 }).throws(new Error()) + const result = await Model.destroyByParticipantId(1) + test.equal(result, true) + test.fail('Error not thrown') + sandbox.restore() + test.end() + } catch (err) { + Logger.error(`destroy participant failed with error - ${err}`) + test.pass('Error thrown') + sandbox.restore() + test.end() + } + }) + + participantProxyTest.end() +}) From db088008aa667b9bbeb684777f68be0b195f932e Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 24 May 2024 08:46:16 -0500 Subject: [PATCH 2/7] image revert --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 65e8f217a..378589967 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -164,7 +164,7 @@ executors: BASH_ENV: /etc/profile ## Ref: https://circleci.com/docs/env-vars/#alpine-linux NVM_ARCH_UNOFFICIAL_OVERRIDE: x64-musl ## Ref: https://github.com/nvm-sh/nvm/issues/1102#issuecomment-550572252 docker: - - image: node:lts-alpine # Ref: https://hub.docker.com/_/node?tab=tags&page=1&name=alpine + - image: node:18-alpine3.19 # Ref: https://hub.docker.com/_/node?tab=tags&page=1&name=alpine default-machine: working_directory: *WORKING_DIR From a0988058490ba065356bd985b5736075a918a1d2 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 24 May 2024 09:14:10 -0500 Subject: [PATCH 3/7] audit --- audit-ci.jsonc | 6 ++++-- package-lock.json | 36 ++++++++---------------------------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/audit-ci.jsonc b/audit-ci.jsonc index 435039347..ecc5a9851 100644 --- a/audit-ci.jsonc +++ b/audit-ci.jsonc @@ -22,6 +22,8 @@ "GHSA-5854-jvxx-2cg9", // hapi-auth-basic>hapi>subtext "GHSA-2mvq-xp48-4c77", // hapi-auth-basic>hapi>subtext "GHSA-w5p7-h5w8-2hfq", // tap-spec>tap-out>trim - "GHSA-p9pc-299p-vxgp" // widdershins>yargs>yargs-parser + "GHSA-p9pc-299p-vxgp", // widdershins>yargs>yargs-parser + "GHSA-ghr5-ch3p-vcr6", // https://github.com/advisories/GHSA-ghr5-ch3p-vcr6 + "GHSA-cgfm-xwp7-2cvr" // https://github.com/advisories/GHSA-cgfm-xwp7-2cvr ] -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index f7b715351..6e24fde69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,15 +95,13 @@ } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.1.0.tgz", - "integrity": "sha512-g/VW9ZQEFJAOwAyUb8JFf7MLiLy2uEB4rU270rGzDwICxnxMlPy0O11KVePSgS36K1NI29gSlK84n5INGhd4Ag==", + "version": "11.6.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.6.2.tgz", + "integrity": "sha512-ENUdLLT04aDbbHCRwfKf8gR67AhV0CdFrOAtk+FcakBAgaq6ds3HLK9X0BCyiFUz8pK9uP+k6YZyJaGG7Mt7vQ==", "dependencies": { "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.13", - "@types/lodash.clonedeep": "^4.5.7", - "js-yaml": "^4.1.0", - "lodash.clonedeep": "^4.5.0" + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" }, "engines": { "node": ">= 16" @@ -2472,19 +2470,6 @@ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true }, - "node_modules/@types/lodash": { - "version": "4.14.201", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.201.tgz", - "integrity": "sha512-y9euML0cim1JrykNxADLfaG0FgD1g/yTHwUs/Jg9ZIU7WKj2/4IW9Lbb1WZbvck78W/lfGXFfe+u2EGfIJXdLQ==" - }, - "node_modules/@types/lodash.clonedeep": { - "version": "4.5.9", - "resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.9.tgz", - "integrity": "sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q==", - "dependencies": { - "@types/lodash": "*" - } - }, "node_modules/@types/luxon": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", @@ -9687,11 +9672,6 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, "node_modules/lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", @@ -16328,9 +16308,9 @@ } }, "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, "dependencies": { "chownr": "^2.0.0", From e143de0d463a90bb757b89189b160b6e755c9713 Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 31 May 2024 07:40:03 -0500 Subject: [PATCH 4/7] changes --- migrations/950108_participantProxy.js | 14 +- package-lock.json | 108 +++++--------- package.json | 6 +- src/api/participants/handler.js | 3 - src/domain/participant/index.js | 17 +-- src/models/participant/participant.js | 3 +- src/models/participant/participantProxy.js | 34 ----- test/unit/domain/participant/index.test.js | 4 - .../models/participant/participant.test.js | 8 +- .../participant/participantProxy.test.js | 132 ------------------ 10 files changed, 54 insertions(+), 275 deletions(-) delete mode 100644 src/models/participant/participantProxy.js delete mode 100644 test/unit/models/participant/participantProxy.test.js diff --git a/migrations/950108_participantProxy.js b/migrations/950108_participantProxy.js index ac1306313..2cab3950a 100644 --- a/migrations/950108_participantProxy.js +++ b/migrations/950108_participantProxy.js @@ -1,18 +1,18 @@ 'use strict' exports.up = async (knex) => { - return await knex.schema.hasTable('participantProxy').then(function(exists) { - if (!exists) { - return knex.schema.createTable('participantProxy', (t) => { - t.increments('participantProxyId').primary().notNullable() - t.integer('participantId').unsigned().notNullable() - t.foreign('participantId').references('participantId').inTable('participant') + return await knex.schema.hasTable('participant').then(function(exists) { + if (exists) { + return knex.schema.alterTable('participant', (t) => { t.boolean('isProxy').defaultTo(false).notNullable() + }) } }) } exports.down = function (knex) { - return knex.schema.dropTableIfExists('participantProxy') + return knex.schema.alterTable('participant', (t) => { + t.dropColumn('isProxy') + }) } diff --git a/package-lock.json b/package-lock.json index 6e24fde69..ae5810052 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,11 +22,11 @@ "@mojaloop/central-services-shared": "18.3.6", "@mojaloop/central-services-stream": "11.3.0", "@mojaloop/database-lib": "11.0.5", - "@mojaloop/event-sdk": "14.0.2", + "@mojaloop/event-sdk": "14.1.0", "@mojaloop/ml-number": "11.2.4", "@mojaloop/object-store-lib": "12.0.3", "@now-ims/hapi-now-auth": "2.1.0", - "ajv": "8.13.0", + "ajv": "8.14.0", "ajv-keywords": "5.1.0", "base64url": "3.0.1", "blipp": "4.0.2", @@ -54,7 +54,7 @@ "get-port": "5.1.1", "jsdoc": "4.0.3", "jsonpath": "1.1.1", - "nodemon": "3.1.0", + "nodemon": "3.1.2", "npm-check-updates": "16.14.20", "nyc": "15.1.0", "pre-commit": "1.2.2", @@ -772,11 +772,11 @@ "dev": true }, "node_modules/@grpc/grpc-js": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.3.tgz", - "integrity": "sha512-qiO9MNgYnwbvZ8MK0YLWbnGrNX3zTcj6/Ef7UHu5ZofER3e2nF3Y35GaPo9qNJJ/UJQKa4KL+z/F4Q8Q+uCdUQ==", + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.8.tgz", + "integrity": "sha512-vYVqYzHicDqyKB+NQhAc54I1QWCBLCrYG6unqOIcBTHx+7x8C9lcoLj3KVJXs2VB4lUbpWY+Kk9NipcbXYWmvg==", "dependencies": { - "@grpc/proto-loader": "^0.7.10", + "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" }, "engines": { @@ -784,13 +784,13 @@ } }, "node_modules/@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { @@ -1627,48 +1627,6 @@ "winston": "3.13.0" } }, - "node_modules/@mojaloop/central-services-logger/node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@mojaloop/central-services-logger/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@mojaloop/central-services-logger/node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/@mojaloop/central-services-metrics": { "version": "12.0.8", "resolved": "https://registry.npmjs.org/@mojaloop/central-services-metrics/-/central-services-metrics-12.0.8.tgz", @@ -1785,31 +1743,35 @@ } }, "node_modules/@mojaloop/event-sdk": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/@mojaloop/event-sdk/-/event-sdk-14.0.2.tgz", - "integrity": "sha512-yWqoGP/Vrm4N66iMm4vyz94Z1UJedv29xuurxHIDPHcdqjvZZGeA383ATRfDpwB2tJlxHeukajBJFOiwLK3fYw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@mojaloop/event-sdk/-/event-sdk-14.1.0.tgz", + "integrity": "sha512-uXtfQ6KWNychL0Hg13bbVyne4OYnoa8gMKzHAmTmswgSFZdBdFtIMMkL+lPi1oYUuJk9Sv1PIdwfnY5RbFniEA==", "dependencies": { - "@grpc/grpc-js": "^1.10.3", - "@grpc/proto-loader": "0.7.10", + "@grpc/grpc-js": "^1.10.8", + "@grpc/proto-loader": "0.7.13", "brototype": "0.0.6", "error-callsites": "2.0.4", "lodash": "4.17.21", "moment": "2.30.1", "parse-strings-in-object": "2.0.0", - "protobufjs": "7.2.6", + "protobufjs": "7.3.0", "rc": "1.2.8", "serialize-error": "8.1.0", "traceparent": "1.0.0", "tslib": "2.6.2", "uuid4": "2.0.3", - "winston": "3.12.0" + "winston": "3.13.0" }, "peerDependencies": { - "@mojaloop/central-services-logger": ">=11.x.x" + "@mojaloop/central-services-logger": ">=11.x.x", + "@mojaloop/central-services-stream": ">=11.2.4" }, "peerDependenciesMeta": { "@mojaloop/central-services-logger": { "optional": false + }, + "@mojaloop/central-services-stream": { + "optional": true } } }, @@ -2625,9 +2587,9 @@ } }, "node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz", + "integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==", "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", @@ -11172,9 +11134,9 @@ "dev": true }, "node_modules/nodemon": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", - "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.2.tgz", + "integrity": "sha512-/Ib/kloefDy+N0iRTxIUzyGcdW9lzlnca2Jsa5w73bs3npXjg+WInmiX6VY13mIb6SykkthYX/U5t0ukryGqBw==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -13033,9 +12995,9 @@ "dev": true }, "node_modules/protobufjs": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", - "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz", + "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -17522,9 +17484,9 @@ } }, "node_modules/winston": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz", - "integrity": "sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", + "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", diff --git a/package.json b/package.json index 0c4a3df98..bbc85a26a 100644 --- a/package.json +++ b/package.json @@ -92,11 +92,11 @@ "@mojaloop/central-services-metrics": "12.0.8", "@mojaloop/central-services-shared": "18.3.6", "@mojaloop/central-services-stream": "11.3.0", - "@mojaloop/event-sdk": "14.0.2", + "@mojaloop/event-sdk": "14.1.0", "@mojaloop/ml-number": "11.2.4", "@mojaloop/object-store-lib": "12.0.3", "@now-ims/hapi-now-auth": "2.1.0", - "ajv": "8.13.0", + "ajv": "8.14.0", "ajv-keywords": "5.1.0", "base64url": "3.0.1", "blipp": "4.0.2", @@ -127,7 +127,7 @@ "get-port": "5.1.1", "jsdoc": "4.0.3", "jsonpath": "1.1.1", - "nodemon": "3.1.0", + "nodemon": "3.1.2", "npm-check-updates": "16.14.20", "nyc": "15.1.0", "pre-commit": "1.2.2", diff --git a/src/api/participants/handler.js b/src/api/participants/handler.js index 912a7353e..9dfea9a41 100644 --- a/src/api/participants/handler.js +++ b/src/api/participants/handler.js @@ -105,9 +105,6 @@ const create = async function (request, h) { participant.currencyList = await Promise.all([ParticipantService.getParticipantCurrencyById(participantCurrencyId1), ParticipantService.getParticipantCurrencyById(participantCurrencyId2)]) } } - if (request.payload.isProxy) { - await ParticipantService.createParticipantProxy(participant.participantId, request.payload.isProxy) - } return h.response(entityItem(participant, ledgerAccountIds)).code(201) } catch (err) { Logger.isErrorEnabled && Logger.error(err) diff --git a/src/domain/participant/index.js b/src/domain/participant/index.js index 49db0eec4..bbeb0cd39 100644 --- a/src/domain/participant/index.js +++ b/src/domain/participant/index.js @@ -33,7 +33,6 @@ const ParticipantCurrencyModel = require('../../models/participant/participantCu const ParticipantPositionModel = require('../../models/participant/participantPosition') const ParticipantPositionChangeModel = require('../../models/participant/participantPositionChange') const ParticipantLimitModel = require('../../models/participant/participantLimit') -const ParticipantProxyModel = require('../../models/participant/participantProxy') const LedgerAccountTypeModel = require('../../models/ledgerAccountType/ledgerAccountType') const ParticipantFacade = require('../../models/participant/facade') const PositionFacade = require('../../models/position/facade') @@ -71,7 +70,6 @@ const getAll = async () => { const all = await ParticipantModel.getAll() await Promise.all(all.map(async (participant) => { participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId) - participant.isProxy = await ParticipantProxyModel.checkParticipantProxy(participant.participantId) })) return all } catch (err) { @@ -83,7 +81,6 @@ const getById = async (id) => { const participant = await ParticipantModel.getById(id) if (participant) { participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId) - participant.isProxy = await ParticipantProxyModel.checkParticipantProxy(participant.participantId) } return participant } @@ -92,7 +89,6 @@ const getByName = async (name) => { const participant = await ParticipantModel.getByName(name) if (participant) { participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId) - participant.isProxy = await ParticipantProxyModel.checkParticipantProxy(participant.participantId) } return participant } @@ -152,7 +148,6 @@ const destroyByName = async (name) => { await ParticipantLimitModel.destroyByParticipantId(participant.participantId) await ParticipantPositionModel.destroyByParticipantId(participant.participantId) await ParticipantCurrencyModel.destroyByParticipantId(participant.participantId) - await ParticipantProxyModel.destroyByParticipantId(participant.participantId) await destroyParticipantEndpointByParticipantId(participant.participantId) return await ParticipantModel.destroyByName(name) } catch (err) { @@ -769,15 +764,6 @@ const createAssociatedParticipantAccounts = async (currency, ledgerAccountTypeId } } -const createParticipantProxy = async (participantId, isProxy) => { - try { - const participantProxy = await ParticipantProxyModel.create(participantId, isProxy) - return participantProxy - } catch (err) { - throw ErrorHandler.Factory.reformatFSPIOPError(err) - } -} - module.exports = { create, getAll, @@ -809,6 +795,5 @@ module.exports = { hubAccountExists: ParticipantCurrencyModel.hubAccountExists, getLimitsForAllParticipants, validateHubAccounts, - createAssociatedParticipantAccounts, - createParticipantProxy + createAssociatedParticipantAccounts } diff --git a/src/models/participant/participant.js b/src/models/participant/participant.js index 8c379e06b..5f47cd836 100644 --- a/src/models/participant/participant.js +++ b/src/models/participant/participant.js @@ -43,7 +43,8 @@ exports.create = async (participant) => { try { const result = await Db.from('participant').insert({ name: participant.name, - createdBy: 'unknown' + createdBy: 'unknown', + isProxy: !!participant.isProxy }) return result } catch (err) { diff --git a/src/models/participant/participantProxy.js b/src/models/participant/participantProxy.js deleted file mode 100644 index 92468b9c7..000000000 --- a/src/models/participant/participantProxy.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -const Db = require('../../lib/db') -const ErrorHandler = require('@mojaloop/central-services-error-handling') - -exports.create = async (participantId, isProxy) => { - try { - const result = await Db.from('participantProxy').insert({ - participantId, - isProxy - }) - return result - } catch (err) { - throw ErrorHandler.Factory.reformatFSPIOPError(err) - } -} - -exports.checkParticipantProxy = async (id) => { - try { - const params = { participantId: id, isProxy: 1 } - const participantProxy = await Db.from('participantProxy').findOne(params) - return participantProxy ? 1 : 0 - } catch (err) { - throw ErrorHandler.Factory.reformatFSPIOPError(err) - } -} - -exports.destroyByParticipantId = async (id) => { - try { - return await Db.from('participantProxy').destroy({ participantId: id }) - } catch (err) { - throw ErrorHandler.Factory.reformatFSPIOPError(err) - } -} diff --git a/test/unit/domain/participant/index.test.js b/test/unit/domain/participant/index.test.js index df8bd694d..66be4818a 100644 --- a/test/unit/domain/participant/index.test.js +++ b/test/unit/domain/participant/index.test.js @@ -34,7 +34,6 @@ const ParticipantModelCached = require('../../../../src/models/participant/parti const ParticipantCurrencyModel = require('../../../../src/models/participant/participantCurrencyCached') const ParticipantPositionModel = require('../../../../src/models/participant/participantPosition') const ParticipantLimitModel = require('../../../../src/models/participant/participantLimit') -const ParticipantProxyModel = require('../../../../src/models/participant/participantProxy') const ParticipantFacade = require('../../../../src/models/participant/facade') const PositionFacade = require('../../../../src/models/position/facade') const ParticipantPositionChangeModel = require('../../../../src/models/participant/participantPositionChange') @@ -169,8 +168,6 @@ Test('Participant service', async (participantTest) => { sandbox.stub(ParticipantPositionChangeModel, 'getByParticipantPositionId') - sandbox.stub(ParticipantProxyModel, 'checkParticipantProxy') - sandbox.stub(PositionFacade, 'getByNameAndCurrency') sandbox.stub(PositionFacade, 'getAllByNameAndCurrency') @@ -217,7 +214,6 @@ Test('Participant service', async (participantTest) => { isActive: 1 }) ParticipantCurrencyModel.getByParticipantId.withArgs(participant.participantId, 1).returns(participant.currency) - ParticipantProxyModel.checkParticipantProxy.withArgs(participant.participantId).returns(0) ParticipantModelCached.destroyByName.withArgs(participant.name).returns(Promise.resolve(true)) ParticipantCurrencyModel.destroyByParticipantId.withArgs(participant.participantId).returns(Promise.resolve(true)) Db.participant.destroy.withArgs({ name: participant.name }).returns(Promise.resolve(true)) diff --git a/test/unit/models/participant/participant.test.js b/test/unit/models/participant/participant.test.js index 0105f176e..0cdf543e0 100644 --- a/test/unit/models/participant/participant.test.js +++ b/test/unit/models/participant/participant.test.js @@ -42,6 +42,7 @@ Test('Participant model', async (participantTest) => { name: 'fsp1z', currency: 'USD', isActive: 1, + isProxy: false, createdDate: new Date() }, { @@ -49,6 +50,7 @@ Test('Participant model', async (participantTest) => { name: 'fsp2', currency: 'EUR', isActive: 1, + isProxy: true, createdDate: new Date() } ] @@ -97,7 +99,8 @@ Test('Participant model', async (participantTest) => { try { Db.participant.insert.withArgs({ name: participantFixtures[0].name, - createdBy: 'unknown' + createdBy: 'unknown', + isProxy: false }).returns(1) const result = await Model.create(participantFixtures[0]) assert.equal(result, 1, ` returns ${result}`) @@ -113,7 +116,8 @@ Test('Participant model', async (participantTest) => { try { Db.participant.insert.withArgs({ name: participantFixtures[0].name, - createdBy: 'unknown' + createdBy: 'unknown', + isProxy: false }).throws(new Error()) const result = await Model.create(participantFixtures[0]) test.equal(result, 1, ` returns ${result}`) diff --git a/test/unit/models/participant/participantProxy.test.js b/test/unit/models/participant/participantProxy.test.js deleted file mode 100644 index 5145a5c26..000000000 --- a/test/unit/models/participant/participantProxy.test.js +++ /dev/null @@ -1,132 +0,0 @@ -'use strict' - -const Test = require('tapes')(require('tape')) -const Sinon = require('sinon') -const Db = require('../../../../src/lib/db') -const Logger = require('@mojaloop/central-services-logger') -const Model = require('../../../../src/models/participant/participantProxy') - -Test('Participant Proxy model', async (participantProxyTest) => { - let sandbox - - participantProxyTest.beforeEach(t => { - sandbox = Sinon.createSandbox() - Db.participantProxy = { - insert: sandbox.stub(), - findOne: sandbox.stub(), - find: sandbox.stub(), - destroy: sandbox.stub(), - update: sandbox.stub() - } - Db.from = (table) => { - return Db[table] - } - t.end() - }) - - participantProxyTest.afterEach(t => { - sandbox.restore() - t.end() - }) - - await participantProxyTest.test('create participant Proxy', async (assert) => { - try { - const participantId = 1 - const isProxy = true - Db.participantProxy.insert.withArgs({ participantId, isProxy }).returns(1) - const result = await Model.create(participantId, isProxy) - assert.equal(result, 1, `returns ${result}`) - assert.end() - } catch (err) { - Logger.error(`create participant proxy failed with error - ${err}`) - assert.fail() - assert.end() - } - }) - - await participantProxyTest.test('create participant proxy should throw an error', async (assert) => { - Db.participantProxy.insert.throws(new Error('message')) - try { - const result = await Model.create({ participantId: 1, proxyId: 'USD', createdBy: 'unknown' }) - assert.comment(result) - assert.fail(' should throw') - } catch (err) { - assert.assert(err instanceof Error) - Logger.error(`create participant proxy failed with error - ${err}`) - assert.pass('Error thrown') - } - assert.end() - }) - - await participantProxyTest.test('checkParticipantProxy', async (assert) => { - try { - Db.participantProxy.findOne.withArgs({ participantId: 5, isProxy: 1 }).returns(1) - const result = await Model.checkParticipantProxy(5) - assert.equal(result, 1) - assert.end() - } catch (err) { - Logger.error(`get participant proxy by Id failed with error - ${err}`) - assert.fail() - assert.end() - } - }) - - await participantProxyTest.test('checkParticipantProxy returns falsy on no record', async (assert) => { - try { - Db.participantProxy.findOne.withArgs({ participantId: 5, isProxy: 1 }).returns(null) - const result = await Model.checkParticipantProxy(5) - assert.equal(result, 0) - assert.end() - } catch (err) { - Logger.error(`get participant proxy by Id failed with error - ${err}`) - assert.fail() - assert.end() - } - }) - - await participantProxyTest.test('getById should fail', async (test) => { - try { - Db.participantProxy.findOne.withArgs({ participantId: 5, isProxy: 1 }).throws(new Error()) - await Model.checkParticipantProxy(5) - test.fail('Error not thrown') - test.end() - } catch (err) { - Logger.error(`get participant proxy by Id failed with error - ${err}`) - test.pass('Error thrown') - test.end() - } - }) - - await participantProxyTest.test('destroyByParticipantId', async (assert) => { - try { - Db.participantProxy.destroy.withArgs({ participantId: 1 }).returns(Promise.resolve(true)) - const result = await Model.destroyByParticipantId(1) - assert.equal(result, true) - sandbox.restore() - assert.end() - } catch (err) { - Logger.error(`destroy participant failed with error - ${err}`) - sandbox.restore() - assert.fail() - assert.end() - } - }) - - await participantProxyTest.test('destroyByParticipantId should throw an error', async (test) => { - try { - Db.participantProxy.destroy.withArgs({ participantId: 1 }).throws(new Error()) - const result = await Model.destroyByParticipantId(1) - test.equal(result, true) - test.fail('Error not thrown') - sandbox.restore() - test.end() - } catch (err) { - Logger.error(`destroy participant failed with error - ${err}`) - test.pass('Error thrown') - sandbox.restore() - test.end() - } - }) - - participantProxyTest.end() -}) From 09856d1e8268ff2db806c69769f093fd4264040e Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 31 May 2024 08:03:36 -0500 Subject: [PATCH 5/7] changes --- src/domain/participant/index.js | 2 +- test/integration/domain/participant/index.test.js | 4 +--- test/integration/helpers/participant.js | 5 +++-- test/unit/domain/participant/index.test.js | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/domain/participant/index.js b/src/domain/participant/index.js index bbeb0cd39..394508c63 100644 --- a/src/domain/participant/index.js +++ b/src/domain/participant/index.js @@ -59,7 +59,7 @@ const { destroyParticipantEndpointByParticipantId } = require('../../models/part const create = async (payload) => { try { - return ParticipantModel.create({ name: payload.name }) + return ParticipantModel.create({ name: payload.name, isProxy: !!payload.isProxy }) } catch (err) { throw ErrorHandler.Factory.reformatFSPIOPError(err) } diff --git a/test/integration/domain/participant/index.test.js b/test/integration/domain/participant/index.test.js index bf957c748..e74e3c938 100644 --- a/test/integration/domain/participant/index.test.js +++ b/test/integration/domain/participant/index.test.js @@ -38,7 +38,6 @@ const ParticipantService = require('../../../../src/domain/participant') const ParticipantCached = require('../../../../src/models/participant/participantCached') const ParticipantCurrencyCached = require('../../../../src/models/participant/participantCurrencyCached') const ParticipantLimitCached = require('../../../../src/models/participant/participantLimitCached') -const ParticipantProxy = require('../../../../src/models/participant/participantProxy') const ParticipantHelper = require('../../helpers/participant') const ParticipantEndpointHelper = require('../../helpers/participantEndpoint') const ParticipantLimitHelper = require('../../helpers/participantLimit') @@ -418,8 +417,7 @@ Test('Participant service', async (participantTest) => { await participantTest.test('create participant with proxy', async (assert) => { try { const getByNameResult = await ParticipantService.getByName(testData.proxyParticipant) - const result = await ParticipantHelper.prepareData(testData.proxyParticipant, testData.currency, undefined, !!getByNameResult) - await ParticipantProxy.create(result.participant.participantId, true) + const result = await ParticipantHelper.prepareData(testData.proxyParticipant, testData.currency, undefined, !!getByNameResult, true) participantProxyFixtures.push(result.participant) for (const participant of participantProxyFixtures) { diff --git a/test/integration/helpers/participant.js b/test/integration/helpers/participant.js index 004985684..9ba247e5d 100644 --- a/test/integration/helpers/participant.js +++ b/test/integration/helpers/participant.js @@ -42,13 +42,14 @@ const testParticipant = { createdDate: new Date() } -exports.prepareData = async (name, currencyId = 'USD', secondaryCurrencyId = 'XXX', isUnique = true) => { +exports.prepareData = async (name, currencyId = 'USD', secondaryCurrencyId = 'XXX', isUnique = true, isProxy = false) => { try { const participantId = await Model.create(Object.assign( {}, testParticipant, { - name: (name || testParticipant.name) + (isUnique ? time.msToday().toString() : '') + name: (name || testParticipant.name) + (isUnique ? time.msToday().toString() : ''), + isProxy } )) const participantCurrencyId = await ParticipantCurrencyModel.create(participantId, currencyId, Enum.Accounts.LedgerAccountType.POSITION, false) diff --git a/test/unit/domain/participant/index.test.js b/test/unit/domain/participant/index.test.js index 66be4818a..003590965 100644 --- a/test/unit/domain/participant/index.test.js +++ b/test/unit/domain/participant/index.test.js @@ -199,7 +199,7 @@ Test('Participant service', async (participantTest) => { participantFixtures.forEach((participant, index) => { participantMap.set(index + 1, participantResult[index]) Db.participant.insert.withArgs({ participant }).returns(index) - ParticipantModelCached.create.withArgs({ name: participant.name }).returns((index + 1)) + ParticipantModelCached.create.withArgs({ name: participant.name, isProxy: !!participant.isProxy }).returns((index + 1)) ParticipantModelCached.getByName.withArgs(participant.name).returns(participantResult[index]) ParticipantModelCached.getById.withArgs(index).returns(participantResult[index]) ParticipantModelCached.update.withArgs(participant, 1).returns((index + 1)) @@ -254,7 +254,7 @@ Test('Participant service', async (participantTest) => { }) await participantTest.test('create false participant', async (assert) => { - const falseParticipant = { name: 'fsp3' } + const falseParticipant = { name: 'fsp3', isProxy: false } ParticipantModelCached.create.withArgs(falseParticipant).throws(new Error()) try { await Service.create(falseParticipant) From 6190e714237a5d4911d4ac7ec6ca7a188ed36eec Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 31 May 2024 09:24:46 -0500 Subject: [PATCH 6/7] add filter --- src/api/participants/handler.js | 3 ++ test/unit/api/participants/handler.test.js | 33 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/api/participants/handler.js b/src/api/participants/handler.js index 9dfea9a41..b2f2ff95a 100644 --- a/src/api/participants/handler.js +++ b/src/api/participants/handler.js @@ -161,6 +161,9 @@ const getAll = async function (request) { const results = await ParticipantService.getAll() const ledgerAccountTypes = await Enums.getEnums('ledgerAccountType') const ledgerAccountIds = Util.transpose(ledgerAccountTypes) + if (request.query.isProxy) { + return results.map(record => entityItem(record, ledgerAccountIds)).filter(record => record.isProxy) + } return results.map(record => entityItem(record, ledgerAccountIds)) } diff --git a/test/unit/api/participants/handler.test.js b/test/unit/api/participants/handler.test.js index 6f0e33aa7..60ee170e5 100644 --- a/test/unit/api/participants/handler.test.js +++ b/test/unit/api/participants/handler.test.js @@ -68,6 +68,18 @@ Test('Participant', participantHandlerTest => { { participantCurrencyId: 5, currencyId: 'USD', ledgerAccountTypeId: 5, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' } ], isProxy: 0 + }, + { + participantId: 4, + name: 'xnProxy', + currency: 'EUR', + isActive: 1, + createdDate: '2018-07-17T16:04:24.185Z', + currencyList: [ + { participantCurrencyId: 6, currencyId: 'EUR', ledgerAccountTypeId: 1, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' }, + { participantCurrencyId: 7, currencyId: 'EUR', ledgerAccountTypeId: 2, isActive: 1, createdBy: 'unknown', createdDate: '2018-07-17T16:04:24.185Z' } + ], + isProxy: 1 } ] @@ -112,6 +124,20 @@ Test('Participant', participantHandlerTest => { { id: 5, currency: 'USD', ledgerAccountType: 'HUB_FEE', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') } ], isProxy: 0 + }, + { + name: 'xnProxy', + id: 'http://central-ledger/participants/xnProxy', + created: '2018-07-17T16:04:24.185Z', + isActive: 1, + links: { + self: 'http://central-ledger/participants/xnProxy' + }, + accounts: [ + { id: 6, currency: 'EUR', ledgerAccountType: 'POSITION', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') }, + { id: 7, currency: 'EUR', ledgerAccountType: 'SETTLEMENT', isActive: 1, createdBy: 'unknown', createdDate: new Date('2018-07-17T16:04:24.185Z') } + ], + isProxy: 1 } ] const settlementModelFixtures = [ @@ -155,6 +181,13 @@ Test('Participant', participantHandlerTest => { test.end() }) + handlerTest.test('getAll should return all proxies when isProxy query is true', async function (test) { + Participant.getAll.returns(Promise.resolve(participantFixtures)) + const result = await Handler.getAll(createRequest({ query: { isProxy: true } })) + test.deepEqual(result, participantResults.filter(record => record.isProxy), 'The results match') + test.end() + }) + handlerTest.test('getByName should return the participant', async function (test) { Participant.getByName.withArgs(participantFixtures[0].name).returns(Promise.resolve(participantFixtures[0])) const result = await Handler.getByName(createRequest({ params: { name: participantFixtures[0].name } })) From 513dfde77438f4e73e4e42614a09daeb52305f1c Mon Sep 17 00:00:00 2001 From: Kevin Leyow Date: Fri, 31 May 2024 10:19:34 -0500 Subject: [PATCH 7/7] update swagger --- src/api/interface/swagger.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/api/interface/swagger.json b/src/api/interface/swagger.json index 848a82b0b..5a79a9b73 100644 --- a/src/api/interface/swagger.json +++ b/src/api/interface/swagger.json @@ -66,6 +66,15 @@ "tags": [ "participants" ], + "parameters": [ + { + "type": "boolean", + "description": "Filter by if participant is a proxy", + "name": "isProxy", + "in": "query", + "required": false + } + ], "responses": { "default": { "schema": {