From d4be22e25fb5220306d6fc174be703c3e91ce9df Mon Sep 17 00:00:00 2001 From: yoution Date: Tue, 7 Jan 2020 22:26:28 +0800 Subject: [PATCH 1/9] New Fields for Project Templates --- migrations/elasticsearch_sync.js | 6 ++++++ src/services/ProcessorServiceProjectTemplate.js | 2 ++ test/data/project.template/project.action.create.json | 2 +- test/e2e/processor.metadata.index.test.js | 10 ++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/migrations/elasticsearch_sync.js b/migrations/elasticsearch_sync.js index 655f6e5..162fd24 100644 --- a/migrations/elasticsearch_sync.js +++ b/migrations/elasticsearch_sync.js @@ -359,6 +359,12 @@ function getRequestBody (indexName) { type: 'string', index: 'not_analyzed' }, + subCategory: { + type: 'string' + }, + metadata: { + type: 'object' + }, name: { type: 'string' }, diff --git a/src/services/ProcessorServiceProjectTemplate.js b/src/services/ProcessorServiceProjectTemplate.js index dc3330e..89eda98 100644 --- a/src/services/ProcessorServiceProjectTemplate.js +++ b/src/services/ProcessorServiceProjectTemplate.js @@ -58,6 +58,8 @@ function createSchema () { name: Joi.string().max(255).required(), key: Joi.string().max(45).required(), category: Joi.string().max(45).required(), + subCategory: Joi.string().max(45).empty(null), + metadata: Joi.object(), icon: Joi.string().max(255).required(), question: Joi.string().max(255).required(), info: Joi.string().max(255).required(), diff --git a/test/data/project.template/project.action.create.json b/test/data/project.template/project.action.create.json index aa1cfc1..42b5d8d 100644 --- a/test/data/project.template/project.action.create.json +++ b/test/data/project.template/project.action.create.json @@ -1 +1 @@ -{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T02:00:27.369Z","mime-type":"application/json","payload":{"resource":"project.template","createdAt":"2019-06-21T02:00:27.263Z","updatedAt":"2019-06-21T02:00:27.264Z","disabled":false,"hidden":false,"id":1,"name":"new name","key":"new key 2","category":"app","icon":"http://example.com/icon1.ico","question":"question 1","info":"info 1","aliases":["key-1","key_1"],"scope":{"scope1":"scope 1"},"phases":{"phase1":"phase 1"},"createdBy":40051333,"updatedBy":40051333,"form":null,"planConfig":null,"priceConfig":null,"deletedAt":null,"deletedBy":null}} \ No newline at end of file +{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T02:00:27.369Z","mime-type":"application/json","payload":{"resource":"project.template","createdAt":"2019-06-21T02:00:27.263Z","updatedAt":"2019-06-21T02:00:27.264Z","disabled":false,"hidden":false,"id":1,"name":"new name","key":"new key 2","metadata":{},"subCategory":"app","category":"app","icon":"http://example.com/icon1.ico","question":"question 1","info":"info 1","aliases":["key-1","key_1"],"scope":{"scope1":"scope 1"},"phases":{"phase1":"phase 1"},"createdBy":40051333,"updatedBy":40051333,"form":null,"planConfig":null,"priceConfig":null,"deletedAt":null,"deletedBy":null}} diff --git a/test/e2e/processor.metadata.index.test.js b/test/e2e/processor.metadata.index.test.js index ea47583..0dd714b 100644 --- a/test/e2e/processor.metadata.index.test.js +++ b/test/e2e/processor.metadata.index.test.js @@ -423,6 +423,16 @@ describe('TC Project Template Topic Tests', () => { _.keys(_.omit(projectTemplateCreatedMessage.payload, ['resource']))) }) + it('create project template add subCategory and metadata correctly', async () => { + await ProcessorService.create(projectTemplateCreatedMessage) + const data = await testHelper.getMetadataESData(metadataId) + let projectTemplate = _.find(data.projectTemplates, { id: projectTemplateId }) + expect(projectTemplate).to.have.property('subCategory') + expect(projectTemplate).to.have.property('metadata') + expect(projectTemplate.subCategory).to.eql('app') + expect(projectTemplate.metadata).to.eql({}) + }) + it('create project template message - already exists', async () => { await ProcessorService.create(projectTemplateCreatedMessage) const data = await testHelper.getMetadataESData(metadataId) From 74a25137c0d483ba8357ffa718e7a547b0605465 Mon Sep 17 00:00:00 2001 From: yoution Date: Fri, 10 Jan 2020 17:28:54 +0800 Subject: [PATCH 2/9] Improve local setup --- README.md | 101 +++++++++++++++++----------- docker-es/docker-compose.yml | 6 -- local/docker-compose.yml | 28 ++++++++ local/kafka-client/Dockerfile | 5 ++ local/kafka-client/create-topics.sh | 5 ++ local/kafka-client/topics.txt | 3 + 6 files changed, 103 insertions(+), 45 deletions(-) delete mode 100644 docker-es/docker-compose.yml create mode 100644 local/docker-compose.yml create mode 100644 local/kafka-client/Dockerfile create mode 100755 local/kafka-client/create-topics.sh create mode 100644 local/kafka-client/topics.txt diff --git a/README.md b/README.md index 15c2086..cf2b33c 100644 --- a/README.md +++ b/README.md @@ -40,40 +40,24 @@ Also note that there is a `/health` endpoint that checks for the health of the a Config for tests are at `config/test.js`, it overrides some default config. -## Local Kafka setup -- Call extracted directory kafka_2.11-0.11.0.1 : `path_to_kafka` -- Call our project root directory : `our_project_root_directory` -- `http://kafka.apache.org/quickstart` contains details to setup and manage Kafka server, - below provides details to setup Kafka server in Mac, Windows will use bat commands in bin/windows instead -- Download kafka at `https://www.apache.org/dyn/closer.cgi?path=/kafka/1.1.0/kafka_2.11-1.1.0.tgz` -- Extract out the doanlowded tgz file -- Go to extracted directory kafka_2.11-0.11.0.1 -- Start ZooKeeper server: - `bin/zookeeper-server-start.sh config/zookeeper.properties` -- Use another terminal, go to same directory, start the Kafka server: - `bin/kafka-server-start.sh config/server.properties` -- Note that the zookeeper server is at localhost:2181, and Kafka server is at localhost:9092 -- Use another terminal, go to same directory, create some topics: - `bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic project.action.create` - `bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic project.action.update` - `bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic project.action.delete` -- Verify that the topics are created: - `bin/kafka-topics.sh --list --zookeeper localhost:2181`, - it should list out the created topics -- run the producer and then write some message into the console to send to the `project.action.create` topic: - `bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.create` - in the console, write message, one message per line: - `{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-20T13:43:25.817Z","mime-type":"application/json","payload":{"resource":"project","createdAt":"2019-06-20T13:43:23.554Z","updatedAt":"2019-06-20T13:43:23.555Z","terms":[],"id":1,"name":"test project","description":"Hello I am a test project","type":"app","createdBy":40051333,"updatedBy":40051333,"projectEligibility":[],"bookmarks":[],"external":null,"status":"draft","lastActivityAt":"2019-06-20T13:43:23.514Z","lastActivityUserId":"40051333","members":[{"createdAt":"2019-06-20T13:43:23.555Z","updatedAt":"2019-06-20T13:43:23.625Z","id":2,"isPrimary":true,"role":"manager","userId":40051333,"updatedBy":40051333,"createdBy":40051333,"projectId":2,"deletedAt":null,"deletedBy":null}],"version":"v2","directProjectId":null,"billingAccountId":null,"estimatedPrice":null,"actualPrice":null,"details":null,"cancelReason":null,"templateId":null,"deletedBy":null,"attachments":null,"phases":null,"projectUrl":"https://connect.topcoder-dev.com/projects/2"}}` -- Optionally, use another terminal, go to same directory, start a consumer to view the messages: - `bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic project.action.create --from-beginning` -- If the kafka don't allow to input long message you can use this script to write message from file: - `path_to_kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.create < our_project_root_directory/test/data/project/project.action.create.json` -- Writing/reading messages to/from other topics are similar. All example for messages are in: -`our_project_root_directory/test/data` -## Local Elasticsearch setup +### Local Deployment for Kafka + +* There exists an alternate `docker-compose.yml` file that can be used to spawn containers for the following services: + + | Service | Name | Port | + |----------|:-----:|:----:| + | ElasticSearch | esearch | 9200 | + | Zookeeper | zookeeper | 2181 | + | Kafka | kafka | 9092 | -- In the `docker-es` folder, run `docker-compose up` +* To have kafka create a list of desired topics on startup, there exists a file with the path `local/kafka-client/topics.txt`. Each line from the file will be added as a topic. +* To run these services simply run the following commands: + + ```bash + cd local + docker-compose up -d + ``` ## Local deployment - Install dependencies `npm i` @@ -135,12 +119,10 @@ npm run test:cov ``` ## Verification - -- Call extracted directory kafka_2.11-0.11.0.1 : `path_to_kafka` - Call our project root directory : `our_project_root_directory` -- Start kafka server, start elasticsearch, initialize Elasticsearch, start processor app +- Start Docker servicees, initialize Elasticsearch, start processor app - Send message: - `path_to_kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.create < our_project_root_directory/test/data/project/project.action.create.json` + `docker exec -i tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.create.json` - run command `npm run view-data projects 1` to view the created data, you will see the data are properly created: ```bash @@ -193,7 +175,8 @@ info: { - Run the producer and then write some invalid message into the console to send to the `project.action.create` topic: - `bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.create` + + `docker exec -it tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092` in the console, write message, one message per line: `{ "topic": "project.action.create", "originator": "project-api", "timestamp": "2019-02-16T00:00:00", "mime-type": "application/json", "payload": { "id": "invalid", "typeId": "8e17090c-465b-4c17-b6d9-dfa16300b0ff", "track": "Code", "name": "test", "description": "desc", "timelineTemplateId": "8e17090c-465b-4c17-b6d9-dfa16300b0aa", "phases": [{ "id": "8e17090c-465b-4c17-b6d9-dfa16300b012", "name": "review", "isActive": true, "duration": 10000 }], "prizeSets": [{ "type": "prize", "prizes": [{ "type": "winning prize", "value": 500 }] }], "reviewType": "code review", "tags": ["code"], "projectId": 123, "forumId": 456, "status": "Active", "created": "2019-02-16T00:00:00", "createdBy": "admin" } }` @@ -203,7 +186,8 @@ info: { - Then in the app console, you will see error messages - Sent message to update data: - `path_to_kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.update < our_project_root_directory/test/data/project/project.action.update.json` + + `docker exec -i tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.update --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.update.json` - Run command `npm run view-data projects 1` to view the updated data, you will see the data are properly updated: ```bash @@ -258,7 +242,7 @@ info: { - Run the producer and then write some invalid message into the console to send to the `project.action.create` topic: - `bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.create` + `docker exec -it tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create` in the console, write message, one message per line: `{ "topic": "project.action.update", "originator": "project-api", "timestamp": "2019-02-17T01:00:00", "mime-type": "application/json", "payload": { "id": "173803d3-019e-4033-b1cf-d7205c7f774c", "typeId": "123", "track": "Code", "name": "test3", "description": "desc3", "timelineTemplateId": "8e17090c-465b-4c17-b6d9-dfa16300b0dd", "groups": ["group2", "group3"], "updated": "2019-02-17T01:00:00", "updatedBy": "admin" } }` @@ -270,3 +254,42 @@ info: { - To test the health check API, run `export PORT=5000`, start the processor, then browse `http://localhost:5000/health` in a browser, and you will see result `{"checksRun":1}` + + + +### Kafka Commands + +If you've used `docker-compose` with the file `local/docker-compose.yml` to spawn kafka & zookeeper, you can use the following commands to manipulate kafka topics and messages: +(Replace TOPIC_NAME with the name of the desired topic) + +**Create Topic** + +```bash +docker exec tc-projects-kafka /opt/kafka/bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic TOPIC_NAME +``` + +**List Topics** + +```bash +docker exec tc-projects-kafka /opt/kafka/bin/kafka-topics.sh --list --zookeeper zookeeper:2181 +``` + +**Watch Topic** + +```bash +docker exec tc-projects-kafka /opt/kafka/bin/kafka-console-consumer --bootstrap-server localhost:9092 --zookeeper zookeeper:2181 --topic TOPIC_NAME +``` + +**Post Message to Topic** + +```bash +docker exec -it tc-projects-kafka /opt/kafka/bin/kafka-console-producer --topic TOPIC_NAME --broker-list localhost:9092 +``` +The message can be passed using `stdin` + +### Test +```bash +docker exec -i tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < test_message.json + +``` +All example for messages are in: our_project_root_directory/test/data diff --git a/docker-es/docker-compose.yml b/docker-es/docker-compose.yml deleted file mode 100644 index efc2bdc..0000000 --- a/docker-es/docker-compose.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: "2" -services: - esearch: - image: "elasticsearch:2.3" - ports: - - "9200:9200" diff --git a/local/docker-compose.yml b/local/docker-compose.yml new file mode 100644 index 0000000..b1775aa --- /dev/null +++ b/local/docker-compose.yml @@ -0,0 +1,28 @@ +version: "2" +services: + esearch: + image: "elasticsearch:2.3" + ports: + - "9200:9200" + zookeeper: + image: confluent/zookeeper + ports: + - "2181:2181" + environment: + zk_id: "1" + kafka: + image: wurstmeister/kafka + container_name: tc-projects-kafka + depends_on: + - zookeeper + ports: + - "9092:9092" + environment: + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092 + KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + kafka-client: + build: ./kafka-client + depends_on: + - kafka + - zookeeper diff --git a/local/kafka-client/Dockerfile b/local/kafka-client/Dockerfile new file mode 100644 index 0000000..3d332b8 --- /dev/null +++ b/local/kafka-client/Dockerfile @@ -0,0 +1,5 @@ +From confluent/kafka +WORKDIR /app/ +COPY topics.txt . +COPY create-topics.sh . +ENTRYPOINT ["/app/create-topics.sh"] diff --git a/local/kafka-client/create-topics.sh b/local/kafka-client/create-topics.sh new file mode 100755 index 0000000..c5b33e6 --- /dev/null +++ b/local/kafka-client/create-topics.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +while read topic; do + /usr/bin/kafka-topics --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic $topic +done < topics.txt diff --git a/local/kafka-client/topics.txt b/local/kafka-client/topics.txt new file mode 100644 index 0000000..0dde473 --- /dev/null +++ b/local/kafka-client/topics.txt @@ -0,0 +1,3 @@ +project.action.create +project.action.delete +project.action.update From 3ae25a2d72b911f19fe5bc96874100dba2a52b39 Mon Sep 17 00:00:00 2001 From: yoution Date: Sun, 12 Jan 2020 15:12:29 +0800 Subject: [PATCH 3/9] change confluent/kafka to wurstmeister/kafka --- README.md | 18 +++++++++--------- local/docker-compose.yml | 4 ++-- local/kafka-client/Dockerfile | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index cf2b33c..0641777 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ npm run test:cov - Call our project root directory : `our_project_root_directory` - Start Docker servicees, initialize Elasticsearch, start processor app - Send message: - `docker exec -i tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.create.json` + `docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.create.json` - run command `npm run view-data projects 1` to view the created data, you will see the data are properly created: ```bash @@ -176,7 +176,7 @@ info: { - Run the producer and then write some invalid message into the console to send to the `project.action.create` topic: - `docker exec -it tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092` + `docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092` in the console, write message, one message per line: `{ "topic": "project.action.create", "originator": "project-api", "timestamp": "2019-02-16T00:00:00", "mime-type": "application/json", "payload": { "id": "invalid", "typeId": "8e17090c-465b-4c17-b6d9-dfa16300b0ff", "track": "Code", "name": "test", "description": "desc", "timelineTemplateId": "8e17090c-465b-4c17-b6d9-dfa16300b0aa", "phases": [{ "id": "8e17090c-465b-4c17-b6d9-dfa16300b012", "name": "review", "isActive": true, "duration": 10000 }], "prizeSets": [{ "type": "prize", "prizes": [{ "type": "winning prize", "value": 500 }] }], "reviewType": "code review", "tags": ["code"], "projectId": 123, "forumId": 456, "status": "Active", "created": "2019-02-16T00:00:00", "createdBy": "admin" } }` @@ -187,7 +187,7 @@ info: { - Sent message to update data: - `docker exec -i tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.update --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.update.json` + `docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.update --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.update.json` - Run command `npm run view-data projects 1` to view the updated data, you will see the data are properly updated: ```bash @@ -242,7 +242,7 @@ info: { - Run the producer and then write some invalid message into the console to send to the `project.action.create` topic: - `docker exec -it tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create` + `docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create` in the console, write message, one message per line: `{ "topic": "project.action.update", "originator": "project-api", "timestamp": "2019-02-17T01:00:00", "mime-type": "application/json", "payload": { "id": "173803d3-019e-4033-b1cf-d7205c7f774c", "typeId": "123", "track": "Code", "name": "test3", "description": "desc3", "timelineTemplateId": "8e17090c-465b-4c17-b6d9-dfa16300b0dd", "groups": ["group2", "group3"], "updated": "2019-02-17T01:00:00", "updatedBy": "admin" } }` @@ -265,31 +265,31 @@ If you've used `docker-compose` with the file `local/docker-compose.yml` to spaw **Create Topic** ```bash -docker exec tc-projects-kafka /opt/kafka/bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic TOPIC_NAME +docker exec project-processor-es-kafka /opt/kafka/bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic TOPIC_NAME ``` **List Topics** ```bash -docker exec tc-projects-kafka /opt/kafka/bin/kafka-topics.sh --list --zookeeper zookeeper:2181 +docker exec project-processor-es-kafka /opt/kafka/bin/kafka-topics.sh --list --zookeeper zookeeper:2181 ``` **Watch Topic** ```bash -docker exec tc-projects-kafka /opt/kafka/bin/kafka-console-consumer --bootstrap-server localhost:9092 --zookeeper zookeeper:2181 --topic TOPIC_NAME +docker exec project-processor-es-kafka /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --zookeeper zookeeper:2181 --topic TOPIC_NAME ``` **Post Message to Topic** ```bash -docker exec -it tc-projects-kafka /opt/kafka/bin/kafka-console-producer --topic TOPIC_NAME --broker-list localhost:9092 +docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic TOPIC_NAME --broker-list localhost:9092 ``` The message can be passed using `stdin` ### Test ```bash -docker exec -i tc-projects-kafka /opt/kafka//bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < test_message.json +docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < test_message.json ``` All example for messages are in: our_project_root_directory/test/data diff --git a/local/docker-compose.yml b/local/docker-compose.yml index b1775aa..e066659 100644 --- a/local/docker-compose.yml +++ b/local/docker-compose.yml @@ -5,14 +5,14 @@ services: ports: - "9200:9200" zookeeper: - image: confluent/zookeeper + image: wurstmeister/zookeeper ports: - "2181:2181" environment: zk_id: "1" kafka: image: wurstmeister/kafka - container_name: tc-projects-kafka + container_name: project-processor-es-kafka depends_on: - zookeeper ports: diff --git a/local/kafka-client/Dockerfile b/local/kafka-client/Dockerfile index 3d332b8..15c2083 100644 --- a/local/kafka-client/Dockerfile +++ b/local/kafka-client/Dockerfile @@ -1,4 +1,4 @@ -From confluent/kafka +From wurstmeister/kafka WORKDIR /app/ COPY topics.txt . COPY create-topics.sh . From 04d3faad11475821479fc4aff05620d12f9e8ddd Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Mon, 13 Jan 2020 12:03:46 +0800 Subject: [PATCH 4/9] feat: improved README to be easier to follow during local setup --- README.md | 199 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 121 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 0641777..0411e1a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,122 @@ - ElasticSearch - Docker, Docker Compose +## Local setup + +1. Install node dependencies: + + ```bash + npm install + ``` + +2. Run docker compose with dependant services: + + ```bash + cd local/ + docker-compose up + ``` + +
Click to see details + + This docker-compose run all the dependencies which are necessary for `project-processor-es` to work. + + | Service | Name | Port | + |----------|:-----:|:----:| + | Elasticsearch | esearch | 9200 | + | Zookeeper | zookeeper | 2181 | + | Kafka | kafka | 9092 | + + `docker-compose` automatically creates Kafka topics which are used by `project-processor-es` listed in `local/kafka-client/topics.txt`. + +
+ + +3. Set environment variables for M2M authentication: `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_URL`, `AUTH0_AUDIENCE`, `AUTH0_PROXY_SERVER_URL`: + + ```bash + export AUTH0_CLIENT_ID= + export AUTH0_CLIENT_SECRET= + export AUTH0_URL= + export AUTH0_AUDIENCE= + export AUTH0_PROXY_SERVER_URL= + ``` + +4. Initialize Elasticsearch indexes: + + ```bash + npm run sync:es + ``` + +5. Start processor app: + + ```bash + npm start + ``` + +## Commands + +### Lint & Tests commands + +| Command | Description | +|----------|--------------| +| `npm run lint` | Run lint check. | +| `npm run lin:fix` | Run lint check with automatic fixing of errors and warnings where possible. | +| `npm run test` | Run integration tests. | +| `npm run test:cov` | Run integration tests with coverage report. | + +### View data in Elasticsearch indexes + +You may run the next command to output documents in the Elasticsearch indexes for debugging purposes. + +```bash +npm run view-data +``` + +##### Examples + +- `npm run view-data projects 1` view document with id `1` in `projects` index +- `npm run view-data timelines 1` view document with id `1` in `timelines` index +- `npm run view-data metadata 1` view document with id `1` in `timelines` index *(this index has only one document and all the data is stored inside one document which might be very big)*. + +### Kafka commands + +If you've used `docker-compose` with the file `local/docker-compose.yml` during local setup to spawn kafka & zookeeper, you can use the following commands to manipulate kafka topics and messages: +(Replace `TOPIC_NAME` with the name of the desired topic) + +#### Create Topic + +```bash +docker exec project-processor-es-kafka /opt/kafka/bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic TOPIC_NAME +``` + +#### List Topics + +```bash +docker exec project-processor-es-kafka /opt/kafka/bin/kafka-topics.sh --list --zookeeper zookeeper:2181 +``` + +#### Watch Topic + +```bash +docker exec project-processor-es-kafka /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic TOPIC_NAME +``` + +#### Post Message to Topic (from stdin) + +```bash +docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic TOPIC_NAME +``` + +- Enter or copy/paste the message into the console after starting this command. + +#### Post Message to Topic (from file) + +```bash +docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < test_message.json +``` + +- All example for messages are in: `./test/data`. + ## Configuration Configuration for the processor is at `config/default.js`. @@ -40,40 +156,6 @@ Also note that there is a `/health` endpoint that checks for the health of the a Config for tests are at `config/test.js`, it overrides some default config. - -### Local Deployment for Kafka - -* There exists an alternate `docker-compose.yml` file that can be used to spawn containers for the following services: - - | Service | Name | Port | - |----------|:-----:|:----:| - | ElasticSearch | esearch | 9200 | - | Zookeeper | zookeeper | 2181 | - | Kafka | kafka | 9092 | - -* To have kafka create a list of desired topics on startup, there exists a file with the path `local/kafka-client/topics.txt`. Each line from the file will be added as a topic. -* To run these services simply run the following commands: - - ```bash - cd local - docker-compose up -d - ``` - -## Local deployment -- Install dependencies `npm i` -- Run code lint check `npm run lint`, running `npm run lint:fix` can fix some lint errors if any -- Initialize Elasticsearch, create configured Elasticsearch index if not present: `npm run sync:es` -- Start processor app `npm start` - -Note that you need to set AUTH0 related environment variables belows before you can start the processor. - -- AUTH0_URL -- AUTH0_AUDIENCE -- TOKEN_CACHE_TIME -- AUTH0_CLIENT_ID -- AUTH0_CLIENT_SECRET -- AUTH0_PROXY_SERVER_URL - ## Local Deployment with Docker To run the Challenge ES Processor using docker, follow the below steps @@ -119,10 +201,10 @@ npm run test:cov ``` ## Verification -- Call our project root directory : `our_project_root_directory` -- Start Docker servicees, initialize Elasticsearch, start processor app +- Start Docker services, initialize Elasticsearch, start processor app +- Navigate to the repository root directory. - Send message: - `docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.create.json` + `docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < ./test/data/project/project.action.create.json` - run command `npm run view-data projects 1` to view the created data, you will see the data are properly created: ```bash @@ -187,7 +269,7 @@ info: { - Sent message to update data: - `docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.update --broker-list localhost:9092 < our_project_root_directory/test/data/project/project.action.update.json` + `docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.update --broker-list localhost:9092 < ./test/data/project/project.action.update.json` - Run command `npm run view-data projects 1` to view the updated data, you will see the data are properly updated: ```bash @@ -242,7 +324,7 @@ info: { - Run the producer and then write some invalid message into the console to send to the `project.action.create` topic: - `docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create` + `docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic project.action.create` in the console, write message, one message per line: `{ "topic": "project.action.update", "originator": "project-api", "timestamp": "2019-02-17T01:00:00", "mime-type": "application/json", "payload": { "id": "173803d3-019e-4033-b1cf-d7205c7f774c", "typeId": "123", "track": "Code", "name": "test3", "description": "desc3", "timelineTemplateId": "8e17090c-465b-4c17-b6d9-dfa16300b0dd", "groups": ["group2", "group3"], "updated": "2019-02-17T01:00:00", "updatedBy": "admin" } }` @@ -254,42 +336,3 @@ info: { - To test the health check API, run `export PORT=5000`, start the processor, then browse `http://localhost:5000/health` in a browser, and you will see result `{"checksRun":1}` - - - -### Kafka Commands - -If you've used `docker-compose` with the file `local/docker-compose.yml` to spawn kafka & zookeeper, you can use the following commands to manipulate kafka topics and messages: -(Replace TOPIC_NAME with the name of the desired topic) - -**Create Topic** - -```bash -docker exec project-processor-es-kafka /opt/kafka/bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic TOPIC_NAME -``` - -**List Topics** - -```bash -docker exec project-processor-es-kafka /opt/kafka/bin/kafka-topics.sh --list --zookeeper zookeeper:2181 -``` - -**Watch Topic** - -```bash -docker exec project-processor-es-kafka /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --zookeeper zookeeper:2181 --topic TOPIC_NAME -``` - -**Post Message to Topic** - -```bash -docker exec -it project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic TOPIC_NAME --broker-list localhost:9092 -``` -The message can be passed using `stdin` - -### Test -```bash -docker exec -i project-processor-es-kafka /opt/kafka/bin/kafka-console-producer.sh --topic project.action.create --broker-list localhost:9092 < test_message.json - -``` -All example for messages are in: our_project_root_directory/test/data From c70bd7d42861eeb75f9d7eb5d4f3a15d3591de93 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Fri, 17 Jan 2020 15:39:56 +0800 Subject: [PATCH 5/9] fix: command to create topics --- local/kafka-client/create-topics.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local/kafka-client/create-topics.sh b/local/kafka-client/create-topics.sh index c5b33e6..a411690 100755 --- a/local/kafka-client/create-topics.sh +++ b/local/kafka-client/create-topics.sh @@ -1,5 +1,5 @@ #!/bin/bash while read topic; do - /usr/bin/kafka-topics --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic $topic + /opt/kafka/bin/kafka-topics.sh --create --zookeeper zookeeper:2181 --partitions 1 --replication-factor 1 --topic $topic done < topics.txt From ef1aa9057a40db561070abaf4739d468f24368a2 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Fri, 17 Jan 2020 16:38:48 +0800 Subject: [PATCH 6/9] chore: fix indents in README --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0411e1a..835bb44 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,13 @@ 3. Set environment variables for M2M authentication: `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_URL`, `AUTH0_AUDIENCE`, `AUTH0_PROXY_SERVER_URL`: - ```bash - export AUTH0_CLIENT_ID= - export AUTH0_CLIENT_SECRET= - export AUTH0_URL= - export AUTH0_AUDIENCE= - export AUTH0_PROXY_SERVER_URL= - ``` + ```bash + export AUTH0_CLIENT_ID= + export AUTH0_CLIENT_SECRET= + export AUTH0_URL= + export AUTH0_AUDIENCE= + export AUTH0_PROXY_SERVER_URL= + ``` 4. Initialize Elasticsearch indexes: @@ -55,9 +55,9 @@ 5. Start processor app: - ```bash - npm start - ``` + ```bash + npm start + ``` ## Commands From 3e11776907f55b2704c41f8fbf44f7ac62da2f1d Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Thu, 30 Jan 2020 18:46:59 +0800 Subject: [PATCH 7/9] feat: increase ProjectTemplate.info allowed size to 1024 --- src/services/ProcessorServiceProjectTemplate.js | 2 +- test/data/project.template/project.action.create.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/ProcessorServiceProjectTemplate.js b/src/services/ProcessorServiceProjectTemplate.js index 89eda98..2cfdb3d 100644 --- a/src/services/ProcessorServiceProjectTemplate.js +++ b/src/services/ProcessorServiceProjectTemplate.js @@ -62,7 +62,7 @@ function createSchema () { metadata: Joi.object(), icon: Joi.string().max(255).required(), question: Joi.string().max(255).required(), - info: Joi.string().max(255).required(), + info: Joi.string().max(1024).required(), aliases: Joi.array().required() }) // TODO rewrite these condition so only one of these must be "present" and "not-null" diff --git a/test/data/project.template/project.action.create.json b/test/data/project.template/project.action.create.json index 42b5d8d..624ad92 100644 --- a/test/data/project.template/project.action.create.json +++ b/test/data/project.template/project.action.create.json @@ -1 +1 @@ -{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T02:00:27.369Z","mime-type":"application/json","payload":{"resource":"project.template","createdAt":"2019-06-21T02:00:27.263Z","updatedAt":"2019-06-21T02:00:27.264Z","disabled":false,"hidden":false,"id":1,"name":"new name","key":"new key 2","metadata":{},"subCategory":"app","category":"app","icon":"http://example.com/icon1.ico","question":"question 1","info":"info 1","aliases":["key-1","key_1"],"scope":{"scope1":"scope 1"},"phases":{"phase1":"phase 1"},"createdBy":40051333,"updatedBy":40051333,"form":null,"planConfig":null,"priceConfig":null,"deletedAt":null,"deletedBy":null}} +{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T02:00:27.369Z","mime-type":"application/json","payload":{"resource":"project.template","createdAt":"2019-06-21T02:00:27.263Z","updatedAt":"2019-06-21T02:00:27.264Z","disabled":false,"hidden":false,"id":1,"name":"new name","key":"new key 2","metadata":{},"subCategory":"app","category":"app","icon":"http://example.com/icon1.ico","question":"question 1","info":"info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters","aliases":["key-1","key_1"],"scope":{"scope1":"scope 1"},"phases":{"phase1":"phase 1"},"createdBy":40051333,"updatedBy":40051333,"form":null,"planConfig":null,"priceConfig":null,"deletedAt":null,"deletedBy":null}} From 5fa17456bbf646039b8b6f64fc49bcd96e490afe Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Fri, 31 Jan 2020 09:44:45 +0800 Subject: [PATCH 8/9] feat: increase ProjectType's and ProductCategory's "info" field allowed size to 1024 --- src/services/ProcessorServiceProductCategory.js | 2 +- src/services/ProcessorServiceProjectType.js | 2 +- test/data/product.category/project.action.create.json | 2 +- test/data/project.type/project.action.create.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/ProcessorServiceProductCategory.js b/src/services/ProcessorServiceProductCategory.js index 5f66073..4cd486b 100644 --- a/src/services/ProcessorServiceProductCategory.js +++ b/src/services/ProcessorServiceProductCategory.js @@ -47,7 +47,7 @@ function createSchema () { displayName: Joi.string().max(255).required(), icon: Joi.string().max(255).required(), question: Joi.string().max(255).required(), - info: Joi.string().max(255).required(), + info: Joi.string().max(1024).required(), aliases: Joi.array().required() }) .unknown(true) diff --git a/src/services/ProcessorServiceProjectType.js b/src/services/ProcessorServiceProjectType.js index 90b9268..962aefb 100644 --- a/src/services/ProcessorServiceProjectType.js +++ b/src/services/ProcessorServiceProjectType.js @@ -44,7 +44,7 @@ function createSchema () { displayName: Joi.string().max(255).required(), icon: Joi.string().max(255).required(), question: Joi.string().max(255).required(), - info: Joi.string().max(255).required(), + info: Joi.string().max(1024).required(), aliases: Joi.array().required(), metadata: Joi.object().required() }) diff --git a/test/data/product.category/project.action.create.json b/test/data/product.category/project.action.create.json index cc64219..af53903 100644 --- a/test/data/product.category/project.action.create.json +++ b/test/data/product.category/project.action.create.json @@ -1 +1 @@ -{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T04:36:00.714Z","mime-type":"application/json","payload":{"resource":"product.category","createdAt":"2019-06-21T04:36:00.684Z","updatedAt":"2019-06-21T04:36:00.684Z","disabled":false,"hidden":false,"key":"generic","displayName":"new displayName","icon":"icon","question":"question","info":"info","form":[],"aliases":[{"key-1":"key-1"},{"key-2":"key-2"}],"createdBy":40135978,"updatedBy":40135978,"deletedAt":null,"deletedBy":null}} \ No newline at end of file +{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T04:36:00.714Z","mime-type":"application/json","payload":{"resource":"product.category","createdAt":"2019-06-21T04:36:00.684Z","updatedAt":"2019-06-21T04:36:00.684Z","disabled":false,"hidden":false,"key":"generic","displayName":"new displayName","icon":"icon","question":"question","info":"info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters","form":[],"aliases":[{"key-1":"key-1"},{"key-2":"key-2"}],"createdBy":40135978,"updatedBy":40135978,"deletedAt":null,"deletedBy":null}} \ No newline at end of file diff --git a/test/data/project.type/project.action.create.json b/test/data/project.type/project.action.create.json index 05909be..ee94d95 100644 --- a/test/data/project.type/project.action.create.json +++ b/test/data/project.type/project.action.create.json @@ -1 +1 @@ -{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T02:13:37.666Z","mime-type":"application/json","payload":{"resource":"project.type","createdAt":"2019-06-21T02:13:37.620Z","updatedAt":"2019-06-21T02:13:37.620Z","disabled":false,"hidden":false,"id": 1,"key":"new key","displayName":"new displayName","icon":"http://example.com/icon4.ico","question":"question 4","info":"info 4","aliases":["key-41","key_42"],"metadata":{},"createdBy":40051333,"updatedBy":40051333,"deletedAt":null,"deletedBy":null}} \ No newline at end of file +{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T02:13:37.666Z","mime-type":"application/json","payload":{"resource":"project.type","createdAt":"2019-06-21T02:13:37.620Z","updatedAt":"2019-06-21T02:13:37.620Z","disabled":false,"hidden":false,"id": 1,"key":"new key","displayName":"new displayName","icon":"http://example.com/icon4.ico","question":"question 4","info":"info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters, info which is very long and more than 255 characters","aliases":["key-41","key_42"],"metadata":{},"createdBy":40051333,"updatedBy":40051333,"deletedAt":null,"deletedBy":null}} \ No newline at end of file From 40290800d94614caf2a78e3ee3a0c4ab03b1cf3d Mon Sep 17 00:00:00 2001 From: hesibo Date: Wed, 19 Feb 2020 20:09:03 +0800 Subject: [PATCH 9/9] add handler for project member invite delete event --- package-lock.json | 869 +++++++++++++++++- src/services/ProcessorServiceProject.js | 2 +- .../ProcessorServiceProjectMemberInvite.js | 38 +- test/common/testData.js | 4 + .../project.action.create.json | 2 +- .../project.action.delete.json | 1 + .../project.action.update.json | 2 +- test/e2e/processor.project.index.test.js | 19 + 8 files changed, 892 insertions(+), 45 deletions(-) create mode 100644 test/data/project.member.invite/project.action.delete.json diff --git a/package-lock.json b/package-lock.json index d971540..6205390 100644 --- a/package-lock.json +++ b/package-lock.json @@ -186,11 +186,88 @@ "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.0.tgz", "integrity": "sha1-JjNHCk6r6aR82aRf2yDtX5NAe8o=" }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz", + "integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-jwt": { + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.42.tgz", + "integrity": "sha512-WszgUddvM1t5dPpJ3LhWNH8kfNN8GPIBrAGxgIYXVCEGx6Bx4A036aAuf/r5WH9DIEdlmp7gHOYvSM6U87B0ag==", + "requires": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz", + "integrity": "sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==", + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/express-unless": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.1.tgz", + "integrity": "sha512-5fuvg7C69lemNgl0+v+CUxDYWVPSfXHhJPst4yTLcqi4zKJpORCxnDrnnilk3k0DTq/WrAUdvXFs01+vUqUZHw==", + "requires": { + "@types/express": "*" + } + }, "@types/lodash": { "version": "4.14.134", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.134.tgz", "integrity": "sha512-2/O0khFUCFeDlbi7sZ7ZFRCcT812fAeOLm7Ev4KbwASkZ575TDrDcY7YyaoHdTOzKcNbfiwLYZqPmoC4wadrsw==" }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" + }, + "@types/node": { + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.1.tgz", + "integrity": "sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==" + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -224,7 +301,6 @@ "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -299,6 +375,19 @@ "es-abstract": "^1.7.0" } }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -313,6 +402,25 @@ "lodash": "^4.17.11" } }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "auth0-js": { + "version": "9.12.2", + "resolved": "https://registry.npmjs.org/auth0-js/-/auth0-js-9.12.2.tgz", + "integrity": "sha512-0VfPu5UcgkGKQc7Q8KPqgkqqhLgXGsDCro2tde7hHPYK9JEzOyq82v0szUTHWlwQE1VT8K2/qZAsGDf7hFjI7g==", + "requires": { + "base64-js": "^1.3.0", + "idtoken-verifier": "^2.0.1", + "js-cookie": "^2.2.0", + "qs": "^6.7.0", + "superagent": "^3.8.3", + "url-join": "^4.0.1", + "winchan": "^0.2.2" + } + }, "aws-sdk": { "version": "2.480.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.480.0.tgz", @@ -329,6 +437,24 @@ "xml2js": "0.4.19" } }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + }, + "axios": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.12.0.tgz", + "integrity": "sha1-uQewIhzDTsHJ+sGOx/B935V4W6Q=", + "requires": { + "follow-redirects": "0.0.7" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -340,17 +466,40 @@ "js-tokens": "^3.0.2" } }, + "babel-runtime": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.6.1.tgz", + "integrity": "sha1-eIuUtvY04luRvWxd9y1GdFevsAA=", + "requires": { + "core-js": "^2.1.0" + } + }, + "backoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", + "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "requires": { + "precond": "0.2" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, "bin-protocol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/bin-protocol/-/bin-protocol-3.1.1.tgz", @@ -387,7 +536,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -414,6 +562,22 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -452,6 +616,11 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -545,6 +714,21 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "codependency": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/codependency/-/codependency-0.1.4.tgz", + "integrity": "sha1-0XY6tyZL1wyR2WJumIYtN5K/jUo=", + "requires": { + "semver": "5.0.1" + }, + "dependencies": { + "semver": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.1.tgz", + "integrity": "sha1-n7P0AE+QDYPEeWj+QvdYPgWDLMk=" + } + } + }, "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", @@ -595,6 +779,14 @@ "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==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", @@ -608,11 +800,15 @@ "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==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "config": { "version": "3.1.0", @@ -665,6 +861,16 @@ "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==" + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -696,6 +902,19 @@ "which": "^1.2.9" } }, + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -778,6 +997,11 @@ } } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -813,6 +1037,39 @@ "esutils": "^2.0.2" } }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + } + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -909,6 +1166,11 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1422,6 +1684,11 @@ "vary": "~1.1.2" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "external-editor": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", @@ -1433,17 +1700,20 @@ "tmp": "^0.0.33" } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-levenshtein": { "version": "2.0.6", @@ -1549,6 +1819,15 @@ "write": "^0.2.1" } }, + "follow-redirects": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", + "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", + "requires": { + "debug": "^2.2.0", + "stream-consume": "^0.1.0" + } + }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", @@ -1571,6 +1850,26 @@ } } }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "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==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -1631,6 +1930,14 @@ "pump": "^3.0.0" } }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", @@ -1677,6 +1984,20 @@ } } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1758,6 +2079,16 @@ "toidentifier": "1.0.0" } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -1774,6 +2105,19 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "idtoken-verifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/idtoken-verifier/-/idtoken-verifier-2.0.1.tgz", + "integrity": "sha512-sLLFPPc6D6Ske7JNHHrrWHbQKuY1OJN9GcJd6Y1LjMvInJBr26Axbo6o07JYPPTRUzJahBWHudabgFoNo23lMw==", + "requires": { + "base64-js": "^1.3.0", + "crypto-js": "^3.1.9-1", + "es6-promise": "^4.2.8", + "jsbn": "^1.1.0", + "unfetch": "^4.1.0", + "url-join": "^4.0.1" + } + }, "ieee754": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", @@ -1795,7 +2139,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1942,6 +2285,11 @@ "has-symbols": "^1.0.0" } }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1968,6 +2316,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "istanbul-lib-coverage": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", @@ -2082,6 +2435,11 @@ "topo": "3.x.x" } }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -2098,17 +2456,26 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" + }, "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", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -2116,6 +2483,11 @@ "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=" + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -2124,6 +2496,34 @@ "minimist": "^1.2.0" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "jsx-ast-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz", @@ -2133,6 +2533,49 @@ "array-includes": "^3.0.3" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jwks-rsa": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.6.2.tgz", + "integrity": "sha512-c/mFFq/wVXSkHzHGH+hLUwLeRKSCofNHJZKPzHho4YmO9LGwAazk7akfABvWhduS9OejWvqBS2jA69YeruEvNA==", + "requires": { + "@types/express-jwt": "0.0.42", + "debug": "^4.1.0", + "jsonwebtoken": "^8.5.1", + "limiter": "^1.1.4", + "lru-memoizer": "^2.0.1", + "ms": "^2.1.2", + "request": "^2.88.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", @@ -2150,6 +2593,26 @@ "invert-kv": "^2.0.0" } }, + "le_node": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/le_node/-/le_node-1.8.0.tgz", + "integrity": "sha512-NXzjxBskZ4QawTNwlGdRG05jYU0LhV2nxxmP3x7sRMHyROV0jPdyyikO9at+uYrWX3VFt0Y/am11oKITedx0iw==", + "requires": { + "babel-runtime": "6.6.1", + "codependency": "0.1.4", + "json-stringify-safe": "5.0.1", + "lodash": "4.17.11", + "reconnect-core": "1.3.0", + "semver": "5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz", + "integrity": "sha1-hfLPhVBGXE3wAM99hvawVBBqueU=" + } + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2160,6 +2623,11 @@ "type-check": "~0.3.2" } }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -2195,12 +2663,52 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -2277,6 +2785,26 @@ "yallist": "^2.1.2" } }, + "lru-memoizer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.0.tgz", + "integrity": "sha512-oKjxgJhL+m1wfEkez7/a6iyRZUdohej+2u04qCaAQ7BBfx/qD4RH3jOQhPsd8Y3pcm7IhcNtE3kCEIDCMPiJFQ==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", + "requires": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + } + } + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -2339,6 +2867,11 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "millisecond": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/millisecond/-/millisecond-0.1.2.tgz", + "integrity": "sha1-bMWtOGJByrjniv+WT4cCjuyS2sU=" + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -2367,7 +2900,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2381,7 +2913,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" }, @@ -2389,8 +2920,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, @@ -2465,6 +2995,12 @@ } } }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "optional": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2481,12 +3017,59 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + } + } + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "optional": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -2605,6 +3188,11 @@ "yargs-parser": "^13.0.0" } }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2651,7 +3239,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -2819,8 +3406,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -2868,6 +3454,11 @@ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -2955,6 +3546,11 @@ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, + "precond": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", + "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -3000,8 +3596,12 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" }, "pump": { "version": "3.0.0", @@ -3081,6 +3681,14 @@ "util-deprecate": "^1.0.1" } }, + "reconnect-core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reconnect-core/-/reconnect-core-1.3.0.tgz", + "integrity": "sha1-+65SkZp4d9hE4yRtAaLyZwHIM8g=", + "requires": { + "backoff": "~2.5.0" + } + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -3096,6 +3704,50 @@ "es6-error": "^4.0.1" } }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3189,6 +3841,12 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "optional": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3202,8 +3860,7 @@ "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "send": { "version": "0.17.1", @@ -3355,6 +4012,29 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + } + } + }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -3394,6 +4074,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stream-consume": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==" + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -3455,6 +4140,55 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -3511,6 +4245,21 @@ } } }, + "tc-core-library-js": { + "version": "github:appirio-tech/tc-core-library-js#d16413db30b1eed21c0cf426e185bedb2329ddab", + "from": "github:appirio-tech/tc-core-library-js#v2.6", + "requires": { + "auth0-js": "^9.4.2", + "axios": "^0.12.0", + "bunyan": "^1.8.12", + "jsonwebtoken": "^8.3.0", + "jwks-rsa": "^1.3.0", + "le_node": "^1.3.1", + "lodash": "^4.17.10", + "millisecond": "^0.1.2", + "request": "^2.88.0" + } + }, "test-exclude": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", @@ -3570,6 +4319,22 @@ "hoek": "6.x.x" } }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -3581,6 +4346,19 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -3625,6 +4403,11 @@ } } }, + "unfetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.1.0.tgz", + "integrity": "sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg==" + }, "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", @@ -3640,7 +4423,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" }, @@ -3648,8 +4430,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" } } }, @@ -3662,6 +4443,19 @@ "querystring": "0.2.0" } }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, + "urlencode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/urlencode/-/urlencode-1.1.0.tgz", + "integrity": "sha1-HyuibwE8hfATP3o61v8nMK33y7c=", + "requires": { + "iconv-lite": "~0.4.11" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3692,6 +4486,16 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -3716,6 +4520,11 @@ "string-width": "^1.0.2 || 2" } }, + "winchan": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/winchan/-/winchan-0.2.2.tgz", + "integrity": "sha512-pvN+IFAbRP74n/6mc6phNyCH8oVkzXsto4KCHPJ2AScniAnA1AmeLI03I2BzjePpaClGSI4GUMowzsD3qz5PRQ==" + }, "winston": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", @@ -3806,8 +4615,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", @@ -3866,8 +4674,7 @@ "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { "version": "13.2.2", diff --git a/src/services/ProcessorServiceProject.js b/src/services/ProcessorServiceProject.js index 1f5568d..becf604 100644 --- a/src/services/ProcessorServiceProject.js +++ b/src/services/ProcessorServiceProject.js @@ -47,7 +47,7 @@ function createSchema () { createdAt: Joi.date(), createdBy: Joi.number().integer().positive(), updatedAt: Joi.date(), - updatedBy: Joi.number().integer().positive(), + updatedBy: Joi.number().integer().positive() })).optional().allow(null), external: Joi.object().keys({ id: Joi.string(), diff --git a/src/services/ProcessorServiceProjectMemberInvite.js b/src/services/ProcessorServiceProjectMemberInvite.js index c80e15f..afa31c1 100644 --- a/src/services/ProcessorServiceProjectMemberInvite.js +++ b/src/services/ProcessorServiceProjectMemberInvite.js @@ -22,6 +22,7 @@ function createSchema () { .email() .optional() .allow(null), + hashEmail: Joi.string().optional().allow(null), status: Joi.any() .valid(_.values(INVITE_STATUS)) .required() @@ -52,22 +53,22 @@ create.schema = { message: createSchema() } +// handle ES Update or Delete on invites +const updateInvitesPromise = message => async (doc) => { + // now merge the updated changes and re-index the document + const invites = _.isArray(doc._source.invites) ? doc._source.invites : [] + _.remove(invites, invite => (!!message.email && invite.email === message.email) || + (!!message.userId && invite.userId === message.userId)) + return _.assign(doc._source, { invites }) +} + /** * Update message in Elasticsearch. * @param {Object} message the challenge updated message * @return {Promise} promise result */ async function update (message) { - // handle ES Update - async function updateDocPromise (doc) { - // now merge the updated changes and reindex the document - const invites = _.isArray(doc._source.invites) ? doc._source.invites : [] - _.remove(invites, invite => (!!message.email && invite.email === message.email) || - (!!message.userId && invite.userId === message.userId)) - return _.assign(doc._source, { invites }) - } - - await helper.updateProjectESPromise(message.projectId, updateDocPromise) + await helper.updateProjectESPromise(message.projectId, updateInvitesPromise(message)) logger.debug(`Member invite updated successfully in elasticsearch index, (memberInviteId: ${message.id})`) } @@ -75,10 +76,25 @@ update.schema = { message: createSchema() } +/** + * Delete message in Elasticsearch. + * @param {Object} message the deleted message + * @return {Promise} promise result + */ +async function deleteMessage (message) { + await helper.updateProjectESPromise(message.projectId, updateInvitesPromise(message)) + logger.debug(`Member invite deleted successfully in elasticsearch index, (memberInviteId: ${message.id})`) +} + +deleteMessage.schema = { + message: createSchema() +} + // Exports module.exports = { create, - update + update, + deleteMessage } logger.buildService(module.exports) diff --git a/test/common/testData.js b/test/common/testData.js index 493df0e..64218cc 100644 --- a/test/common/testData.js +++ b/test/common/testData.js @@ -100,6 +100,9 @@ const projectMemberInviteCreatedMessage = require( const projectMemberInviteUpdatedMessage = require( '../data/project.member.invite/project.action.update.json' ) +const projectMemberInviteDeletedMessage = require( + '../data/project.member.invite/project.action.delete.json' +) const orgConfigCreatedMessage = require('../data/project.orgConfig/project.action.create.json') const orgConfigUpdatedMessage = require('../data/project.orgConfig/project.action.update.json') const orgConfigDeletedMessage = require('../data/project.orgConfig/project.action.delete.json') @@ -202,6 +205,7 @@ module.exports = { orgConfigDeletedMessage, projectMemberInviteUpdatedMessage, projectMemberInviteCreatedMessage, + projectMemberInviteDeletedMessage, projectMemberUpdatedMessage, projectMemberCreatedMessage, projectMemberDeletedMessage, diff --git a/test/data/project.member.invite/project.action.create.json b/test/data/project.member.invite/project.action.create.json index b071d6c..0cb3342 100644 --- a/test/data/project.member.invite/project.action.create.json +++ b/test/data/project.member.invite/project.action.create.json @@ -1 +1 @@ -{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T04:58:12.671Z","mime-type":"application/json","payload":{"resource":"project.member.invite","createdAt":"2019-06-21T04:58:12.594Z","updatedAt":"2019-06-21T04:58:12.594Z","id":1,"projectId":1,"role":"customer","status":"pending","createdBy":40051334,"updatedBy":40051334,"userId":40051331,"email":null,"deletedAt":null,"deletedBy":null}} \ No newline at end of file +{"topic":"project.action.create","originator":"project-api","timestamp":"2019-06-21T04:58:12.671Z","mime-type":"application/json","payload":{"resource":"project.member.invite","createdAt":"2019-06-21T04:58:12.594Z","updatedAt":"2019-06-21T04:58:12.594Z","id":1,"projectId":1,"role":"customer","status":"pending","createdBy":40051334,"updatedBy":40051334,"userId":40051331,"email":"test@topcoder.com","hashEmail":"dummy_value","deletedAt":null,"deletedBy":null}} \ No newline at end of file diff --git a/test/data/project.member.invite/project.action.delete.json b/test/data/project.member.invite/project.action.delete.json new file mode 100644 index 0000000..df59a68 --- /dev/null +++ b/test/data/project.member.invite/project.action.delete.json @@ -0,0 +1 @@ +{"topic":"project.action.update","originator":"project-api","timestamp":"2019-06-21T04:59:38.562Z","mime-type":"application/json","payload":{"resource":"project.member.invite","status":"canceled","userId":40051331,"email":"test@topcoder.com","hashEmail":"dummy_value","id":1,"projectId":1}} \ No newline at end of file diff --git a/test/data/project.member.invite/project.action.update.json b/test/data/project.member.invite/project.action.update.json index 36e1188..10f58cd 100644 --- a/test/data/project.member.invite/project.action.update.json +++ b/test/data/project.member.invite/project.action.update.json @@ -1 +1 @@ -{"topic":"project.action.update","originator":"project-api","timestamp":"2019-06-21T04:59:38.562Z","mime-type":"application/json","payload":{"resource":"project.member.invite","status":"pending","userId":40051331,"email":"test@topcoder.com","id":1,"projectId":1}} \ No newline at end of file +{"topic":"project.action.update","originator":"project-api","timestamp":"2019-06-21T04:59:38.562Z","mime-type":"application/json","payload":{"resource":"project.member.invite","status":"pending","userId":40051331,"email":"test@topcoder.com","hashEmail":"dummy_value","id":1,"projectId":1}} \ No newline at end of file diff --git a/test/e2e/processor.project.index.test.js b/test/e2e/processor.project.index.test.js index 6dbfec8..ae12eb1 100644 --- a/test/e2e/processor.project.index.test.js +++ b/test/e2e/processor.project.index.test.js @@ -23,6 +23,7 @@ const { projectMemberInviteId, projectMemberInviteUpdatedMessage, projectMemberInviteCreatedMessage, + projectMemberInviteDeletedMessage, projectMemberUpdatedMessage, projectMemberCreatedMessage, projectMemberDeletedMessage, @@ -891,6 +892,24 @@ describe('TC Project Member Invite Topic Tests', () => { expect(_.find(data.invites, { id: notFoundId })).to.be.an('undefined') }) + it('delete project member invite message', async () => { + await ProcessorService.create(projectMemberInviteCreatedMessage) + let data = await testHelper.getProjectESData(projectId) + testHelper.expectObj(_.find(data.invites, { id: projectMemberInviteId }), projectMemberInviteCreatedMessage.payload, + _.keys(_.omit(projectMemberInviteCreatedMessage.payload, ['resource']))) + await ProcessorService.deleteMessage(projectMemberInviteDeletedMessage) + data = await testHelper.getProjectESData(projectId) + expect(_.find(data.invites, { id: projectMemberInviteId })).to.be.an('undefined') + }) + + it('delete project member invite message - not found', async () => { + const message = _.cloneDeep(projectMemberInviteDeletedMessage) + message.payload.id = notFoundId + await ProcessorService.deleteMessage(message) + const data = await testHelper.getProjectESData(projectId) + expect(_.find(data.invites, { id: notFoundId })).to.be.an('undefined') + }) + it('test logger', async () => { /** * test long array