From 09731374e8966af23bc579d350baed2fd1c82752 Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Sun, 11 Mar 2018 21:49:46 -0700 Subject: [PATCH 01/11] WIP: Add script to build coverage badge for README (#63) * Add script to build coverage badge for README * Fix linting issues * Use Webtask API to update coverage badge --- .travis.yml | 2 +- README.md | 19 ++++++++----------- config/lcov2badge.js | 32 ++++++++++++++++++++++++++++++++ package.json | 4 +++- 4 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 config/lcov2badge.js diff --git a/.travis.yml b/.travis.yml index 0e88807..60d3426 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,4 +16,4 @@ script: - npm run lint - npm run test:check-coverage after_script: - # - npm run report-coverage + - npm run report-coverage diff --git a/README.md b/README.md index dda85b2..cf283b0 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,21 @@ [![logo](https://i.imgur.com/3OtP3p8.png)](https://softwareengineeringdaily.com/) -# SEDaily Event Stream Processor +# SEDaily Logging, Monitoring, and Analytics -The real time event processing infrastructure gateway server for the Software Engineering Daily [Android](https://github.com/SoftwareEngineeringDaily/SEDaily-Android), [iOS](https://github.com/SoftwareEngineeringDaily/se-daily-iOS), and [web front end](https://github.com/SoftwareEngineeringDaily/sedaily-front-end). The SEDaily event stream is responsible for authenticating connecting clients and validating event payload schemas before putting the event on the SED event bus. Interested clients can subscribe to events on the stream. +The real time event processing infrastructure gateway server for the Software Engineering Daily [Android](https://github.com/SoftwareEngineeringDaily/SEDaily-Android), [iOS](https://github.com/SoftwareEngineeringDaily/se-daily-iOS), and [web front end](https://github.com/SoftwareEngineeringDaily/sedaily-front-end). The SEDaily event stream is responsible for validating event payload schemas before putting the event into InfluxDB. The resulting database is queried using Grafana to get up to the second analytics reporting. - - +
+ + +
## Getting Started ```sh -$ git clone https://github.com/SoftwareEngineeringDaily/sedaily-event-stream.git -$ cd sedaily-event-stream +$ git clone https://github.com/SoftwareEngineeringDaily/sedaily-devops.git +$ cd sedaily-devops ``` ### Set up (local) - - Install and run a local [InfluxDB](https://github.com/influxdata/influxdb) client - `cp .env.local_example .env` - `npm install` or `yarn install` @@ -26,10 +27,6 @@ $ cd sedaily-event-stream - Run `docker-compose up` - If dependencies are updated in package.json, run `docker-compose down` and then `docker-compose up --build`. This will remove the old container and rebuild the API image which installs the new dependencies. -## Current State - -The current state of the SEDaily event stream is analytics focused. The event stream backend relies on Redis Streams, which is only currently available in the [`unstable`](https://github.com/antirez/redis/tree/unstable) branch. Until it is stable, the SEDaily event stream will only directly input events into InfluxDB. Data analytics can be run against queries on the InfluxDB events database. - ## Contributing We use the develop branch to perform work in. Fork the project and clone it, create a branch off of develop and perform your changes. Then submit a pull request to merge your branch into the develop branch here. We have an active Slack community that you can reach out to for more information or just to chat with anyone. Check out the [Slack Channel SED app development](https://softwaredaily.slack.com/app_redirect?channel=sed_app_development) slack channel. Also see the [Open Source Guide](https://softwareengineeringdaily.github.io/). diff --git a/config/lcov2badge.js b/config/lcov2badge.js new file mode 100644 index 0000000..ceddbc3 --- /dev/null +++ b/config/lcov2badge.js @@ -0,0 +1,32 @@ +const request = require('request'); +const lcov2badge = require('lcov2badge'); + +const filePath = process.argv[2]; + +const options = { + filePath: filePath || './coverage/lcov.info', + warnThreshold: 80, // default is 80 + koThreshold: 60, // default is 60 +}; + +function sendCoverageBadge(coverageBadge) { + const requestOptions = { + method: 'post', + body: { coverageBadge, coverageBadgeToken: process.env.COVERAGE_BADGE_TOKEN }, + json: true, + url: process.env.COVERAGE_BADGE_URL + }; + request(requestOptions, (err, res, body) => { + if (err) { + throw err; + } else { + console.log(body.result); // eslint-disable-line no-console + } + }); +} + + +lcov2badge.badge(options, (err, svgBadge) => { + if (err) throw err; + sendCoverageBadge(svgBadge); +}); diff --git a/package.json b/package.json index d732497..b93b9d6 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:watch": "npm run test -- --watch", "test:coverage": "cross-env NODE_ENV=test ./node_modules/.bin/istanbul cover _mocha -- --ui bdd --reporter spec --colors --compilers js:babel-core/register tests --recursive", "test:check-coverage": "npm run test:coverage && istanbul check-coverage", - "report-coverage": "coveralls < ./coverage/lcov.info" + "report-coverage": "node config/lcov2badge.js" }, "repository": { "type": "git", @@ -103,7 +103,9 @@ ] }, "devDependencies": { + "lcov2badge": "^0.1.0", "minimist": "^1.2.0", + "request": "^2.83.0", "swagger-node-express": "^2.1.3" } } From ad280db3bb968b7412289fb77c68ea01ef858cbc Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Sun, 11 Mar 2018 21:57:28 -0700 Subject: [PATCH 02/11] Rename coverageReporter --- config/{lcov2badge.js => coverageReporter.js} | 0 package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename config/{lcov2badge.js => coverageReporter.js} (100%) diff --git a/config/lcov2badge.js b/config/coverageReporter.js similarity index 100% rename from config/lcov2badge.js rename to config/coverageReporter.js diff --git a/package.json b/package.json index b93b9d6..cc29a04 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:watch": "npm run test -- --watch", "test:coverage": "cross-env NODE_ENV=test ./node_modules/.bin/istanbul cover _mocha -- --ui bdd --reporter spec --colors --compilers js:babel-core/register tests --recursive", "test:check-coverage": "npm run test:coverage && istanbul check-coverage", - "report-coverage": "node config/lcov2badge.js" + "report-coverage": "node config/coverageReporter.js" }, "repository": { "type": "git", From a45d484ee35ee3fa87bac078096dcfc97ec8c7c7 Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Sun, 11 Mar 2018 22:02:26 -0700 Subject: [PATCH 03/11] Move request and lcov2badge to dependencies so travis ci can build --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cc29a04..34d7805 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "joi": "10.6.0", "jsonwebtoken": "8.0.0", "kafka-node": "2.2.3", + "lcov2badge": "^0.1.0", "lodash": "4.17.4", "method-override": "2.3.9", "mocha": "3.5.0", @@ -79,6 +80,7 @@ "passport-facebook-token": "3.3.0", "raccoon": "0.2.8", "redis": "^2.8.0", + "request": "^2.83.0", "run-sequence": "2.1.0", "sinon": "^4.1.2", "supertest": "3.0.0", @@ -103,9 +105,7 @@ ] }, "devDependencies": { - "lcov2badge": "^0.1.0", "minimist": "^1.2.0", - "request": "^2.83.0", "swagger-node-express": "^2.1.3" } } From 33987ca37207d1ebd8a23ef243814a0195087792 Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Sun, 11 Mar 2018 22:06:26 -0700 Subject: [PATCH 04/11] Add coverage reporter to test coverage excludes --- .istanbul.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.istanbul.yml b/.istanbul.yml index 350acff..136b186 100644 --- a/.istanbul.yml +++ b/.istanbul.yml @@ -1,6 +1,6 @@ verbose: false instrumentation: - excludes: ['dist/**', 'coverage/**', 'gulpfile.babel.js', 'api/**', 'cli/**'] + excludes: ['dist/**', 'coverage/**', 'gulpfile.babel.js', 'api/**', 'cli/**', 'config/coverageReporter.js'] include-all-sources: true reporting: print: summary From b11524100bc6c2aa9f78cc8759046d91d0bdf3cb Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Sun, 11 Mar 2018 22:16:01 -0700 Subject: [PATCH 05/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf283b0..bcdda56 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The real time event processing infrastructure gateway server for the Software En
- +
## Getting Started From 3ea79e42bd8a466e0f78b38fa281f63700952eb2 Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Sat, 31 Mar 2018 18:59:12 -0700 Subject: [PATCH 06/11] Add a field to identify the environment (Test or Prod) (#67) * Add a field to identify the environment * Allow only types 'production' and 'test' for eventApiEnvs * Add unit tests --- config/param-validation.js | 2 + tests/server/errors/error.test.js | 48 +++++++++++++++++++++++ tests/server/events/event.test.js | 55 ++++++++++++++++++++++++++- tests/server/events/register.event.js | 1 + 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/config/param-validation.js b/config/param-validation.js index 12d312c..c47a3b9 100644 --- a/config/param-validation.js +++ b/config/param-validation.js @@ -5,6 +5,7 @@ export default { body: { clientId: Joi.string().required(), deviceType: Joi.string().required().valid(['iOS', 'Android', 'Browser', 'API']), + eventApiEnv: Joi.string().required().valid(['production', 'test']), eventTime: Joi.date().timestamp('unix').required(), eventData: Joi.object().required(), eventType: Joi.string().required().valid([ @@ -26,6 +27,7 @@ export default { body: { clientId: Joi.string().required(), deviceType: Joi.string().required().valid(['iOS', 'Android', 'Browser', 'API']), + eventApiEnv: Joi.string().required().valid(['production', 'test']), errorTime: Joi.date().timestamp('unix').required(), errorData: Joi.object().required(), } diff --git a/tests/server/errors/error.test.js b/tests/server/errors/error.test.js index 297f8c8..cc7e846 100644 --- a/tests/server/errors/error.test.js +++ b/tests/server/errors/error.test.js @@ -9,6 +9,7 @@ describe('## Basic Error APIs', () => { it('sending valid error is successful', (done) => { const error = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'API', errorTime: new Date().getTime(), errorData: { @@ -30,6 +31,7 @@ describe('## Basic Error APIs', () => { it('errors when no clientId is sent', (done) => { const error = { deviceType: 'Browser', + eventApiEnv: 'production', errorTime: new Date().getTime(), errorData: {} }; @@ -48,6 +50,7 @@ describe('## Basic Error APIs', () => { it('errors when no deviceType is sent', (done) => { const error = { clientId: '1234567', + eventApiEnv: 'production', errorTime: new Date().getTime(), errorData: { userId: '3462562' @@ -68,6 +71,7 @@ describe('## Basic Error APIs', () => { it('errors when no errorTime is sent', (done) => { const error = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'API', errorData: { userId: '3462562' @@ -88,6 +92,7 @@ describe('## Basic Error APIs', () => { it('errors when no errorData is sent', (done) => { const error = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'API', errorTime: new Date().getTime() }; @@ -102,4 +107,47 @@ describe('## Basic Error APIs', () => { }) .catch(done); }); + + it('errors when no eventApiEnv is sent', (done) => { + const error = { + clientId: '1234567', + errorData: { + userId: '3462562' + }, + deviceType: 'API', + errorTime: new Date().getTime() + }; + request(app) + .post('/api/v1/error') + .send(error) + .expect(httpStatus.BAD_REQUEST) + .then((res) => { + expect(res.body).to.exist; //eslint-disable-line + expect(res.body.message).to.equal('"eventApiEnv" is required') + done(); + }) + .catch(done); + }); + + it('errors when eventApiEnv sent is wrong type', (done) => { + const error = { + clientId: '1234567', + eventApiEnv: 'prod', + errorData: { + userId: '3462562' + }, + deviceType: 'API', + errorTime: new Date().getTime() + }; + request(app) + .post('/api/v1/error') + .send(error) + .expect(httpStatus.BAD_REQUEST) + .then((res) => { + expect(res.body).to.exist; //eslint-disable-line + expect(res.body.message).to.equal('"eventApiEnv" must be one of [production, test]'); //eslint-disable-line + done(); + }) + .catch(done); + }); }); diff --git a/tests/server/events/event.test.js b/tests/server/events/event.test.js index 735edd9..f3bac36 100644 --- a/tests/server/events/event.test.js +++ b/tests/server/events/event.test.js @@ -9,6 +9,7 @@ describe('## Basic Event APIs', () => { it('sending valid event is successful', (done) => { const event = { clientId: '1234567', + eventApiEnv: 'test', deviceType: 'iOS', eventTime: new Date().getTime(), eventType: 'login', @@ -40,6 +41,7 @@ describe('## Basic Event APIs', () => { it('errors with invalid deviceType', (done) => { const event = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'Windows phone', eventTime: new Date().getTime(), eventType: 'login', @@ -62,6 +64,7 @@ describe('## Basic Event APIs', () => { it('errors with invalid timestamp', (done) => { const event = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'Browser', eventTime: new Date(), eventType: 'login', @@ -89,7 +92,7 @@ describe('## Basic Event APIs', () => { .expect(httpStatus.BAD_REQUEST) .then((res) => { expect(res.body).to.exist; //eslint-disable-line - expect(res.body.message).to.equal('"clientId" is required and "deviceType" is required and "eventTime" is required and "eventData" is required and "eventType" is required'); //eslint-disable-line + expect(res.body.message).to.equal('"clientId" is required and "deviceType" is required and "eventApiEnv" is required and "eventTime" is required and "eventData" is required and "eventType" is required'); //eslint-disable-line done(); }) .catch(done); @@ -98,6 +101,7 @@ describe('## Basic Event APIs', () => { it('errors when no clientId sent', (done) => { const event = { deviceType: 'Browser', + eventApiEnv: 'production', eventTime: new Date().getTime(), eventType: 'login', eventData: { @@ -119,6 +123,7 @@ describe('## Basic Event APIs', () => { it('errors when no deviceType sent', (done) => { const event = { clientId: '45426562', + eventApiEnv: 'production', eventTime: new Date().getTime(), eventType: 'login', eventData: { @@ -140,6 +145,7 @@ describe('## Basic Event APIs', () => { it('errors when no eventData sent', (done) => { const event = { clientId: '45426562', + eventApiEnv: 'production', deviceType: 'API', eventTime: new Date().getTime(), eventType: 'login' @@ -159,6 +165,7 @@ describe('## Basic Event APIs', () => { it('errors when no eventType sent', (done) => { const event = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'Android', eventTime: new Date().getTime(), eventData: { @@ -180,6 +187,7 @@ describe('## Basic Event APIs', () => { it('errors when no eventTime sent', (done) => { const event = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'iOS', eventType: 'login', eventData: { @@ -197,4 +205,49 @@ describe('## Basic Event APIs', () => { }) .catch(done); }); + + it('errors when no eventApiEnv sent', (done) => { + const event = { + clientId: '1234567', + deviceType: 'iOS', + eventTime: new Date().getTime(), + eventType: 'login', + eventData: { + userId: '8675309' + } + } + request(app) + .post('/api/v1/event') + .send(event) + .expect(httpStatus.BAD_REQUEST) + .then((res) => { + expect(res.body).to.exist; //eslint-disable-line + expect(res.body.message).to.equal('"eventApiEnv" is required'); //eslint-disable-line + done(); + }) + .catch(done); + }); + + it('errors when eventApiEnv sent is wrong type', (done) => { + const event = { + clientId: '1234567', + deviceType: 'iOS', + eventApiEnv: 'testing', + eventTime: new Date().getTime(), + eventType: 'login', + eventData: { + userId: '8675309' + } + } + request(app) + .post('/api/v1/event') + .send(event) + .expect(httpStatus.BAD_REQUEST) + .then((res) => { + expect(res.body).to.exist; //eslint-disable-line + expect(res.body.message).to.equal('"eventApiEnv" must be one of [production, test]'); //eslint-disable-line + done(); + }) + .catch(done); + }); }); diff --git a/tests/server/events/register.event.js b/tests/server/events/register.event.js index 10487a1..8e2e880 100644 --- a/tests/server/events/register.event.js +++ b/tests/server/events/register.event.js @@ -9,6 +9,7 @@ describe('## Register Events', () => { it('sending valid register event is successful', (done) => { const event = { clientId: '1234567', + eventApiEnv: 'production', deviceType: 'Android', eventTime: new Date().getTime(), eventType: 'register', From 09cce49001eeeeed90ed0e4d5bd8fe2229c96afc Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Mon, 9 Apr 2018 12:21:20 -0700 Subject: [PATCH 07/11] Store errors in DB with each field separately. Allow error types authorization and other for now. Build InfluxDB fields using the param-validation schema (#71) --- config/param-validation.js | 8 ++- server/helpers/InfluxErrorInterface.js | 28 ++++++++-- tests/server/errors/error.test.js | 71 ++++++++++++++++++++++---- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/config/param-validation.js b/config/param-validation.js index c47a3b9..af21c0f 100644 --- a/config/param-validation.js +++ b/config/param-validation.js @@ -29,7 +29,13 @@ export default { deviceType: Joi.string().required().valid(['iOS', 'Android', 'Browser', 'API']), eventApiEnv: Joi.string().required().valid(['production', 'test']), errorTime: Joi.date().timestamp('unix').required(), - errorData: Joi.object().required(), + errorType: Joi.string().required().valid([ + 'auth', + 'other' + ]), + errorData: Joi.object().required().keys({ + message: Joi.string().required() + }) } }, register: Joi.object().required().keys(), diff --git a/server/helpers/InfluxErrorInterface.js b/server/helpers/InfluxErrorInterface.js index f0b8ed3..6a5522a 100644 --- a/server/helpers/InfluxErrorInterface.js +++ b/server/helpers/InfluxErrorInterface.js @@ -1,5 +1,25 @@ +import _ from 'lodash'; import { FieldType, escape } from 'influx'; import InfluxInterface from './InfluxInterface'; +import paramValidation from '../../config/param-validation'; + +const fieldList = Object.keys(paramValidation.error.body); +fieldList.splice(fieldList.indexOf('errorData'), 1); + +Object.keys(paramValidation.error.body.errorData).forEach((key) => { + const inner = paramValidation.error.body.errorData[key]; + + if (inner && inner.children) { + inner.children.forEach((child) => { + fieldList.push(child.key); + }); + } +}); + +const fields = {}; +Array.from(new Set(fieldList)).forEach((field) => { + fields[field] = FieldType.STRING; +}); const databaseName = 'errorsDb'; @@ -8,18 +28,18 @@ export default class InfluxErrorInterface extends InfluxInterface { super(databaseName, [ { measurement: 'errors', - fields: { - errorData: FieldType.STRING - }, + fields, tags: [] } ]); } write(topic, errorData, callback) { + _.merge(errorData, errorData.errorData); + delete errorData.errorData; // eslint-disable-line no-param-reassign this.influx.writeMeasurement('errors', [ { - fields: { errorData: JSON.stringify(errorData) } + fields: { ...errorData } } ]) .then(() => { diff --git a/tests/server/errors/error.test.js b/tests/server/errors/error.test.js index cc7e846..92d9f3d 100644 --- a/tests/server/errors/error.test.js +++ b/tests/server/errors/error.test.js @@ -12,8 +12,9 @@ describe('## Basic Error APIs', () => { eventApiEnv: 'production', deviceType: 'API', errorTime: new Date().getTime(), + errorType: 'auth', errorData: { - errorType: 'Unauthorized' + message: 'Unauthorized user' } }; request(app) @@ -33,7 +34,10 @@ describe('## Basic Error APIs', () => { deviceType: 'Browser', eventApiEnv: 'production', errorTime: new Date().getTime(), - errorData: {} + errorType: 'auth', + errorData: { + message: 'Unauthorized user' + } }; request(app) .post('/api/v1/error') @@ -52,8 +56,9 @@ describe('## Basic Error APIs', () => { clientId: '1234567', eventApiEnv: 'production', errorTime: new Date().getTime(), + errorType: 'other', errorData: { - userId: '3462562' + message: 'Error sending mailchimp email' } }; request(app) @@ -73,8 +78,9 @@ describe('## Basic Error APIs', () => { clientId: '1234567', eventApiEnv: 'production', deviceType: 'API', + errorType: 'other', errorData: { - userId: '3462562' + message: 'Username not found: Andrew' } }; request(app) @@ -94,7 +100,8 @@ describe('## Basic Error APIs', () => { clientId: '1234567', eventApiEnv: 'production', deviceType: 'API', - errorTime: new Date().getTime() + errorTime: new Date().getTime(), + errorType: 'other', }; request(app) .post('/api/v1/error') @@ -111,11 +118,12 @@ describe('## Basic Error APIs', () => { it('errors when no eventApiEnv is sent', (done) => { const error = { clientId: '1234567', + deviceType: 'API', + errorTime: new Date().getTime(), + errorType: 'auth', errorData: { - userId: '3462562' + message: 'User not allowed to perform function' }, - deviceType: 'API', - errorTime: new Date().getTime() }; request(app) .post('/api/v1/error') @@ -133,8 +141,9 @@ describe('## Basic Error APIs', () => { const error = { clientId: '1234567', eventApiEnv: 'prod', + errorType: 'other', errorData: { - userId: '3462562' + message: 'Username not found' }, deviceType: 'API', errorTime: new Date().getTime() @@ -150,4 +159,48 @@ describe('## Basic Error APIs', () => { }) .catch(done); }); + + it('errors when errorType sent is wrong type', (done) => { + const error = { + clientId: '1234567', + eventApiEnv: 'production', + errorType: '404', + errorData: { + message: 'Web page not found' + }, + deviceType: 'API', + errorTime: new Date().getTime() + }; + request(app) + .post('/api/v1/error') + .send(error) + .expect(httpStatus.BAD_REQUEST) + .then((res) => { + expect(res.body).to.exist; //eslint-disable-line + expect(res.body.message).to.equal('"errorType" must be one of [auth, other]'); //eslint-disable-line + done(); + }) + .catch(done); + }); + + it('errors when errorData sent has no message', (done) => { + const error = { + clientId: '1234567', + eventApiEnv: 'production', + errorType: 'other', + errorData: {}, + deviceType: 'API', + errorTime: new Date().getTime() + }; + request(app) + .post('/api/v1/error') + .send(error) + .expect(httpStatus.BAD_REQUEST) + .then((res) => { + expect(res.body).to.exist; //eslint-disable-line + expect(res.body.message).to.equal('"message" is required'); //eslint-disable-line + done(); + }) + .catch(done); + }); }); From cb51b8cb516559bc8a695b6587e8c992d8677b91 Mon Sep 17 00:00:00 2001 From: AbdulBasit Kabir Date: Mon, 9 Apr 2018 21:32:34 +0100 Subject: [PATCH 08/11] Add swagger doc (#70) * Add swagger doc --- README.md | 6 +- server/docs/definitions.yaml | 61 +++++++++++++++++++ server/docs/index.html | 91 ++++++++++++++++++++++++++++ server/docs/index.js | 41 +++++++++++++ server/docs/responses.yaml | 28 +++++++++ server/docs/securityDefinitions.yaml | 9 +++ server/routes/event.route.js | 32 ++++++++++ server/routes/index.route.js | 21 +++++++ 8 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 server/docs/definitions.yaml create mode 100644 server/docs/index.html create mode 100644 server/docs/index.js create mode 100644 server/docs/responses.yaml create mode 100644 server/docs/securityDefinitions.yaml diff --git a/README.md b/README.md index bcdda56..d26c944 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ loginEvent: (username) => { deviceType: 'Browser', eventTime: new Date().getTime(), eventType: 'login', - eventData: {} + eventData: {}, + eventApiEnv: `${EVENT_API_ENV}` }) } ``` @@ -62,7 +63,8 @@ playEpisodeEvent: (username, playEvent) => { episodeName: playEvent.episodeName, minutesPlayed: playEvent.minutesPlayed, minutesRemaining: playEvent.minutesRemaining - } + }, + eventApiEnv: `${EVENT_API_ENV}` }) } ``` diff --git a/server/docs/definitions.yaml b/server/docs/definitions.yaml new file mode 100644 index 0000000..8df871b --- /dev/null +++ b/server/docs/definitions.yaml @@ -0,0 +1,61 @@ +definitions: + Error: + type: object + properties: + message: + type: string + description: Reason for error + example: Error message + stack: + type: string + description: Stack trace resulting in error + Event: + type: object + properties: + clientId: + type: string + description: Id of user initiating event + example: user01 + deviceType: + type: string + description: type of device where the event originates + enum: [iOS, Android, Browser, API] + example: Android + eventApiEnv: + type: string + description: environment where the event originates + enum: [production, test] + example: test + eventTime: + type: string + format: unix-time + description: valid timestamp of when event is triggered + example: 1522767185 + eventData: + type: object + description: raw data of the event being streamed + eventType: + type: string + description: type of event being streamed + enum: [register, + login, + logout, + playEpisode, + pauseEpisode, + likeEpisode, + completedEpisode, + fastForwardEpisode, + rewindEpisode, + seekEpisode, + searchEpisode] + required: + - clientId + - deviceType + - eventApiEnv + - eventTime + - eventData + - eventType + Token: + type: string + description: JSON web token to store credentials + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1OWY4Njc3YzFkNmZmZDNkMGJkODMzNGIiLCJwYXNzd29yZCI6IiQyYSQwOCRoMEgyR2FWbWh1V0tNd1hSWlRYekxPcDMuWG85OGJmYVZYWXp2cURuU2p1SGlrZE9YRmd3LiIsInVzZXJuYW1lIjoiam9obkBqYWNvYi5jb20iLCJfX3YiOjAsImNyZWF0ZWRBdCI6IjIwMTctMTAtMzFUMTI6MDc6MjQuNTAyWiIsImlhdCI6MTUwOTQ1Mjk0MywiZXhwIjoxNjUzNDUyOTQzfQ.2yECxNnmM6u9wcUkYq1OPX6HzfcLeaOgoQ35PJ2fQZs \ No newline at end of file diff --git a/server/docs/index.html b/server/docs/index.html new file mode 100644 index 0000000..cb331f1 --- /dev/null +++ b/server/docs/index.html @@ -0,0 +1,91 @@ + + + + + + + SED API Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + \ No newline at end of file diff --git a/server/docs/index.js b/server/docs/index.js new file mode 100644 index 0000000..f9ef0dd --- /dev/null +++ b/server/docs/index.js @@ -0,0 +1,41 @@ +const swaggerJSDoc = require('swagger-jsdoc'); +const express = require('express'); + +const router = express.Router(); // eslint-disable-line new-cap + +// Swagger definition aka OpenAPI v2.0 +// https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md + +const swaggerDefinition = { + info: { + // API information (required) + title: 'SEDaily DevOps', // Title (required) + version: '1.0.0', // Version (required) + description: 'Software Engineering Daily Logging, Monitoring, and Analytics API Documentation. You can use these by not only browsing the API routes, but also by executing requests against the server.' + }, + basePath: '/api/v1', + produces: ['application/json'], + consumes: ['application/json'], +}; + +const options = { + swaggerDefinition, + apis: [ + // controllers include parameters, tags and paths + './server/controllers/*.js', + // a few "general" paths are defined in index + './server/routes/*.route.js', + // responses, securityDefinitions and general definitions/parameters in separate yaml + './server/docs/*.yaml', + ] +}; +const swaggerSpec = swaggerJSDoc(options); + +router.get('/swagger.json', (req, res) => { + res.setHeader('Content-Type', 'application/json'); + res.send(swaggerSpec); +}); + +router.use('/', express.static(__dirname)); + +module.exports = router; diff --git a/server/docs/responses.yaml b/server/docs/responses.yaml new file mode 100644 index 0000000..efd62c3 --- /dev/null +++ b/server/docs/responses.yaml @@ -0,0 +1,28 @@ +responses: + NotFound: + description: The specified resource was not found + schema: + $ref: '#/definitions/Error' + Unauthorized: + description: Unauthorized + schema: + $ref: '#/definitions/Error' + BadRequest: + description: Bad request - missing required elements + schema: + $ref: '#/definitions/Error' + SuccessfulAuthentication: + description: Successful authentication + schema: + type: object + properties: + token: + $ref: '#/definitions/Token' + Success: + description: successful operation + schema: + type: object + properties: + result: + type: string + enum: 'success' diff --git a/server/docs/securityDefinitions.yaml b/server/docs/securityDefinitions.yaml new file mode 100644 index 0000000..d3acd51 --- /dev/null +++ b/server/docs/securityDefinitions.yaml @@ -0,0 +1,9 @@ +securityDefinitions: + Token: + description: | + For accessing the protected API resources, you must have received a a valid JWT token after registering or logging in. This JWT token must then be used for all protected resources by passing it in via the 'Authorization' header. + + A JWT token is generated by the API by either registering via /auth/register or logging in via /auth/login. + type: apiKey + name: Authorization + in: header diff --git a/server/routes/event.route.js b/server/routes/event.route.js index ed713b4..8c1176a 100644 --- a/server/routes/event.route.js +++ b/server/routes/event.route.js @@ -8,6 +8,38 @@ const router = express.Router(); // Disabling validation for now // router.use(expressJwt({ secret: config.jwtSecret })); +/** + * @swagger + * tags: + * - name: event + * description: Sending user events + */ + +/** + * @swagger + * /event: + * post: + * summary: Stream an event + * description: Stream an event + * tags: [event] + * parameters: + * - in: body + * name: event + * schema: + * $ref: '#/definitions/Event' + * required: true + * description: Event to stream + * responses: + * '200': + * $ref: '#/responses/Success' + * '400': + * $ref: '#/responses/BadRequest' + * '401': + * $ref: '#/responses/Unauthorized' + * '404': + * $ref: '#/responses/NotFound' + */ + router.route('/') .post(validate(paramValidation.event), eventCtrl.validateEventType, eventCtrl.newEvent); diff --git a/server/routes/index.route.js b/server/routes/index.route.js index 90bd2cf..d670b38 100644 --- a/server/routes/index.route.js +++ b/server/routes/index.route.js @@ -1,13 +1,34 @@ import express from 'express'; import eventRoutes from './event.route'; import errorRoutes from './error.route'; +import docRoutes from '../docs'; const router = express.Router(); // eslint-disable-line new-cap +/** + * @swagger + * tags: + * - name: general + * description: General/server-related + */ + +/** + * @swagger + * /health-check: + * get: + * summary: Health check of server + * description: Confirm SED API server running and okay + * tags: [general] + * responses: + * 200: + * description: successful operation + */ + router.get('/health-check', (req, res) => res.send('OK')); router.use('/event', eventRoutes); router.use('/error', errorRoutes); +router.use('/docs', docRoutes); export default router; From 4f1f353d6916ebf6ef3f020423679db1a46f005e Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Mon, 9 Apr 2018 13:40:49 -0700 Subject: [PATCH 09/11] Exclude docs directory from unit testing --- .istanbul.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.istanbul.yml b/.istanbul.yml index 136b186..5912a8e 100644 --- a/.istanbul.yml +++ b/.istanbul.yml @@ -1,6 +1,6 @@ verbose: false instrumentation: - excludes: ['dist/**', 'coverage/**', 'gulpfile.babel.js', 'api/**', 'cli/**', 'config/coverageReporter.js'] + excludes: ['dist/**', 'coverage/**', 'gulpfile.babel.js', 'api/**', 'cli/**', 'config/coverageReporter.js', 'server/docs/**'] include-all-sources: true reporting: print: summary From b74c8f3ee4a4474210b213281746a3360369275e Mon Sep 17 00:00:00 2001 From: AbdulBasit Kabir Date: Sat, 21 Apr 2018 01:06:53 +0100 Subject: [PATCH 10/11] add test for login event (#74) * Add swagger doc * remove parameters.yaml file * add test for login event --- tests/server/events/login.event.js | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/server/events/login.event.js diff --git a/tests/server/events/login.event.js b/tests/server/events/login.event.js new file mode 100644 index 0000000..b5be6ad --- /dev/null +++ b/tests/server/events/login.event.js @@ -0,0 +1,41 @@ +import request from 'supertest-as-promised'; +import httpStatus from 'http-status'; +import chai, { expect } from 'chai'; +import app from '../../../index'; + +chai.config.includeStack = true; + +describe('## Login Events', () => { + const loginEvent = { + clientId: '1234567', + eventApiEnv: 'test', + deviceType: 'Android', + eventTime: new Date().getTime(), + eventType: 'register', + eventData: {} + }; + it('succeed for valig login envent', (done) =>{ + request(app) + .post('/api/v1/event') + .send(loginEvent) + .expect(httpStatus.OK) + .then((res) => { + expect(res.body).to.exist; // eslint-disable-line + done(); + }) + .catch(done); + }); + + it('errors with invalid eventData', (done) => { + loginEvent.eventData = { username: 'user' }; + request(app) + .post('/api/v1/event') + .send(loginEvent) + .expect(httpStatus.INTERNAL_SERVER_ERROR) + .then((res) => { + expect(res.body).to.exist; // eslint-disable-line + done(); + }) + .catch(done); + }); +}); From 66e28ce9bebc9330431c896f6709cef01c911389 Mon Sep 17 00:00:00 2001 From: Andrew Lloyd Date: Fri, 20 Apr 2018 17:07:08 -0700 Subject: [PATCH 11/11] Update moment dependency to 2.19.3 (#75) --- package-lock.json | 399 +++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 292 insertions(+), 109 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61058ec..bb3794e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "sedaily-event", + "name": "sedaily-event-stream", "version": "1.0.0", "lockfileVersion": 1, "requires": true, @@ -111,7 +111,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "requires": { "is-fullwidth-code-point": "2.0.0", "strip-ansi": "4.0.0" @@ -145,7 +145,7 @@ "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=", "requires": { "micromatch": "2.3.11", "normalize-path": "2.1.1" @@ -162,7 +162,7 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", "optional": true }, "archy": { @@ -199,7 +199,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=" }, "array-differ": { "version": "1.0.0", @@ -285,9 +285,9 @@ "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" }, "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, "babel-cli": { "version": "6.26.0", @@ -1030,7 +1030,7 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=" }, "balanced-match": { "version": "1.0.0", @@ -1083,7 +1083,7 @@ "bindings": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==", + "integrity": "sha1-s0b27PapX1qBXFg5/HzbIlAvHtc=", "optional": true }, "bl": { @@ -1188,7 +1188,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "requires": { "is-fullwidth-code-point": "2.0.0", "strip-ansi": "4.0.0" @@ -1274,6 +1274,11 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, + "byline": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/byline/-/byline-4.2.2.tgz", + "integrity": "sha1-wgOpilsCkIIqk4anjtosvVvNsy8=" + }, "bytes": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", @@ -1408,7 +1413,7 @@ "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" + "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=" }, "cli-boxes": { "version": "1.0.0", @@ -1630,7 +1635,7 @@ "configstore": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.1.tgz", - "integrity": "sha512-5oNkD/L++l0O6xGXxb1EWS7SivtjfGQlRyxJsYgE0Z495/L81e2h4/d3r969hoPXuFItzNOKMtsXgYG4c7dYvw==", + "integrity": "sha1-CU7mYquD+tmRdnjeEU+q6o/NypA=", "requires": { "dot-prop": "4.2.0", "graceful-fs": "4.1.11", @@ -1772,6 +1777,38 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=" + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.7.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.4.3", + "uuid": "3.1.0" + } } } }, @@ -1902,7 +1939,7 @@ "debug": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/debug/-/debug-3.0.1.tgz", - "integrity": "sha512-6nVc6S36qbt/mutyt+UGMnawAMrPDZUPQjRZI3FS9tCtDRhvxJbK79unYBLPi+z5SLXQ3ftoVBFCblQtNSls8w==", + "integrity": "sha1-BWTGErUh3JLZ8piPBUnjT5yY22Q=", "requires": { "ms": "2.0.0" } @@ -1951,7 +1988,7 @@ "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "integrity": "sha1-38lARACtHI/gI+faHfHBR8S0RN8=", "requires": { "type-detect": "4.0.3" } @@ -2076,10 +2113,15 @@ "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz", "integrity": "sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=" }, + "dot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/dot/-/dot-1.1.2.tgz", + "integrity": "sha1-xzdwGfxOVQeYkosrmv62ar+h8vk=" + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=", "requires": { "is-obj": "1.0.1" } @@ -2334,7 +2376,7 @@ "esprima": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" }, "external-editor": { "version": "2.0.4", @@ -2419,7 +2461,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "requires": { "is-fullwidth-code-point": "2.0.0", "strip-ansi": "4.0.0" @@ -2454,7 +2496,7 @@ "eslint-config-airbnb-base": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.0.0.tgz", - "integrity": "sha512-/XlFQGn3Mkwm642/GYBtOH3pgFX4Z7saBsqqyp96v0bEUPq24nIrZ6N72qAoD0lR2wAne4EC4YsHYkbPfaRfiA==", + "integrity": "sha1-mQY6rvS4aYCDSBoA4WXL4V6C1hU=", "requires": { "eslint-restricted-globals": "0.1.1" } @@ -2481,7 +2523,7 @@ "eslint-module-utils": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", - "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", + "integrity": "sha1-q67IJBd2E7ipWymWOeG2+s9HNEk=", "requires": { "debug": "2.6.8", "pkg-dir": "1.0.0" @@ -2500,7 +2542,7 @@ "eslint-plugin-import": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz", - "integrity": "sha512-HGYmpU9f/zJaQiKNQOVfHUh2oLWW3STBrCgH0sHTX1xtsxYlH1zjLh8FlQGEIdZSdTbUMaV36WaZ6ImXkenGxQ==", + "integrity": "sha1-Id4zOAue+1X1720uIQ7A4H5/pp8=", "requires": { "builtin-modules": "1.1.1", "contains-path": "0.1.0", @@ -2750,7 +2792,7 @@ "qs": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==" + "integrity": "sha1-jQSVTTZN7z78VbWgeT4eLIsebkk=" } } }, @@ -2772,7 +2814,7 @@ "requires": { "hoek": "2.16.3", "isemail": "1.2.0", - "moment": "2.18.1", + "moment": "2.19.3", "topo": "1.1.0" } }, @@ -3152,7 +3194,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", - "dev": true, "requires": { "samsam": "1.3.0" } @@ -3210,7 +3251,7 @@ "fsevents": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "integrity": "sha1-EfgjGPX+e7LNIpZaEI6TBiCCFtg=", "optional": true, "requires": { "nan": "2.7.0", @@ -4010,7 +4051,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" }, "functional-red-black-tree": { "version": "1.0.1", @@ -4082,7 +4123,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -4212,7 +4253,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=" }, "globby": { "version": "6.1.0", @@ -4372,7 +4413,7 @@ "gulp-babel": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-7.0.0.tgz", - "integrity": "sha512-TiUuFLW6FD2hx3mJ7QBPXN2nzpu6gRWFyjfChWxE1A9xaASRA5nsxrvHcqMDl5Ha6TvSBB9r74GbkVd1GO4mDA==", + "integrity": "sha1-e5PJdRWfegVT5CY7SlUQDMwjmyg=", "requires": { "gulp-util": "3.0.8", "replace-ext": "0.0.1", @@ -4418,7 +4459,7 @@ "gulp-sourcemaps": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.1.tgz", - "integrity": "sha512-1qHCI3hdmsMdq/SUotxwUh/L8YzlI6J9zQ5ifNOtx4Y6KV5y5sGuORv1KZzWhuKtz/mXNh5xLESUtwC4EndCjA==", + "integrity": "sha1-gzpOKPC49GYQdQMs14JBf3zY+ws=", "requires": { "@gulp-sourcemaps/identity-map": "1.0.1", "@gulp-sourcemaps/map-sources": "1.0.0", @@ -4529,6 +4570,11 @@ } } }, + "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": "2.0.6", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", @@ -4536,7 +4582,7 @@ "requires": { "chalk": "1.1.3", "commander": "2.12.2", - "is-my-json-valid": "2.16.1", + "is-my-json-valid": "2.17.2", "pinkie-promise": "2.0.1" }, "dependencies": { @@ -4608,7 +4654,7 @@ "helmet": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.8.1.tgz", - "integrity": "sha512-HzcpQ74kE1gNFvTd8fI/Nz2N0b0Aa/38dSiSVt/ijkwjc50tUp5siXTE9lTBibQ4JlRzp/35Qf+j2bZgHYwg1g==", + "integrity": "sha1-vvK2j/uqGXWehYwZzKfbITu1iy0=", "requires": { "connect": "3.6.2", "dns-prefetch-control": "0.1.0", @@ -4628,7 +4674,7 @@ "helmet-csp": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.5.1.tgz", - "integrity": "sha512-PLLch8wVcVF2+ViTtSGHIvXqQVjcwGRtBwrNPggC+j28J7eSoPHxbJBr9SvLgh9V3HZa0C1zZFZ6gYVLIrPD0Q==", + "integrity": "sha1-Xz3uyPki+n4HTbw5h8FopQVzw20=", "requires": { "camelize": "1.0.0", "content-security-policy-builder": "1.1.0", @@ -4682,7 +4728,7 @@ "hsts": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.1.0.tgz", - "integrity": "sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA==" + "integrity": "sha1-y9bJGKI4X+4d1WgL+ys6GUwBIcw=" }, "http-errors": { "version": "1.6.2", @@ -4702,7 +4748,7 @@ "requires": { "assert-plus": "0.2.0", "jsprim": "1.4.1", - "sshpk": "1.13.1" + "sshpk": "1.14.1" } }, "http-status": { @@ -4749,6 +4795,11 @@ "wrappy": "1.0.2" } }, + "influx": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/influx/-/influx-5.0.7.tgz", + "integrity": "sha1-NeZfa/E8uqF2MQi1WWqAanJ6Upo=" + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -4894,13 +4945,19 @@ "is-extglob": "1.0.0" } }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==" + }, "is-my-json-valid": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", - "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", "requires": { "generate-function": "2.0.0", "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", "jsonpointer": "4.0.1", "xtend": "4.0.1" } @@ -4947,7 +5004,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "requires": { "isobject": "3.0.1" }, @@ -5120,7 +5177,7 @@ "esprima": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" }, "js-yaml": { "version": "3.10.0", @@ -5224,7 +5281,7 @@ "joi": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", + "integrity": "sha1-Ulh/AtUri3XNsMdPCxZKGRoOH8I=", "requires": { "hoek": "4.2.0", "isemail": "2.2.1", @@ -5302,7 +5359,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "requires": { "ms": "2.0.0" } @@ -5406,8 +5463,7 @@ "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", - "dev": true + "integrity": "sha1-7G55QQ/5FORyZSq/oOYDwD1g6QU=" }, "jwa": { "version": "1.1.5", @@ -5454,7 +5510,7 @@ "async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "integrity": "sha1-YaKau2/MAm/qd+VtHG7FOnlZUfQ=", "requires": { "lodash": "4.17.4" } @@ -5462,7 +5518,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "requires": { "ms": "2.0.0" } @@ -5519,6 +5575,15 @@ "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=" }, + "lcov2badge": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lcov2badge/-/lcov2badge-0.1.0.tgz", + "integrity": "sha1-GIqiVEBw8efTs5a0sqfwXwG3Z0g=", + "requires": { + "byline": "4.2.2", + "shields-lightweight": "0.1.0" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -5822,8 +5887,7 @@ "lolex": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", - "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==", - "dev": true + "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==" }, "long": { "version": "1.1.2", @@ -5992,7 +6056,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { "brace-expansion": "1.1.8" } @@ -6021,7 +6085,7 @@ "mocha": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.0.tgz", - "integrity": "sha512-pIU2PJjrPYvYRqVpjXzj76qltO9uBYI7woYAMoxbSefsa+vqAfptjoeevd6bUgwD0mPIO+hv9f7ltvsNreL2PA==", + "integrity": "sha1-EyhWfScX+ZcDD4AGI0vOm4zXJGU=", "requires": { "browser-stdout": "1.3.0", "commander": "2.9.0", @@ -6081,9 +6145,9 @@ } }, "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.3.tgz", + "integrity": "sha1-vbmdJw1tf9p4zA+6zoVeJ/59pp8=" }, "mongodb": { "version": "2.2.31", @@ -6128,7 +6192,7 @@ "mongoose": { "version": "4.11.10", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.11.10.tgz", - "integrity": "sha512-+D+sS0aU1asnVhHCZnR9PHnaeJqcN+E9v3vMApbru8KRMbHek06njMnZ7EPLjQffwwXm/wnFVQ8OeF9EfOp9pA==", + "integrity": "sha1-9osTHfCYk7nwBz9G1dyrARZ4n1Y=", "requires": { "async": "2.1.4", "bson": "1.0.4", @@ -6278,7 +6342,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.0.tgz", "integrity": "sha512-q9jXh3UNsMV28KeqI43ILz5+c3l+RiNW8mhurEwCKckuHQbL+hTJIKKTiUlCPKlgQ/OukFvSnKB/Jk3+sFbkGA==", - "dev": true, "requires": { "formatio": "1.2.0", "just-extend": "1.1.27", @@ -6290,20 +6353,17 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "lolex": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", - "dev": true + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=" }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, "requires": { "isarray": "0.0.1" } @@ -6329,7 +6389,7 @@ "nopt": "3.0.6", "npmlog": "4.1.2", "osenv": "0.1.4", - "request": "2.79.0", + "request": "2.85.0", "rimraf": "2.6.1", "semver": "5.3.0", "tar": "2.2.1", @@ -6412,7 +6472,7 @@ "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "requires": { "hosted-git-info": "2.5.0", "is-builtin-module": "1.0.0", @@ -6439,7 +6499,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", "optional": true, "requires": { "are-we-there-yet": "1.1.4", @@ -6576,7 +6636,7 @@ "optional": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", - "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" + "integrity": "sha1-zbGpvtxzfSAl9pDO61DgSURP1bM=" }, "optionator": { "version": "0.8.2", @@ -6853,6 +6913,11 @@ "through": "2.3.8" } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -6995,7 +7060,7 @@ "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", "requires": { "is-number": "3.0.0", "kind-of": "4.0.0" @@ -7132,7 +7197,7 @@ "redis": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", - "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "integrity": "sha1-ICKI4/WMSfYHnZevehDhMDrhSwI=", "requires": { "double-ended-queue": "2.1.0-0", "redis-commands": "1.3.1", @@ -7167,7 +7232,7 @@ "regenerator-transform": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "integrity": "sha1-HkmWg3Ix2ot/PPQRTXG1aRoGgN0=", "requires": { "babel-runtime": "6.26.0", "babel-types": "6.26.0", @@ -7177,7 +7242,7 @@ "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", "requires": { "is-equal-shallow": "0.1.3" } @@ -7263,36 +7328,150 @@ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" }, "request": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.11.0", + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", "combined-stream": "1.0.5", "extend": "3.0.1", "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", "mime-types": "2.1.17", "oauth-sign": "0.8.2", - "qs": "6.3.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.4.3", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", "uuid": "3.1.0" }, "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "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=" + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.17" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "1.0.0" + } + } + } + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.2.2", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + }, + "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.4.1", + "sshpk": "1.14.1" + } + }, "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.1" + } + }, + "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.1.1" + } } } }, @@ -7308,7 +7487,7 @@ "require_optional": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "integrity": "sha1-TPNaQkf2TKPfjC7yCMxJSxyo/C4=", "requires": { "resolve-from": "2.0.0", "semver": "5.4.1" @@ -7436,13 +7615,12 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", - "dev": true + "integrity": "sha1-jR2TUOJWItow3j5EumkrUiGrfFA=" }, "semver": { "version": "5.4.1", @@ -7547,6 +7725,14 @@ "rechoir": "0.6.2" } }, + "shields-lightweight": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/shields-lightweight/-/shields-lightweight-0.1.0.tgz", + "integrity": "sha1-qZj8mDtClhXiPUqBhJJUJIF5V6o=", + "requires": { + "dot": "1.1.2" + } + }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", @@ -7561,7 +7747,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.2.tgz", "integrity": "sha512-5uLBZPdCWl59Lpbf45ygKj7Z0LVol+ftBe7RDIXOQV/sF58pcFmbK8raA7bt6eljNuGnvBP+/ZxlicVn0emDjA==", - "dev": true, "requires": { "diff": "3.2.0", "formatio": "1.2.0", @@ -7576,7 +7761,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, "requires": { "has-flag": "2.0.0" } @@ -7601,7 +7785,7 @@ "snappy": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/snappy/-/snappy-6.0.1.tgz", - "integrity": "sha512-wrbLPjpDgDOA/VTQk/okf/qRhnWLueejiiZYMhvM9zK8NzPyLD14hIoItXya4q76u58OuUGduANks6DS8jOaJg==", + "integrity": "sha1-dH0jhTEC5qG4+jgvUkWrlLtDSE4=", "optional": true, "requires": { "bindings": "1.3.0", @@ -7692,9 +7876,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", + "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "requires": { "asn1": "0.2.3", "assert-plus": "1.0.0", @@ -7749,7 +7933,7 @@ "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", "requires": { "safe-buffer": "5.1.1" } @@ -7859,7 +8043,7 @@ "esprima": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" }, "js-yaml": { "version": "3.10.0", @@ -7897,7 +8081,7 @@ "swagger-parser": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-3.4.2.tgz", - "integrity": "sha512-himpIkA50AjTvrgtz0PPbzwWoTjj3F3ye/y1PcW/514YEp1A3IhAcJFkkEu7b1zHnSIthnzxC8aTy+XZG0D+iA==", + "integrity": "sha1-JE1n1u7tCMAKy12VlQ1a771hhaM=", "requires": { "call-me-maybe": "1.0.1", "debug": "3.0.1", @@ -7983,7 +8167,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "requires": { "is-fullwidth-code-point": "2.0.0", "strip-ansi": "4.0.0" @@ -8021,8 +8205,7 @@ "text-encoding": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" }, "text-table": { "version": "0.2.0", @@ -8094,15 +8277,15 @@ "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=", "requires": { "nopt": "1.0.10" } }, "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "requires": { "punycode": "1.4.1" } @@ -8441,7 +8624,7 @@ "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", "requires": { "isexe": "2.0.0" } @@ -8449,7 +8632,7 @@ "wide-align": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "integrity": "sha1-Vx4PGwYEY268DfwhsDObvjE0FxA=", "optional": true, "requires": { "string-width": "1.0.2" @@ -8497,7 +8680,7 @@ "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=" }, "wordwrap": { "version": "1.0.0", @@ -8520,7 +8703,7 @@ "write-file-atomic": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "integrity": "sha1-H/YVdcLipOjlENb6TiQ8zhg5mas=", "requires": { "graceful-fs": "4.1.11", "imurmurhash": "0.1.4", diff --git a/package.json b/package.json index 34d7805..9fea21b 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "lodash": "4.17.4", "method-override": "2.3.9", "mocha": "3.5.0", - "moment": "2.18.1", + "moment": "2.19.3", "mongoose": "4.11.10", "morgan": "1.8.2", "passport": "0.4.0",