From e13e30b25781ca6eb967992bb7c84354219383b7 Mon Sep 17 00:00:00 2001 From: yoution Date: Wed, 18 Aug 2021 12:05:22 +0800 Subject: [PATCH 1/2] feat: disable topic from u-bahn-api --- src/app.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/app.js b/src/app.js index 1748595..8e12a34 100644 --- a/src/app.js +++ b/src/app.js @@ -71,19 +71,19 @@ const dataHandler = (messageSet, topic, partition) => Promise.each(messageSet, a const transactionId = _.uniqueId('transaction_') try { if (messageJSON.payload.originalTopic) { - switch (messageJSON.payload.originalTopic) { - case config.UBAHN_CREATE_TOPIC: - await ProcessorService.processCreate(messageJSON, transactionId) - break - case config.UBAHN_UPDATE_TOPIC: - await ProcessorService.processUpdate(messageJSON, transactionId) - break - case config.UBAHN_DELETE_TOPIC: - await ProcessorService.processDelete(messageJSON, transactionId) - break - default: - throw new Error(`Unknown original topic: ${messageJSON.payload.originalTopic}`) - } + // switch (messageJSON.payload.originalTopic) { + // case config.UBAHN_CREATE_TOPIC: + // await ProcessorService.processCreate(messageJSON, transactionId) + // break + // case config.UBAHN_UPDATE_TOPIC: + // await ProcessorService.processUpdate(messageJSON, transactionId) + // break + // case config.UBAHN_DELETE_TOPIC: + // await ProcessorService.processDelete(messageJSON, transactionId) + // break + // default: + // throw new Error(`Unknown original topic: ${messageJSON.payload.originalTopic}`) + // } } else { switch (topic) { case config.GROUPS_MEMBER_ADD_TOPIC: From afad5f40e5ca503fcef0ad8b10c05889965ff373 Mon Sep 17 00:00:00 2001 From: yoution Date: Thu, 2 Sep 2021 10:26:11 +0800 Subject: [PATCH 2/2] clean up for cqrs --- README.md | 59 - VERIFICATION.md | 256 ---- config/default.js | 79 -- config/test.js | 17 - docker-kafka-es/docker-compose.yml | 2 +- docker/api.env | 1 + package-lock.json | 1926 +--------------------------- package.json | 16 +- src/app.js | 20 +- src/common/constants.js | 177 --- src/common/helper.js | 69 - src/services/ProcessorService.js | 279 ---- test/common/init-es.js | 61 - test/common/testData.js | 702 ---------- test/common/testHelper.js | 99 -- test/common/view-data.js | 40 - test/e2e/test.js | 345 ----- test/unit/prepare.js | 90 -- test/unit/test.js | 239 ---- 19 files changed, 33 insertions(+), 4444 deletions(-) delete mode 100644 VERIFICATION.md delete mode 100644 config/test.js create mode 100644 docker/api.env delete mode 100644 src/common/constants.js delete mode 100644 src/services/ProcessorService.js delete mode 100644 test/common/init-es.js delete mode 100644 test/common/testData.js delete mode 100644 test/common/testHelper.js delete mode 100644 test/common/view-data.js delete mode 100644 test/e2e/test.js delete mode 100644 test/unit/prepare.js delete mode 100644 test/unit/test.js diff --git a/README.md b/README.md index 049d748..508988b 100644 --- a/README.md +++ b/README.md @@ -20,70 +20,22 @@ The following parameters can be set in config files or in env variables: if not provided, then SSL connection is not used, direct insecure connection is used; if provided, it can be either path to private key file or private key content - KAFKA_GROUP_ID: the Kafka group id, default value is 'ubahn-processor-es' -- UBAHN_CREATE_TOPIC: the create ubahn entity Kafka message topic, default value is 'u-bahn.action.create' -- UBAHN_UPDATE_TOPIC: the update ubahn entity Kafka message topic, default value is 'u-bahn.action.update' -- UBAHN_DELETE_TOPIC: the delete ubahn entity Kafka message topic, default value is 'u-bahn.action.delete' -- UBAHN_AGGREGATE_TOPIC: the ubahn entity aggregate topic, that contains create, update and delete topics. Default value is 'u-bahn.action.aggregate' - GROUPS_MEMBER_ADD_TOPIC: the add groups member Kafka message topic, default value is 'groups.notification.member.add' - GROUPS_MEMBER_DELETE_TOPIC: the delete groups member Kafka message topic, default value is 'groups.notification.member.delete' - GROUPS_MEMBERSHIP_TYPE: the groups membership type that should be processed, default value is 'user' - ES_HOST: Elasticsearch host, default value is 'localhost:9200' - ES.AWS_REGION: The Amazon region to use when using AWS Elasticsearch service, default value is 'us-east-1' -- ES.ACHIEVEMENT_PROVIDER_INDEX: Elasticsearch index name for achievement provider, default value is 'achievement_provider' -- ES.ACHIEVEMENT_PROVIDER_TYPE: Elasticsearch index type for achievement provider, default value is '_doc' -- ES.ATTRIBUTE_INDEX: Elasticsearch index name for attribute, default value is 'attribute' -- ES.ATTRIBUTE_TYPE: Elasticsearch index type for attribute, default value is '_doc' -- ES.ATTRIBUTE_GROUP_INDEX: Elasticsearch index name for attribute group, default value is 'attribute_group' -- ES.ATTRIBUTE_GROUP_TYPE: Elasticsearch index type for attribute group, default value is '_doc' -- ES.ORGANIZATION_INDEX: Elasticsearch index name for organization, default value is 'organization' -- ES.ORGANIZATION_TYPE: Elasticsearch index type for organization, default value is '_doc' -- ES.ROLE_INDEX: Elasticsearch index name for role, default value is 'role' -- ES.ROLE_TYPE: Elasticsearch index type for role, default value is '_doc' -- ES.SKILL_INDEX: Elasticsearch index name for skill, default value is 'skill' -- ES.SKILL_TYPE: Elasticsearch index type for skill, default value is '_doc' -- ES.SKILL_PROVIDER_INDEX: Elasticsearch index name for skill provider, default value is 'skill_provider' -- ES.SKILL_PROVIDER_TYPE: Elasticsearch index type for skill provider, default value is '_doc' -- ES.USER_INDEX: Elasticsearch index name for user, default value is 'user' -- ES.USER_TYPE: Elasticsearch index type for user, default value is '_doc' -- ES.USER_ACHIEVEMENT_PROPERTY_NAME: the user property name of achievement, default value is 'achievements', -- ES.USER_EXTERNALPROFILE_PROPERTY_NAME: the user property name of externalProfile, default value is 'externalProfiles', -- ES.USER_ATTRIBUTE_PROPERTY_NAME: the user property name of attribute, default value is 'attributes', -- ES.USER_ROLE_PROPERTY_NAME: the user property name of role, default value is 'roles', -- ES.USER_SKILL_PROPERTY_NAME: the user property name of skill, default value is 'skills' -- ES.ORGANIZATION_SKILLPROVIDER_PROPERTY_NAME: the org property name of org skill providers, default value is 'skillProviders' - ES.USER_GROUP_PROPERTY_NAME: the user property name of group, default value is 'groups' -- 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 - ELASTICCLOUD_PASSWORD: The elastic cloud password for basic authentication. Provide this only if your elasticsearch instance is hosted on elastic cloud -- AUTH0_URL: The auth0 url, Default is 'https://topcoder-dev.auth0.com/oauth/token' -- AUTH0_AUDIENCE: The auth0 audience for accessing ubahn api(s), Default is 'https://m2m.topcoder-dev.com/' -- AUTH0_CLIENT_ID: The auth0 client id -- AUTH0_CLIENT_SECRET: The auth0 client secret -- AUTH0_PROXY_SERVER_URL: The auth0 proxy server url -- TOKEN_CACHE_TIME: The token cache time -- TOPCODER_GROUP_API: The topcoder groups api, Default is 'https://api.topcoder-dev.com/v5/groups' There is a `/health` endpoint that checks for the health of the app. This sets up an expressjs server and listens on the environment variable `PORT`. It's not part of the configuration file and needs to be passed as an environment variable Configuration for the tests is at `config/test.js`, only add such new configurations different from `config/default.js` - WAIT_TIME: wait time used in test, default is 1500 or 1.5 second -- ES.ACHIEVEMENT_PROVIDER_INDEX: Elasticsearch index name for achievement provider in testing environment -- ES.ATTRIBUTE_INDEX: Elasticsearch index name for attribute in testing environment -- ES.ATTRIBUTE_GROUP_INDEX: Elasticsearch index name for attribute group in testing environment -- ES.ORGANIZATION_INDEX: Elasticsearch index name for organization in testing environment -- ES.ROLE_INDEX: Elasticsearch index name for role in testing environment -- ES.SKILL_INDEX: Elasticsearch index name for skill in testing environment -- ES.SKILL_PROVIDER_INDEX: Elasticsearch index name for skill provider in testing environment - ES.USER_INDEX: Elasticsearch index name for user in testing environment ## Local Kafka and ElasticSearch setup @@ -150,14 +102,3 @@ To run the UBahn ES Processor using docker, follow the below steps ``` 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 - -## Unit Tests and E2E Tests - -- Run `npm run test` to execute unit tests. -- Run `npm run test:cov` to execute unit tests and generate coverage report. -- RUN `npm run e2e` to execute e2e tests. -- RUN `npm run e2e:cov` to execute e2e tests and generate coverage report. - -## Verification - -see [VERIFICATION.md](VERIFICATION.md) diff --git a/VERIFICATION.md b/VERIFICATION.md deleted file mode 100644 index 6a8aaef..0000000 --- a/VERIFICATION.md +++ /dev/null @@ -1,256 +0,0 @@ -# Verification - -**NOTE** - For all kafka message below, update the topic to be the one set in config.UBAHN_AGGREGATE_TOPIC and inside the payload object, create a new attribute named `originalTopic` with the value of the original topic. Example: - -``` -{ - "topic": "u-bahn.action.aggregate", - "originator": "u-bahn-api", - "timestamp": "2019-07-08T00:00:00.000Z", - "mime-type": "application/json", - "payload": { - "originalTopic": "u-bahn.action.create" - "resource": "user", - "id": "391a3656-9a01-47d4-8c6d-64b68c44f212", - "handle": "user" - } -} -``` - -Additionally, you will be entering the messages into only one topic: - -``` -docker exec -it ubahn-data-processor-es_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic u-bahn.action.aggregate -``` - -1. start kafka server, start elasticsearch, initialize Elasticsearch, start processor app -2. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"user","id":"391a3656-9a01-47d4-8c6d-64b68c44f212","handle":"user","originalTopic":"u-bahn.action.create"}}` -4. Watch the app console, It will show message successfully handled. -5. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -6. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"achievement","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","achievementsProviderId":"c77326d8-ef16-4be0-b844-d5c384b7bb8b","name":"achievement","uri":"https://google.com","certifierId":"b8726ca1-557e-4502-8f9b-25044b9c123d","certifiedDate":"2019-07-08T00:00:00.000Z","originalTopic":"u-bahn.action.create"}}` -7. Watch the app console, It will show message successfully handled. -8. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -9. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"achievementprovider","id":"7b4f98b1-5831-45fe-a71f-8454d11eb8e8","name":"achievementprovider","originalTopic":"u-bahn.action.create"}}` -10. Watch the app console, It will show message successfully handled. -11. Run Command `npm run view-data achievementprovider 7b4f98b1-5831-45fe-a71f-8454d11eb8e8` to verify the elastic data. - -12. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"attributegroup","id":"720c34f9-0fd4-46fd-9293-4a8cfdcd3e96","organizationId":"017733ad-4704-4c7e-ae60-36b3332731df","name":"attributegroup","originalTopic":"u-bahn.action.create"}}` -13. Watch the app console, It will show message successfully handled. -14. Run Command `npm run view-data attributegroup 720c34f9-0fd4-46fd-9293-4a8cfdcd3e96` to verify the elastic data. - -15. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"externalprofile","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","organizationId":"e2aecf8b-532d-4625-b8e2-575110b9f944","uri":"https:google.com","originalTopic":"u-bahn.action.create"}}` -16. Watch the app console, It will show message successfully handled. -17. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -18. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"organization","id":"603d4264-cdb0-47f1-914e-f053abc60422","name":"organization","originalTopic":"u-bahn.action.create"}}` -19. Watch the app console, It will show message successfully handled. -20. Run Command `npm run view-data organization 603d4264-cdb0-47f1-914e-f053abc60422` to verify the elastic data. - -21. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"role","id":"188446f1-02dc-4fc7-b74e-ab7ea3033a57","name":"role","originalTopic":"u-bahn.action.create"}}` -22. Watch the app console, It will show message successfully handled. -23. Run Command `npm run view-data role 188446f1-02dc-4fc7-b74e-ab7ea3033a57` to verify the elastic data. - -24. write message: - `{"topic":"u-bahn.action.create","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"skill","id":"a75d95d7-6ab8-472d-8103-19d7e642e8f7","skillProviderId":"63061b84-9784-4b71-b695-4a777eeb7601","externalId":"ba395d36-6ce8-4bd1-9d6c-754f0389abcb","uri":"https://google.com","name":"skill"}}` -25. Watch the app console, It will show message successfully handled. -26. Run Command `npm run view-data skill a75d95d7-6ab8-472d-8103-19d7e642e8f7` to verify the elastic data. - -27. write message: - `{"topic":"u-bahn.action.create","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"skillprovider","id":"2375564d-c5eb-4b80-9b35-465c6b700ac1","name":"skillprovider"}}` -28. Watch the app console, It will show message successfully handled. -29. Run Command `npm run view-data skillprovider 2375564d-c5eb-4b80-9b35-465c6b700ac1` to verify the elastic data. - -30. write message: - `{"topic":"u-bahn.action.create","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userattribute","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","attributeId":"b5a50f73-08e2-43d1-a78a-4652f15d950e","value":"userattribute"}}` -31. Watch the app console, It will show message successfully handled. -32. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -33. write message: - `{"topic":"u-bahn.action.create","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userrole","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","roleId":"22028da5-0563-48e8-b84c-e480eb8ed98c"}}` -34. Watch the app console, It will show message successfully handled. -35. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -36. write message: - `{"topic":"u-bahn.action.create","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userskill","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","skillId":"8a8c8d3a-9165-4dae-8a8c-f828cbe01d5d","metricValue":"userskill","certifierId":"7cf786d9-a8c0-48ed-a7cc-09dcf91d904c","certifiedDate":"2019-07-08T00:00:00.000Z"}}` -37. Watch the app console, It will show message successfully handled. -38. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -39. Repeat step 3 again and you will see error message in app console indicate conflict error. - - - - - -40. Now, let's perform the update operations and verify. -41. write message to update the user: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"user","id":"391a3656-9a01-47d4-8c6d-64b68c44f212","handle":"update_user","originalTopic":"u-bahn.action.update"}}` -42. Watch the app console, It will show message successfully handled. -43. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been updated. - -44. write message to update the achievement: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"achievement","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","achievementsProviderId":"c77326d8-ef16-4be0-b844-d5c384b7bb8b","name":"update_name","uri":"https://facebook.com","originalTopic":"u-bahn.action.update"}}` -45. Watch the app console, It will show message successfully handled. -46. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been updated. - -47. write message to update the achievementprovider: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"achievementprovider","id":"7b4f98b1-5831-45fe-a71f-8454d11eb8e8","name":"update_name"}}` -48. Watch the app console, It will show message successfully handled. -49. Run Command `npm run view-data achievementprovider 7b4f98b1-5831-45fe-a71f-8454d11eb8e8` to verify the elastic data has been updated. - -50. write message to update the attributegroup: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"attributegroup","id":"720c34f9-0fd4-46fd-9293-4a8cfdcd3e96","organizationId":"017733ad-4704-4c7e-ae60-36b3332731df","name":"update_name"}}` -51. Watch the app console, It will show message successfully handled. -52. Run Command `npm run view-data attributegroup 720c34f9-0fd4-46fd-9293-4a8cfdcd3e96` to verify the elastic data has been updated. - -53. write message to update the externalprofile: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"externalprofile","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","organizationId":"e2aecf8b-532d-4625-b8e2-575110b9f944","uri":"https://facebook.com"}}` -54. Watch the app console, It will show message successfully handled. -55. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been updated. - -56. write message to update the organization: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"organization","id":"603d4264-cdb0-47f1-914e-f053abc60422","name":"update_name"}}` -57. Watch the app console, It will show message successfully handled. -58. Run Command `npm run view-data organization 603d4264-cdb0-47f1-914e-f053abc60422` to verify the elastic data has been updated. - -59. write message to update the role: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"role","id":"188446f1-02dc-4fc7-b74e-ab7ea3033a57","name":"update_name"}}` -60. Watch the app console, It will show message successfully handled. -61. Run Command `npm run view-data role 188446f1-02dc-4fc7-b74e-ab7ea3033a57` to verify the elastic data has been updated. - -62. write message to update the skill: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"skill","id":"a75d95d7-6ab8-472d-8103-19d7e642e8f7","skillProviderId":"63061b84-9784-4b71-b695-4a777eeb7601","externalId":"ba395d36-6ce8-4bd1-9d6c-754f0389abcb","uri":"https://facebook.com","name":"update_skill"}}` -63. Watch the app console, It will show message successfully handled. -64. Run Command `npm run view-data skill a75d95d7-6ab8-472d-8103-19d7e642e8f7` to verify the elastic data has been updated. - -65. write message to update the skillprovider: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"skillprovider","id":"2375564d-c5eb-4b80-9b35-465c6b700ac1","name":"update_skillprovider"}}` -66. Watch the app console, It will show message successfully handled. -67. Run Command `npm run view-data skillprovider 2375564d-c5eb-4b80-9b35-465c6b700ac1` to verify the elastic data has been updated. - -68. write message to update the userattribute: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userattribute","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","attributeId":"b5a50f73-08e2-43d1-a78a-4652f15d950e","value":"update_userattribute"}}` -69. Watch the app console, It will show message successfully handled. -70. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been updated. - -71. write message to update the userskill: - `{"topic":"u-bahn.action.update","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userskill","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","skillId":"8a8c8d3a-9165-4dae-8a8c-f828cbe01d5d","metricValue":"update_userskill"}}` -72. Watch the app console, It will show message successfully handled. -73. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been updated. - -74. start kafka-console-producer to write messages to `u-bahn.action.delete` -topic: - `docker exec -it ubahn-data-processor-es_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic u-bahn.action.delete` - -75. write message to delete the achievement: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"achievement","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","achievementsProviderId":"c77326d8-ef16-4be0-b844-d5c384b7bb8b"}}` -76. Watch the app console, It will show message successfully handled. -77. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. - -78. write message to delete the achievementprovider: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"achievementprovider","id":"7b4f98b1-5831-45fe-a71f-8454d11eb8e8"}}` -79. Watch the app console, It will show message successfully handled. -80. Run Command `npm run view-data achievementprovider 7b4f98b1-5831-45fe-a71f-8454d11eb8e8` to verify the elastic data has been deleted. - -81. write message to delete the attributegroup: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"attributegroup","id":"720c34f9-0fd4-46fd-9293-4a8cfdcd3e96"}}` -82. Watch the app console, It will show message successfully handled. -83. Run Command `npm run view-data attributegroup 720c34f9-0fd4-46fd-9293-4a8cfdcd3e96` to verify the elastic data has been deleted. - -84. write message to delete the externalprofile: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"externalprofile","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","organizationId":"e2aecf8b-532d-4625-b8e2-575110b9f944"}}` -85. Watch the app console, It will show message successfully handled. -86. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. - -87. write message to delete the organization: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"organization","id":"603d4264-cdb0-47f1-914e-f053abc60422"}}` -88. Watch the app console, It will show message successfully handled. -89. Run Command `npm run view-data organization 603d4264-cdb0-47f1-914e-f053abc60422` to verify the elastic data has been deleted. - -90. write message to delete the role: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"role","id":"188446f1-02dc-4fc7-b74e-ab7ea3033a57"}}` -91. Watch the app console, It will show message successfully handled. -92. Run Command `npm run view-data role 188446f1-02dc-4fc7-b74e-ab7ea3033a57` to verify the elastic data has been deleted. - -93. write message to delete the skill: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"skill","id":"a75d95d7-6ab8-472d-8103-19d7e642e8f7"}}` -94. Watch the app console, It will show message successfully handled. -95. Run Command `npm run view-data skill a75d95d7-6ab8-472d-8103-19d7e642e8f7` to verify the elastic data has been deleted. - -96. write message to delete the skillprovider: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"skillprovider","id":"2375564d-c5eb-4b80-9b35-465c6b700ac1"}}` -97. Watch the app console, It will show message successfully handled. -98. Run Command `npm run view-data skillprovider 2375564d-c5eb-4b80-9b35-465c6b700ac1` to verify the elastic data has been deleted. - -99. write message to delete the userattribute: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userattribute","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","attributeId":"b5a50f73-08e2-43d1-a78a-4652f15d950e"}}` -100. Watch the app console, It will show message successfully handled. -101. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. - -102. write message to delete the userrole: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userrole","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","roleId":"22028da5-0563-48e8-b84c-e480eb8ed98c"}}` -103. Watch the app console, It will show message successfully handled. -104. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. - -105. write message to delete the userskill: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"userskill","userId":"391a3656-9a01-47d4-8c6d-64b68c44f212","skillId":"8a8c8d3a-9165-4dae-8a8c-f828cbe01d5d"}}` -106. Watch the app console, It will show message successfully handled. -107. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. - -108. write message to delete the user: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"user","id":"391a3656-9a01-47d4-8c6d-64b68c44f212"}}` -109. Watch the app console, It will show message successfully handled. -110. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. - - -# Verification (with groups) - -1. start kafka server, start elasticsearch, initialize Elasticsearch, start processor app -2. start kafka-console-producer to write messages to `u-bahn.action.aggregate` -topic: - `docker exec -it ubahn-data-processor-es_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic u-bahn.action.create` -3. write message: - `{"topic":"u-bahn.action.aggregate","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"user","id":"391a3656-9a01-47d4-8c6d-64b68c44f212","handle":"user","originalTopic":"u-bahn.action.aggregate"}}` -4. Watch the app console, It will show message successfully handled. -5. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - -6. start kafka-console-producer to write messages to `groups.notification.member.add` -topic: - `docker exec -it ubahn-data-processor-es_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic groups.notification.member.add` -7. write message: - `{"topic":"groups.notification.member.add","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"id":"c2f302cf-759a-4847-8acd-843e258359db","groupId":"036cc9c1-189a-4cf6-853b-0f5bc9b4ce75","oldId":"20000309","name":"House Stark","createdAt":"2020-09-11T13:14:54.108Z","createdBy":"8547899","universalUID":"391a3656-9a01-47d4-8c6d-64b68c44f212","membershipType":"user"}}` -8. Watch the app console, It will show message successfully handled. -9. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data. - - -10. Repeat again and you will see error message in app console indicate conflict error. - write message: - `{"topic":"groups.notification.member.add","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"id":"c2f302cf-759a-4847-8acd-843e258359db","groupId":"036cc9c1-189a-4cf6-853b-0f5bc9b4ce75","oldId":"20000309","name":"House Stark","createdAt":"2020-09-11T13:14:54.108Z","createdBy":"8547899","universalUID":"391a3656-9a01-47d4-8c6d-64b68c44f212","membershipType":"user"}}` - -11. start kafka-console-producer to write messages to `groups.notification.member.delete` -topic: - `docker exec -it ubahn-data-processor-es_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic groups.notification.member.delete` -12. write message to remove the groups user: - `{"topic":"groups.notification.member.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"groupId":"036cc9c1-189a-4cf6-853b-0f5bc9b4ce75","name":".NET Taas Project","oldId":"20000335","memberId":"00000000","universalUID":"391a3656-9a01-47d4-8c6d-64b68c44f212"}}` -13. Watch the app console, It will show message successfully handled. -14. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data - -15. Repeat again and you will see error message in app console indicate not found error. - write message: - `{"topic":"groups.notification.member.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"groupId":"036cc9c1-189a-4cf6-853b-0f5bc9b4ce75","name":".NET Taas Project","oldId":"20000335","memberId":"00000000","universalUID":"391a3656-9a01-47d4-8c6d-64b68c44f212"}}` - -16. start kafka-console-producer to write messages to `u-bahn.action.delete` -topic: - `docker exec -it ubahn-data-processor-es_kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic u-bahn.action.delete` -17. write message to delete the user: - `{"topic":"u-bahn.action.delete","originator":"u-bahn-api","timestamp":"2019-07-08T00:00:00.000Z","mime-type":"application/json","payload":{"resource":"user","id":"391a3656-9a01-47d4-8c6d-64b68c44f212"}}` -18. Watch the app console, It will show message successfully handled. -19. Run Command `npm run view-data user 391a3656-9a01-47d4-8c6d-64b68c44f212` to verify the elastic data has been deleted. diff --git a/config/default.js b/config/default.js index 3e698d7..f037c96 100644 --- a/config/default.js +++ b/config/default.js @@ -14,19 +14,6 @@ module.exports = { // Kafka group id KAFKA_GROUP_ID: process.env.KAFKA_GROUP_ID || 'ubahn-processor-es', - TOPCODER_GROUP_API: process.env.TOPCODER_GROUP_API || 'https://api.topcoder-dev.com/v5/groups', - - AUTH0_URL: process.env.AUTH0_URL || 'https://topcoder-dev.auth0.com/oauth/token', // Auth0 credentials - AUTH0_AUDIENCE: process.env.AUTH0_AUDIENCE || 'https://m2m.topcoder-dev.com/', - TOKEN_CACHE_TIME: process.env.TOKEN_CACHE_TIME, - AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID, - AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET, - AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL, - - UBAHN_CREATE_TOPIC: process.env.UBAHN_CREATE_TOPIC || 'u-bahn.action.create', - UBAHN_UPDATE_TOPIC: process.env.UBAHN_UPDATE_TOPIC || 'u-bahn.action.update', - UBAHN_DELETE_TOPIC: process.env.UBAHN_DELETE_TOPIC || 'u-bahn.action.delete', - UBAHN_AGGREGATE_TOPIC: process.env.UBAHN_AGGREGATE_TOPIC || 'u-bahn.action.aggregate', GROUPS_MEMBER_ADD_TOPIC: process.env.GROUPS_MEMBER_ADD_TOPIC || 'groups.notification.member.add', GROUPS_MEMBER_DELETE_TOPIC: process.env.GROUPS_MEMBER_DELETE_TOPIC || 'groups.notification.member.delete', GROUPS_MEMBERSHIP_TYPE: process.env.GROUPS_MEMBERSHIP_TYPE || 'user', @@ -41,78 +28,12 @@ module.exports = { }, AWS_REGION: process.env.AWS_REGION || 'us-east-1', // AWS Region to be used if we use AWS ES - ACHIEVEMENT_PROVIDER_INDEX: process.env.ACHIEVEMENT_PROVIDER_INDEX || 'achievement_provider', - ACHIEVEMENT_PROVIDER_TYPE: process.env.ACHIEVEMENT_PROVIDER_TYPE || '_doc', - ATTRIBUTE_INDEX: process.env.ATTRIBUTE_INDEX || 'attribute', - ATTRIBUTE_TYPE: process.env.ATTRIBUTE_TYPE || '_doc', - ATTRIBUTE_GROUP_INDEX: process.env.ATTRIBUTE_GROUP_INDEX || 'attribute_group', - ATTRIBUTE_GROUP_TYPE: process.env.ATTRIBUTE_GROUP_TYPE || '_doc', - ORGANIZATION_INDEX: process.env.ORGANIZATION_INDEX || 'organization', - ORGANIZATION_TYPE: process.env.ORGANIZATION_TYPE || '_doc', - ROLE_INDEX: process.env.ROLE_INDEX || 'role', - ROLE_TYPE: process.env.ROLE_TYPE || '_doc', - SKILL_INDEX: process.env.SKILL_INDEX || 'skill', - SKILL_TYPE: process.env.SKILL_TYPE || '_doc', - SKILL_PROVIDER_INDEX: process.env.SKILL_PROVIDER_INDEX || 'skill_provider', - SKILL_PROVIDER_TYPE: process.env.SKILL_PROVIDER_TYPE || '_doc', USER_INDEX: process.env.USER_INDEX || 'user', USER_TYPE: process.env.USER_TYPE || '_doc', - USER_ACHIEVEMENT_PROPERTY_NAME: process.env.USER_ACHIEVEMENT_PROPERTY_NAME || 'achievements', - USER_EXTERNALPROFILE_PROPERTY_NAME: process.env.USER_EXTERNALPROFILE_PROPERTY_NAME || 'externalProfiles', - USER_ATTRIBUTE_PROPERTY_NAME: process.env.USER_ATTRIBUTE_PROPERTY_NAME || 'attributes', - USER_ROLE_PROPERTY_NAME: process.env.USER_ROLE_PROPERTY_NAME || 'roles', - USER_SKILL_PROPERTY_NAME: process.env.USER_SKILL_PROPERTY_NAME || 'skills', - USER_GROUP_PROPERTY_NAME: process.env.USER_GROUP_PROPERTY_NAME || 'groups', - - ORGANIZATION_SKILLPROVIDER_PROPERTY_NAME: process.env.ORGANIZATION_SKILLPROVIDER_PROPERTY_NAME || 'skillProviders', - ENRICHMENT: { - attributegroup: { - enrichPolicyName: process.env.ATTRIBUTE_GROUP_ENRICH_POLICYNAME || 'attributegroup-policy', - pipelineId: process.env.ATTRIBUTE_GROUP_PIPELINE_ID || 'attributegroup-pipeline' - }, - skillprovider: { - enrichPolicyName: process.env.SKILL_PROVIDER_ENRICH_POLICYNAME || 'skillprovider-policy', - pipelineId: process.env.SKILL_PROVIDER_PIPELINE_ID || 'skillprovider-pipeline' - }, user: { pipelineId: process.env.USER_PIPELINE_ID || 'user-pipeline' - }, - role: { - enrichPolicyName: process.env.ROLE_ENRICH_POLICYNAME || 'role-policy' - }, - achievementprovider: { - enrichPolicyName: process.env.ACHIEVEMENT_PROVIDER_ENRICH_POLICYNAME || 'achievementprovider-policy' - }, - skill: { - enrichPolicyName: process.env.SKILL_ENRICH_POLICYNAME || 'skill-policy' - }, - attribute: { - enrichPolicyName: process.env.ATTRIBUTE_ENRICH_POLICYNAME || 'attribute-policy' - }, - organization: { - enrichPolicyName: process.env.ORGANIZATION_ENRICH_POLICYNAME || 'organization-policy' - }, - // sub resources under user - achievement: { - userField: process.env.USER_ACHIEVEMENT_PROPERTY_NAME || 'achievements' - }, - externalprofile: { - userField: process.env.USER_EXTERNALPROFILE_PROPERTY_NAME || 'externalProfiles' - }, - userattribute: { - userField: process.env.USER_ATTRIBUTE_PROPERTY_NAME || 'attributes' - }, - userrole: { - userField: process.env.USER_ROLE_PROPERTY_NAME || 'roles' - }, - userskill: { - userField: process.env.USER_SKILL_PROPERTY_NAME || 'skills' - }, - // sub resources under organization - organizationskillprovider: { - orgField: process.env.ORGANIZATION_SKILLPROVIDER_PROPERTY_NAME || 'skillProviders' } } } diff --git a/config/test.js b/config/test.js deleted file mode 100644 index b5854de..0000000 --- a/config/test.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * The test configuration. - */ - -module.exports = { - WAIT_TIME: 1500 - // ES: { - // ACHIEVEMENT_PROVIDER_INDEX: process.env.ACHIEVEMENT_PROVIDER_INDEX || 'achievement_provider_test', - // ATTRIBUTE_INDEX: process.env.ATTRIBUTE_INDEX || 'attribute_test', - // ATTRIBUTE_GROUP_INDEX: process.env.ATTRIBUTE_GROUP_INDEX || 'attribute_group_test', - // ORGANIZATION_INDEX: process.env.ORGANIZATION_INDEX || 'organization_test', - // ROLE_INDEX: process.env.ROLE_INDEX || 'role_test', - // SKILL_INDEX: process.env.SKILL_INDEX || 'skill_test', - // SKILL_PROVIDER_INDEX: process.env.SKILL_PROVIDER_INDEX || 'skill_provider_test', - // USER_INDEX: process.env.USER_INDEX || 'user_test' - // } -} diff --git a/docker-kafka-es/docker-compose.yml b/docker-kafka-es/docker-compose.yml index 8e08541..566741d 100755 --- a/docker-kafka-es/docker-compose.yml +++ b/docker-kafka-es/docker-compose.yml @@ -12,7 +12,7 @@ services: - "9092:9092" environment: KAFKA_ADVERTISED_HOST_NAME: localhost - KAFKA_CREATE_TOPICS: "u-bahn.action.aggregate:1:1,groups.notification.member.add:1:1,groups.notification.member.delete:1:1" + KAFKA_CREATE_TOPICS: "groups.notification.member.add:1:1,groups.notification.member.delete:1:1" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 esearch: image: elasticsearch:7.7.1 diff --git a/docker/api.env b/docker/api.env new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docker/api.env @@ -0,0 +1 @@ + diff --git a/package-lock.json b/package-lock.json index aa6bfe2..0fdeead 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,155 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/generator": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.0.tgz", - "integrity": "sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA==", - "dev": true, - "requires": { - "@babel/types": "^7.5.0", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.0.tgz", - "integrity": "sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA==", - "dev": true - }, - "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/traverse": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.0.tgz", - "integrity": "sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.5.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.5.0", - "@babel/types": "^7.5.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "@babel/types": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.0.tgz", - "integrity": "sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, "@elastic/elasticsearch": { "version": "7.9.1", "resolved": "https://registry.npmjs.org/@elastic/elasticsearch/-/elasticsearch-7.9.1.tgz", @@ -265,12 +116,6 @@ "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, "ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", @@ -289,31 +134,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "requires": { - "default-require-extensions": "^2.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", @@ -354,12 +174,6 @@ "tslib": "^2.0.0" } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, "aws-sdk": { "version": "2.488.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.488.0.tgz", @@ -376,6 +190,14 @@ "xml2js": "0.4.19" } }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -416,12 +238,6 @@ "protocol-buffers-schema": "^3.0.0" } }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", - "dev": true - }, "bluebird": { "version": "3.5.5", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", @@ -454,21 +270,6 @@ "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 - }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -489,18 +290,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", - "dev": true, - "requires": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - } - }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -516,12 +305,6 @@ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -541,22 +324,6 @@ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", "dev": true }, - "chokidar": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", - "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.2.0" - } - }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", @@ -578,40 +345,6 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", @@ -662,27 +395,6 @@ "text-hex": "1.0.x" } }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "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", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -721,15 +433,6 @@ "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.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", @@ -740,30 +443,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - } - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -798,12 +482,6 @@ "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "decompress-response": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", @@ -818,15 +496,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", - "dev": true, - "requires": { - "strip-bom": "^3.0.0" - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -858,12 +527,6 @@ } } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -884,12 +547,6 @@ "kuler": "1.0.x" } }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -904,12 +561,6 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, "enabled": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", @@ -978,12 +629,6 @@ "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 - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1443,21 +1088,6 @@ "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -1553,15 +1183,6 @@ "object-assign": "^4.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", @@ -1576,41 +1197,12 @@ "unpipe": "~1.0.0" } }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, "find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "dev": true }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, "flat-cache": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", @@ -1623,45 +1215,29 @@ "write": "^0.2.1" } }, - "foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", - "dev": true, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" + "debug": "=3.1.0" }, "dependencies": { - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, - "form-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.0.tgz", - "integrity": "sha512-WXieX3G/8side6VIqx44ablyULoGruSde5PNTxoUyo5CeyAMX6nVWUd0rgist/EuX655cjhUhTo1Fo3tRYqbcA==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", - "dev": true - }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -1678,13 +1254,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -1697,12 +1266,6 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "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 - }, "get-parameter-names": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/get-parameter-names/-/get-parameter-names-0.3.0.tgz", @@ -1714,15 +1277,6 @@ "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", "dev": true }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -1737,15 +1291,6 @@ "path-is-absolute": "^1.0.0" } }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -1758,12 +1303,6 @@ "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", "dev": true }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1794,15 +1333,6 @@ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, - "hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", - "dev": true, - "requires": { - "is-stream": "^1.0.1" - } - }, "hashring": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/hashring/-/hashring-3.2.0.tgz", @@ -1812,24 +1342,12 @@ "simple-lru-cache": "0.0.x" } }, - "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 - }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, - "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", @@ -1949,12 +1467,6 @@ } } }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, "ipaddr.js": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", @@ -1965,21 +1477,6 @@ "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-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true - }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", @@ -1992,33 +1489,12 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "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-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -2065,105 +1541,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", - "dev": true, - "requires": { - "append-transform": "^1.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", - "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "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": "2.2.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0" - } - }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", @@ -2185,12 +1562,6 @@ "esprima": "^4.0.0" } }, - "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", @@ -2209,12 +1580,6 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -2241,15 +1606,6 @@ "colornames": "^1.1.1" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2280,67 +1636,11 @@ } } }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, "lodash": { "version": "4.17.19", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, - "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 - }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "logform": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", @@ -2367,73 +1667,16 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - } - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } - } - }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -2457,12 +1700,6 @@ "mime-db": "1.40.0" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "mimic-response": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", @@ -2491,145 +1728,6 @@ "minimist": "^1.2.5" } }, - "mocha": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", - "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "chokidar": "3.3.0", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "3.0.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.5", - "ms": "2.1.1", - "node-environment-flags": "1.0.6", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.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": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - } - } - }, - "mocha-prepare": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/mocha-prepare/-/mocha-prepare-0.1.0.tgz", - "integrity": "sha1-VRMidoEiLkNJSB7k5GJHLzHGu4I=", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2657,12 +1755,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, - "nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true - }, "nice-simple-logger": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nice-simple-logger/-/nice-simple-logger-1.0.1.tgz", @@ -2701,39 +1793,6 @@ } } }, - "nock": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", - "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.13", - "propagate": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "node-environment-flags": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -2746,70 +1805,10 @@ "validate-npm-package-license": "^3.0.1" } }, - "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 - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "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=", - "dev": true - }, - "nyc": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object-keys": { @@ -2830,69 +1829,6 @@ "object-keys": "^1.0.11" } }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -2953,83 +1889,12 @@ } } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - } - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, - "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.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 - }, - "package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -3080,35 +1945,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, "pkg-conf": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", @@ -3175,15 +2011,6 @@ "xtend": "^4.0.1" } }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -3218,12 +2045,6 @@ "react-is": "^16.8.1" } }, - "propagate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", - "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", - "dev": true - }, "protocol-buffers-schema": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz", @@ -3238,12 +2059,6 @@ "ipaddr.js": "1.9.0" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -3290,27 +2105,6 @@ "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", "dev": true }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, "readable-stream": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", @@ -3321,42 +2115,12 @@ "util-deprecate": "^1.0.1" } }, - "readdirp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", - "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", - "dev": true, - "requires": { - "picomatch": "^2.0.4" - } - }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "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" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "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 - }, "require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -3384,12 +2148,6 @@ "path-parse": "^1.0.6" } }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -3497,12 +2255,6 @@ "send": "0.17.1" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -3523,60 +2275,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "requires": { - "should-type": "^1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -3605,26 +2303,6 @@ "is-fullwidth-code-point": "^2.0.0" } }, - "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": "1.4.3", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", - "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", @@ -3729,260 +2407,6 @@ } } }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - } - } - }, "string_decoder": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", @@ -4006,60 +2430,12 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, - "superagent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.1.0.tgz", - "integrity": "sha512-7V6JVx5N+eTL1MMqRBX0v0bG04UjrjAvvZJTF/VDH/SH2GjSLqlrcYepFlpTrXpm37aSY6h3GGVWGxXl/98TKA==", - "dev": true, - "requires": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.6", - "form-data": "^2.3.3", - "formidable": "^1.2.1", - "methods": "^1.1.2", - "mime": "^2.4.4", - "qs": "^6.7.0", - "readable-stream": "^3.4.0", - "semver": "^6.1.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", - "dev": true - }, - "semver": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", - "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==", - "dev": true - } - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -4117,18 +2493,6 @@ } } }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - } - }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -4155,21 +2519,6 @@ "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", @@ -4183,12 +2532,6 @@ "express": "^4.16.3" } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -4293,21 +2636,6 @@ "isexe": "^2.0.0" } }, - "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 - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "winston": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", @@ -4357,38 +2685,6 @@ } } }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -4403,17 +2699,6 @@ "mkdirp": "^0.5.1" } }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, "wrr-pool": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/wrr-pool/-/wrr-pool-1.1.4.tgz", @@ -4441,163 +2726,6 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", - "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.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": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - } - } } } } diff --git a/package.json b/package.json index 4aabcf7..48c4002 100644 --- a/package.json +++ b/package.json @@ -6,23 +6,12 @@ "scripts": { "start": "node src/app.js", "lint": "standard", - "lint:fix": "standard --fix", - "view-data": "node test/common/view-data.js", - "test": "mocha test/unit/test.js --require test/unit/prepare.js --timeout 20000 --exit", - "test:cov": "nyc --reporter=html --reporter=text mocha test/unit/test.js --require test/unit/prepare.js --timeout 20000 --exit", - "e2e": "mocha test/e2e/test.js --timeout 20000 --exit", - "e2e:cov": "nyc --reporter=html --reporter=text mocha test/e2e/test.js --timeout 20000 --exit" + "lint:fix": "standard --fix" }, "author": "TCSCODER", "license": "none", "devDependencies": { - "mocha": "^7.1.2", - "mocha-prepare": "^0.1.0", - "nock": "^12.0.3", - "nyc": "^14.1.1", - "should": "^13.2.3", - "standard": "^12.0.1", - "superagent": "^5.1.0" + "standard": "^12.0.1" }, "dependencies": { "@elastic/elasticsearch": "^7.9.1", @@ -35,7 +24,6 @@ "lodash": "^4.17.19", "no-kafka": "^3.4.3", "axios": "^0.19.2", - "tc-core-library-js": "appirio-tech/tc-core-library-js.git#v2.6", "topcoder-healthcheck-dropin": "^1.0.3", "winston": "^3.2.1" }, diff --git a/src/app.js b/src/app.js index 8e12a34..d3690b4 100644 --- a/src/app.js +++ b/src/app.js @@ -9,7 +9,6 @@ const _ = require('lodash') const healthcheck = require('topcoder-healthcheck-dropin') const logger = require('./common/logger') const helper = require('./common/helper') -const ProcessorService = require('./services/ProcessorService') const GroupsProcessorService = require('./services/GroupsProcessorService') const Mutex = require('async-mutex').Mutex @@ -70,21 +69,7 @@ const dataHandler = (messageSet, topic, partition) => Promise.each(messageSet, a } const transactionId = _.uniqueId('transaction_') try { - if (messageJSON.payload.originalTopic) { - // switch (messageJSON.payload.originalTopic) { - // case config.UBAHN_CREATE_TOPIC: - // await ProcessorService.processCreate(messageJSON, transactionId) - // break - // case config.UBAHN_UPDATE_TOPIC: - // await ProcessorService.processUpdate(messageJSON, transactionId) - // break - // case config.UBAHN_DELETE_TOPIC: - // await ProcessorService.processDelete(messageJSON, transactionId) - // break - // default: - // throw new Error(`Unknown original topic: ${messageJSON.payload.originalTopic}`) - // } - } else { + if (!messageJSON.payload.originalTopic) { switch (topic) { case config.GROUPS_MEMBER_ADD_TOPIC: await GroupsProcessorService.processMemberAdd(messageJSON, transactionId) @@ -122,8 +107,7 @@ const check = () => { return connected } -// const topics = [config.UBAHN_CREATE_TOPIC, config.UBAHN_UPDATE_TOPIC, config.UBAHN_DELETE_TOPIC] -const topics = [config.UBAHN_AGGREGATE_TOPIC, config.GROUPS_MEMBER_ADD_TOPIC, config.GROUPS_MEMBER_DELETE_TOPIC] +const topics = [config.GROUPS_MEMBER_ADD_TOPIC, config.GROUPS_MEMBER_DELETE_TOPIC] consumer .init([{ diff --git a/src/common/constants.js b/src/common/constants.js deleted file mode 100644 index d4adfb4..0000000 --- a/src/common/constants.js +++ /dev/null @@ -1,177 +0,0 @@ -/** - * This module contains es resources configuration. - */ - -const config = require('config') -const { validProperties } = require('./helper') - -const topResources = { - achievementprovider: { - index: config.get('ES.ACHIEVEMENT_PROVIDER_INDEX'), - type: config.get('ES.ACHIEVEMENT_PROVIDER_TYPE'), - enrich: { - policyName: config.get('ES.ENRICHMENT.achievementprovider.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy'] - } - }, - attribute: { - index: config.get('ES.ATTRIBUTE_INDEX'), - type: config.get('ES.ATTRIBUTE_TYPE'), - enrich: { - policyName: config.get('ES.ENRICHMENT.attribute.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'attributeGroupId', 'created', 'updated', 'createdBy', 'updatedBy', 'attributegroup'] - }, - ingest: { - pipeline: { - id: config.get('ES.ENRICHMENT.attributegroup.pipelineId') - } - } - }, - attributegroup: { - index: config.get('ES.ATTRIBUTE_GROUP_INDEX'), - type: config.get('ES.ATTRIBUTE_GROUP_TYPE'), - enrich: { - policyName: config.get('ES.ENRICHMENT.attributegroup.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'organizationId', 'created', 'updated', 'createdBy', 'updatedBy'] - }, - pipeline: { - id: config.get('ES.ENRICHMENT.attributegroup.pipelineId'), - field: 'attributeGroupId', - targetField: 'attributegroup', - maxMatches: '1' - } - }, - organization: { - index: config.get('ES.ORGANIZATION_INDEX'), - type: config.get('ES.ORGANIZATION_TYPE') - }, - role: { - index: config.get('ES.ROLE_INDEX'), - type: config.get('ES.ROLE_TYPE'), - enrich: { - policyName: config.get('ES.ENRICHMENT.role.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy'] - } - }, - skill: { - index: config.get('ES.SKILL_INDEX'), - type: config.get('ES.SKILL_TYPE'), - enrich: { - policyName: config.get('ES.ENRICHMENT.skill.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'skillProviderId', 'name', 'externalId', 'uri', 'created', 'updated', 'createdBy', 'updatedBy', 'skillprovider'] - }, - ingest: { - pipeline: { - id: config.get('ES.ENRICHMENT.skillprovider.pipelineId') - } - } - }, - skillprovider: { - index: config.get('ES.SKILL_PROVIDER_INDEX'), - type: config.get('ES.SKILL_PROVIDER_TYPE'), - enrich: { - policyName: config.get('ES.ENRICHMENT.skillprovider.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy'] - }, - pipeline: { - id: config.get('ES.ENRICHMENT.skillprovider.pipelineId'), - field: 'skillProviderId', - targetField: 'skillprovider', - maxMatches: '1' - } - }, - user: { - index: config.get('ES.USER_INDEX'), - type: config.get('ES.USER_TYPE'), - ingest: { - pipeline: { - id: config.get('ES.ENRICHMENT.user.pipelineId') - } - }, - pipeline: { - id: config.get('ES.ENRICHMENT.user.pipelineId'), - processors: [ - { - referenceField: config.get('ES.ENRICHMENT.achievement.userField'), - enrichPolicyName: config.get('ES.ENRICHMENT.achievementprovider.enrichPolicyName'), - field: '_ingest._value.achievementsProviderId', - targetField: '_ingest._value.achievementprovider', - maxMatches: '1' - }, - { - referenceField: config.get('ES.ENRICHMENT.userattribute.userField'), - enrichPolicyName: config.get('ES.ENRICHMENT.attribute.enrichPolicyName'), - field: '_ingest._value.attributeId', - targetField: '_ingest._value.attribute', - maxMatches: '1' - }, - { - referenceField: config.get('ES.ENRICHMENT.userrole.userField'), - enrichPolicyName: config.get('ES.ENRICHMENT.role.enrichPolicyName'), - field: '_ingest._value.roleId', - targetField: '_ingest._value.role', - maxMatches: '1' - }, - { - referenceField: config.get('ES.ENRICHMENT.userskill.userField'), - enrichPolicyName: config.get('ES.ENRICHMENT.skill.enrichPolicyName'), - field: '_ingest._value.skillId', - targetField: '_ingest._value.skill', - maxMatches: '1' - } - ] - } - } -} - -const userResources = { - achievement: { - propertyName: config.get('ES.USER_ACHIEVEMENT_PROPERTY_NAME'), - relateKey: 'achievementsProviderId', - validate: payload => validProperties(payload, ['userId', 'achievementsProviderId']) - }, - externalprofile: { - propertyName: config.get('ES.USER_EXTERNALPROFILE_PROPERTY_NAME'), - relateKey: 'organizationId', - validate: payload => validProperties(payload, ['userId', 'organizationId']) - }, - userattribute: { - propertyName: config.get('ES.USER_ATTRIBUTE_PROPERTY_NAME'), - relateKey: 'attributeId', - validate: payload => validProperties(payload, ['userId', 'attributeId']), - isNested: true // For ES index creation - }, - userrole: { - propertyName: config.get('ES.USER_ROLE_PROPERTY_NAME'), - relateKey: 'roleId', - validate: payload => validProperties(payload, ['userId', 'roleId']) - }, - userskill: { - propertyName: config.get('ES.USER_SKILL_PROPERTY_NAME'), - relateKey: 'skillId', - validate: payload => validProperties(payload, ['userId', 'skillId']) - } -} - -const organizationResources = { - organizationskillprovider: { - propertyName: config.get('ES.ORGANIZATION_SKILLPROVIDER_PROPERTY_NAME'), - relateKey: 'skillProviderId', - validate: payload => validProperties(payload, ['organizationId', 'skillProviderId']), - enrich: { - policyName: config.get('ES.ENRICHMENT.organization.enrichPolicyName'), - matchField: 'id', - enrichFields: ['id', 'name', 'created', 'updated', 'createdBy', 'updatedBy', 'skillProviders'] - } - } -} - -module.exports = { - topResources, userResources, organizationResources -} diff --git a/src/common/helper.js b/src/common/helper.js index b496a37..aba3965 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -8,10 +8,7 @@ const elasticsearch = require('@elastic/elasticsearch') const _ = require('lodash') const Joi = require('@hapi/joi') const { Mutex } = require('async-mutex') -const axios = require('axios') const logger = require('./logger') -const m2mAuth = require('tc-core-library-js').auth.m2m -const topcoderM2M = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL'])) AWS.config.region = config.ES.AWS_REGION @@ -22,34 +19,6 @@ let transactionId const esClientMutex = new Mutex() const mutexReleaseMap = {} -/* Function to get M2M token - * (Topcoder APIs only) - * @returns {Promise} - */ -async function getTopcoderM2Mtoken () { - return topcoderM2M.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET) -} - -/** - * Returns the user in Topcoder identified by the email - * @param {String} email The user email - */ -async function getUserGroup (memberId) { - const url = config.TOPCODER_GROUP_API - const token = await getTopcoderM2Mtoken() - const params = { memberId, membershipType: 'user', page: 1 } - - logger.debug(`request GET ${url} with params: ${JSON.stringify(params)}`) - let groups = [] - let groupRes = await axios.get(url, { headers: { Authorization: `Bearer ${token}` }, params }) - while (groupRes.data.length > 0) { - groups = _.concat(groups, _.map(groupRes.data, g => _.pick(g, 'id', 'name'))) - params.page = params.page + 1 - groupRes = await axios.get(url, { headers: { Authorization: `Bearer ${token}` }, params }) - } - return groups -} - /** * Get Kafka options * @return {Object} the Kafka options @@ -175,41 +144,6 @@ async function updateUser (userId, body, seqNo, primaryTerm, transactionId) { } } -/** - * Function to get org from es - * @param {String} organizationId - * @param {String} transactionId - * @returns {Object} organization - */ -async function getOrg (organizationId, transactionId) { - const client = await getESClient() - const { body: org } = await client.get({ index: config.get('ES.ORGANIZATION_INDEX'), type: config.get('ES.ORGANIZATION_TYPE'), id: organizationId, transactionId }) - return { seqNo: org._seq_no, primaryTerm: org._primary_term, org: org._source } -} - -/** - * Function to update es organization - * @param {String} organizationId - * @param {Number} seqNo - * @param {Number} primaryTerm - * @param {String} transactionId - * @param {Object} body - */ -async function updateOrg (organizationId, body, seqNo, primaryTerm, transactionId) { - const client = await getESClient() - await client.index({ - index: config.get('ES.ORGANIZATION_INDEX'), - type: config.get('ES.ORGANIZATION_TYPE'), - id: organizationId, - transactionId, - body, - if_seq_no: seqNo, - if_primary_term: primaryTerm, - refresh: 'wait_for' - }) - await client.enrich.executePolicy({ name: config.get('ES.ENRICHMENT.organization.enrichPolicyName') }) -} - /** * Fuction to get an Error with statusCode property * @param {String} message error message @@ -242,10 +176,7 @@ module.exports = { getESClient, validProperties, getUser, - getUserGroup, updateUser, - getOrg, - updateOrg, getErrorWithStatus, checkEsMutexRelease } diff --git a/src/services/ProcessorService.js b/src/services/ProcessorService.js deleted file mode 100644 index 0797fe1..0000000 --- a/src/services/ProcessorService.js +++ /dev/null @@ -1,279 +0,0 @@ -/** - * Processor Service - */ - -const _ = require('lodash') -const Joi = require('@hapi/joi') -const logger = require('../common/logger') -const helper = require('../common/helper') -const { - topResources, - userResources, - organizationResources -} = require('../common/constants') -const config = require('config') - -/** - * Process create entity message - * @param {Object} message the kafka message - * @param {String} transactionId - */ -async function processCreate (message, transactionId) { - const resource = message.payload.resource - - // shapeup - CQRS standards update - const fixedTopResources = _.filter(_.keys(topResources), (key) => key !== 'user') - - if (_.includes(_.keys(fixedTopResources), resource)) { - // process the top resources such as user, skill... - helper.validProperties(message.payload, ['id']) - const client = await helper.getESClient() - await client.index({ - index: topResources[resource].index, - type: topResources[resource].type, - id: message.payload.id, - transactionId, - body: _.omit(message.payload, ['resource', 'originalTopic']), - pipeline: topResources[resource].ingest ? topResources[resource].ingest.pipeline.id : undefined, - refresh: 'wait_for' - }) - if (topResources[resource].enrich) { - await client.enrich.executePolicy({ - name: topResources[resource].enrich.policyName, - transactionId - }) - } - } else if (_.includes(_.keys(userResources), resource)) { - // process user resources such as userSkill, userAttribute... - const userResource = userResources[resource] - userResource.validate(message.payload) - const { seqNo, primaryTerm, user } = await helper.getUser(message.payload.userId, transactionId) - const relateId = message.payload[userResource.relateKey] - if (!user[userResource.propertyName]) { - user[userResource.propertyName] = [] - } - - // import groups for a new user - if (resource === 'externalprofile' && message.payload.externalId) { - const userGroups = await helper.getUserGroup(message.payload.externalId) - user[config.get('ES.USER_GROUP_PROPERTY_NAME')] = _.unionBy(user[config.get('ES.USER_GROUP_PROPERTY_NAME')], userGroups, 'id') - } - - // check the resource does not exist - if (_.some(user[userResource.propertyName], [userResource.relateKey, relateId])) { - logger.error(`Can't create existed ${resource} with the ${userResource.relateKey}: ${relateId}, userId: ${message.payload.userId}`) - throw helper.getErrorWithStatus('[version_conflict_engine_exception]', 409) - } else { - user[userResource.propertyName].push(_.omit(message.payload, ['resource', 'originalTopic'])) - await helper.updateUser(message.payload.userId, user, seqNo, primaryTerm, transactionId) - } - } else if (_.includes(_.keys(organizationResources), resource)) { - // process org resources such as org skill provider - const orgResources = organizationResources[resource] - orgResources.validate(message.payload) - const { seqNo, primaryTerm, org } = await helper.getOrg(message.payload.organizationId, transactionId) - const relateId = message.payload[orgResources.relateKey] - if (!org[orgResources.propertyName]) { - org[orgResources.propertyName] = [] - } - - // check the resource does not exist - if (_.some(org[orgResources.propertyName], [orgResources.relateKey, relateId])) { - logger.error(`Can't create existing ${resource} with the ${orgResources.relateKey}: ${relateId}, organizationId: ${message.payload.organizationId}`) - throw helper.getErrorWithStatus('[version_conflict_engine_exception]', 409) - } else { - org[orgResources.propertyName].push(_.omit(message.payload, ['resource', 'originalTopic'])) - await helper.updateOrg(message.payload.organizationId, org, seqNo, primaryTerm, transactionId) - } - } else { - logger.info(`Ignore this message since resource is not in [${_.union(_.values(fixedTopResources), _.keys(userResources), _.keys(organizationResources))}]`) - } -} - -processCreate.schema = { - message: Joi.object().keys({ - topic: Joi.string().required(), - originator: Joi.string().required(), - timestamp: Joi.date().required(), - 'mime-type': Joi.string().required(), - payload: Joi.object().keys({ - resource: Joi.string().required(), - originalTopic: Joi.string().required().valid(config.UBAHN_CREATE_TOPIC) - }).required().unknown(true) - }).required(), - transactionId: Joi.string().required() -} - -/** - * Process update entity message - * @param {Object} message the kafka message - * @param {String} transactionId - */ -async function processUpdate (message, transactionId) { - const resource = message.payload.resource - - // shapeup - CQRS standards update - const fixedTopResources = _.filter(_.keys(topResources), (key) => key !== 'user') - - if (_.includes(fixedTopResources, resource)) { - logger.info(`Processing top level resource: ${resource}`) - // process the top resources such as user, skill... - helper.validProperties(message.payload, ['id']) - const client = await helper.getESClient() - const { index, type } = topResources[resource] - const id = message.payload.id - const { body: source } = await client.get({ index, type, id, transactionId }) - await client.index({ - index, - type, - id, - transactionId, - body: _.assign(source._source, _.omit(message.payload, ['resource', 'originalTopic'])), - pipeline: topResources[resource].ingest ? topResources[resource].ingest.pipeline.id : undefined, - if_seq_no: source._seq_no, - if_primary_term: source._primary_term, - refresh: 'wait_for' - }) - if (topResources[resource].enrich) { - await client.enrich.executePolicy({ - name: topResources[resource].enrich.policyName, - transactionId - }) - } - } else if (_.includes(_.keys(userResources), resource)) { - // process user resources such as userSkill, userAttribute... - const userResource = userResources[resource] - const relateId = message.payload[userResource.relateKey] - logger.info(`Processing user level resource: ${resource}:${relateId}`) - userResource.validate(message.payload) - logger.info(`Resource validated for ${relateId}`) - const { seqNo, primaryTerm, user } = await helper.getUser(message.payload.userId, transactionId) - logger.info(`User fetched ${user.id} and ${relateId}`) - - // check the resource exist - if (!user[userResource.propertyName] || !_.some(user[userResource.propertyName], [userResource.relateKey, relateId])) { - logger.error(`The ${resource} with the ${userResource.relateKey}: ${relateId}, userId: ${message.payload.userId} not exist`) - throw helper.getErrorWithStatus('[resource_not_found_exception]', 404) - } else { - const updateIndex = _.findIndex(user[userResource.propertyName], [userResource.relateKey, relateId]) - user[userResource.propertyName].splice(updateIndex, 1, _.omit(message.payload, ['resource', 'originalTopic'])) - logger.info(`Updating ${user.id} and ${relateId}`) - await helper.updateUser(message.payload.userId, user, seqNo, primaryTerm, transactionId) - logger.info(`Updated ${user.id} and ${relateId}`) - } - } else if (_.includes(_.keys(organizationResources), resource)) { - logger.info(`Processing org level resource: ${resource}`) - // process org resources such as org skill providers - const orgResource = organizationResources[resource] - orgResource.validate(message.payload) - const { seqNo, primaryTerm, org } = await helper.getOrg(message.payload.organizationId, transactionId) - const relateId = message.payload[orgResource.relateKey] - - // check the resource exist - if (!org[orgResource.propertyName] || !_.some(org[orgResource.propertyName], [orgResource.relateKey, relateId])) { - logger.error(`The ${resource} with the ${orgResource.relateKey}: ${relateId}, organizationId: ${message.payload.organizationId} not exist`) - throw helper.getErrorWithStatus('[resource_not_found_exception]', 404) - } else { - const updateIndex = _.findIndex(org[orgResource.propertyName], [orgResource.relateKey, relateId]) - org[orgResource.propertyName].splice(updateIndex, 1, _.omit(message.payload, ['resource', 'originalTopic'])) - await helper.updateOrg(message.payload.organizationId, org, seqNo, primaryTerm, transactionId) - } - } else { - logger.info(`Ignore this message since resource is not in [${_.union(_.values(fixedTopResources), _.keys(userResources), _.keys(organizationResources))}]`) - } -} - -processUpdate.schema = { - message: Joi.object().keys({ - topic: Joi.string().required(), - originator: Joi.string().required(), - timestamp: Joi.date().required(), - 'mime-type': Joi.string().required(), - payload: Joi.object().keys({ - resource: Joi.string().required(), - originalTopic: Joi.string().required().valid(config.UBAHN_UPDATE_TOPIC) - }).required().unknown(true) - }).required(), - transactionId: Joi.string().required() -} - -/** - * Process delete entity message - * @param {Object} message the kafka message - * @param {String} transactionId - */ -async function processDelete (message, transactionId) { - const resource = message.payload.resource - if (_.includes(_.keys(topResources), resource)) { - // process the top resources such as user, skill... - helper.validProperties(message.payload, ['id']) - const client = await helper.getESClient() - await client.delete({ - index: topResources[resource].index, - type: topResources[resource].type, - id: message.payload.id, - transactionId, - refresh: 'wait_for' - }) - if (topResources[resource].enrich) { - await client.enrich.executePolicy({ - name: topResources[resource].enrich.policyName, - transactionId - }) - } - } else if (_.includes(_.keys(userResources), resource)) { - // process user resources such as userSkill, userAttribute... - const userResource = userResources[resource] - userResource.validate(message.payload) - const { seqNo, primaryTerm, user } = await helper.getUser(message.payload.userId, transactionId) - const relateId = message.payload[userResource.relateKey] - - // check the resource exist - if (!user[userResource.propertyName] || !_.some(user[userResource.propertyName], [userResource.relateKey, relateId])) { - logger.error(`The ${resource} with the ${userResource.relateKey}: ${relateId}, userId: ${message.payload.userId} not exist`) - throw helper.getErrorWithStatus('[resource_not_found_exception]', 404) - } else { - _.remove(user[userResource.propertyName], [userResource.relateKey, relateId]) - await helper.updateUser(message.payload.userId, user, seqNo, primaryTerm, transactionId) - } - } else if (_.includes(_.keys(organizationResources), resource)) { - // process user resources such as org skill provider - const orgResource = organizationResources[resource] - orgResource.validate(message.payload) - const { seqNo, primaryTerm, org } = await helper.getOrg(message.payload.organizationId, transactionId) - const relateId = message.payload[orgResource.relateKey] - - // check the resource exist - if (!org[orgResource.propertyName] || !_.some(org[orgResource.propertyName], [orgResource.relateKey, relateId])) { - logger.error(`The ${resource} with the ${orgResource.relateKey}: ${relateId}, organizationId: ${message.payload.organizationId} not exist`) - throw helper.getErrorWithStatus('[resource_not_found_exception]', 404) - } else { - _.remove(org[orgResource.propertyName], [orgResource.relateKey, relateId]) - await helper.updateOrg(message.payload.organizationId, org, seqNo, primaryTerm, transactionId) - } - } else { - logger.info(`Ignore this message since resource is not in [${_.union(_.keys(topResources), _.keys(userResources), _.keys(organizationResources))}]`) - } -} - -processDelete.schema = { - message: Joi.object().keys({ - topic: Joi.string().required(), - originator: Joi.string().required(), - timestamp: Joi.date().required(), - 'mime-type': Joi.string().required(), - payload: Joi.object().keys({ - resource: Joi.string().required(), - originalTopic: Joi.string().required().valid(config.UBAHN_DELETE_TOPIC) - }).required().unknown(true) - }).required(), - transactionId: Joi.string().required() -} - -module.exports = { - processCreate, - processUpdate, - processDelete -} - -logger.buildService(module.exports) diff --git a/test/common/init-es.js b/test/common/init-es.js deleted file mode 100644 index 5e9dae0..0000000 --- a/test/common/init-es.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * !OBSOLETE SCRIPT. Use the one from ubahn-api instead - * !( https://github.com/topcoder-platform/u-bahn-api ) - */ - -/** - * Initialize elastic search. - * It will create configured index in elastic search if it is not present. - * It can delete and re-create index if providing an extra 'force' argument. - * Usage: - * node src/init-es - * node src/init-es force - */ -const logger = require('../../src/common/logger') -const helper = require('../../src/common/helper') -const { topResources } = require('../../src/common/constants') - -let client - -/** - * Check if elastic search is empty - */ -const checkEmpty = async () => { - if (!client) { - client = await helper.getESClient() - } - for (const key in topResources) { - try { - const { body } = await client.search({ index: topResources[key].index }) - if (body.hits.total.value > 0) { - return false - } - } catch (err) { - // ignore - } - } - return true -} - -/** - * Clear elastic search data - */ -const clearData = async () => { - if (!client) { - client = await helper.getESClient() - } - for (const key in topResources) { - logger.info(`Clear index ${topResources[key].index} data if any.`) - try { - await client.deleteByQuery({ index: topResources[key].index, body: { query: { match_all: {} } } }) - } catch (err) { - // ignore - logger.logFullError(err) - } - } -} - -module.exports = { - checkEmpty, - clearData -} diff --git a/test/common/testData.js b/test/common/testData.js deleted file mode 100644 index 3e80b2d..0000000 --- a/test/common/testData.js +++ /dev/null @@ -1,702 +0,0 @@ -module.exports = { - fields: { - achievement: { - createIndex: 2, - updateIndex: 2, - deleteIndex: 0, - requiredFields: ['payload.resource', 'payload.userId', 'payload.achievementsProviderId'] - }, - achievementprovider: { - createIndex: 1, - updateIndex: 1, - deleteIndex: 1, - requiredFields: ['payload.resource', 'payload.id'] - }, - attributegroup: { - createIndex: 3, - updateIndex: 3, - deleteIndex: 2, - requiredFields: ['payload.resource', 'payload.id'] - }, - externalprofile: { - createIndex: 4, - updateIndex: 4, - deleteIndex: 3, - requiredFields: ['payload.resource', 'payload.userId', 'payload.organizationId'] - }, - organization: { - createIndex: 5, - updateIndex: 5, - deleteIndex: 4, - requiredFields: ['payload.resource', 'payload.id'] - }, - role: { - createIndex: 6, - updateIndex: 6, - deleteIndex: 5, - requiredFields: ['payload.resource', 'payload.id'] - }, - skill: { - createIndex: 8, - updateIndex: 8, - deleteIndex: 6, - requiredFields: ['payload.resource', 'payload.id'] - }, - skillprovider: { - createIndex: 7, - updateIndex: 7, - deleteIndex: 7, - requiredFields: ['payload.resource', 'payload.id'] - }, - user: { - createIndex: 0, - updateIndex: 0, - deleteIndex: 11, - requiredFields: ['payload.resource', 'payload.id'] - }, - userattribute: { - createIndex: 9, - updateIndex: 9, - deleteIndex: 8, - requiredFields: ['payload.resource', 'payload.userId', 'payload.attributeId'] - }, - userrole: { - createIndex: 10, - deleteIndex: 9, - requiredFields: ['payload.resource', 'payload.userId', 'payload.roleId'] - }, - userskill: { - createIndex: 11, - updateIndex: 10, - deleteIndex: 10, - requiredFields: ['payload.resource', 'payload.userId', 'payload.skillId'] - } - }, - testTopics: { - Create: [ - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'user', - id: '391a3656-9a01-47d4-8c6d-64b68c44f212', - handle: 'user', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievementprovider', - id: '7b4f98b1-5831-45fe-a71f-8454d11eb8e8', - name: 'achievementprovider', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievement', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - achievementsProviderId: '7b4f98b1-5831-45fe-a72f-8454d11eb8e8', - name: 'achievement', - uri: 'https://google.com', - certifierId: 'b8726ca1-557e-4502-8f9b-25044b9c123d', - certifiedDate: '2019-07-08T00:00:00.000Z', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'attributegroup', - id: '720c34f9-0fd4-46fd-9293-4a8cfdcd3e96', - organizationId: '017733ad-4704-4c7e-ae60-36b3332731df', - name: 'attributegroup', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'externalprofile', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - organizationId: 'e2aecf8b-532d-4625-b8e2-575110b9f944', - uri: 'https:google.com', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'organization', - id: '603d4264-cdb0-47f1-914e-f053abc60422', - name: 'organization', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'role', - id: '188446f1-02dc-4fc7-b74e-ab7ea3033a57', - name: 'role', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skillprovider', - id: '2375564d-c5eb-4b80-9b35-465c6b700ac1', - name: 'skillprovider', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skill', - id: 'a75d95d7-6ab8-472d-8103-19d7e642e8f7', - skillProviderId: '2375564d-c5eb-4b80-9b35-465c6b700ac1', - externalId: 'ba395d36-6ce8-4bd1-9d6c-754f0389abcb', - uri: 'https://google.com', - name: 'skill', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userattribute', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - attributeId: 'b5a50f73-08e2-43d1-a78a-4652f15d950e', - value: 'userattribute', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userrole', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - roleId: '288446f1-02dc-4fc7-b74e-ab7ea3033a57', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userskill', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - skillId: 'b75d95d7-6ab8-472d-8103-19d7e642e8f7', - metricValue: 'userskill', - certifierId: '7cf786d9-a8c0-48ed-a7cc-09dcf91d904c', - certifiedDate: '2019-07-08T00:00:00.000Z', - originalTopic: 'u-bahn.action.create' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'user', - id: '391a3656-9a01-47d4-8c6d-64b68c44f213', - handle: 'user', - originalTopic: 'u-bahn.action.create' - } - } - ], - Update: [ - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'user', - id: '391a3656-9a01-47d4-8c6d-64b68c44f213', - handle: 'update_user', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievementprovider', - id: '7b4f98b1-5831-45fe-a71f-8454d11eb8e8', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievement', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - achievementsProviderId: '7b4f98b1-5831-45fe-a72f-8454d11eb8e8', - name: 'update_name', - uri: 'https://facebook.com', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'attributegroup', - id: '720c34f9-0fd4-46fd-9293-4a8cfdcd3e96', - organizationId: '017733ad-4704-4c7e-ae60-36b3332731df', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'externalprofile', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - organizationId: 'e2aecf8b-532d-4625-b8e2-575110b9f944', - uri: 'https://facebook.com', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'organization', - id: '603d4264-cdb0-47f1-914e-f053abc60422', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'role', - id: '188446f1-02dc-4fc7-b74e-ab7ea3033a57', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skillprovider', - id: '2375564d-c5eb-4b80-9b35-465c6b700ac1', - name: 'update_skillprovider', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skill', - id: 'a75d95d7-6ab8-472d-8103-19d7e642e8f7', - skillProviderId: '2375564d-c5eb-4b80-9b35-465c6b700ac1', - externalId: 'ba395d36-6ce8-4bd1-9d6c-754f0389abcb', - uri: 'https://facebook.com', - name: 'update_skill', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userattribute', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - attributeId: 'b5a50f73-08e2-43d1-a78a-4652f15d950e', - value: 'update_userattribute', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userskill', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - skillId: 'b75d95d7-6ab8-472d-8103-19d7e642e8f7', - metricValue: 'update_userskill', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievement', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - achievementsProviderId: 'A77326d8-ef16-4be0-b844-d5c384b7bb8b', - name: 'update_name', - uri: 'https://facebook.com', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievementprovider', - id: 'Ab4f98b1-5831-45fe-a71f-8454d11eb8e8', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'attributegroup', - id: 'A20c34f9-0fd4-46fd-9293-4a8cfdcd3e96', - organizationId: 'A17733ad-4704-4c7e-ae60-36b3332731df', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'externalprofile', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - organizationId: 'A2aecf8b-532d-4625-b8e2-575110b9f944', - uri: 'https://facebook.com', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'organization', - id: 'A03d4264-cdb0-47f1-914e-f053abc60422', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'role', - id: 'A88446f1-02dc-4fc7-b74e-ab7ea3033a57', - name: 'update_name', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skill', - id: 'A75d95d7-6ab8-472d-8103-19d7e642e8f7', - skillProviderId: '63061b84-9784-4b71-b695-4a777eeb7601', - externalId: 'ba395d36-6ce8-4bd1-9d6c-754f0389abcb', - uri: 'https://facebook.com', - name: 'update_skill', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skillprovider', - id: 'A375564d-c5eb-4b80-9b35-465c6b700ac1', - name: 'update_skillprovider', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'user', - id: 'A91a3656-9a01-47d4-8c6d-64b68c44f212', - handle: 'update_user', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userattribute', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - attributeId: 'A5a50f73-08e2-43d1-a78a-4652f15d950e', - value: 'update_userattribute', - originalTopic: 'u-bahn.action.update' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userskill', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - skillId: 'Aa8c8d3a-9165-4dae-8a8c-f828cbe01d5d', - metricValue: 'update_userskill', - originalTopic: 'u-bahn.action.update' - } - } - ], - Delete: [ - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievement', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - achievementsProviderId: '7b4f98b1-5831-45fe-a72f-8454d11eb8e8', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'achievementprovider', - id: '7b4f98b1-5831-45fe-a71f-8454d11eb8e8', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'attributegroup', - id: '720c34f9-0fd4-46fd-9293-4a8cfdcd3e96', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'externalprofile', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - organizationId: 'e2aecf8b-532d-4625-b8e2-575110b9f944', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'organization', - id: '603d4264-cdb0-47f1-914e-f053abc60422', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'role', - id: '188446f1-02dc-4fc7-b74e-ab7ea3033a57', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skill', - id: 'a75d95d7-6ab8-472d-8103-19d7e642e8f7', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'skillprovider', - id: '2375564d-c5eb-4b80-9b35-465c6b700ac1', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userattribute', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - attributeId: 'b5a50f73-08e2-43d1-a78a-4652f15d950e', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userrole', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - roleId: '288446f1-02dc-4fc7-b74e-ab7ea3033a57', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'userskill', - userId: '391a3656-9a01-47d4-8c6d-64b68c44f212', - skillId: 'b75d95d7-6ab8-472d-8103-19d7e642e8f7', - originalTopic: 'u-bahn.action.delete' - } - }, - { - topic: 'u-bahn.action.aggregate', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - resource: 'user', - id: '391a3656-9a01-47d4-8c6d-64b68c44f212', - originalTopic: 'u-bahn.action.delete' - } - } - ] - }, - groupsTopics: { - addData: { - topic: 'groups.notification.member.add', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - id: 'c2f302cf-759a-4847-8acd-843e258359db', - groupId: '036cc9c1-189a-4cf6-853b-0f5bc9b4ce75', - oldId: '20000309', - name: 'House Stark', - createdAt: '2020-09-11T13:14:54.108Z', - createdBy: '8547899', - universalUID: '391a3656-9a01-47d4-8c6d-64b68c44f212', - membershipType: 'user' - } - }, - deleteData: { - topic: 'groups.notification.member.delete', - originator: 'u-bahn-api', - timestamp: '2019-07-08T00:00:00.000Z', - 'mime-type': 'application/json', - payload: { - groupId: '036cc9c1-189a-4cf6-853b-0f5bc9b4ce75', - name: '.NET Taas Project', - oldId: '20000335', - memberId: '00000000', - universalUID: '391a3656-9a01-47d4-8c6d-64b68c44f212' - } - } - } -} diff --git a/test/common/testHelper.js b/test/common/testHelper.js deleted file mode 100644 index cba1d1a..0000000 --- a/test/common/testHelper.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Contains generic helper methods - */ -const _ = require('lodash') -const config = require('config') -const helper = require('../../src/common/helper') -const { topResources, userResources, organizationResources } = require('../../src/common/constants') - -var client -(async function () { - client = await helper.getESClient() -})() - -/** - * Get record from ES. - * @param {Object} kafka message payload - * @return {Object} the record entity - */ -async function getESRecord (payload) { - if (topResources[payload.resource]) { - const ret = await client.getSource({ - index: topResources[payload.resource].index, - type: topResources[payload.resource].type, - id: payload.id - }) - return ret.body - } else if (organizationResources[payload.resource]) { - const orgResource = organizationResources[payload.resource] - const { org } = await helper.getOrg(payload.organizationId) - if (!org || !org[orgResource.propertyName] || !_.some(org[orgResource.propertyName], [orgResource.relateKey, payload[orgResource.relateKey]])) { - const err = Error('[resource_not_found_exception]') - err.statusCode = 404 - throw err - } - return _.find(org[orgResource.propertyName], [orgResource.relateKey, payload[orgResource.relateKey]]) - } else { - const userResource = userResources[payload.resource] - const { user } = await helper.getUser(payload.userId) - if (!user || !user[userResource.propertyName] || !_.some(user[userResource.propertyName], [userResource.relateKey, payload[userResource.relateKey]])) { - const err = Error('[resource_not_found_exception]') - err.statusCode = 404 - throw err - } - return _.find(user[userResource.propertyName], [userResource.relateKey, payload[userResource.relateKey]]) - } -} - -/** - * Get user groups record from ES. - * @param {string} userId the user id - * @param {string} groupId the group id - */ -async function getESGroupRecord (userId, groupId) { - const propertyName = config.get('ES.USER_GROUP_PROPERTY_NAME') - const { user } = await helper.getUser(userId) - if (!user || !user[propertyName] || !_.some(user[propertyName], { id: groupId })) { - const err = Error('[resource_not_found_exception]') - err.statusCode = 404 - throw err - } - return _.find(user[propertyName], { id: groupId }) -} - -/** - * Get expect value. - * @param {object} payload message payload - * @param {array} relationRecord test payload list - */ -function getExpectValue (payload, relationRecord) { - const result = _.omit(payload, ['resource', 'originalTopic']) - if (topResources[payload.resource] && topResources[payload.resource].ingest) { - if (topResources[payload.resource].pipeline) { - _.each(topResources[payload.resource].pipeline.processors, p => { - const relationResource = _.keys(_.pickBy(topResources, value => value.enrich && value.enrich.policyName === p.policyName))[0] - if (relationResource) { - const record = _.find(relationRecord, r => r.payload.resource === relationResource && payload[p.field] === r.payload.id) - if (record) { - result[p.referenceField] = _.pick(record.payload, topResources[relationResource].enrich.enrichFields) - } - } - }) - } else { - const relationResource = _.keys(_.pickBy(topResources, value => value.enrich && value.pipeline && value.pipeline.id === topResources[payload.resource].ingest.pipeline.id))[0] - if (relationResource) { - const record = _.find(relationRecord, r => r.payload.resource === relationResource && payload[topResources[relationResource].pipeline.field] === r.payload[topResources[relationResource].enrich.matchField]) - if (record) { - result[topResources[relationResource].pipeline.targetField] = _.pick(record.payload, topResources[relationResource].enrich.enrichFields) - } - } - } - } - return result -} - -module.exports = { - getESRecord, - getESGroupRecord, - getExpectValue -} diff --git a/test/common/view-data.js b/test/common/view-data.js deleted file mode 100644 index 9490edf..0000000 --- a/test/common/view-data.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This is used to view Elasticsearch data of given id - * Usage: - * node test/view-data {elasticsearch-id} - */ -const _ = require('lodash') -const logger = require('../../src/common/logger') -const helper = require('../../src/common/helper') -const { topResources } = require('../../src/common/constants') - -let client - -if (process.argv.length < 4) { - logger.error('Missing argument for Resource and Elasticsearch id.') - process.exit() -} - -const view = async (resource, id) => { - if (!client) { - client = await helper.getESClient() - } - if (_.includes(_.keys(topResources), resource)) { - const ret = await client.getSource({ index: topResources[resource].index, type: topResources[resource].type, id }) - logger.info('Elasticsearch data:') - logger.info(JSON.stringify(ret.body, null, 4)) - } else { - logger.warn(`resource is invalid, it should in [${_.keys(topResources)}]`) - } -} - -view(process.argv[2], process.argv[3]).then(() => { - process.exit() -}).catch((e) => { - if (e.statusCode === 404) { - logger.info('The data is not found.') - } else { - logger.error(e) - } - process.exit() -}) diff --git a/test/e2e/test.js b/test/e2e/test.js deleted file mode 100644 index 77253e2..0000000 --- a/test/e2e/test.js +++ /dev/null @@ -1,345 +0,0 @@ -/** - * E2E test of the UBahn ES Processor. - */ -global.Promise = require('bluebird') -process.env.NODE_ENV = 'test' - -const _ = require('lodash') -const config = require('config') -const helper = require('../../src/common/helper') -const { topResources, userResources, organizationResources } = require('../../src/common/constants') -const request = require('superagent') -const Kafka = require('no-kafka') -const should = require('should') -const logger = require('../../src/common/logger') -const { fields, testTopics, groupsTopics } = require('../common/testData') -const { checkEmpty, clearData } = require('../common/init-es') -const { getESRecord, getESGroupRecord, getExpectValue } = require('../common/testHelper') - -describe('UBahn - Elasticsearch Data Processor E2E Test', () => { - let app - let infoLogs = [] - let errorLogs = [] - let debugLogs = [] - const info = logger.info - const error = logger.error - const debug = logger.debug - - const producer = new Kafka.Producer(helper.getKafkaOptions()) - - /** - * Sleep with time from input - * @param time the time input - */ - async function sleep (time) { - await new Promise((resolve) => { - setTimeout(resolve, time) - }) - } - - /** - * Send message - * @param testMessage the test message - */ - async function sendMessage (testMessage) { - await producer.send({ - topic: testMessage.topic, - message: { - value: JSON.stringify(testMessage) - } - }) - } - - /** - * Consume not committed messages before e2e test - */ - async function consumeMessages () { - // remove all not processed messages - const consumer = new Kafka.GroupConsumer(helper.getKafkaOptions()) - await consumer.init([{ - subscriptions: [config.UBAHN_AGGREGATE_TOPIC, config.GROUPS_MEMBER_ADD_TOPIC, config.GROUPS_MEMBER_DELETE_TOPIC], - handler: (messageSet, topic, partition) => Promise.each(messageSet, - (m) => consumer.commitOffset({ topic, partition, offset: m.offset })) - }]) - // make sure process all not committed messages before test - await sleep(2 * config.WAIT_TIME) - await consumer.end() - } - - /** - * Wait job finished with successful log or error log is found - */ - async function waitJob () { - while (true) { - if (errorLogs.length > 0) { - break - } - if (debugLogs.some(x => String(x).includes('Successfully processed message'))) { - break - } - // use small time to wait job and will use global timeout so will not wait too long - await sleep(config.WAIT_TIME) - } - } - - function assertErrorMessage (message) { - errorLogs.should.not.be.empty() - errorLogs.some(x => String(x).includes(message)).should.be.true() - } - - before(async () => { - const isESEmpty = await checkEmpty() - if (!isESEmpty) { - throw Error('Can not run e2e test when elastic search already have data') - } - - // inject logger with log collector - logger.info = (message) => { - infoLogs.push(message) - info(message) - } - logger.debug = (message) => { - debugLogs.push(message) - debug(message) - } - logger.error = (message) => { - errorLogs.push(message) - error(message) - } - await consumeMessages() - // start kafka producer - await producer.init() - // start the application (kafka listener) - app = require('../../src/app') - // wait until consumer init successfully - while (true) { - if (infoLogs.some(x => String(x).includes('Kick Start'))) { - break - } - await sleep(config.WAIT_TIME) - } - }) - - after(async () => { - // restore logger - logger.error = error - logger.info = info - logger.debug = debug - - try { - await producer.end() - } catch (err) { - // ignore - } - try { - await app.end() - } catch (err) { - // ignore - } - - await clearData() - }) - - beforeEach(() => { - // clear logs - infoLogs = [] - debugLogs = [] - errorLogs = [] - }) - - it('Should setup healthcheck with check on kafka connection', async () => { - const healthcheckEndpoint = `http://localhost:${process.env.PORT || 3000}/health` - const result = await request.get(healthcheckEndpoint) - should.equal(result.status, 200) - should.deepEqual(result.body, { checksRun: 1 }) - debugLogs.should.match(/connected=true/) - }) - - it('Should handle invalid json message', async () => { - await producer.send({ - topic: testTopics.Create[0].topic, - message: { - value: '[ invalid' - } - }) - await waitJob() - should.equal(errorLogs[0], 'Invalid message JSON.') - }) - - it('Should handle incorrect topic field message', async () => { - const message = _.cloneDeep(testTopics.Create[0]) - message.topic = 'invalid' - await producer.send({ - topic: testTopics.Create[0].topic, - message: { - value: JSON.stringify(message) - } - }) - await waitJob() - should.equal(errorLogs[0], 'The message topic invalid doesn\'t match the Kafka topic u-bahn.action.aggregate.') - }) - - for (const op of ['Create', 'Update', 'Delete']) { - for (let i = 0; i < testTopics[op].length; i++) { - const resource = _.upperFirst(testTopics[op][i].payload.resource) - it(`process ${_.lowerFirst(op)} ${resource} success`, async () => { - if (op === 'Delete' || (op === 'Update' && i < 11)) { - // ensure document exist before delete or update - try { - await getESRecord(testTopics[op][i].payload) - } catch (e) { - throw new Error('should not throw error here') - } - } - - if (op !== 'Update' || i < 11) { - await sendMessage(testTopics[op][i]) - await waitJob() - } - - if (op === 'Delete') { - // ensure document not exist after delete - try { - await getESRecord(testTopics[op][i].payload) - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 404) - e.message.includes('resource_not_found_exception').should.be.true() - } - } else if (op !== 'Update' || i < 11) { - const ret = await getESRecord(testTopics[op][i].payload) - if (testTopics[op][i].payload.resource === 'user') { - should.equal(ret.handle, testTopics[op][i].payload.handle) - } else { - // should.deepEqual(ret, _.omit(testTopics[op][i].payload, ['resource', 'originalTopic'])) - should.deepEqual(ret, getExpectValue(testTopics[op][i].payload, testTopics[op])) - } - } - }) - - if (op === 'Update' && i >= 11) { - // ensure document doesn't exist before update - // when perform update operation later, it will throw error - it(`failure - process update ${resource} with document doesn't exist`, async () => { - await sendMessage(testTopics[op][i]) - await waitJob() - if (topResources[_.lowerFirst(resource)]) { - assertErrorMessage('Response Error') - } else { - assertErrorMessage('resource_not_found_exception') - } - }) - } - - if (op === 'Create' && !topResources[_.lowerFirst(resource)]) { - it(`failure - process create ${resource} with duplicate id`, async () => { - await sendMessage(testTopics[op][i]) - await waitJob() - - assertErrorMessage('version_conflict_engine_exception') - }) - } - - if (op === 'Delete') { - it(`failure - process delete ${resource} not found`, async () => { - await sendMessage(testTopics[op][i]) - await waitJob() - if (topResources[_.lowerFirst(resource)]) { - assertErrorMessage('Response Error') - } else { - assertErrorMessage('resource_not_found_exception') - } - }) - } - } - - for (const resourceKey in fields) { - const messageIndex = fields[resourceKey][`${_.lowerFirst(op)}Index`] - // there is not update role test data - if (!messageIndex) { - continue - } - for (const requiredField of fields[resourceKey].requiredFields) { - it(`test process ${_.lowerFirst(op)} ${resourceKey} message with invalid parameters, required field ${requiredField} is missing`, async () => { - let message = _.cloneDeep(testTopics[op][messageIndex]) - message = _.omit(message, requiredField) - - await sendMessage(message) - await waitJob() - - assertErrorMessage(`"${_.last(requiredField.split('.'))}" is required`) - }) - - if (requiredField !== 'payload.resource') { - it(`test process ${_.lowerFirst(op)} ${resourceKey} message with invalid parameters, invalid string field ${requiredField}`, async () => { - const message = _.cloneDeep(testTopics[op][messageIndex]) - _.set(message, requiredField, '12345') - - await sendMessage(message) - await waitJob() - - assertErrorMessage(`"${_.last(requiredField.split('.'))}" must be a valid GUID`) - }) - } - } - } - - it(`test process ${_.lowerFirst(op)} message with incorrect resource, message is ignored`, async () => { - const message = _.cloneDeep(testTopics[op][0]) - message.payload.resource = 'invalid' - - await sendMessage(message) - await waitJob() - - should.equal(_.last(infoLogs), `Ignore this message since resource is not in [${_.union(_.keys(topResources), _.keys(userResources), _.keys(organizationResources))}]`) - }) - } - - describe('UBahn - Elasticsearch Groups Processor E2E Test', () => { - before(async () => { - await sendMessage(testTopics.Create[0]) - await waitJob() - await sleep(1000) - }) - - after(async () => { - await sendMessage(testTopics.Delete[11]) - await waitJob() - }) - - it(`test process add groups member message success`, async () => { - const message = groupsTopics.addData.payload - await sendMessage(groupsTopics.addData) - await waitJob() - await sleep(1000) - const ret = await getESGroupRecord(message.universalUID, message.groupId) - const { groupId, name: groupName } = message - should.deepEqual(ret, { id: groupId, name: groupName }) - }) - - it(`test process add groups member message with duplicate id`, async () => { - await sendMessage(groupsTopics.addData) - await waitJob() - assertErrorMessage('[version_conflict_engine_exception]') - }) - - it(`test process add groups member message with ignore membershipType`, async () => { - const message = _.cloneDeep(groupsTopics.addData) - message.payload.membershipType = 'ignore' - await sendMessage(message) - await waitJob() - should.equal(_.last(infoLogs), `Ignoring this groups member add message since membershipType is not 'user'`) - }) - - it(`test process remove groups member message success`, async () => { - await sendMessage(groupsTopics.deleteData) - await waitJob() - }) - - it(`test process remove groups member message with user not exist in group`, async () => { - await sendMessage(groupsTopics.deleteData) - await waitJob() - assertErrorMessage('resource_not_found_exception') - }) - }) -}) diff --git a/test/unit/prepare.js b/test/unit/prepare.js deleted file mode 100644 index 0a25c27..0000000 --- a/test/unit/prepare.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Setting up Mock for all tests - */ - -// During the test the env variable is set to test -process.env.NODE_ENV = 'test' - -const _ = require('lodash') -const nock = require('nock') -const prepare = require('mocha-prepare') - -const content = {} - -prepare(function (done) { - // called before loading of test cases - nock(/.com|localhost/) - .persist() - .put(uri => uri.includes('_create')) - .query(true) - .reply((uri, body) => { - const id = _.nth(_.split(uri, '/'), -2) - if (content[id]) { - return [409] - } else { - content[id] = body - return [200] - } - }) - .post(uri => uri.includes('_update')) - .query(true) - .reply((uri, body) => { - const id = _.nth(_.split(uri, '/'), -2) - if (content[id]) { - content[id] = body.doc - return [200] - } else { - return [404] - } - }) - .put(uri => uri.includes('_doc')) - .query(true) - .reply((uri, body) => { - const id = _.last(_.split(uri, '/')).split('?')[0] - content[id] = body - return [200] - }) - .delete(() => true) - .query(true) - .reply(uri => { - const id = _.last(_.split(uri, '/')).split('?')[0] - if (content[id]) { - _.unset(content, id) - return [204] - } else { - return [404] - } - }) - .get(uri => uri.includes('_source')) - .query(true) - .reply(uri => { - const id = _.nth(_.split(uri, '/'), -2) - if (content[id]) { - return [200, content[id]] - } else { - return [404] - } - }) - .get(uri => uri.includes('_doc')) - .query(true) - .reply(uri => { - const id = _.last(_.split(uri, '/')).split('?')[0] - if (content[id]) { - return [200, { '_source': content[id] }] - } else { - return [404] - } - }) - .put(uri => uri.includes('_enrich')) - .query(true) - .reply(200) - .get(() => true) - .query(true) - .reply(404) - done() -}, function (done) { - // called after all test completes (regardless of errors) - _.unset(content, '*') - nock.cleanAll() - done() -}) diff --git a/test/unit/test.js b/test/unit/test.js deleted file mode 100644 index 4f8d8fa..0000000 --- a/test/unit/test.js +++ /dev/null @@ -1,239 +0,0 @@ -/** - * Mocha tests of the UBahn ES Processor. - */ - -process.env.NODE_ENV = 'test' -global.Promise = require('bluebird') -const _ = require('lodash') -const should = require('should') -const helper = require('../../src/common/helper') -const logger = require('../../src/common/logger') -const { topResources, userResources, organizationResources } = require('../../src/common/constants') -const service = require('../../src/services/ProcessorService') -const groupsProcessorService = require('../../src/services/GroupsProcessorService') -const { fields, testTopics, groupsTopics } = require('../common/testData') -const { getESRecord, getESGroupRecord } = require('../common/testHelper') - -describe('UBahn - Elasticsearch Data Processor Unit Test', () => { - let infoLogs = [] - let errorLogs = [] - let debugLogs = [] - const info = logger.info - const error = logger.error - const debug = logger.debug - - /** - * Assert validation error - * @param err the error - * @param message the message - */ - const assertValidationError = (err, message) => { - err.isJoi.should.be.true() - should.equal(err.name, 'ValidationError') - err.details.map(x => x.message).should.containEql(message) - errorLogs.should.not.be.empty() - } - - before(async () => { - // inject logger with log collector - logger.info = (message) => { - infoLogs.push(message) - info(message) - } - logger.debug = (message) => { - debugLogs.push(message) - debug(message) - } - logger.error = (message) => { - errorLogs.push(message) - error(message) - } - }) - - after(async () => { - // restore logger - logger.error = error - logger.info = info - logger.debug = debug - }) - - beforeEach(() => { - // clear logs - infoLogs = [] - debugLogs = [] - errorLogs = [] - }) - - for (const op of ['Create', 'Update', 'Delete']) { - for (let i = 0; i < testTopics[op].length; i++) { - const resource = _.upperFirst(testTopics[op][i].payload.resource) - it(`process ${_.lowerFirst(op)} ${resource} success`, async () => { - if (op === 'Delete' || (op === 'Update' && i < 11)) { - // ensure document exist before delete or update - try { - await getESRecord(testTopics[op][i].payload) - } catch (e) { - throw new Error('should not throw error here') - } - } - - if (op !== 'Update' || i < 11) { - await service[`process${op}`](testTopics[op][i], 'transaction_11111') - } - - if (op === 'Delete') { - // ensure document not exist after delete - try { - await getESRecord(testTopics[op][i].payload) - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 404) - } - } else if (op !== 'Update' || i < 11) { - const ret = await getESRecord(testTopics[op][i].payload) - if (testTopics[op][i].payload.resource === 'user') { - should.equal(ret.handle, testTopics[op][i].payload.handle) - } else { - should.deepEqual(ret, _.omit(testTopics[op][i].payload, ['resource', 'originalTopic'])) - } - } - }) - - if (op === 'Update' && i >= 11) { - // ensure document doesn't exist before update - // when perform update operation later, it will throw error - it(`failure - process update ${resource} with document doesn't exist`, async () => { - try { - await service[`process${op}`](testTopics[op][i], 'transaction_11111') - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 404) - helper.checkEsMutexRelease('transaction_11111') - } - }) - } - - if (op === 'Create' && !topResources[_.lowerFirst(resource)]) { - it(`failure - process create ${resource} with duplicate id`, async () => { - try { - await service.processCreate(testTopics[op][i], 'transaction_11111') - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 409) - helper.checkEsMutexRelease('transaction_11111') - } - }) - } - - if (op === 'Delete') { - it(`failure - process delete ${resource} not found`, async () => { - try { - await service.processDelete(testTopics[op][i], 'transaction_11111') - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 404) - if (topResources[_.lowerFirst(resource)]) { - should.equal(e.message, 'Response Error') - } else { - should.equal(e.message, '[resource_not_found_exception]') - helper.checkEsMutexRelease('transaction_11111') - } - } - }) - } - } - - for (const resourceKey in fields) { - const messageIndex = fields[resourceKey][`${_.lowerFirst(op)}Index`] - // there is not update role test data - if (!messageIndex || op !== 'Update') { - continue - } - for (const requiredField of fields[resourceKey].requiredFields) { - it(`test process ${_.lowerFirst(op)} ${resourceKey} message with invalid parameters, required field ${requiredField} is missing`, async () => { - let message = _.cloneDeep(testTopics[op][messageIndex]) - message = _.omit(message, requiredField) - try { - await service[`process${op}`](message, 'transaction_11111') - throw new Error('should not throw error here') - } catch (err) { - assertValidationError(err, `"${_.last(requiredField.split('.'))}" is required`) - } - }) - if (requiredField !== 'payload.resource') { - it(`test process ${_.lowerFirst(op)} ${resourceKey} message with invalid parameters, invalid string field ${requiredField}`, async () => { - const message = _.cloneDeep(testTopics[op][messageIndex]) - _.set(message, requiredField, '12345') - try { - await service[`process${op}`](message, 'transaction_11111') - throw new Error('should not throw error here') - } catch (err) { - assertValidationError(err, `"${_.last(requiredField.split('.'))}" must be a valid GUID`) - } - }) - } - } - } - - it(`test process ${_.lowerFirst(op)} message with incorrect resource, message is ignored`, async () => { - const message = _.cloneDeep(testTopics[op][0]) - message.payload.resource = 'invalid' - await service[`process${op}`](message, 'transaction_11111') - should.equal(_.last(infoLogs), `Ignore this message since resource is not in [${_.union(_.keys(topResources), _.keys(userResources), _.keys(organizationResources))}]`) - }) - } - - describe('UBahn - Elasticsearch Groups Processor Unit Test', () => { - before(async () => { - await service.processCreate(testTopics.Create[0], 'transaction_11111') - }) - - after(async () => { - await service.processDelete(testTopics.Delete[11], 'transaction_11111') - }) - - it(`test process add groups member message success`, async () => { - const message = groupsTopics.addData.payload - await groupsProcessorService.processMemberAdd(groupsTopics.addData, 'transaction_11111') - const ret = await getESGroupRecord(message.universalUID, message.groupId) - const { groupId, name: groupName } = message - should.deepEqual(ret, { id: groupId, name: groupName }) - }) - - it(`test process add groups member message with duplicate id`, async () => { - try { - await groupsProcessorService.processMemberAdd(groupsTopics.addData, 'transaction_11111') - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 409) - } - }) - - it(`test process add groups member message with ignore membershipType`, async () => { - const message = _.cloneDeep(groupsTopics.addData) - message.payload.membershipType = 'ignore' - await groupsProcessorService.processMemberAdd(message, 'transaction_11111') - should.equal(_.last(infoLogs), `Ignoring this groups member add message since membershipType is not 'user'`) - }) - - it(`test process remove groups member message success`, async () => { - const message = groupsTopics.deleteData.payload - await groupsProcessorService.processMemberDelete(groupsTopics.deleteData, 'transaction_11111') - try { - await getESGroupRecord(message.universalUID, message.groupId) - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 404) - } - }) - - it(`test process remove groups member message with user not exist in group`, async () => { - try { - await groupsProcessorService.processMemberDelete(groupsTopics.deleteData, 'transaction_11111') - throw new Error('should not throw error here') - } catch (e) { - should.equal(e.statusCode, 404) - } - }) - }) -})