diff --git a/README.md b/README.md index 8637573..1abe545 100755 --- a/README.md +++ b/README.md @@ -41,13 +41,10 @@ Configuration for the application is at config/default.js and config/production. - ES_HOST: Elasticsearch host - ES.DOCUMENTS: Elasticsearch index, type and id mapping for resources. - ATTRIBUTE_GROUP_PIPELINE_ID: The pipeline id for enrichment with attribute group. Default is `attributegroup-pipeline` -- SKILL_PROVIDER_PIPELINE_ID: The pipeline id for enrichment with skill provider. Default is `skillprovider-pipeline` - USER_PIPELINE_ID: The pipeline id for enrichment of user details. Default is `user-pipeline` - ATTRIBUTE_GROUP_ENRICH_POLICYNAME: The enrich policy for attribute group. Default is `attributegroup-policy` -- SKILL_PROVIDER_ENRICH_POLICYNAME: The enrich policy for skill provider. Default is `skillprovider-policy` - ROLE_ENRICH_POLICYNAME: The enrich policy for role. Default is `role-policy` - ACHIEVEMENT_PROVIDER_ENRICH_POLICYNAME: The enrich policy for achievement provider. Default is `achievementprovider-policy` -- SKILL_ENRICH_POLICYNAME: The enrich policy for skill. Default is `skill-policy` - ATTRIBUTE_ENRICH_POLICYNAME: The enrich policy for skill. Default is `attribute-policy` - ELASTICCLOUD_ID: The elastic cloud id, if your elasticsearch instance is hosted on elastic cloud. DO NOT provide a value for ES_HOST if you are using this - ELASTICCLOUD_USERNAME: The elastic cloud username for basic authentication. Provide this only if your elasticsearch instance is hosted on elastic cloud @@ -105,3 +102,8 @@ Make sure all config values are right, and you can run on local successfully, th 5. When you are running the application for the first time, It will take some time initially to download the image and install the dependencies You can also head into `docker-pgsql-es` folder and run `docker-compose up -d` to have docker instances of pgsql and elasticsearch to use with the api + +## Testing + +- Run `npm run test` to execute unit tests +- Run `npm run test:cov` to execute unit tests and generate coverage report. diff --git a/app.js b/app.js index f54dd4d..0ecbf1f 100755 --- a/app.js +++ b/app.js @@ -112,3 +112,7 @@ app.use('*', (req, res) => { logger.info(`Express server listening on port ${app.get('port')}`) }) })() + +if (process.env.NODE_ENV === 'test') { + module.exports = app +} diff --git a/config/default.js b/config/default.js index 98f4903..75552d2 100755 --- a/config/default.js +++ b/config/default.js @@ -32,6 +32,7 @@ module.exports = { BUSAPI_URL: process.env.BUSAPI_URL || 'https://api.topcoder-dev.com/v5', TOPCODER_GROUP_API: process.env.TOPCODER_GROUP_API || 'https://api.topcoder-dev.com/v5/groups', + TOPCODER_SKILL_API: process.env.TOPCODER_SKILL_API || 'https://api.topcoder-dev.com/v5/skills', KAFKA_ERROR_TOPIC: process.env.KAFKA_ERROR_TOPIC || 'common.error.reporting', KAFKA_MESSAGE_ORIGINATOR: process.env.KAFKA_MESSAGE_ORIGINATOR || 'u-bahn-api', @@ -101,17 +102,6 @@ module.exports = { type: '_doc', enrichPolicyName: process.env.ROLE_ENRICH_POLICYNAME || 'role-policy' }, - skill: { - index: process.env.SKILL_INDEX || 'skill', - type: '_doc', - enrichPolicyName: process.env.SKILL_ENRICH_POLICYNAME || 'skill-policy' - }, - skillprovider: { - index: process.env.SKILL_PROVIDER_INDEX || 'skill_provider', - type: '_doc', - pipelineId: process.env.SKILL_PROVIDER_PIPELINE_ID || 'skillprovider-pipeline', - enrichPolicyName: process.env.SKILL_PROVIDER_ENRICH_POLICYNAME || 'skillprovider-policy' - }, user: { index: process.env.USER_INDEX || 'user', type: '_doc', diff --git a/config/test.js b/config/test.js new file mode 100755 index 0000000..46af0a6 --- /dev/null +++ b/config/test.js @@ -0,0 +1,8 @@ +module.exports = { + AUTH0_URL: 'https://topcoder-dev.auth0.com/oauth/token', + AUTH0_AUDIENCE: 'https://m2m.topcoder-dev.com/', + TOKEN_CACHE_TIME: 6000, + AUTH0_CLIENT_ID: 'client_id', + AUTH0_CLIENT_SECRET: 'secret', + AUTH0_PROXY_SERVER_URL: 'proxy_url' +} diff --git a/docs/UBahn_API.postman_collection.json b/docs/UBahn_API.postman_collection.json index d63ad7e..e35baec 100644 --- a/docs/UBahn_API.postman_collection.json +++ b/docs/UBahn_API.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "6d99ffc9-3c8b-4c0a-a006-5f1d3d23801d", + "_postman_id": "9cf5a9d4-0c94-4882-a2ad-497bb85c223d", "name": "UBahn_API", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,6 @@ { "listen": "test", "script": { - "id": "769b9779-be21-4518-9276-f8b13c44c0d0", "exec": [ "var rsp = pm.response.json();", "if(rsp.id) pm.environment.set(\"userId\", rsp.id);" @@ -67,7 +66,6 @@ { "listen": "test", "script": { - "id": "b2b52a88-23c3-4547-89b5-0a0afa0dad19", "exec": [ "" ], @@ -119,7 +117,6 @@ { "listen": "test", "script": { - "id": "35cfaef0-78f5-4ff9-83f3-c2a705dc0e9d", "exec": [ "" ], @@ -143,7 +140,7 @@ } ], "url": { - "raw": "{{HOST}}/skill-search/skills?organizationId=36ed815b-3da1-49f1-a043-aaed0a4e81ad&keyword=net", + "raw": "{{HOST}}/skill-search/skills?organizationId={{organizationId}}&keyword=net", "host": [ "{{HOST}}" ], @@ -154,7 +151,7 @@ "query": [ { "key": "organizationId", - "value": "36ed815b-3da1-49f1-a043-aaed0a4e81ad" + "value": "{{organizationId}}" }, { "key": "keyword", @@ -171,7 +168,6 @@ { "listen": "test", "script": { - "id": "23733012-4565-480e-9c0c-66b7c2fd2933", "exec": [ "var rsp = pm.response.json();", "if(rsp.id) pm.environment.set(\"userId\", rsp.id);" @@ -197,10 +193,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"isAvailable\": \"false\",\n \"locations\": [\"New York\", \"London\"],\n \"skills\": [\"Angular (Web Framework)\", \"Python (Programming Language)\"],\n \"achievements\": [\"Upwork\", \"Topcoder\"],\n \"attributes\": [{\n \"id\": \"c44d4bee-1356-46d6-9f1f-991936dec297\",\n \"value\": [\"Senior Consultant\", \"IT Support Specialist\", \"Consultant\"]\n }, {\n \"id\": \"f3fd623f-a613-4e3c-bf2f-9df529ff4317\",\n \"value\": [\"Bulwark International Inc\"]\n }]\n}", - "options": { - "raw": {} - } + "raw": "{\n \"isAvailable\": \"false\",\n \"locations\": [\"New York\", \"London\"],\n \"skills\": [\"Angular (Web Framework)\", \"Python (Programming Language)\"],\n \"achievements\": [\"Upwork\", \"Topcoder\"],\n \"attributes\": [{\n \"id\": \"c44d4bee-1356-46d6-9f1f-991936dec297\",\n \"value\": [\"Senior Consultant\", \"IT Support Specialist\", \"Consultant\"]\n }, {\n \"id\": \"f3fd623f-a613-4e3c-bf2f-9df529ff4317\",\n \"value\": [\"Bulwark International Inc\"]\n }]\n}" }, "url": { "raw": "{{HOST}}/skill-search/users", @@ -220,7 +213,6 @@ { "listen": "prerequest", "script": { - "id": "e1951d10-6818-4d2d-8d49-452f3eb31f74", "type": "text/javascript", "exec": [ "" @@ -230,15 +222,13 @@ { "listen": "test", "script": { - "id": "bb0d8108-d90a-4b16-ac59-7d0720a86c81", "type": "text/javascript", "exec": [ "" ] } } - ], - "protocolProfileBehavior": {} + ] }, { "name": "users", @@ -249,7 +239,6 @@ { "listen": "test", "script": { - "id": "a80d76a2-572f-47e8-bb5b-7594906e6f17", "exec": [ "var rsp = pm.response.json();", "if(rsp.id) pm.environment.set(\"userId\", rsp.id);" @@ -275,10 +264,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"handle\":\"handle_01\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"handle\":\"handle_01\",\n \"firstName\": \"fn\",\n \"lastName\": \"ln\"\n}" }, "url": { "raw": "{{HOST}}/users", @@ -341,10 +327,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"handle\":\"handle_05\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"handle\":\"handle_05\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}", @@ -401,7 +384,7 @@ } ], "url": { - "raw": "{{HOST}}/users?enrich=true&role.name=role-2", + "raw": "{{HOST}}/users?enrich=true", "host": [ "{{HOST}}" ], @@ -428,16 +411,6 @@ "value": "userskill", "disabled": true }, - { - "key": "skill.name", - "value": "userskill", - "disabled": true - }, - { - "key": "skillProvider.name", - "value": "skillprovider-2", - "disabled": true - }, { "key": "userrole.roleId", "value": "bbec5193-bef2-4907-93bc-3e82cbf81dc0", @@ -445,7 +418,8 @@ }, { "key": "role.name", - "value": "role-2" + "value": "role-2", + "disabled": true } ] } @@ -464,7 +438,7 @@ } ], "url": { - "raw": "{{HOST}}/users?enrich=true&skill=React&skill=skill_name_update&achievement=achievement-name-01&achievement=string&location=London&location=New York&isAvailable=true", + "raw": "{{HOST}}/users?enrich=true&achievement=achievement-name-01&achievement=string&location=London&location=New York&isAvailable=true", "host": [ "{{HOST}}" ], @@ -491,16 +465,6 @@ "value": "userskill", "disabled": true }, - { - "key": "skill.name", - "value": "userskill", - "disabled": true - }, - { - "key": "skillProvider.name", - "value": "skillprovider-2", - "disabled": true - }, { "key": "userrole.roleId", "value": "bbec5193-bef2-4907-93bc-3e82cbf81dc0", @@ -511,514 +475,33 @@ "value": "role-2", "disabled": true }, - { - "key": "skill", - "value": "React" - }, - { - "key": "skill", - "value": "skill_name_update" - }, { "key": "achievement", "value": "achievement-name-01" - }, - { - "key": "achievement", - "value": "string" - }, - { - "key": "location", - "value": "London" - }, - { - "key": "location", - "value": "New York" - }, - { - "key": "isAvailable", - "value": "true" - } - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/users", - "request": { - "method": "HEAD", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token}}", - "type": "text" - } - ], - "url": { - "raw": "{{HOST}}/users", - "host": [ - "{{HOST}}" - ], - "path": [ - "users" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/users/:id", - "request": { - "method": "DELETE", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": {} - } - }, - "url": { - "raw": "{{HOST}}/users/{{userId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "users", - "{{userId}}" - ] - } - }, - "response": [] - } - ], - "protocolProfileBehavior": {} - }, - { - "name": "roles", - "item": [ - { - "name": "{{HOST}}/roles", - "event": [ - { - "listen": "test", - "script": { - "id": "021253da-d913-43df-b490-28001f14b233", - "exec": [ - "var rsp = pm.response.json();", - "if(rsp.id) pm.environment.set(\"roleId\", rsp.id);" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"name\":\"Admin\"\n}", - "options": { - "raw": {} - } - }, - "url": { - "raw": "{{HOST}}/roles", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/roles/:id", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - } - ], - "url": { - "raw": "{{HOST}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/roles/:id", - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"name\":\"Admin02\"\n}", - "options": { - "raw": {} - } - }, - "url": { - "raw": "{{HOST}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/roles/:id", - "request": { - "method": "HEAD", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "url": { - "raw": "{{HOST}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/roles", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token}}", - "type": "text" - } - ], - "url": { - "raw": "{{HOST}}/roles?name=m", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles" - ], - "query": [ - { - "key": "name", - "value": "m" - } - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/roles", - "request": { - "method": "HEAD", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token}}", - "type": "text" - } - ], - "url": { - "raw": "{{HOST}}/roles", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/roles/:id", - "request": { - "method": "DELETE", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": {} - } - }, - "url": { - "raw": "{{HOST}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - } - ], - "protocolProfileBehavior": {} - }, - { - "name": "usersRoles", - "item": [ - { - "name": "{{HOST}}/users/:userId/roles", - "event": [ - { - "listen": "test", - "script": { - "id": "4a70f27f-df1b-43cf-a0fa-a2ca58a5521a", - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"roleId\":\"{{roleId}}\"\n}", - "options": { - "raw": {} - } - }, - "url": { - "raw": "{{HOST}}/users/{{userId}}/roles", - "host": [ - "{{HOST}}" - ], - "path": [ - "users", - "{{userId}}", - "roles" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/users/:userId/roles/:roleId", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - } - ], - "url": { - "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "users", - "{{userId}}", - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/users/:userId/roles/:roleId", - "request": { - "method": "PATCH", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n\t\"roleId\":\"8607ddb3-abf6-4512-a618-c60d4771174b\"\n}", - "options": { - "raw": {} - } - }, - "url": { - "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "users", - "{{userId}}", - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/users/:userId/roles/:roleId", - "request": { - "method": "HEAD", - "header": [ - { - "key": "Authorization", - "type": "text", - "value": "Bearer {{token}}" - }, - { - "key": "Content-Type", - "name": "Content-Type", - "type": "text", - "value": "application/json" - } - ], - "url": { - "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", - "host": [ - "{{HOST}}" - ], - "path": [ - "users", - "{{userId}}", - "roles", - "{{roleId}}" - ] - } - }, - "response": [] - }, - { - "name": "{{HOST}}/users/:userId/roles", - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "Bearer {{token}}", - "type": "text" - } - ], - "url": { - "raw": "{{HOST}}/users/{{userId}}/roles", - "host": [ - "{{HOST}}" - ], - "path": [ - "users", - "{{userId}}", - "roles" + }, + { + "key": "achievement", + "value": "string" + }, + { + "key": "location", + "value": "London" + }, + { + "key": "location", + "value": "New York" + }, + { + "key": "isAvailable", + "value": "true" + } ] } }, "response": [] }, { - "name": "{{HOST}}/users/:userId/roles", + "name": "{{HOST}}/users", "request": { "method": "HEAD", "header": [ @@ -1029,21 +512,19 @@ } ], "url": { - "raw": "{{HOST}}/users/{{userId}}/roles", + "raw": "{{HOST}}/users", "host": [ "{{HOST}}" ], "path": [ - "users", - "{{userId}}", - "roles" + "users" ] } }, "response": [] }, { - "name": "{{HOST}}/users/:userId/roles/:roleId", + "name": "{{HOST}}/users/:id", "request": { "method": "DELETE", "header": [ @@ -1061,42 +542,35 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { - "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", + "raw": "{{HOST}}/users/{{userId}}", "host": [ "{{HOST}}" ], "path": [ "users", - "{{userId}}", - "roles", - "{{roleId}}" + "{{userId}}" ] } }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { - "name": "organizations", + "name": "roles", "item": [ { - "name": "{{HOST}}/organizations", + "name": "{{HOST}}/roles", "event": [ { "listen": "test", "script": { - "id": "9194de70-291f-4660-82d3-5883c23d12bb", "exec": [ "var rsp = pm.response.json();", - "if(rsp.id) pm.environment.set(\"organizationId\", rsp.id);" + "if(rsp.id) pm.environment.set(\"roleId\", rsp.id);" ], "type": "text/javascript" } @@ -1119,25 +593,22 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"organization_01\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"Admin\"\n}" }, "url": { - "raw": "{{HOST}}/organizations", + "raw": "{{HOST}}/roles", "host": [ "{{HOST}}" ], "path": [ - "organizations" + "roles" ] } }, "response": [] }, { - "name": "{{HOST}}/organizations/:id", + "name": "{{HOST}}/roles/:id", "request": { "method": "GET", "header": [ @@ -1148,20 +619,20 @@ } ], "url": { - "raw": "{{HOST}}/organizations/603d4264-cdb0-47f1-914e-f053abc60422", + "raw": "{{HOST}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "organizations", - "603d4264-cdb0-47f1-914e-f053abc60422" + "roles", + "{{roleId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/organizations/:id", + "name": "{{HOST}}/roles/:id", "request": { "method": "PATCH", "header": [ @@ -1179,26 +650,23 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"organization_update\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"Admin02\"\n}" }, "url": { - "raw": "{{HOST}}/organizations/{{organizationId}}", + "raw": "{{HOST}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "organizations", - "{{organizationId}}" + "roles", + "{{roleId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/organizations/:id", + "name": "{{HOST}}/roles/:id", "request": { "method": "HEAD", "header": [ @@ -1215,20 +683,20 @@ } ], "url": { - "raw": "{{HOST}}/organizations/{{organizationId}}", + "raw": "{{HOST}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "organizations", - "{{organizationId}}" + "roles", + "{{roleId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/organizations", + "name": "{{HOST}}/roles", "request": { "method": "GET", "header": [ @@ -1239,17 +707,17 @@ } ], "url": { - "raw": "{{HOST}}/organizations?name=o", + "raw": "{{HOST}}/roles?name=m", "host": [ "{{HOST}}" ], "path": [ - "organizations" + "roles" ], "query": [ { "key": "name", - "value": "o" + "value": "m" } ] } @@ -1257,7 +725,7 @@ "response": [] }, { - "name": "{{HOST}}/organizations", + "name": "{{HOST}}/roles", "request": { "method": "HEAD", "header": [ @@ -1268,19 +736,19 @@ } ], "url": { - "raw": "{{HOST}}/organizations", + "raw": "{{HOST}}/roles", "host": [ "{{HOST}}" ], "path": [ - "organizations" + "roles" ] } }, "response": [] }, { - "name": "{{HOST}}/organizations/:id", + "name": "{{HOST}}/roles/:id", "request": { "method": "DELETE", "header": [ @@ -1298,40 +766,34 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { - "raw": "{{HOST}}/organizations/{{organizationId}}", + "raw": "{{HOST}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "organizations", - "{{organizationId}}" + "roles", + "{{roleId}}" ] } }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { - "name": "skillsProviders", + "name": "usersRoles", "item": [ { - "name": "{{HOST}}/skillsProviders", + "name": "{{HOST}}/users/:userId/roles", "event": [ { "listen": "test", "script": { - "id": "f40cae85-9ad1-4c54-ad87-b592395027ac", "exec": [ - "var rsp = pm.response.json();", - "if(rsp.id) pm.environment.set(\"skillsProviderId\", rsp.id);" + "" ], "type": "text/javascript" } @@ -1354,25 +816,24 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"skillsProviders_01\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"roleId\":\"{{roleId}}\"\n}" }, "url": { - "raw": "{{HOST}}/skillsProviders", + "raw": "{{HOST}}/users/{{userId}}/roles", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders" + "users", + "{{userId}}", + "roles" ] } }, "response": [] }, { - "name": "{{HOST}}/skillsProviders/:id", + "name": "{{HOST}}/users/:userId/roles/:roleId", "request": { "method": "GET", "header": [ @@ -1383,20 +844,22 @@ } ], "url": { - "raw": "{{HOST}}/skillsProviders/{{skillsProviderId}}", + "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders", - "{{skillsProviderId}}" + "users", + "{{userId}}", + "roles", + "{{roleId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/skillsProviders/:id", + "name": "{{HOST}}/users/:userId/roles/:roleId", "request": { "method": "PATCH", "header": [ @@ -1414,26 +877,25 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"skillsProviders_update\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"roleId\":\"8607ddb3-abf6-4512-a618-c60d4771174b\"\n}" }, "url": { - "raw": "{{HOST}}/skillsProviders/{{skillsProviderId}}", + "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders", - "{{skillsProviderId}}" + "users", + "{{userId}}", + "roles", + "{{roleId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/skillsProviders/:id", + "name": "{{HOST}}/users/:userId/roles/:roleId", "request": { "method": "HEAD", "header": [ @@ -1450,20 +912,22 @@ } ], "url": { - "raw": "{{HOST}}/skillsProviders/{{skillsProviderId}}", + "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders", - "{{skillsProviderId}}" + "users", + "{{userId}}", + "roles", + "{{roleId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/skillsProviders", + "name": "{{HOST}}/users/:userId/roles", "request": { "method": "GET", "header": [ @@ -1474,25 +938,21 @@ } ], "url": { - "raw": "{{HOST}}/skillsProviders?name=ski", + "raw": "{{HOST}}/users/{{userId}}/roles", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders" - ], - "query": [ - { - "key": "name", - "value": "ski" - } + "users", + "{{userId}}", + "roles" ] } }, "response": [] }, { - "name": "{{HOST}}/skillsProviders", + "name": "{{HOST}}/users/:userId/roles", "request": { "method": "HEAD", "header": [ @@ -1503,19 +963,21 @@ } ], "url": { - "raw": "{{HOST}}/skillsProviders", + "raw": "{{HOST}}/users/{{userId}}/roles", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders" + "users", + "{{userId}}", + "roles" ] } }, "response": [] }, { - "name": "{{HOST}}/skillsProviders/:id", + "name": "{{HOST}}/users/:userId/roles/:roleId", "request": { "method": "DELETE", "header": [ @@ -1533,40 +995,37 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { - "raw": "{{HOST}}/skillsProviders/{{skillsProviderId}}", + "raw": "{{HOST}}/users/{{userId}}/roles/{{roleId}}", "host": [ "{{HOST}}" ], "path": [ - "skillsProviders", - "{{skillsProviderId}}" + "users", + "{{userId}}", + "roles", + "{{roleId}}" ] } }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { - "name": "skills", + "name": "organizations", "item": [ { - "name": "{{HOST}}/skills", + "name": "{{HOST}}/organizations", "event": [ { "listen": "test", "script": { - "id": "a0153fe7-82ee-4a03-af43-19cf44fab4f0", "exec": [ "var rsp = pm.response.json();", - "if(rsp.id) pm.environment.set(\"skillId\", rsp.id);" + "if(rsp.id) pm.environment.set(\"organizationId\", rsp.id);" ], "type": "text/javascript" } @@ -1589,25 +1048,22 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"skillProviderId\":\"{{skillsProviderId}}\",\n\t\"name\":\"jump\",\n\t\"uri\":\"http://www.google.com\",\n\t\"externalId\":\"externalId\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"organization_001\"\n}" }, "url": { - "raw": "{{HOST}}/skills", + "raw": "{{HOST}}/organizations", "host": [ "{{HOST}}" ], "path": [ - "skills" + "organizations" ] } }, "response": [] }, { - "name": "{{HOST}}/skills/:id", + "name": "{{HOST}}/organizations/:id", "request": { "method": "GET", "header": [ @@ -1618,20 +1074,20 @@ } ], "url": { - "raw": "{{HOST}}/skills/{{skillId}}", + "raw": "{{HOST}}/organizations/{{organizationId}}", "host": [ "{{HOST}}" ], "path": [ - "skills", - "{{skillId}}" + "organizations", + "{{organizationId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/skills/:id", + "name": "{{HOST}}/organizations/:id", "request": { "method": "PATCH", "header": [ @@ -1649,26 +1105,23 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"skill_name_update\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"organization_update\"\n}" }, "url": { - "raw": "{{HOST}}/skills/{{skillId}}", + "raw": "{{HOST}}/organizations/{{organizationId}}", "host": [ "{{HOST}}" ], "path": [ - "skills", - "{{skillId}}" + "organizations", + "{{organizationId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/skills/:id", + "name": "{{HOST}}/organizations/:id", "request": { "method": "HEAD", "header": [ @@ -1685,20 +1138,20 @@ } ], "url": { - "raw": "{{HOST}}/skills/{{skillId}}", + "raw": "{{HOST}}/organizations/{{organizationId}}", "host": [ "{{HOST}}" ], "path": [ - "skills", - "{{skillId}}" + "organizations", + "{{organizationId}}" ] } }, "response": [] }, { - "name": "{{HOST}}/skills", + "name": "{{HOST}}/organizations", "request": { "method": "GET", "header": [ @@ -1709,17 +1162,17 @@ } ], "url": { - "raw": "{{HOST}}/skills", + "raw": "{{HOST}}/organizations", "host": [ "{{HOST}}" ], "path": [ - "skills" + "organizations" ], "query": [ { - "key": "perPage", - "value": "2", + "key": "name", + "value": "organization_001", "disabled": true } ] @@ -1728,7 +1181,7 @@ "response": [] }, { - "name": "{{HOST}}/skills", + "name": "{{HOST}}/organizations", "request": { "method": "HEAD", "header": [ @@ -1739,19 +1192,19 @@ } ], "url": { - "raw": "{{HOST}}/skills", + "raw": "{{HOST}}/organizations", "host": [ "{{HOST}}" ], "path": [ - "skills" + "organizations" ] } }, "response": [] }, { - "name": "{{HOST}}/skills/:id", + "name": "{{HOST}}/organizations/:id", "request": { "method": "DELETE", "header": [ @@ -1769,26 +1222,22 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { - "raw": "{{HOST}}/skills/{{skillId}}", + "raw": "{{HOST}}/organizations/{{organizationId}}", "host": [ "{{HOST}}" ], "path": [ - "skills", - "{{skillId}}" + "organizations", + "{{organizationId}}" ] } }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "usersSkills", @@ -1799,7 +1248,6 @@ { "listen": "test", "script": { - "id": "b4d7a5cc-9e17-4d45-84c3-6dfbdcf09579", "exec": [ "" ], @@ -1824,10 +1272,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"skillId\":\"{{skillId}}\",\n\t\"metricValue\":\"3L\",\n\t\"certifierId\":\"certifier_id\",\n\t\"certifiedDate\":\"2020-05-04T07:36:28.036Z\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"skillId\":\"{{skillId}}\",\n\t\"metricValue\":\"3L\",\n\t\"certifierId\":\"certifier_id\",\n\t\"certifiedDate\":\"2020-05-04T07:36:28.036Z\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/skills", @@ -1888,10 +1333,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"metricValue\":\"4.5L\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"metricValue\":\"4.5L\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/skills/{{skillId}}", @@ -1952,7 +1394,7 @@ } ], "url": { - "raw": "{{HOST}}/users/{{userId}}/skills?skillName=skill-2", + "raw": "{{HOST}}/users/{{userId}}/skills", "host": [ "{{HOST}}" ], @@ -1960,12 +1402,6 @@ "users", "{{userId}}", "skills" - ], - "query": [ - { - "key": "skillName", - "value": "skill-2" - } ] } }, @@ -2015,10 +1451,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/users/{{userId}}/skills/{{skillId}}", @@ -2035,8 +1468,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "externalProfiles", @@ -2047,7 +1479,6 @@ { "listen": "test", "script": { - "id": "08a6d74a-268c-403b-8cb1-85bee3c88855", "exec": [ "" ], @@ -2072,10 +1503,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"organizationId\":\"{{organizationId}}\",\n\t\"uri\":\"http://uri.com/uri\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"organizationId\":\"{{organizationId}}\",\n\t\"uri\":\"http://uri.com/uri\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/externalProfiles", @@ -2136,10 +1564,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"uri\":\"http://www.new.com/new-uri\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"uri\":\"http://www.new.com/new-uri\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/externalProfiles/{{organizationId}}", @@ -2263,10 +1688,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/users/{{userId}}/externalProfiles/{{organizationId}}", @@ -2283,8 +1705,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "achievementsProviders", @@ -2295,7 +1716,6 @@ { "listen": "test", "script": { - "id": "680443d3-c817-4939-8461-445fbeea6b00", "exec": [ "var rsp = pm.response.json();", "if(rsp.id) pm.environment.set(\"achievementsProviderId\", rsp.id);" @@ -2321,10 +1741,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"achievementsProviders_02\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"achievementsProviders_02\"\n}" }, "url": { "raw": "{{HOST}}/achievementsProviders", @@ -2381,10 +1798,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"achievementsProviders_update\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"achievementsProviders_update\"\n}" }, "url": { "raw": "{{HOST}}/achievementsProviders/{{achievementsProviderId}}", @@ -2500,10 +1914,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/achievementsProviders/{{achievementsProviderId}}", @@ -2518,8 +1929,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "achievements", @@ -2530,7 +1940,6 @@ { "listen": "test", "script": { - "id": "4ccce827-71ed-4373-b14f-e103b334e73f", "exec": [ "" ], @@ -2555,10 +1964,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"achievementsProviderId\":\"{{achievementsProviderId}}\",\n\t\"name\":\"achievement-name-01\",\n\t\"uri\":\"http://www.google.com/xx\",\n\t\"certifierId\":\"certifierId\",\n\t\"certifiedDate\":\"2020-05-04T07:36:28.036Z\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"achievementsProviderId\":\"{{achievementsProviderId}}\",\n\t\"name\":\"achievement-name-01\",\n\t\"uri\":\"http://www.google.com/xx\",\n\t\"certifierId\":\"certifierId\",\n\t\"certifiedDate\":\"2020-05-04T07:36:28.036Z\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/achievements", @@ -2619,10 +2025,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t \"name\": \"string\",\n\t \"uri\": \"string\",\n\t \"certifierId\": \"string\",\n\t \"certifiedDate\": \"2020-05-13T06:33:54.708Z\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t \"name\": \"string\",\n\t \"uri\": \"string\",\n\t \"certifierId\": \"string\",\n\t \"certifiedDate\": \"2020-05-13T06:33:54.708Z\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/achievements/{{achievementsProviderId}}", @@ -2747,10 +2150,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/users/{{userId}}/externalProfiles/{{organizationId}}", @@ -2767,8 +2167,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "attributeGroups", @@ -2779,7 +2178,6 @@ { "listen": "test", "script": { - "id": "6670cb30-0276-4625-9688-8cb1aa78d8fb", "exec": [ "var rsp = pm.response.json();", "if (rsp.id) pm.environment.set(\"attributeGroupId\", rsp.id);" @@ -2805,10 +2203,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"organizationId\":\"{{organizationId}}\",\n\t\"name\":\"attributeGroup_01\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"organizationId\":\"{{organizationId}}\",\n\t\"name\":\"attributeGroup_01\"\n}" }, "url": { "raw": "{{HOST}}/attributeGroups", @@ -2865,10 +2260,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"group 03\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"group 03\"\n}" }, "url": { "raw": "{{HOST}}/attributeGroups/{{attributeGroupId}}", @@ -2990,10 +2382,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/attributeGroups/{{attributeGroupId}}", @@ -3008,8 +2397,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "attributes", @@ -3020,7 +2408,6 @@ { "listen": "test", "script": { - "id": "bad538df-7c33-4d34-a90e-9e60e279f40d", "exec": [ "var rsp = pm.response.json();", "if (rsp.id) pm.environment.set(\"attributeId\", rsp.id);" @@ -3046,10 +2433,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"attributeGroupId\":\"{{attributeGroupId}}\",\n\t\"name\":\"attribute_02\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"attributeGroupId\":\"{{attributeGroupId}}\",\n\t\"name\":\"attribute_02\"\n}" }, "url": { "raw": "{{HOST}}/attributes", @@ -3106,10 +2490,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"name\":\"attr-04\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"name\":\"attr-04\"\n}" }, "url": { "raw": "{{HOST}}/attributes/{{attributeId}}", @@ -3230,10 +2611,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/attributes/{{attributeId}}", @@ -3248,8 +2626,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "userAttributes", @@ -3260,7 +2637,6 @@ { "listen": "test", "script": { - "id": "b91ea1ce-88a2-48fa-8e90-ed689232b5e5", "exec": [ "" ], @@ -3285,10 +2661,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"attributeId\":\"{{attributeId}}\",\n\t\"value\":\"1.23\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"attributeId\":\"{{attributeId}}\",\n\t\"value\":\"1.23\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/attributes", @@ -3349,10 +2722,7 @@ ], "body": { "mode": "raw", - "raw": "{\n\t\"value\":\"2.56\"\n}", - "options": { - "raw": {} - } + "raw": "{\n\t\"value\":\"2.56\"\n}" }, "url": { "raw": "{{HOST}}/users/{{userId}}/attributes/{{attributeId}}", @@ -3484,10 +2854,7 @@ ], "body": { "mode": "raw", - "raw": "", - "options": { - "raw": {} - } + "raw": "" }, "url": { "raw": "{{HOST}}/users/{{userId}}/attributes/{{attributeId}}", @@ -3504,8 +2871,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "Group API", @@ -3537,8 +2903,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] }, { "name": "organizationSkillsProvider", @@ -3628,7 +2993,7 @@ "response": [] }, { - "name": "{{HOST}}/organizations/{{organizationId}}/skillProviders", + "name": "{{HOST}}/organizations/{{organizationId}}/skillProviders/:id", "request": { "method": "GET", "header": [ @@ -3705,9 +3070,7 @@ }, "response": [] } - ], - "protocolProfileBehavior": {} + ] } - ], - "protocolProfileBehavior": {} + ] } \ No newline at end of file diff --git a/docs/UBahn_ENV.postman_environment.json b/docs/UBahn_ENV.postman_environment.json index 6645a14..d373666 100644 --- a/docs/UBahn_ENV.postman_environment.json +++ b/docs/UBahn_ENV.postman_environment.json @@ -1,20 +1,20 @@ { - "id": "1f07c3cc-5af9-4dc1-b038-129aaf1fac6e", + "id": "00b2830d-9838-44e4-a15e-37980c7aba23", "name": "UBahn_ENV", "values": [ { "key": "HOST", - "value": "http://127.0.0.1:3002/api/1.0", + "value": "http://127.0.0.1:3001/api/1.0", "enabled": true }, { "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29waWxvdCIsIkFkbWluIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLmNvbSIsImhhbmRsZSI6InRjLUFkbWluIiwiZXhwIjoxNjg1NTcxNDYwLCJ1c2VySWQiOiIyMzE2Njc2OCIsImlhdCI6MTU4NTU3MDg2MCwiZW1haWwiOiJ0Yy1BZG1pbkBnbWFpbC5jb20iLCJqdGkiOiIwZjFlZjFkMy0yYjMzLTQ5MDAtYmI0My00OGYyMjg1Zjk2MzAifQ.D_TtClF4xkuSPSWoUYvkWigUWVFhH5UuF7Eci4S1_xg", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29waWxvdCIsIkFkbWluIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLmNvbSIsImhhbmRsZSI6InRjLUFkbWluIiwiZXhwIjoxNjg1NTcxNDYwLCJ1c2VySWQiOiIyMzE2Njc2OCIsImlhdCI6MTY4NTU3MTQ2MCwiZW1haWwiOiJ0Yy1BZG1pbkBnbWFpbC5jb20iLCJqdGkiOiIwZjFlZjFkMy0yYjMzLTQ5MDAtYmI0My00OGYyMjg1Zjk2MzAifQ.PeJDhtvFY5Io-ZNfiiWQZtAesp-rYS-1TCSsu3sncpE", "enabled": true }, { "key": "userId", - "value": "55f6fa1c-fc38-4b74-83ad-278babd7efd2", + "value": "ce348067-e73f-49d7-af72-fcf11a6c88bf", "enabled": true }, { @@ -24,7 +24,7 @@ }, { "key": "skillsProviderId", - "value": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d", + "value": "6a21394e-1278-4835-9e4d-cb4ff151fcd3", "enabled": true }, { @@ -39,6 +39,6 @@ } ], "_postman_variable_scope": "environment", - "_postman_exported_at": "2020-08-02T07:47:16.803Z", - "_postman_exported_using": "Postman/7.29.1" + "_postman_exported_at": "2021-10-02T14:50:38.084Z", + "_postman_exported_using": "Postman/8.12.1" } \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 12914bc..abf4c74 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -520,11 +520,6 @@ paths: required: true type: "string" format: "UUID" - - name: "skillName" - in: "query" - description: "Filter by skill name (through skill id)" - required: false - type: "string" responses: "200": description: "OK - the request was successful" @@ -579,11 +574,6 @@ paths: required: true type: "string" format: "UUID" - - name: "skillName" - in: "query" - description: "Filter by skill name (through skill id)" - required: false - type: "string" responses: "200": description: "Success response" @@ -4565,11 +4555,6 @@ definitions: description: "The organization id" type: "string" format: "UUID" - skills: - type: "array" - items: - type: "string" - description: "The skill name to filter users with. Specify multiple times to provide multiple values" Unauthorized: type: "object" properties: diff --git a/package-lock.json b/package-lock.json index def25a5..ff886f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,248 @@ "@babel/highlight": "^7.8.3" } }, + "@babel/compat-data": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "dev": true + }, + "@babel/core": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", + "dev": true, + "requires": { + "@babel/types": "^7.15.6", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-module-imports": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + } + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" + } + }, "@babel/helper-validator-identifier": { "version": "7.9.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", "dev": true }, + "@babel/helper-validator-option": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "dev": true + }, + "@babel/helpers": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "dev": true, + "requires": { + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, "@babel/highlight": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", @@ -30,6 +266,135 @@ "js-tokens": "^4.0.0" } }, + "@babel/parser": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", + "dev": true + }, + "@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + } + } + }, + "@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.14.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + } + } + }, "@elastic/elasticsearch": { "version": "7.9.1", "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.9.1.tgz", @@ -105,6 +470,123 @@ "@hapi/hoek": "^8.3.0" } }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/samsam": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz", + "integrity": "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -119,6 +601,12 @@ "@types/node": "*" } }, + "@types/chai": { + "version": "4.2.22", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", + "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", + "dev": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -133,6 +621,12 @@ "@types/node": "*" } }, + "@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, "@types/express": { "version": "4.17.8", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", @@ -200,6 +694,22 @@ "@types/mime": "*" } }, + "@types/superagent": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", + "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -244,6 +754,16 @@ } } }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { "version": "6.12.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", @@ -266,6 +786,12 @@ "semaphore-async-await": "^1.5.1" } }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-escapes": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", @@ -303,6 +829,31 @@ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -340,6 +891,12 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -434,6 +991,12 @@ "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -465,6 +1028,34 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserslist": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", + "escalade": "^3.1.1", + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" + } + }, "buffer": { "version": "4.9.2", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", @@ -501,6 +1092,18 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -512,11 +1115,55 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" }, + "caniuse-lite": { + "version": "1.0.30001265", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", + "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, + "chai-http": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", + "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", + "dev": true, + "requires": { + "@types/chai": "4", + "@types/superagent": "^3.8.3", + "cookiejar": "^2.1.1", + "is-ip": "^2.0.0", + "methods": "^1.1.2", + "qs": "^6.5.1", + "superagent": "^3.7.0" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -534,6 +1181,45 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -675,6 +1361,12 @@ "delayed-stream": "~1.0.0" } }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -712,6 +1404,15 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", @@ -794,12 +1495,38 @@ "mimic-response": "^2.0.0" } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -870,6 +1597,12 @@ "kuler": "1.0.x" } }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -915,6 +1648,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "electron-to-chromium": { + "version": "1.3.864", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz", + "integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -992,6 +1731,18 @@ "is-symbol": "^1.0.2" } }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1411,6 +2162,15 @@ "flat-cache": "^2.0.1" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -1425,6 +2185,77 @@ "unpipe": "~1.0.0" } }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, "find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -1440,6 +2271,12 @@ "locate-path": "^2.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -1500,6 +2337,59 @@ } } }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1530,12 +2420,25 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -1553,11 +2456,29 @@ "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.4.3.tgz", "integrity": "sha1-eAw29p360FpaBF3Te+etyhGk9v8=" }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, "get-parameter-names": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/get-parameter-names/-/get-parameter-names-0.3.0.tgz", @@ -1613,6 +2534,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -1661,6 +2588,30 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + } + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hoek": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", @@ -1671,6 +2622,12 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -1777,6 +2734,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflection": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", @@ -1899,6 +2862,12 @@ "jsbi": "^3.1.1" } }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1909,6 +2878,15 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", @@ -1942,6 +2920,27 @@ "is-extglob": "^2.1.1" } }, + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "dev": true, + "requires": { + "ip-regex": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -1976,11 +2975,23 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2007,10 +3018,204 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.3.tgz", + "integrity": "sha512-0i77ZFLsb9U3DHi22WzmIngVzfoyxxbQcZRqlF3KoKmCJGq9nhFHoGi8FqBztN2rE8w6hURnZghetn0xpkVb6A==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } }, "jmespath": { "version": "0.15.0", @@ -2057,6 +3262,12 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -2137,6 +3348,12 @@ "object.assign": "^4.1.0" } }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -2255,6 +3472,18 @@ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -2290,6 +3519,67 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "logform": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", @@ -2336,6 +3626,23 @@ "lru-cache": "~4.0.0" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2406,6 +3713,265 @@ "minimist": "^1.2.5" } }, + "mocha": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.2.tgz", + "integrity": "sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + } + } + }, "moment": { "version": "2.25.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.25.1.tgz", @@ -2447,6 +4013,12 @@ "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "optional": true }, + "nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -2470,6 +4042,36 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "nise": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz", + "integrity": "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^7.0.4", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, "node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", @@ -2478,6 +4080,21 @@ "clone": "2.x" } }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "node-releases": { + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -2489,11 +4106,252 @@ "validate-npm-package-license": "^3.0.1" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -2640,12 +4498,33 @@ "p-limit": "^1.1.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, "packet-reader": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", @@ -2709,6 +4588,12 @@ "pify": "^2.0.0" } }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -2855,6 +4740,18 @@ } } }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -3022,6 +4919,15 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -3107,6 +5013,15 @@ } } }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -3160,6 +5075,15 @@ "util-deprecate": "^1.0.1" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "reconnect-core": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/reconnect-core/-/reconnect-core-1.3.0.tgz", @@ -3174,6 +5098,15 @@ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -3413,6 +5346,15 @@ "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==" }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -3463,6 +5405,37 @@ "is-arrayish": "^0.3.1" } }, + "sinon": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz", + "integrity": "sha512-59237HChms4kg7/sXhiRcUzdSkKuydDeTiamT/jesUVHshBgL8XAmhgFo0GfK6RruMDM/iRSij1EybmMog9cJw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^7.1.2", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -3482,6 +5455,60 @@ } } }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", @@ -3823,6 +5850,33 @@ "request": "^2.88.0" } }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -3849,6 +5903,21 @@ "os-tmpdir": "~1.0.2" } }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -3923,6 +5992,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -3938,6 +6013,15 @@ "mime-types": "~2.1.24" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "umzug": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", @@ -4118,6 +6202,12 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true + }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", @@ -4174,6 +6264,18 @@ "mkdirp": "^0.5.1" } }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", @@ -4331,6 +6433,38 @@ "camelcase": "^3.0.0", "lodash.assign": "^4.1.0" } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 4c8d737..ca6194f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "migrations": "node scripts/db/migrations.js", "insert-data": "node scripts/db/insert-data.js", "migrate-qldb-to-pg": "node scripts/db/migrateQldbToPg.js", - "import-s3-data": "node scripts/db/importS3ToQldb.js" + "import-s3-data": "node scripts/db/importS3ToQldb.js", + "test": "mocha test/unit/*.test.js --timeout 30000 --require test/prepare.js --exit", + "test:cov": "nyc --reporter=html --reporter=text npm run test" }, "repository": { "type": "git", @@ -47,8 +49,25 @@ "winston": "^3.2.1" }, "devDependencies": { + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "chai-http": "^4.3.0", + "mocha": "^9.1.2", + "nyc": "^15.1.0", + "sinon": "^11.1.2", "standard": "^14.3.0" }, + "standard": { + "env": [ + "mocha" + ] + }, + "nyc": { + "exclude": [ + "src/common/logger.js", + "test/unit/**" + ] + }, "engines": { "node": "12.x" } diff --git a/scripts/constants.js b/scripts/constants.js index c5d976c..fa90e93 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -6,22 +6,6 @@ const config = require('config') const topResources = { - skillprovider: { - index: config.get('ES.DOCUMENTS.skillprovider.index'), - type: config.get('ES.DOCUMENTS.skillprovider.type'), - enrich: { - policyName: config.get('ES.DOCUMENTS.skillprovider.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy'] - }, - pipeline: { - id: config.get('ES.DOCUMENTS.skillprovider.pipelineId'), - field: 'skillProviderId', - targetField: 'skillprovider', - maxMatches: '1' - } - }, - role: { index: config.get('ES.DOCUMENTS.role.index'), type: config.get('ES.DOCUMENTS.role.type'), @@ -58,21 +42,6 @@ const topResources = { } }, - skill: { - index: config.get('ES.DOCUMENTS.skill.index'), - type: config.get('ES.DOCUMENTS.skill.type'), - enrich: { - policyName: config.get('ES.DOCUMENTS.skill.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'skillProviderId', 'name', 'externalId', 'uri', 'created', 'updated', 'createdBy', 'updatedBy', 'skillprovider'] - }, - ingest: { - pipeline: { - id: config.get('ES.DOCUMENTS.skillprovider.pipelineId') - } - } - }, - attribute: { index: config.get('ES.DOCUMENTS.attribute.index'), type: config.get('ES.DOCUMENTS.attribute.type'), @@ -126,13 +95,6 @@ const topResources = { field: '_ingest._value.roleId', targetField: '_ingest._value.role', maxMatches: '1' - }, - { - referenceField: config.get('ES.DOCUMENTS.userskill.userField'), - enrichPolicyName: 'skill-policy', - field: '_ingest._value.skillId', - targetField: '_ingest._value.skill', - maxMatches: '1' } ] } @@ -178,9 +140,7 @@ const organizationResources = { const modelToESIndexMapping = { User: 'user', Role: 'role', - SkillsProvider: 'skillprovider', Organization: 'organization', - Skill: 'skill', UsersRole: 'userrole', UsersSkill: 'userskill', Achievement: 'achievement', diff --git a/scripts/db/data/OrganizationSkillsProvider.json b/scripts/db/data/OrganizationSkillsProvider.json index c9ec16b..ede1b1e 100644 --- a/scripts/db/data/OrganizationSkillsProvider.json +++ b/scripts/db/data/OrganizationSkillsProvider.json @@ -7,5 +7,14 @@ "updatedBy": "tc-Copilot", "organizationId": "36ed815b-3da1-49f1-a043-aaed0a4e81ad", "skillProviderId": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d" + }, + { + "id": "6a21394e-1278-4835-9e4d-cb4ff151fcd3", + "created": "2020-05-05T11:01:31.334Z", + "updated": "2020-05-05T11:02:10.574Z", + "createdBy": "tc-Copilot", + "updatedBy": "tc-Copilot", + "organizationId": "6a21394e-1278-4835-9e4d-cb4ff151fcd3", + "skillProviderId": "26fb37b1-5f9f-4727-baa9-f3c87de84ab1" } ] diff --git a/scripts/db/data/Skill.json b/scripts/db/data/Skill.json deleted file mode 100644 index a0e8da1..0000000 --- a/scripts/db/data/Skill.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "id": "0de5cb8b-d217-4133-8483-a3a09db9ab3d", - "created": "2020-05-05T11:03:56.711Z", - "updated": "2020-05-05T11:04:25.798Z", - "createdBy": "tc-Copilot", - "updatedBy": "tc-Copilot", - "skillProviderId": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d", - "name": ".NET Framework 4", - "externalId": "KS126XR63RKYVCKYDNBN", - "uri": "http://www.google.com" - }, - { - "id": "0aec2956-cbcb-4c80-8c00-25cc02a71611", - "created": "2020-05-05T11:03:56.711Z", - "updated": "2020-05-05T11:04:25.798Z", - "createdBy": "tc-Copilot", - "updatedBy": "tc-Copilot", - "skillProviderId": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d", - "name": "C++ (Programming Language)", - "externalId": "KS1219W70LY1GXZDSKW5", - "uri": "http://www.google.com" - }, - { - "id": "ab8f01fc-9686-4cc1-9b59-c412b4bae3f2", - "created": "2020-05-05T11:03:56.711Z", - "updated": "2020-05-05T11:04:25.798Z", - "createdBy": "tc-Copilot", - "updatedBy": "tc-Copilot", - "skillProviderId": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d", - "name": "Angular (Web Framework)", - "externalId": "KS120H6772VQ0MQ5RLVD", - "uri": "http://www.google.com" - }, - { - "id": "6df99fc1-3115-4b0c-bf2b-21ecd52fa64b", - "created": "2020-05-05T11:03:56.711Z", - "updated": "2020-05-05T11:04:25.798Z", - "createdBy": "tc-Copilot", - "updatedBy": "tc-Copilot", - "skillProviderId": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d", - "name": "Python (Programming Language)", - "externalId": "KS125LS6N7WP4S6SFTCK", - "uri": "http://www.google.com" - } -] diff --git a/scripts/db/data/SkillsProvider.json b/scripts/db/data/SkillsProvider.json deleted file mode 100644 index b567a3c..0000000 --- a/scripts/db/data/SkillsProvider.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "id": "7637ae1a-3b7c-44eb-a5ed-10ea02f1885d", - "created": "2020-05-05T11:02:49.718Z", - "updated": null, - "createdBy": "tc-Copilot", - "updatedBy": null, - "name": "EMSI" - } -] diff --git a/scripts/db/dropAll.js b/scripts/db/dropAll.js index fa2aba2..7d1b044 100644 --- a/scripts/db/dropAll.js +++ b/scripts/db/dropAll.js @@ -20,9 +20,6 @@ async function main () { await client.ingest.deletePipeline({ id: topResources.user.pipeline.id }) - await client.ingest.deletePipeline({ - id: topResources.skillprovider.pipeline.id - }) await client.ingest.deletePipeline({ id: topResources.attributegroup.pipeline.id }) diff --git a/scripts/db/dumpDbToEs.js b/scripts/db/dumpDbToEs.js index 60bf96d..29869d0 100644 --- a/scripts/db/dumpDbToEs.js +++ b/scripts/db/dumpDbToEs.js @@ -15,11 +15,9 @@ const models = sequelize.models // Declares the ordering of the resource data insertion, to ensure that enrichment happens correctly const RESOURCES_IN_ORDER = [ - 'skillprovider', 'role', 'achievementprovider', 'attributegroup', - 'skill', 'attribute', 'organization', 'organizationskillprovider', @@ -54,18 +52,6 @@ async function cleanupES (keys) { } } - try { - await client.ingest.deletePipeline({ - id: topResources.skillprovider.pipeline.id - }) - } catch (e) { - if (e.meta && e.meta.body.error.type === RESOURCE_NOT_FOUND) { - // Ignore - } else { - throw e - } - } - try { await client.ingest.deletePipeline({ id: topResources.attributegroup.pipeline.id diff --git a/scripts/db/insert-data.js b/scripts/db/insert-data.js index dfcfe40..e2d069c 100644 --- a/scripts/db/insert-data.js +++ b/scripts/db/insert-data.js @@ -4,8 +4,8 @@ const logger = require('../../src/common/logger') const models = sequelize.models const dataKeys = ['User', 'Organization', 'AchievementsProvider', 'Achievement', - 'AttributeGroup', 'Attribute', 'ExternalProfile', 'SkillsProvider', - 'OrganizationSkillsProvider', 'Role', 'Skill', 'UserAttribute', 'UsersRole', 'UsersSkill'] + 'AttributeGroup', 'Attribute', 'ExternalProfile', + 'OrganizationSkillsProvider', 'Role', 'UserAttribute', 'UsersRole', 'UsersSkill'] /** * import seed data diff --git a/scripts/db/migrateQldbToPg.js b/scripts/db/migrateQldbToPg.js index e9b3904..b040a2e 100644 --- a/scripts/db/migrateQldbToPg.js +++ b/scripts/db/migrateQldbToPg.js @@ -9,8 +9,8 @@ const logger = require('../../src/common/logger') const models = sequelize.models const dataKeys = ['User', 'Organization', 'AchievementsProvider', 'Achievement', - 'AttributeGroup', 'Attribute', 'ExternalProfile', 'SkillsProvider', - 'OrganizationSkillsProvider', 'Role', 'Skill', 'UserAttribute', 'UsersRole', 'UsersSkill'] + 'AttributeGroup', 'Attribute', 'ExternalProfile', + 'OrganizationSkillsProvider', 'Role', 'UserAttribute', 'UsersRole', 'UsersSkill'] /** * Query all records from db. diff --git a/scripts/db/migrations.js b/scripts/db/migrations.js index baf1d45..359597f 100644 --- a/scripts/db/migrations.js +++ b/scripts/db/migrations.js @@ -1,7 +1,6 @@ const sequelize = require('../../src/models/index') const path = require('path') const Umzug = require('umzug') -const { createDb } = require('../../src/common/db-helper') function getUmzug () { return new Umzug({ diff --git a/scripts/db/migrations/15_remove-skills-skillsProvider.js b/scripts/db/migrations/15_remove-skills-skillsProvider.js new file mode 100644 index 0000000..c0a6508 --- /dev/null +++ b/scripts/db/migrations/15_remove-skills-skillsProvider.js @@ -0,0 +1,92 @@ +const { DataTypes } = require('sequelize') + +module.exports = { + up: async (query) => { + await query.removeConstraint('UsersSkills', 'UsersSkills_skillId_fkey') + await query.removeConstraint('OrganizationSkillsProviders', 'OrganizationSkillsProviders_skillProviderId_fkey') + await query.dropTable('Skills') + await query.dropTable('SkillsProviders') + }, + down: async (query) => { + await query.createTable('Skills', { + id: { + primaryKey: true, + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4 + }, + createdBy: { + type: DataTypes.STRING + }, + updatedBy: { + type: DataTypes.STRING + }, + name: { + type: DataTypes.STRING + }, + externalId: { + type: DataTypes.STRING + }, + uri: { + type: DataTypes.STRING + }, + created: { + type: DataTypes.DATE, + allowNull: false + }, + updated: { + type: DataTypes.DATE + } + }) + await query.createTable('SkillsProviders', { + id: { + primaryKey: true, + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4 + }, + createdBy: { + type: DataTypes.STRING + }, + updatedBy: { + type: DataTypes.STRING + }, + name: { + type: DataTypes.STRING + }, + created: { + type: DataTypes.DATE, + allowNull: false + }, + updated: { + type: DataTypes.DATE + } + }) + await query.addColumn('Skills', 'skillProviderId', { + type: DataTypes.UUID, + references: { + model: 'SkillsProviders', + key: 'id' + }, + onUpdate: 'CASCADE' + }) + await query.addConstraint('OrganizationSkillsProviders', { + fields: ['skillProviderId'], + type: 'foreign key', + name: 'OrganizationSkillsProviders_skillProviderId_fkey', + references: { + table: 'SkillsProviders', + field: 'id' + }, + onUpdate: 'CASCADE' + }) + await query.addConstraint('UsersSkills', { + fields: ['skillId'], + type: 'foreign key', + name: 'UsersSkills_skillId_fkey', + references: { + table: 'Skills', + field: 'id' + }, + onUpdate: 'CASCADE' + }) + } +} diff --git a/src/common/es-helper.js b/src/common/es-helper.js index 6f5a1f4..399c3e6 100644 --- a/src/common/es-helper.js +++ b/src/common/es-helper.js @@ -43,14 +43,8 @@ const USER_ORGANIZATION = { const USER_FILTER_TO_MODEL = { skill: { - name: 'skill', - isAttribute: false, - model: require('../models/Skill'), - queryField: 'name', - esDocumentQuery: 'skills.skillId.keyword', - values: [] + esDocumentQuery: 'skills.skillId.keyword' }, - get skills () { return this.skill }, achievement: { name: 'achievement', isAttribute: false, @@ -114,26 +108,6 @@ const RESOURCE_FILTER = { queryField: 'name' } }, - skill: { - externalId: { - resource: 'skill', - queryField: 'externalId' - }, - skillProviderId: { - resource: 'skill', - queryField: 'skillProviderId' - }, - name: { - resource: 'skill', - queryField: 'name' - } - }, - skillprovider: { - name: { - resource: 'skillprovider', - queryField: 'name' - } - }, achievementprovider: { name: { resource: 'achievementprovider', @@ -167,12 +141,6 @@ const RESOURCE_FILTER = { } }, // sub-resources - userskill: { - skillName: { - resource: 'skill', - queryField: 'name' - } - }, externalprofile: { organizationName: { resource: 'organization', @@ -214,16 +182,6 @@ const FILTER_CHAIN = { user: { idField: 'id' }, - skillprovider: { - filterNext: 'skill', - queryField: 'skillProviderId', - idField: 'id' - }, - skill: { - filterNext: 'userskill', - queryField: 'skillId', - idField: 'skillProviderId' - }, attribute: { filterNext: 'userattribute', queryField: 'attributeId', @@ -365,7 +323,7 @@ async function updateOrg (organizationId, body, seqNo, primaryTerm) { */ async function processCreate (resource, entity) { if (_.includes(_.keys(TopResources), resource)) { - // process the top resources such as user, skill... + // process the top resources such as user, attribute... helper.validProperties(entity, ['id']) await esClient.index({ index: TopResources[resource].index, @@ -505,7 +463,7 @@ async function processUpdate (resource, entity) { */ async function processDelete (resource, entity) { if (_.includes(_.keys(TopResources), resource)) { - // process the top resources such as user, skill... + // process the top resources such as user, attribute... helper.validProperties(entity, ['id']) await esClient.delete({ index: TopResources[resource].index, @@ -585,13 +543,16 @@ async function getAttributeId (organizationId, attributeName) { const attributeIdLookupResults = await dBHelper.find( sequelize.models.Attribute, { - '$AttributeGroup.organizationId$': organizationId, name: attributeName }, [{ model: sequelize.models.AttributeGroup, as: 'AttributeGroup', - attributes: [] + attributes: [], + where: { + organizationId + }, + required: true }] ) @@ -877,59 +838,8 @@ function hasNonAlphaNumeric (text) { return !regex.test(text) } -/** - * Get skillIds matching the search keyword - * - * @param keyword the search keyword - * @returns array of skillIds - */ -async function searchSkills (keyword, skillProviderIds) { - const queryDoc = DOCUMENTS.skill - keyword = escapeRegex(keyword) - const query = hasNonAlphaNumeric(keyword) ? `\\*${keyword}\\*` : `*${keyword}*` - - const keywordSearchClause = { - query_string: { - default_field: 'name', - minimum_should_match: '100%', - query - } - } - - const searchClause = { - query: {} - } - - if (skillProviderIds == null) { - searchClause.query = keywordSearchClause - searchClause._source = 'id' - } else { - searchClause.query = { - bool: { - filter: [{ - terms: { - [`${RESOURCE_FILTER.skill.skillProviderId.queryField}.keyword`]: skillProviderIds - } - }], - must: [keywordSearchClause] - } - } - } - - const esQuery = { - index: queryDoc.index, - type: queryDoc.type, - body: searchClause - } - - logger.debug(`ES query for searching skills: ${JSON.stringify(esQuery, null, 2)}`) - const { body: results } = await esClient.search(esQuery) - - return results.hits.hits.map(hit => hit._source) -} - async function setUserSearchClausesToEsQuery (boolClause, keyword) { - const skillIds = (await searchSkills(keyword)).map(skill => skill.id) + const skillIds = (await helper.getSkillsByName(keyword)).map(skill => skill.id) boolClause.should.push({ query_string: { fields: ['firstName', 'lastName', 'handle'], @@ -1093,30 +1003,8 @@ function buildEsQueryToGetAttributeValues (attributeId, attributeValue, size) { return esQuery } -function buildEsQueryToGetSkillProviderIds (organizationId) { - const queryDoc = DOCUMENTS.organization - - const esQuery = { - index: queryDoc.index, - type: queryDoc.type, - body: { - size: 1000, - query: { - term: { - 'id.keyword': { - value: organizationId - } - } - } - } - } - - return esQuery -} - async function resolveUserFilterFromDb (filter, { handle }, organizationId) { - const DBHelper = require('../models/index').DBHelper - + const DBHelper = require('../common/db-helper') if (filter.isAttribute) { const esQueryClause = { bool: { @@ -1303,7 +1191,7 @@ async function resolveResFilter (filter, initialRes) { */ function applySubResFilters (results, preResFilterResults, ownResFilters, perPage) { let count = 0 - const filtered = results.filter(item => { + const filtered = _.filter(results, item => { for (const filter of preResFilterResults) { if (item[filter.queryField] !== filter.value) { return false @@ -1635,35 +1523,6 @@ async function searchUsers (authUser, filter, params) { } } -/** - * Search for skills matching the given keyword and are part of the given organization - * @param {Object} param0 the organizationId and keyword - */ -async function searchSkillsInOrganization ({ organizationId, keyword }) { - if (!organizationId) { - throw Error('Cannot search for skills without organization info') - } - const esQueryToGetSkillProviders = buildEsQueryToGetSkillProviderIds(organizationId) - logger.debug(`ES query to get skill provider ids: ${JSON.stringify(esQueryToGetSkillProviders, null, 2)}`) - - const { body: esResultOfQueryToGetSkillProviders } = await esClient.search(esQueryToGetSkillProviders) - logger.debug(`ES result: ${JSON.stringify(esResultOfQueryToGetSkillProviders, null, 2)}`) - - const skillProviderIds = _.flatten(esResultOfQueryToGetSkillProviders.hits.hits.map(hit => hit._source.skillProviders == null ? [] : hit._source.skillProviders.map(sp => sp.skillProviderId))) - logger.debug(`Organization ${organizationId} yielded skillProviderIds: ${JSON.stringify(skillProviderIds, null, 2)}`) - - const skills = await searchSkills(keyword, skillProviderIds) - - return { - result: skills.map(skill => ({ - name: skill.name, - skillId: skill.id, - skillProviderId: skill.skillProviderId - // skillProviderName: 'TODO' - })) - } -} - /** * Searches for matching values for the given attribute value, under the given attribute id * @param {Object} param0 The attribute id and the attribute value properties @@ -1730,7 +1589,6 @@ module.exports = { searchElasticSearch, getFromElasticSearch, searchUsers, - searchSkillsInOrganization, searchAttributeValues, searchAchievementValues } diff --git a/src/common/helper.js b/src/common/helper.js index ea03f67..d90f7dd 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -63,6 +63,26 @@ async function getUserGroup (memberId) { return groups } +/** + * Returns the skills in topcoder skills + * @param {String} name The skill name + */ +async function getSkillsByName (name) { + const url = config.TOPCODER_SKILL_API + const token = await getTopcoderM2Mtoken() + const params = { name, page: 1 } + + logger.debug(`request GET ${url} with params: ${JSON.stringify(params)}`) + let skills = [] + let skillsRes = await axios.get(url, { headers: { Authorization: `Bearer ${token}` }, params }) + while (skillsRes.data.length > 0) { + skills = _.concat(skills, _.map(skillsRes.data, g => _.pick(g, 'id', 'name', 'taxonomyId'))) + params.page = params.page + 1 + skillsRes = await axios.get(url, { headers: { Authorization: `Bearer ${token}` }, params }) + } + return skills +} + /** * Checks if the source matches the term. * @@ -226,6 +246,7 @@ module.exports = { validProperties, getAuthUser, getUserGroup, + getSkillsByName, permissionCheck, checkIfExists, injectSearchMeta, diff --git a/src/common/service-helper.js b/src/common/service-helper.js index afe3dcc..537f6ab 100644 --- a/src/common/service-helper.js +++ b/src/common/service-helper.js @@ -27,7 +27,6 @@ _.forOwn(config.ES.DOCUMENTS, (value, key) => { // map model name to bus message resource if different const MODEL_TO_RESOURCE = { UsersSkill: 'userskill', - SkillsProvider: 'skillprovider', AchievementsProvider: 'achievementprovider', UserAttribute: 'userattribute', UsersRole: 'userrole', diff --git a/src/consts.js b/src/consts.js index 8b28094..a5ef106 100644 --- a/src/consts.js +++ b/src/consts.js @@ -17,8 +17,6 @@ function validProperties (payload, keys) { } } - - /** * roles that used in service, all roles must match topcoder roles * Admin and Administrator are both admin user @@ -42,7 +40,6 @@ const AllAuthenticatedUsers = [ UserRoles.ubahn ] - /** * all admin user */ @@ -106,35 +103,6 @@ const TopResources = { enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy'] } }, - skill: { - index: config.get('ES.DOCUMENTS.skill.index'), - type: config.get('ES.DOCUMENTS.skill.type'), - enrich: { - policyName: config.get('ES.DOCUMENTS.skill.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'skillProviderId', 'name', 'externalId', 'uri', 'created', 'updated', 'createdBy', 'updatedBy', 'skillprovider'] - }, - ingest: { - pipeline: { - id: config.get('ES.DOCUMENTS.skillprovider.pipelineId') - } - } - }, - skillprovider: { - index: config.get('ES.DOCUMENTS.skillprovider.index'), - type: config.get('ES.DOCUMENTS.skillprovider.type'), - enrich: { - policyName: config.get('ES.DOCUMENTS.skillprovider.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy'] - }, - pipeline: { - id: config.get('ES.DOCUMENTS.skillprovider.pipelineId'), - field: 'skillProviderId', - targetField: 'skillprovider', - maxMatches: '1' - } - }, user: { index: config.get('ES.DOCUMENTS.user.index'), type: config.get('ES.DOCUMENTS.user.type'), @@ -166,13 +134,6 @@ const TopResources = { field: '_ingest._value.roleId', targetField: '_ingest._value.role', maxMatches: '1' - }, - { - referenceField: config.get('ES.DOCUMENTS.userskill.userField'), - enrichPolicyName: config.get('ES.DOCUMENTS.skill.enrichPolicyName'), - field: '_ingest._value.skillId', - targetField: '_ingest._value.skill', - maxMatches: '1' } ] } diff --git a/src/models/OrganizationSkillsProvider.js b/src/models/OrganizationSkillsProvider.js index 0756fb2..04d8b51 100644 --- a/src/models/OrganizationSkillsProvider.js +++ b/src/models/OrganizationSkillsProvider.js @@ -10,6 +10,9 @@ module.exports = (sequelize) => { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 }, + skillProviderId: { + type: DataTypes.UUID + }, createdBy: { type: DataTypes.STRING }, @@ -23,7 +26,6 @@ module.exports = (sequelize) => { createdAt: 'created' }) OrganizationSkillsProvider.associate = (models) => { - OrganizationSkillsProvider.belongsTo(models.SkillsProvider, { foreignKey: 'skillProviderId', type: DataTypes.UUID }) OrganizationSkillsProvider.belongsTo(models.Organization, { foreignKey: 'organizationId', type: DataTypes.UUID }) } return OrganizationSkillsProvider diff --git a/src/models/Skill.js b/src/models/Skill.js deleted file mode 100644 index 355f161..0000000 --- a/src/models/Skill.js +++ /dev/null @@ -1,36 +0,0 @@ -const { DataTypes } = require('sequelize') - -module.exports = (sequelize) => { - const Skill = sequelize.define('Skill', { - id: { - primaryKey: true, - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4 - }, - createdBy: { - type: DataTypes.STRING - }, - updatedBy: { - type: DataTypes.STRING - }, - name: { - type: DataTypes.STRING - }, - externalId: { - type: DataTypes.STRING - }, - uri: { - type: DataTypes.STRING - } - }, - { - timestamps: true, - updatedAt: 'updated', - createdAt: 'created' - }) - Skill.associate = (models) => { - Skill.belongsTo(models.SkillsProvider, { foreignKey: 'skillProviderId', type: DataTypes.UUID }) - Skill.hasMany(models.UsersSkill, { foreignKey: 'skillId', type: DataTypes.UUID }) - } - return Skill -} diff --git a/src/models/SkillsProvider.js b/src/models/SkillsProvider.js deleted file mode 100644 index f9aa226..0000000 --- a/src/models/SkillsProvider.js +++ /dev/null @@ -1,30 +0,0 @@ -const { DataTypes } = require('sequelize') - -module.exports = (sequelize) => { - const SkillsProvider = sequelize.define('SkillsProvider', { - id: { - primaryKey: true, - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4 - }, - createdBy: { - type: DataTypes.STRING - }, - updatedBy: { - type: DataTypes.STRING - }, - name: { - type: DataTypes.STRING - } - }, - { - timestamps: true, - updatedAt: 'updated', - createdAt: 'created' - }) - SkillsProvider.associate = (models) => { - SkillsProvider.hasMany(models.Skill, { foreignKey: 'skillProviderId', type: DataTypes.UUID }) - SkillsProvider.hasMany(models.OrganizationSkillsProvider, { foreignKey: 'skillProviderId', type: DataTypes.UUID }) - } - return SkillsProvider -} diff --git a/src/models/UsersSkill.js b/src/models/UsersSkill.js index 11250de..f0d91d8 100644 --- a/src/models/UsersSkill.js +++ b/src/models/UsersSkill.js @@ -7,6 +7,9 @@ module.exports = (sequelize) => { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 }, + skillId: { + type: DataTypes.UUID + }, createdBy: { type: DataTypes.STRING }, @@ -30,7 +33,6 @@ module.exports = (sequelize) => { }) UsersSkill.associate = (models) => { UsersSkill.belongsTo(models.User, { foreignKey: 'userId', type: DataTypes.UUID }) - UsersSkill.belongsTo(models.Skill, { foreignKey: 'skillId', type: DataTypes.UUID }) } return UsersSkill } diff --git a/src/modules/organizationSkillsProvider/service.js b/src/modules/organizationSkillsProvider/service.js index 81ed575..1fe6248 100644 --- a/src/modules/organizationSkillsProvider/service.js +++ b/src/modules/organizationSkillsProvider/service.js @@ -12,7 +12,6 @@ const dbHelper = require('../../common/db-helper') const serviceHelper = require('../../common/service-helper') const sequelize = require('../../models/index') -const SkillsProvider = sequelize.models.SkillsProvider const Organization = sequelize.models.Organization const OrganizationSkillsProvider = sequelize.models.OrganizationSkillsProvider const resource = serviceHelper.getResource('OrganizationSkillsProvider') @@ -26,7 +25,6 @@ const uniqueFields = [['organizationId', 'skillProviderId']] */ async function create (entity, auth) { await dbHelper.get(Organization, entity.organizationId) - await dbHelper.get(SkillsProvider, entity.skillProviderId) await dbHelper.makeSureUnique(OrganizationSkillsProvider, entity, uniqueFields) let newEntity diff --git a/src/modules/search/service.js b/src/modules/search/service.js index 0a5698a..61c69d9 100644 --- a/src/modules/search/service.js +++ b/src/modules/search/service.js @@ -1,10 +1,11 @@ const axios = require('axios') const config = require('config') +const _ = require('lodash') const querystring = require('querystring') const NodeCache = require('node-cache') const joi = require('@hapi/joi') const orgSkillsProviderService = require('../organizationSkillsProvider/service') -const esHelper = require('../../common/es-helper') +const helper = require('../../common/helper') // cache the emsi token const tokenCache = new NodeCache() @@ -60,17 +61,25 @@ async function getEmsiObject (path, params) { * @returns {Object} the Object with skills */ async function getSkills (query, auth) { - let result const skillProviderIds = await orgSkillsProviderService.search({ organizationId: query.organizationId }, auth) if (skillProviderIds.result.length === 1 && skillProviderIds.result[0].skillProviderId === config.EMSI_SKILLPROVIDER_ID) { - result = await getEmsiObject('/skills', { q: query.keyword }) + const result = await getEmsiObject('/skills', { q: query.keyword }) return { result: formatEmsiSkills(result) } } - result = await esHelper.searchSkillsInOrganization(query) + const skills = await helper.getSkillsByName(query.keyword) + // filter by skill providerIds + const providerIds = _.map(skillProviderIds.result, 'skillProviderId') + const filteredSkills = _.filter(skills, skill => _.includes(providerIds, skill.taxonomyId)) - return result + return { + result: _.map(filteredSkills, skill => ({ + name: skill.name, + skillId: skill.id, + skillProviderId: skill.taxonomyId + })) + } } getSkills.schema = { diff --git a/src/modules/usersSkill/service.js b/src/modules/usersSkill/service.js index 2c538f1..c61fcbb 100644 --- a/src/modules/usersSkill/service.js +++ b/src/modules/usersSkill/service.js @@ -11,7 +11,6 @@ const dbHelper = require('../../common/db-helper') const serviceHelper = require('../../common/service-helper') const sequelize = require('../../models/index') -const Skill = sequelize.models.Skill const User = sequelize.models.User const UsersSkill = sequelize.models.UsersSkill const resource = serviceHelper.getResource('UsersSkill') @@ -24,7 +23,6 @@ const uniqueFields = [['userId', 'skillId']] * @return {Promise} the created device */ async function create (entity, auth) { - await dbHelper.get(Skill, entity.skillId) await dbHelper.get(User, entity.userId) await dbHelper.makeSureUnique(UsersSkill, entity, uniqueFields) @@ -64,9 +62,6 @@ create.schema = { * @return {Promise} the updated device */ async function patch (id, entity, auth, params) { - if (entity.skillId) { - await dbHelper.get(Skill, entity.skillId) - } if (entity.userId) { await dbHelper.get(User, entity.userId) } @@ -146,16 +141,7 @@ async function search (query, auth) { return esResult } - // add query for associations - if (query.skillName) { - query['$Skill.name$'] = query.skillName - delete query.skillName - } - const items = await dbHelper.find(UsersSkill, query, auth, [{ - model: Skill, - as: 'Skill', - attributes: [] - }]) + const items = await dbHelper.find(UsersSkill, query, auth) return { fromDb: true, result: items, total: items.length } } @@ -164,8 +150,7 @@ search.schema = { query: { page: joi.id(), perPage: joi.pageSize(), - userId: joi.string().required(), - skillName: joi.string() + userId: joi.string().required() }, auth: joi.object() } diff --git a/test/prepare.js b/test/prepare.js new file mode 100644 index 0000000..91fb7e2 --- /dev/null +++ b/test/prepare.js @@ -0,0 +1,5 @@ +/* + * Prepare for tests. + */ +process.env.NODE_ENV = 'test' +require('../src/bootstrap') diff --git a/test/unit/UserSkillsEndpoint.test.js b/test/unit/UserSkillsEndpoint.test.js new file mode 100644 index 0000000..4b9bbd1 --- /dev/null +++ b/test/unit/UserSkillsEndpoint.test.js @@ -0,0 +1,131 @@ +const _ = require('lodash') +const config = require('config') +const chai = require('chai') +const chaiHttp = require('chai-http') +const chaiAsPromised = require('chai-as-promised') +const service = require('../../src/modules/usersSkill/service') +const sinon = require('sinon') +const app = require('../../app') +const commonData = require('./common/commonData') + +chai.use(chaiHttp) +chai.use(chaiAsPromised) +const should = chai.should() +const expect = chai.expect + +describe('Unit tests for /users/{userId}/skills', () => { + afterEach(() => { + sinon.restore() + }) + describe('Test GET', () => { + beforeEach(() => { + sinon.stub(service, 'search').resolves({ + page: 1, + perPage: 20, + total: 1, + result: [{ + id: 1, + userId: 1, + skillId: 1 + }] + }) + }) + for (const tokenName of ['admin', 'administrator', 'topcoderUser', 'copilot', 'ubahn']) { + it(`Call GET API with ${tokenName} token successfully`, async () => { + const response = await chai.request(app).get(`/${config.API_VERSION}/users/test_user/skills`) + .set('Authorization', 'Bearer ' + commonData[`${tokenName}Token`]) + should.equal(response.status, 200) + should.equal(response.headers['x-page'], '1') + should.equal(response.headers['x-per-page'], '20') + should.equal(response.headers['x-total'], '1') + should.equal(response.headers['x-total-pages'], '1') + should.exist(response.headers.link) + should.equal(response.body.length, 1) + }) + } + it('Call GET API with other token', async () => { + const response = await chai.request(app).get(`/${config.API_VERSION}/users/test_user/skills`) + .set('Authorization', `Bearer ${commonData.unKnownToken}`) + should.equal(response.status, 403) + }) + it('Call GET API without token', async () => { + const response = await chai.request(app).get(`/${config.API_VERSION}/users/test_user/skills`) + should.equal(response.status, 403) + }) + }) + describe('Test HEAD', () => { + beforeEach(() => { + sinon.stub(service, 'search').resolves({ + page: 1, + perPage: 20, + total: 1, + result: [{ + id: 1, + userId: 1, + skillId: 1 + }] + }) + }) + for (const tokenName of ['admin', 'administrator', 'topcoderUser', 'copilot', 'ubahn']) { + it(`Call HEAD API with ${tokenName} token successfully`, async () => { + const response = await chai.request(app).head(`/${config.API_VERSION}/users/test_user/skills`) + .set('Authorization', 'Bearer ' + commonData[`${tokenName}Token`]) + should.equal(response.status, 200) + should.equal(response.headers['x-page'], '1') + should.equal(response.headers['x-per-page'], '20') + should.equal(response.headers['x-total'], '1') + should.equal(response.headers['x-total-pages'], '1') + should.exist(response.headers.link) + should.equal(_.isEmpty(response.body), true) + }) + } + it('Call HEAD API with other token', async () => { + const response = await chai.request(app).head(`/${config.API_VERSION}/users/test_user/skills`) + .set('Authorization', `Bearer ${commonData.unKnownToken}`) + should.equal(response.status, 403) + }) + it('Call HEAD API without token', async () => { + const response = await chai.request(app).head(`/${config.API_VERSION}/users/test_user/skills`) + should.equal(response.status, 403) + }) + }) + describe('Test POST', () => { + const userSkill = { + userId: 'string', + skillId: 'string', + metricValue: 'string', + certifierId: 'string', + certifiedDate: '2021-10-11T10:59:12.816Z', + created: '2021-10-11T10:59:12.816Z', + updated: '2021-10-11T10:59:12.817Z', + createdBy: 'string', + updatedBy: 'string' + } + let stubCreate + beforeEach(() => { + stubCreate = sinon.stub(service, 'create').resolves(userSkill) + }) + for (const tokenName of ['admin', 'administrator', 'topcoderUser', 'copilot', 'ubahn']) { + it(`Call POST API with ${tokenName} token successfully`, async () => { + const response = await chai.request(app).post(`/${config.API_VERSION}/users/test_user/skills`) + .set('Authorization', 'Bearer ' + commonData[`${tokenName}Token`]) + .send({ skillId: 'testSkill' }) + should.equal(response.status, 200) + expect(response.body).to.deep.eq(userSkill) + should.equal(stubCreate.calledOnce, true) + expect(stubCreate.getCall(0).args[0]).to.deep.eq({ userId: 'test_user', skillId: 'testSkill' }) + }) + } + it('Call POST API with other token', async () => { + const response = await chai.request(app).post(`/${config.API_VERSION}/users/test_user/skills`) + .set('Authorization', `Bearer ${commonData.unKnownToken}`) + .send({ skillId: 'testSkill' }) + should.equal(response.status, 403) + }) + it('Call POST API without token', async () => { + const response = await chai.request(app).post(`/${config.API_VERSION}/users/test_user/skills`) + .send({ skillId: 'testSkill' }) + should.equal(response.status, 403) + }) + }) +}) diff --git a/test/unit/UserSkillsService.test.js b/test/unit/UserSkillsService.test.js new file mode 100644 index 0000000..da6b6c1 --- /dev/null +++ b/test/unit/UserSkillsService.test.js @@ -0,0 +1,110 @@ +/* eslint-disable no-unused-expressions */ + +const _ = require('lodash') +const chai = require('chai') +const chaiAsPromised = require('chai-as-promised') +const sinon = require('sinon') +const sequelize = require('../../src/models/index') +const service = require('../../src/modules/usersSkill/service') +const helper = require('../../src/common/helper') +const serviceHelper = require('../../src/common/service-helper') +const dbHelper = require('../../src/common/db-helper') +const errors = require('../../src/common/errors') + +chai.use(chaiAsPromised) +const expect = chai.expect + +describe('user skills service test', () => { + beforeEach(() => { + sinon.stub(sequelize, 'transaction').callsFake(f => f()) + }) + afterEach(() => { + sinon.restore() + }) + + describe('Create user skills', () => { + it('Create user skills successfully', async () => { + const entity = { userId: 'userId', skillId: 'skillId' } + const newEntity = _.assign({ createdBy: 'test' }, entity) + sinon.stub(dbHelper, 'get').resolves({}) + sinon.stub(dbHelper, 'makeSureUnique').resolves({}) + const stubDBCreate = sinon.stub(dbHelper, 'create').resolves({ toJSON: () => newEntity }) + const stubEsInsert = sinon.stub(serviceHelper, 'createRecordInEs').resolves({}) + const result = await service.create(entity, {}) + expect(result).to.deep.eql(newEntity) + expect(stubDBCreate.calledOnce).to.be.true + expect(stubEsInsert.calledOnce).to.be.true + expect(stubDBCreate.getCall(0).args[1]).to.deep.eq(entity) + expect(stubEsInsert.getCall(0).args[1]).to.deep.eq(newEntity) + }) + it('Throw error when require parameters absence', async () => { + await expect(service.create({ userId: 'userId' })).to.be.rejectedWith('"entity.skillId" is required') + await expect(service.create({ skillId: 'skillId' })).to.be.rejectedWith('"entity.userId" is required') + }) + it('Throw error when user id does not exist', async () => { + const error = errors.newEntityNotFoundError('cannot find user where id:userId') + sinon.stub(dbHelper, 'get').rejects(error) + await expect(service.create({ userId: 'userId', skillId: 'skillId' })).to.eventually.rejectedWith(error) + }) + it('Throw error when a record with same user id and skill id exist', async () => { + const error = errors.newConflictError('usersSkill already exists with userId:userId,skillId:skillId') + sinon.stub(dbHelper, 'get').resolves({}) + sinon.stub(dbHelper, 'makeSureUnique').rejects(error) + await expect(service.create({ userId: 'userId', skillId: 'skillId' })).to.eventually.rejectedWith(error) + }) + it('Throw error and does not publish error event when insert into db error', async () => { + const error = new Error('db error') + sinon.stub(dbHelper, 'get').resolves({}) + sinon.stub(dbHelper, 'makeSureUnique').resolves({}) + const stubPublishError = sinon.stub(helper, 'publishError') + sinon.stub(dbHelper, 'create').rejects(error) + await expect(service.create({ userId: 'userId', skillId: 'skillId' })).to.eventually.rejectedWith(error) + expect(stubPublishError.called).to.be.false + }) + it('Throw error and publish error event when insert into es error', async () => { + const error = new Error('es error') + const entity = { userId: 'userId', skillId: 'skillId' } + const newEntity = _.assign({ createdBy: 'test' }, entity) + sinon.stub(dbHelper, 'get').resolves({}) + sinon.stub(dbHelper, 'makeSureUnique').resolves({}) + const stubPublishError = sinon.stub(helper, 'publishError').resolves({}) + const stubDBCreate = sinon.stub(dbHelper, 'create').resolves({ toJSON: () => newEntity }) + sinon.stub(serviceHelper, 'createRecordInEs').rejects(error) + await expect(service.create({ userId: 'userId', skillId: 'skillId' })).to.eventually.rejectedWith(error) + expect(stubPublishError.called).to.be.true + expect(stubDBCreate.called).to.be.true + }) + }) + describe('Search user skills', () => { + it('Throw error when require parameters absence', async () => { + await expect(service.search({ })).to.be.rejectedWith(errors.BadRequestError) + }) + it('Throw error when user id does not exist', async () => { + const error = errors.newEntityNotFoundError('cannot find user where id:userId') + sinon.stub(dbHelper, 'get').rejects(error) + await expect(service.search({ userId: 'userId' })).to.eventually.rejectedWith(error) + }) + it('Search user skills from es successfully', async () => { + const entity = { userId: 'userId', skillId: 'skillId' } + const newEntity = _.assign({ createdBy: 'test' }, entity) + sinon.stub(dbHelper, 'get').resolves({}) + const searchEs = sinon.stub(serviceHelper, 'searchRecordInEs').resolves([newEntity]) + const searchDb = sinon.stub(dbHelper, 'find') + const result = await service.search({ userId: 'userId' }, {}) + expect(result).to.deep.eql([newEntity]) + expect(searchEs.calledOnce).to.be.true + expect(searchDb.called).to.be.false + }) + it('Search user skills from db when es throw errors', async () => { + const entity = { userId: 'userId', skillId: 'skillId' } + const newEntity = _.assign({ createdBy: 'test' }, entity) + sinon.stub(dbHelper, 'get').resolves({}) + const searchEs = sinon.stub(serviceHelper, 'searchRecordInEs').resolves(null) + const searchDb = sinon.stub(dbHelper, 'find').resolves([newEntity]) + const result = await service.search({ userId: 'userId' }, {}) + expect(result).to.deep.eql({ fromDb: true, result: [newEntity], total: 1 }) + expect(searchEs.calledOnce).to.be.true + expect(searchDb.called).to.be.true + }) + }) +}) diff --git a/test/unit/common/commonData.js b/test/unit/common/commonData.js new file mode 100644 index 0000000..99b4d0b --- /dev/null +++ b/test/unit/common/commonData.js @@ -0,0 +1,15 @@ +const adminToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJBZG1pbiJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci5jb20iLCJoYW5kbGUiOiJ0Yy1BZG1pbiIsImV4cCI6MTY4NTU3MTQ2MCwidXNlcklkIjoiMjMxNjY3NjgiLCJpYXQiOjE2ODU1NzE0NjAsImVtYWlsIjoidGMtQWRtaW5AZ21haWwuY29tIiwianRpIjoiMGYxZWYxZDMtMmIzMy00OTAwLWJiNDMtNDhmMjI4NWY5NjMwIn0.VgmOE-DB7cifiEIAKFo0k0Rguo0W3-omZhSGpB4swfM' +const administratorToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJBZG1pbmlzdHJhdG9yIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLmNvbSIsImhhbmRsZSI6InRjLUFkbWluIiwiZXhwIjoxNjg1NTcxNDYwLCJ1c2VySWQiOiIyMzE2Njc2OCIsImlhdCI6MTY4NTU3MTQ2MCwiZW1haWwiOiJ0Yy1BZG1pbkBnbWFpbC5jb20iLCJqdGkiOiIwZjFlZjFkMy0yYjMzLTQ5MDAtYmI0My00OGYyMjg1Zjk2MzAifQ.VGlF135qjKMR6f87SDrhSL4ylwnE0Oa9C1vHfAf-mj0' +const topcoderUserToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLmNvbSIsImhhbmRsZSI6InRjLUFkbWluIiwiZXhwIjoxNjg1NTcxNDYwLCJ1c2VySWQiOiIyMzE2Njc2OCIsImlhdCI6MTY4NTU3MTQ2MCwiZW1haWwiOiJ0Yy1BZG1pbkBnbWFpbC5jb20iLCJqdGkiOiIwZjFlZjFkMy0yYjMzLTQ5MDAtYmI0My00OGYyMjg1Zjk2MzAifQ.rvIfuuhoE73wcCN2c-aV6HkwGJ26H_6YtOdh5z86MVU' +const copilotToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJDb3BpbG90Il0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLmNvbSIsImhhbmRsZSI6InRjLUFkbWluIiwiZXhwIjoxNjg1NTcxNDYwLCJ1c2VySWQiOiIyMzE2Njc2OCIsImlhdCI6MTY4NTU3MTQ2MCwiZW1haWwiOiJ0Yy1BZG1pbkBnbWFpbC5jb20iLCJqdGkiOiIwZjFlZjFkMy0yYjMzLTQ5MDAtYmI0My00OGYyMjg1Zjk2MzAifQ.B3QfvvGDJoKguTQWSwMrOJH25huLQ5K-QOjIfRMkE0c' +const ubahnToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJ1LWJhaG4iXSwiaXNzIjoiaHR0cHM6Ly9hcGkudG9wY29kZXIuY29tIiwiaGFuZGxlIjoidGMtQWRtaW4iLCJleHAiOjE2ODU1NzE0NjAsInVzZXJJZCI6IjIzMTY2NzY4IiwiaWF0IjoxNjg1NTcxNDYwLCJlbWFpbCI6InRjLUFkbWluQGdtYWlsLmNvbSIsImp0aSI6IjBmMWVmMWQzLTJiMzMtNDkwMC1iYjQzLTQ4ZjIyODVmOTYzMCJ9.NxZjs94tzxqhylGrLAyql3wS2onEBorlsv3FlB6CxeQ' +const unKnownToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJvdGhlciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci5jb20iLCJoYW5kbGUiOiJ0Yy1BZG1pbiIsImV4cCI6MTY4NTU3MTQ2MCwidXNlcklkIjoiMjMxNjY3NjgiLCJpYXQiOjE2ODU1NzE0NjAsImVtYWlsIjoidGMtQWRtaW5AZ21haWwuY29tIiwianRpIjoiMGYxZWYxZDMtMmIzMy00OTAwLWJiNDMtNDhmMjI4NWY5NjMwIn0._YCBCZtsEEcTTaWJ__bLEjG6__5jQeehl6dLRCYDimk' + +module.exports = { + adminToken, + administratorToken, + topcoderUserToken, + copilotToken, + ubahnToken, + unKnownToken +}