diff --git a/.gitignore b/.gitignore index 33bef2c..f458eb3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ dist/ tmp/ etc/ +api/apib/documentation.apib # dependencies node_modules @@ -46,7 +47,8 @@ Thumbs.db # Internal Data public/ mongodb-data/ -resource/ +api/resource/ +api/apib/dredd/data/tmp-resource backup/ # System diff --git a/README.md b/README.md index bb94140..5b1d078 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ In addition, it sets up the mongo deamon to start up automatically with the syst For production setup run the script, described in _Setup for development_, adding the parameter `prod` - ./docs/opt-cc-environment/3rd-party-install.sh prod + ./docs/opt-cc-environment/3rd-party-install.sh prod This adds the [`pm2` process manager](http://pm2.keymetrics.io/) to be installed and start the _opt-cc_ server as `pm2` process. Run the `sudo` command printed as last output to configure the `pm2` process for automatic start on the system. diff --git a/api/.eslintrc.js b/api/.eslintrc.js new file mode 100644 index 0000000..ce3478c --- /dev/null +++ b/api/.eslintrc.js @@ -0,0 +1,11 @@ +module.exports = { + 'extends': 'google', + 'parserOptions': { + 'ecmaVersion': 6 + }, + 'rules': { + 'max-len': [2, 120, 4, { + 'ignoreUrls': true + }], + } +}; diff --git a/api/apib/admin/account.apib b/api/apib/admin/account.apib new file mode 100644 index 0000000..75fd27d --- /dev/null +++ b/api/apib/admin/account.apib @@ -0,0 +1,39 @@ +### List App Users [GET /account] + +List all app users, ordered by username + +**Permission: 4** + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[AppUser], fixed-type) + + +### Update App User [PATCH /account/{id}] + +Update an app user, identified by its id + +**Permission: 4** + ++ Parameters + + id: `5abf5064861d950f157c4a09` (string, required) - unique id of app user + ++ Request (application/json) + + + Attributes (UpdateAppUser) + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (AppUser, fixed-type) + + +### Delete App User [DELETE /account/{id}] + +**Permission: 4** + +Delete an app user + ++ Parameters + + id: `5ac0de67b5edc7771c027b94` (string, required) - unique id of app user + ++ Response 204 diff --git a/api/apib/admin/signature.apib b/api/apib/admin/signature.apib new file mode 100644 index 0000000..a718810 --- /dev/null +++ b/api/apib/admin/signature.apib @@ -0,0 +1,16 @@ +### Update signature image [POST /cmd/createSignature/{userId}] + +Update an army members signature image + +**Permission: 4** + ++ Parameters + + userId: `5ab68d42f547ed304064e5f7` (string, required) - army members unique user id + ++ Request (application/json) + {} + ++ Response 200 (application/json; charset=utf-8) + + + Attributes + + status: `success` (string, required) - action result message diff --git a/api/apib/army-management/army.apib b/api/apib/army-management/army.apib new file mode 100644 index 0000000..bdeb99d --- /dev/null +++ b/api/apib/army-management/army.apib @@ -0,0 +1,7 @@ +### Get Army Overview [GET /overview] + +Get bundled army, squad and member data for the participating fractions + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[Fraction]) diff --git a/api/apib/army-management/awardings.apib b/api/apib/army-management/awardings.apib new file mode 100644 index 0000000..fe62355 --- /dev/null +++ b/api/apib/army-management/awardings.apib @@ -0,0 +1,60 @@ +### Get Awardings [GET /awardings{?userId,inProgress,fractFilter}] + +List all awardings + ++ Parameters + + userId: `5ab68d42f547ed304064e5f7` (string, optional) + specific army member Id to show the awardings for + + + inProgress: false (boolean, optional) + true to filter by awarding state 'in progress' + + + Default: false + + + fractFilter: `BLUFOR` (enum[string], optional) + Field to filter by fraction + + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` + + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[AwardingPopulated], fixed-type) + +### Create Awarding [POST /awardings] + +Create a new awarding which is immediatly assigned to the user + +**Permission: 2** + ++ Request (application/json) + + + Attributes + + userId: `5ab68d42f547ed304064e5f7` (string, required) - unique id of the army member to give award + + decorationId: `5abd3dff6e6a0334d95b8ba0` (string, required) - unique id of the decoration + + reason: `Good boy` (string, required) - reason for giving the awarding + + proposer: `5ab68ceef547ed304064e5f6` (string, required) - app user id, who requested this awarding + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Awarding, fixed-type) + +### Create Awarding Proposal [POST /request/award] + +Create a new awarding proposal, that needs to be approved by higher permission level user to take effect + +**Permission: 1** + ++ Request (application/json) + + + Attributes + + userId: `5ab68d42f547ed304064e5f7` (string, required) - unique id of the army member to give award + + decorationId: `5abd3dff6e6a0334d95b8ba0` (string, required) - unique id of the decoration + + reason: `Good boy` (string, required) - reason for giving the awarding + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Awarding, fixed-type) diff --git a/api/apib/army-management/decorations.apib b/api/apib/army-management/decorations.apib new file mode 100644 index 0000000..65b8476 --- /dev/null +++ b/api/apib/army-management/decorations.apib @@ -0,0 +1,127 @@ +### List Decorations [GET /decorations{?q,fractFilter}] + +List all decorations + ++ Parameters + + q: `tapferkeit` (string, optional) + Filter string for the partial decoration name + + + fractFilter: `BLUFOR` (enum[string], optional) + Field to filter by fraction + + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[Decoration], fixed-type) + + +### Get Decoration [GET /decorations/{id}] + +Retrieve single decoration data + ++ Parameters + + id: `5abd3dff6e6a0334d95b8ba0` (string, required) - unique id of the decoration to fetch + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Decoration, fixed-type) + +### Create Decoration [POST /decorations] + +Create a new decoration + +**Permission: 2** + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="name" + Content-Type: text/plain + + Super medal 2000 + -----BOUNDARY + Content-Disposition: form-data; name="fraction" + Content-Type: text/plain + + OPFOR + -----BOUNDARY + Content-Disposition: form-data; name="description" + Content-Type: text/plain + + For good performance in a battle + -----BOUNDARY + Content-Disposition: form-data; name="isMedal" + Content-Type: text/plain + + true + -----BOUNDARY + Content-Disposition: form-data; name="image"; filename="image.png" + Content-Type: image/png + Content-Transfer-Encoding: base64 + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlMA + QObYZgAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII= + -----BOUNDARY-- + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Decoration, fixed-type) + +### Update Decoration [PATCH /decorations/{id}] + +Update decoration, identified by its id + +**Permission: 2** + ++ Parameters + + id: `5abeb420b987672bb1ede643` (string, required) - unique id of the decoration + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="name" + Content-Type: text/plain + + Super medal 2000 + -----BOUNDARY + Content-Disposition: form-data; name="fraction" + Content-Type: text/plain + + OPFOR + -----BOUNDARY + Content-Disposition: form-data; name="description" + Content-Type: text/plain + + For good performance in a battle + -----BOUNDARY + Content-Disposition: form-data; name="sortingNumber" + Content-Type: text/plain + + 2 + -----BOUNDARY + Content-Disposition: form-data; name="image"; filename="image.png" + Content-Type: image/png + Content-Transfer-Encoding: base64 + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlMA + QObYZgAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII= + -----BOUNDARY-- + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Decoration, fixed-type) + +### Delete Decoration [DELETE /decorations/{id}] + +Delete a decoration + +**Permission: 2** + ++ Parameters + + id: `5abeb43cb987672bb1ede644` (string, required) - unique id of the decoration + ++ Response 204 diff --git a/api/apib/army-management/promotions.apib b/api/apib/army-management/promotions.apib new file mode 100644 index 0000000..d95b114 --- /dev/null +++ b/api/apib/army-management/promotions.apib @@ -0,0 +1,65 @@ +### List Promotions [GET /request/promotion{?squadId,inProgress,fractFilter}] + +List all promotion requests + ++ Parameters + + squadId: `591470249e9fae286e008e31` (string, optional) + specific squad Id to show the promotion requests for + + + inProgress: false (boolean, optional) + true to filter by promotion state 'in progress' + + + Default: false + + + fractFilter: `BLUFOR` (enum[string], optional) + Field to filter by fraction + + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[PromotionPopulated]) + +### Create Promotion Proposal [POST /request/promotion] + +Create a new proposal for a promotion, that needs to be approved by higher permission level user to take effect + +**Permission: 1** + ++ Request (application/json) + + + Attributes + + userId: `5ab68d42f547ed304064e5f7` (string, required) - id of the army member to promote + + oldRankLvl: 0 (number, required) - previous rank level + + newRankLvl: 5 (number, required) - new rank level to apply + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Promotion, fixed-type) + + +### Update Promotion Proposal [PATCH /request/promotion/{id}] + +Update the promotion proposal + +**Permission: 2** + ++ Parameters + + id: `5abf50d9861d950f157c4a0a` (string, required) - unique id of the promotion + ++ Request (application/json) + + + Attributes + + _id: `5abf50d9861d950f157c4a0a` (string, optional) - id of the promotion proposal + + userId: `5ab68d42f547ed304064e5f7` (string, optional) - id of the army member to promote + + proposer: `5abf5064861d950f157c4a09` (string, optional) - id of the proposing app user + + oldRankLvl: 0 (number, optional) - previous rank level + + newRankLvl: 5 (number, optional) - new rank level to apply + + confirmed: 1 (number, optional) confirmation status of the promotion (0 - in progress, 1 - approved & applied, 2 - rejected) \nThis automatically applies the *newRankLvl*value as new rank level to the target user when confirmed = 1 + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Promotion, fixed-type) diff --git a/api/apib/army-management/ranks.apib b/api/apib/army-management/ranks.apib new file mode 100644 index 0000000..dda6133 --- /dev/null +++ b/api/apib/army-management/ranks.apib @@ -0,0 +1,116 @@ +### List Ranks [GET /ranks{?q,fractFilter}] + +List all ranks + ++ Parameters + + q: `Gefr` (string, optional) - filter string which filters for partial rank name + + + fractFilter: `BLUFOR` (enum[string], optional) + Field to filter by fraction + + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[Rank], fixed-type) + + +### Get Rank [GET /ranks/{id}] + +Retrieve single rank data + ++ Parameters + + id: `5aba5504eadcce6332c6a775` (string, required) - unique id of the rank to fetch + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Rank, fixed-type) + +### Create Rank [POST /ranks] + +Create a new rank + +**Permission: 2** + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="name" + Content-Type: text/plain + + Obergefreiter + -----BOUNDARY + Content-Disposition: form-data; name="fraction" + Content-Type: text/plain + + BLUFOR + -----BOUNDARY + Content-Disposition: form-data; name="level" + Content-Type: text/plain + + 2 + -----BOUNDARY + Content-Disposition: form-data; name="image"; filename="image.png" + Content-Type: image/png + Content-Transfer-Encoding: base64 + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlMA + QObYZgAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII= + -----BOUNDARY-- + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Rank, fixed-type) + +### Update Rank [PATCH /ranks/{id}] + +Update rank, identified by its id + +**Permission: 2** + ++ Parameters + + id: `5abeb23995cf43205225710b` (string, required) - unique id of the rank + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="name" + Content-Type: text/plain + + Stabsunteroffizier + -----BOUNDARY + Content-Disposition: form-data; name="fraction" + Content-Type: text/plain + + BLUFOR + -----BOUNDARY + Content-Disposition: form-data; name="level" + Content-Type: text/plain + + 10 + -----BOUNDARY + Content-Disposition: form-data; name="image"; filename="image.png" + Content-Type: image/png + Content-Transfer-Encoding: base64 + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlMA + QObYZgAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII= + -----BOUNDARY-- + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Rank, fixed-type) + +### Delete Rank [DELETE /ranks/{id}] + +Delete a rank + +**Permission: 2** + ++ Parameters + + id: `5abeb1b995cf43205225710a` (string, required) - unique id of the rank + ++ Response 204 diff --git a/api/apib/army-management/squads.apib b/api/apib/army-management/squads.apib new file mode 100644 index 0000000..3e6cd03 --- /dev/null +++ b/api/apib/army-management/squads.apib @@ -0,0 +1,110 @@ +### List Squads [GET /squads{?q,fractFilter}] + +Get single army member information + ++ Parameters + + q: `alpha` (string, optional) - filter string which filters for partial squadname + + + fractFilter: `BLUFOR` (enum[string], optional) + Field to filter by fraction + + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[Squad], fixed-type) + +### Get Squad [GET /squads/{id}] + +Get single squad information + ++ Parameters + + id: `5aba54eaeadcce6332c6a774` (string, required) - unique id of the squad + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Squad, fixed-type) + +### Create Squad [POST /squads] + +Create a new squad + +**Permission: 2** + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="name" + Content-Type: text/plain + + Delta + -----BOUNDARY + Content-Disposition: form-data; name="fraction" + Content-Type: text/plain + + BLUFOR + -----BOUNDARY + Content-Disposition: form-data; name="image"; filename="image.png" + Content-Type: image/png + Content-Transfer-Encoding: base64 + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlMA + QObYZgAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII= + -----BOUNDARY-- + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Squad, fixed-type) + +### Update Squad [PATCH /squads/{id}] + +Update squad, identified by its id + +**Permission: 2** + ++ Parameters + + id: `5abe166f8b7488392a623f12` (string, required) - unique id of the squad + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="name" + Content-Type: text/plain + + test-CSAT + -----BOUNDARY + Content-Disposition: form-data; name="fraction" + Content-Type: text/plain + + OPFOR + -----BOUNDARY + Content-Disposition: form-data; name="sortingNumber" + Content-Type: text/plain + + 3 + -----BOUNDARY + Content-Disposition: form-data; name="image"; filename="image.png" + Content-Type: image/png + Content-Transfer-Encoding: base64 + + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlMA + QObYZgAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII= + -----BOUNDARY-- + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Squad, fixed-type) + +### Delete Squad [DELETE /squads/{id}] + +Delete a squad + +**Permission: 2** + ++ Parameters + + id: `5abe16f98b7488392a623f17` (string, required) - unique id of the squad + ++ Response 204 diff --git a/api/apib/army-management/users.apib b/api/apib/army-management/users.apib new file mode 100644 index 0000000..6c4573e --- /dev/null +++ b/api/apib/army-management/users.apib @@ -0,0 +1,93 @@ +### List Users [GET /users{?q,fractFilter,limit,offset}] + +Get single army member information + ++ Parameters + + q: `hardi` (string, optional) - filter string which filters for partial username + + + fractFilter: `BLUFOR` (enum[string], optional) + Field to filter by fraction + + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` + + + limit: 20 (number, optional) + Maximum number of users to return + + + Default: Infinity + + + offset: 0 (number, optional) + Offset into result-set (useful for pagination) + + + Default: 0 + ++ Response 200 (application/json; charset=utf-8) + + + Headers + + X-Total-Count: 1 + + + Attributes (array[UserPopulated], fixed-type) + + +### Get User [GET /users/{id}] + +Get single army member information + ++ Parameters + + id: `5ab68d42f547ed304064e5f7` (string, required) - unique id of army-member + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (UserPopulated, fixed-type) + + +### Create User [POST /users] + +Create a new army member + +**Permission: 2** + ++ Request (application/json) + + + Attributes + + username: `[GNC]Paolo` (string, required) - display name of the user + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (UserInclTimestamp, fixed-type) + +### Update User [PUT /users/{id}] + +Update an army member, identified by its id + +**Permission: 2** + ++ Parameters + + id: `5abd4780396bc0487068be0e` (string, required) - unique id of army-member + ++ Request (application/json) + + + Attributes + + _id: `5abd4780396bc0487068be0e` (string, required) - unique id of army-member + + username: `Paolo` (string, optional) - display name of the user + + rankLvl: 22 (number, optional) - rank level representing the rank + + squadId: `591470249e9fae286e008e31` (string, optional) - squadId of squad which army member is part of + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (User, fixed-type) + + +### Delete User [DELETE /users/{id}] + +Delete an army member + +**Permission: 2** + ++ Parameters + + id: `5abd4780396bc0487068be0e` (string, required) - unique id of army-member + ++ Response 204 diff --git a/api/apib/auth/login.apib b/api/apib/auth/login.apib new file mode 100644 index 0000000..3063457 --- /dev/null +++ b/api/apib/auth/login.apib @@ -0,0 +1,11 @@ +### Login - Generate Token [POST /authenticate] + +Generate a token which can be used to make API requests. + ++ Request Generate Token (application/json) + + + Attributes (Login) + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (LoginResponse) diff --git a/api/apib/auth/signup.apib b/api/apib/auth/signup.apib new file mode 100644 index 0000000..66fc5f0 --- /dev/null +++ b/api/apib/auth/signup.apib @@ -0,0 +1,13 @@ +### Sign up - Create account [POST /authenticate/signup] + +Create a new application user account. + ++ Request Create Account (application/json) + + + Attributes (Registration) + ++ Response 201 (application/json; charset=utf-8) + + + Attributes + + + message: `User successfully created` (string, required) diff --git a/api/apib/base/access.apib b/api/apib/base/access.apib new file mode 100644 index 0000000..14e4ae7 --- /dev/null +++ b/api/apib/base/access.apib @@ -0,0 +1,54 @@ +## Location + +The API can only be accessed via HTTPS in the cloud instance. + +You can reach the API for the cloud instance at + +``` +https://cc.noarch.de/api/ +``` + +Local installations can access the API using the respective domain with the path `/api/` appended. + +So if your server is reachable at `https://cc.myserver.lan` the API endpoint is located at + +``` +# Note: `/api/` is appended to the locale installation server url + +https://cc.myserver.lan/api/ +``` + +## Authentication + +Requests to most of the API endpoints have to be authenticated using an API token which is received after successfully providing your application credentials to the API. + +Once acquired the token has to be provided in the ``X-Access-Token`` header of every request that requires authentication. + +The following example illustrates how to provide the token when using `curl` + + +``` +# via Authorization header + +> curl -H "X-Access-Token: $CC_API_TOKEN" +``` + +## Permission Levels + +The permission level is resolved by the API token you send, which resolves the specific app user information. + +Endpoints that require a certain permission level to be accessed, mention the **minimum** required permission level in the description. + +::: note +Permission Levels: + + 0 - User + + 1 - Squadlead + + 2 - High Command + + 3 - Maintainer + + 4 - Administrator +::: diff --git a/api/apib/base/datetime.apib b/api/apib/base/datetime.apib new file mode 100644 index 0000000..165ca11 --- /dev/null +++ b/api/apib/base/datetime.apib @@ -0,0 +1,10 @@ +## Timezones & Date Format + +**Date Format** + +In general the API returns and expects dates & times in the ISO 8601 format. +For example: `2017-02-27T17:05:33.155Z` for a time or `2017-02-27` for a date. + +**Timezone** + +The default timezone returned will be the UTC timezone diff --git a/api/apib/base/file-resources.apib b/api/apib/base/file-resources.apib new file mode 100644 index 0000000..6eee5ee --- /dev/null +++ b/api/apib/base/file-resources.apib @@ -0,0 +1,36 @@ +The running express server instance saves entity related files like squad logos and statistic logs on the file system. +In the original MEAN application they are served in the `/resource` path of the application server. + +The following examples show where those files are located, to be accessed on the cloud instance. + +## Images +**Decoration Image** + +`https://cc.noarch.de/resource/decoration/{decorationId}.png` + +**Rank Image** + +`https://cc.noarch.de/resource/rank/{rankId}.png` + +**Signature Image** + +`https://cc.noarch.de/resource/signature/{userId}.png` + +**Squad Logo** + +`https://cc.noarch.de/resource/squad/{squadId}.png` + +## Log-Files + +**Sanitized Log File** + +`https://cc.noarch.de/resource/logs/{warId}/clean.log` + +**Original Uploaded Log File** + +`https://cc.noarch.de/resource/logs/{warId}/war.log` + + + + + diff --git a/api/apib/data_structures/_app-user.apib b/api/apib/data_structures/_app-user.apib new file mode 100644 index 0000000..f63ec3c --- /dev/null +++ b/api/apib/data_structures/_app-user.apib @@ -0,0 +1,31 @@ +# Proposer (object) +Representation of an app user who proposed an awarding or a promotion + +## Properties + ++ _id: `5abf5064861d950f157c4a09` (string, required) - unique id of the app user ++ username: `hardiready` (string, required) - username of the app user ++ squad: `591470249e9fae286e308e41` (string, required) - squad id associated with the app user + +# AppUser (Proposer) +An app user instance with populated squad + +## Properties ++ activated: true (boolean, required) - account activation status ++ password: `$1s23$1$H7dl7RTFZUBIBNUZ213IIOUasdNEI571sMuzXmzi4` (string, required) - password hash value ++ permission: 1 (number, required) - permission level ++ secret: `I like tacos` (string, required) - secret used for account activation comparison ++ squad (Squad, required, nullable) - squad the app user is responsible for ++ timestamp: `2017-08-02T07:48:56.378Z` (string, required) - creation timestamp ++ updatedAt: `2017-08-02T08:07:20.929Z` (string, required) - version timestamp ++ __v: 3 (number, required) - version number + +# UpdateAppUser (Proposer) +An app user instance for PATCH updating + +## Properties ++ activated: true (boolean, optional) - account activation status ++ password: `$1s23$1$H7dl7RTFZUBIBNUZ213IIOUasdNEI571sMuzXmzi4` (string, optional) - password hash value ++ permission: 1 (number, optional) - permission level ++ secret: `I like tacos` (string, optional) - secret used for account activation comparison ++ squad: `5abe166f8b7488392a623f12` (string, optional) - id of squad the app user is responsible for diff --git a/api/apib/data_structures/_army.apib b/api/apib/data_structures/_army.apib new file mode 100644 index 0000000..b73f1f1 --- /dev/null +++ b/api/apib/data_structures/_army.apib @@ -0,0 +1,26 @@ +# Fraction (object) +Single fraction object + +## Properties ++ squads (array[ArmySquad], required) - Array containing all squads of the fraction, sorted by 'sortingNumber' ++ memberCount: 1 (number, required) - sum of fraction members in all squads + + +# ArmySquad (object) +A single squad as appearing in the army overview + +## Properties ++ _id: `59146e6aef2ad810623ed519` (string, required) - the unique id of the squad ++ name: `Führungsstab` (string, required) - the squad display name ++ members (array[ArmyMember], required) - List of participants being member in this squad ++ memberCount: 1 (number, required) - Number of members the squad has + + +# ArmyMember (object) +Unique member in a army squad + +## Properties + ++ _id: `5918d2ca574b0b16820a0b28` (string, required) - unique id of the army member ++ username: `Jagernaut` (string, required) - display name of the army member ++ rank: `General` (string, required) - display name of the rank which is assigned to this army member diff --git a/api/apib/data_structures/_auth.apib b/api/apib/data_structures/_auth.apib new file mode 100644 index 0000000..9ebbb4f --- /dev/null +++ b/api/apib/data_structures/_auth.apib @@ -0,0 +1,29 @@ +# Login (object) +User related entity for creating a token using application credentials + +## Properties + ++ username: `testuser` (string, required) - username of the app-user ++ password: `password` (string, required) - password of the app-user + +# LoginResponse (object) +Response object on successful token creation + +## Properties + ++ _id: `593d632772d35225232bcabb` (string, required) - the unique id of the app-user ++ username: `kallek` (string, required) - the username of the app-user ++ permission: 3 (number, required)- the permission level of the app-user (0 - user, 1 - sql, 2 - hl, 3 - maintainer, 4 - admin) ++ squad (Squad, required) - squad the app-user is member of ++ token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1OTNkNWUzZjcyZDM1MjI1MjIyYmNhYmEiLCJpYXQiOjE1MjEzOTQ5NDYsImV4cCI6MTUyMzgxNDE0Nn0.vOAwA5--qrx8BglhyGZWVYx7LeuRKOHH0NQXmHFNhIQ` (string,required) - generated access token ++ tokenExpireDate: `2018-04-15T17:42:25.050Z` (string,required) - expiration date of the token + + +# Registration (object) +User related entity for reflecting membership to another resource (groups, material databases) + +## Properties + ++ username: `kallek` (string, required) - the username of the app-user ++ password: `password` (string, required) - password of the app-user ++ secret: `random secret text` (string, required) - secret used for sign-up identification in connection with board usage diff --git a/api/apib/data_structures/_awarding.apib b/api/apib/data_structures/_awarding.apib new file mode 100644 index 0000000..bf2acfe --- /dev/null +++ b/api/apib/data_structures/_awarding.apib @@ -0,0 +1,22 @@ +# Awarding (object) +Awarding associating a decoration to a user + +## Properties ++ _id: `591ca81c1ee62711cfc19002` (string, required) - unique id of the awarding ++ confirmed: 1 (number, required) - status of the awarding request (0 - in progress, 1 - approved, 2 - rejected) ++ date: `2017-05-17T19:44:24.926Z` (string, required) - date when the awarding was requested ++ decorationId: `591c81981ee62711cfc18f4a` (string, required) - id of decoration that is given with the awarding ++ reason: `war dabei` (string, required) - reason for giving the awarding ++ proposer: 593d5e3f72d35225222bcaba (string, required) - id of app user who requested this awarding ++ timestamp: `2017-05-17T19:44:28.751Z` (string, required) - creation date ++ updatedAt: `"2017-05-17T19:44:28.751Z` (string, required) - version date ++ userId: `5918d2ca574b0b1d820a0b24` (string, required) - the unique id of the user who got this awarding ++ __v: 0 (number, required) - version number + + +# AwardingPopulated (Awarding) +Awarding with populated decoration and proposer + +## Properties ++ proposer (Proposer, required) - app user who requested this awarding ++ decorationId (Decoration, required) - populated decoration object that is given with the awarding diff --git a/api/apib/data_structures/_campaign.apib b/api/apib/data_structures/_campaign.apib new file mode 100644 index 0000000..ea79121 --- /dev/null +++ b/api/apib/data_structures/_campaign.apib @@ -0,0 +1,16 @@ +# Campaign (object) +Campaign entity + +## Properties ++ _id:`5abd55ea9e30a76bfef747d6` (string, required) - unique id of the campaign ++ title: `Ein Kessel Buntes` (string, required) - display title of the campaign ++ timestamp: `2017-05-17T19:44:28.751Z` (string, required) - creation date ++ updatedAt: `"2017-05-17T19:44:28.751Z` (string, required) - version date ++ __v: 0 (number, required) - version number + +#WarCampaign (object) +Cmpaign entity with attached War collection +## Properties ++ _id: `5abd55ea9e30a76bfef747d6` (string, required) - unique id of the campaign ++ title: `Ein Kessel Buntes` (string, required) - display title of the campaign ++ wars (array[WarWithPlayers], requied) diff --git a/api/apib/data_structures/_decoration.apib b/api/apib/data_structures/_decoration.apib new file mode 100644 index 0000000..3ce4655 --- /dev/null +++ b/api/apib/data_structures/_decoration.apib @@ -0,0 +1,19 @@ +# Decoration (object) + +A decoration representing a ribbon or medal + +## Properties + ++ _id: `591c81981ee62711cfc18f4a` (string, required) - unique id of the decoration ++ description: `Verliehen an alle Teilnehmer der ArmA3-Kampagne "Sturm über der Ägäis" im Jahr 2016` (string, required) - description expressing what the decoration should be given for ++ fraction: `GLOBAL` (string, required) - enum expressing the fraction in which the decoration is given + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` ++ isMedal: false (boolean, required) - show if decoration is medal or ribbon ++ name: `OPT4 pt.1 - "Sturm über der Ägäis"` (string, required) - display name of the decoration ++ sortingNumber: 10 (number, required) - sorting number for lists ++ timestamp: `2017-05-17T17:00:08.684Z` (string, required) - creation timestamp ++ updatedAt: `2018-01-13T09:57:50.827Z` (string, required) - version timestamp ++ __v: 2 (number, required) - version number diff --git a/api/apib/data_structures/_log.apib b/api/apib/data_structures/_log.apib new file mode 100644 index 0000000..6feca45 --- /dev/null +++ b/api/apib/data_structures/_log.apib @@ -0,0 +1,79 @@ +# Log (object) +## Properties ++ _id: `` (string, required) - log entry id ++ war: `` (string, required) - warId ++ time: `` (string, required) - logging timestamp ++ __v: 0 (number, required) - object version number + +# LogPoints (Log) +## Properties ++ ptBlufor: 2 (number, required) - standings for BLUFOR ++ ptOpfor: 4 (number, required) - standings for OPFOR ++ fraction: `OPFOR` (enum, required) - dominating fraction + + Members + + `BLUFOR` + + `OPFOR` + + `NONE` + +#LogBudget (Log) +## Properties ++ oldBudget: 400000 (number, required) - budget before buy action ++ newBudget: 380000 (number, required) - budget after buy action ++ fraction: `BLUFOR` (enum, required) - buying fraction + + Members + + `BLUFOR` + + `OPFOR` + +#LogFlag (Log) +## Properties ++ player: `HardiReady` (string, required) - name of player who captured/secured flag ++ capture: true (boolean, required) - true if flag was captured, false if it was secured ++ flagFraction: `BLUFOR` (enum, required) - fraction who owns the flag + + Members + + `BLUFOR` + + `OPFOR` + +#LogKill (Log) +## Properties ++ shooter: `HardiReady` (string, required) - name of player who made the kill ++ target: `KalleK` (string, required) - name of player which got killed ++ friendlyFire: true (boolean, required) - true if it was a friendly fire kill, false if it was a normal kill ++ fraction: `BLUFOR` (enum, required) - fraction of shooter + + Members + + `BLUFOR` + + `OPFOR` + + `NONE` + +#LogRespawn (Log) +## Properties ++ player: `radical1976` (string, required) - name of the player who respawns + +#LogRevive (Log) +## Properties ++ medic: `radical1976` (string, required) - name of the player who revives/stabilizes ++ patient: `HardiReady` (string, required) - name of the player who is revived/stabilized ++ stabilized: false (boolean, required) - false if it is a revive, true if it is stabilizing ++ fraction: `BLUFOR` (enum, required) - fraction of the medic + + Members + + `BLUFOR` + + `OPFOR` + +#LogTransport (Log) +## Properties ++ driver: `radical1976` (string, required) - name of the vehicle driver/pilot ++ passenger: `radical1976` (string, required) - name of the passenger being transported ++ distance: 2435 (number, required) - distance of transport in meters ++ fraction: `BLUFOR` (enum, required) - fraction of the driver + + Members + + `BLUFOR` + + `OPFOR` + +#LogVehicle (Log) +## Properties ++ shooter: `HardiReady` (string, required) - name of player who shot the vehicle ++ target: `T-100` (string, required) - name of the vehicle ++ fraction: `BLUFOR` (enum, required) - fraction of the shooter + + Members + + `BLUFOR` + + `OPFOR` + + `NONE` diff --git a/api/apib/data_structures/_player.apib b/api/apib/data_structures/_player.apib new file mode 100644 index 0000000..0c77839 --- /dev/null +++ b/api/apib/data_structures/_player.apib @@ -0,0 +1,34 @@ +# BasicPlayer (object) + +Basic player statistic information object + +##Properties ++ name: `Jagernaut` (string, required) - the displayed username of the army member ++ fraction: `OPFOR` (string, required) - fraction of the player ++ kill: 5 (number, required) - sum of kills ++ friendlyFire: 0 (number, required) - sum of friendly fire kills ++ vehicle: 1 (number, required) - sum of vehicle kills ++ death: 3 (number, required) - sum of deaths ++ respawn: 2 (number, required) - sum of respawns ++ flagTouch: 1 (number, required) - sum of flag captures ++ revive: 0 (number, required) - sum of revives + + +# WarPlayer (BasicPlayer) +A player campaign statistics object + +## Properties ++ _id: `5ab68d42f547ed304064e5f7` (string, required) - unique id of the army member ++ warId: `5abf65ae3fc5fa349ffd5ca3` (string, required) - war in which this player took part ++ steamUUID: `76561192214911200` (string, required) - unique ID for STEAM platform account ++ sort: 1 (number, required) - sorting number calculated by (kill + revive + flagTouch - friendlyFire - death - respawn) ++ timestamp: `2018-02-24T01:01:25.825Z` - the entity creation timestamp ++ updatedAt: `2018-02-24T01:01:25.825Z` - the version timestamp ++ __v: 0 (number, required) - the version number of the object + + +# HighscorePlayer (BasicPlayer) +A player object as resturned for the highscore arrays + +## Properties ++ num: 1 diff --git a/api/apib/data_structures/_promotion.apib b/api/apib/data_structures/_promotion.apib new file mode 100644 index 0000000..48e5aaa --- /dev/null +++ b/api/apib/data_structures/_promotion.apib @@ -0,0 +1,20 @@ +# Promotion (object) +Representation of a promotion request for a army member + +## Properties ++ _id: `5as7d05dcb90ce4da68c4f5f` (string, required) - unique id of the promotion request ++ confirmed: 0 (number, required) - number representing status of the promotion (0 - in progress, 1 - approved, 2 - rejected) ++ newRankLvl: 14 (number, required)- new rank level that is requested in this promotion ++ oldRankLvl: 10 (number, required)- old rank level of the user ++ proposer: `5abf5064861d950f157c4a09` (string, required) - id of app user who requested the promotion ++ timestamp: `2018-03-25T18:54:21.609Z` (string, required) - creation timestamp ++ updatedAt: `2018-03-25T18:54:21.609Z` (string, required) - version timestamp ++ userId: `5ab68d42f547ed304064e5f7` (string, required) - id of army member the promotion is requested for ++ __v: 0 (number, required) - version number of promotion instance + +# PromotionPopulated (object) +Promotion with populated proposer and army member + +## Properties ++ proposer (Proposer, required) - app user who requested the promotion ++ userId (User, required) - populated user instance of user the promotion is requested for diff --git a/api/apib/data_structures/_rank.apib b/api/apib/data_structures/_rank.apib new file mode 100644 index 0000000..7cfd9e0 --- /dev/null +++ b/api/apib/data_structures/_rank.apib @@ -0,0 +1,16 @@ +# Rank (object) + +A rank that can be applied to army members by level/fraction + +## Properties ++ _id: `591469c9ef4a6810623ed4ea` (string, required) - the unique id of the rank ++ name: `Gefreiter` (string, required) - display name of the rank ++ fraction: `BLUFOR` (enum, required) - enum expressing the fraction in which the decoration is given + + Members + + `BLUFOR` + + `OPFOR` + + `GLOBAL` ++ level: 1 (number, required) - rank level ++ updatedAt: `2017-09-20T20:25:29.995Z` (string, required) - the version timestamp ++ timestamp: `2017-05-11T13:40:25.051Z` (string, required) - the creation timestamp ++ __v: 1 (number, required) - version number diff --git a/api/apib/data_structures/_squad.apib b/api/apib/data_structures/_squad.apib new file mode 100644 index 0000000..58d9273 --- /dev/null +++ b/api/apib/data_structures/_squad.apib @@ -0,0 +1,13 @@ +# Squad (object) + +A Squad entity + +## Properties + ++ _id: `591470249e9fae286e008e31` (string, required) - the unique id of the squad ++ sortingNumber: 30 (number, required) - the number for orders in lists of squads ++ updatedAt: `2017-05-31T20:43:07.165Z` (string, required) - version timestamp ++ timestamp: `2017-05-11T14:07:32.471Z` (string, required) - creation timestamp ++ name: `Alpha` (string, required) - display name of the squad ++ fraction: `BLUFOR` (string, required) - fraction the squad is part of ++ __v: 2 (number, required) - version number diff --git a/api/apib/data_structures/_user.apib b/api/apib/data_structures/_user.apib new file mode 100644 index 0000000..c6b4c4a --- /dev/null +++ b/api/apib/data_structures/_user.apib @@ -0,0 +1,22 @@ +# User (object) +A participant managed in the system + +## Properties ++ _id: `5ab68d42f547ed304064e5f7` (string, required) - unique id of the army member ++ username: `Jagernaut` (string, required) - the displayed username of the army member ++ rankLvl: 22 (number, required) - rank level representing the rank ++ squadId: `591470249e9fae286e008e31` (string, required, nullable) - id of squad which the army member is part of ++ updatedAt: `2018-02-24T01:01:25.825Z` - the version timestamp ++ __v: 35 (number, required) - the version number of the object + +# UserPopulated (User) +User object with populated squad + +## Properties ++ squadId (Squad, required) - populated squad which the army member is part of + +# UserInclTimestamp (User) +A participant managed in the system, incl. creation timestamp + +## Properties ++ timestamp: 2018-01-20T12:11:23.125Z (string, required) - instance creation timestamp diff --git a/api/apib/data_structures/_war.apib b/api/apib/data_structures/_war.apib new file mode 100644 index 0000000..0257ccd --- /dev/null +++ b/api/apib/data_structures/_war.apib @@ -0,0 +1,26 @@ +# War (object) +A war as used in statistics + +## Properties ++ _id: `5ab68d41f537ed304064e5f7` (string, required) - unique id of the war ++ title: `Battle No.1` (string, required) - the display neme of the war ++ date: `2018-02-24T20:01:25.825Z` (string, required) - war start timestamp ++ endDate: `2018-02-24T22:31:26.855Z` (string, required) - war end timestamp ++ ptBlufor: 11 (number, required) - final points fraction Blufor ++ ptOpfor: 12 (number, required) - final points fraction Opfor ++ playersBlufor: 36 (number, required) - player count of fraction Blufor ++ playersOpfor: 34 (number, required) - player count of fraction opfor ++ campaign: `5abd55ea9e30a76bfef747d6` (string, required) - uniquer id of the campaign in which the war was played ++ budgetBlufor: 3900000 (number, required) - start budget of fraction Blufor ++ budgetOpfor: 4100000 (number, required) - start budget of fraction Opfor ++ endBudgetBlufor: 924000 (number, required) - end budget of fraction Blufor ++ endBudgetOpfor: 12400 (number, required) - end budget of fraction Opfor ++ timestamp: `2018-02-24T01:01:25.825Z` (string, required) - creation date ++ updatedAt: `2018-02-24T01:01:25.825Z` (string, required) - the version timestamp ++ __v: 0 (number, required) - the version number of the object + +# WarWithPlayers (War) +A war response object on creation + +## Properties ++ players (array[WarPlayer], required) - collection of all participating players with their statistics diff --git a/api/apib/data_structures/index.apib b/api/apib/data_structures/index.apib new file mode 100644 index 0000000..98a98ec --- /dev/null +++ b/api/apib/data_structures/index.apib @@ -0,0 +1,27 @@ +# Data Structures + +:[Gists](_app-user.apib) + +:[Gists](_army.apib) + +:[Gists](_auth.apib) + +:[Gists](_awarding.apib) + +:[Gists](_campaign.apib) + +:[Gists](_decoration.apib) + +:[Gists](_log.apib) + +:[Gists](_player.apib) + +:[Gists](_promotion.apib) + +:[Gists](_rank.apib) + +:[Gists](_squad.apib) + +:[Gists](_user.apib) + +:[Gists](_war.apib) diff --git a/api/apib/dev-doc.apib b/api/apib/dev-doc.apib new file mode 100644 index 0000000..206c6e6 --- /dev/null +++ b/api/apib/dev-doc.apib @@ -0,0 +1,71 @@ +FORMAT: 1A + +# Operation Pandora Trigger Command Center API Documentation + +:[Gists](data_structures/index.apib) + +# Group General Introduction + +:[Gists](base/access.apib) + +:[Gists](base/datetime.apib) + +# Group File Resources + +:[Gists](base/file-resources.apib) + +# Group Access + +:[Gists](auth/signup.apib) + +:[Gists](auth/login.apib) + +# Group Admin + +:[Gists](admin/account.apib) + +:[Gists](admin/signature.apib) + +# Group Army Overview + +:[Gists](army-management/army.apib) + +# Group Awardings + +:[Gists](army-management/awardings.apib) + +# Group Campaigns + +:[Gists](statistics/campaigns.apib) + +# Group Decorations + +:[Gists](army-management/decorations.apib) + +# Group Logs + +:[Gists](statistics/logs.apib) + +# Group Players + +:[Gists](statistics/players.apib) + +# Group Promotion + +:[Gists](army-management/promotions.apib) + +# Group Ranks + +:[Gists](army-management/ranks.apib) + +# Group Squads + +:[Gists](army-management/squads.apib) + +# Group Users + +:[Gists](army-management/users.apib) + +# Group Wars + +:[Gists](statistics/wars.apib) diff --git a/api/apib/dredd/data/app_user.json b/api/apib/dredd/data/app_user.json new file mode 100644 index 0000000..c06c7c1 --- /dev/null +++ b/api/apib/dredd/data/app_user.json @@ -0,0 +1,3 @@ +{"_id":{"$oid":"5abf5064861d950f157c4a09"},"squad":{"$oid":"5aba54eaeadcce6332c6a774"},"permission":1,"activated":true,"username":"some-squadlead","secret":"asd","password":"$2a$10$PGUw2F6HY.2Q3h0AL4Mea.3EKAGFO8S897z56CyU8q/5BC.5VEPAy","timestamp":{"$date":"2018-03-31T09:09:56.161Z"},"updatedAt":{"$date":"2018-03-31T09:09:56.161Z"},"__v":1} +{"_id":{"$oid":"5ab68ceef547ed304064e5f6"},"squad":{"$oid":"5aba54eaeadcce6332c6a774"},"permission":4,"activated":true,"username":"testuser","secret":"my secret","password":"$2a$10$wvgBbcckHrFu8Ctw8hSPNuFLoBy4sRubioyiK1NabOC0UgYD.KITi","timestamp":{"$date":"2018-03-24T17:37:50.668Z"},"updatedAt":{"$date":"2018-03-24T17:37:50.668Z"},"__v":0} +{"_id":{"$oid":"5ac0de67b5edc7771c027b94"},"squad":null,"permission":0,"activated":false,"username":"lord","secret":"tank","password":"$2a$10$k9LG.OiedyyGrySbDX7KZekesHEU.BadBhUUyS2ujM07NpIrLPFxe","timestamp":{"$date":"2018-04-01T13:28:07.147Z"},"updatedAt":{"$date":"2018-04-01T13:28:07.147Z"},"__v":0} diff --git a/api/apib/dredd/data/awarding.json b/api/apib/dredd/data/awarding.json new file mode 100644 index 0000000..9d3a451 --- /dev/null +++ b/api/apib/dredd/data/awarding.json @@ -0,0 +1 @@ +{"_id":{"$oid":"5abf50e7861d950f157c4a0b"},"confirmed":0,"date":{"$date":"2018-03-31T09:12:07.861Z"},"userId":{"$oid":"5ab68d42f547ed304064e5f7"},"decorationId":{"$oid":"5abd3dff6e6a0334d95b8ba0"},"reason":"bester mann!","proposer":{"$oid":"5abf5064861d950f157c4a09"},"timestamp":{"$date":"2018-03-31T09:12:07.873Z"},"updatedAt":{"$date":"2018-03-31T09:12:07.873Z"},"__v":0} diff --git a/api/apib/dredd/data/campaign.json b/api/apib/dredd/data/campaign.json new file mode 100644 index 0000000..2c31b97 --- /dev/null +++ b/api/apib/dredd/data/campaign.json @@ -0,0 +1,2 @@ +{"_id":{"$oid":"5abd55ea9e30a76bfef747d6"},"title":"Ein Kessel Buntes","timestamp":{"$date":"2018-03-29T21:08:58.123Z"},"updatedAt":{"$date":"2018-03-29T21:08:58.123Z"},"__v":0} +{"_id":{"$oid":"5abd58989e30a76bfef747e6"},"title":"This Is The End","timestamp":{"$date":"2018-03-29T21:20:24.558Z"},"updatedAt":{"$date":"2018-03-29T21:20:24.558Z"},"__v":0} diff --git a/api/apib/dredd/data/decoration.json b/api/apib/dredd/data/decoration.json new file mode 100644 index 0000000..e87471d --- /dev/null +++ b/api/apib/dredd/data/decoration.json @@ -0,0 +1,3 @@ +{"_id":{"$oid":"5abeb420b987672bb1ede643"},"sortingNumber":0,"name":"Teilnehmer der Kampagne X","fraction":"GLOBAL","isMedal":false,"description":"Dabei sein ist alles","timestamp":{"$date":"2018-03-30T22:03:12.228Z"},"updatedAt":{"$date":"2018-03-30T22:03:12.228Z"},"__v":0} +{"_id":{"$oid":"5abd3dff6e6a0334d95b8ba0"},"sortingNumber":0,"name":"Orden der Tapferkeit","fraction":"BLUFOR","isMedal":true,"description":"Das ist ein Orden den tapfere Leute bekommen","timestamp":{"$date":"2018-03-29T19:26:55.387Z"},"updatedAt":{"$date":"2018-03-29T19:26:55.387Z"},"__v":0} +{"_id":{"$oid":"5abeb43cb987672bb1ede644"},"sortingNumber":0,"name":"Ehrenmedaille","fraction":"OPFOR","isMedal":true,"description":"Fuer die Ehre","timestamp":{"$date":"2018-03-30T22:03:40.560Z"},"updatedAt":{"$date":"2018-03-30T22:03:40.560Z"},"__v":0} diff --git a/api/apib/dredd/data/logBudget.json b/api/apib/dredd/data/logBudget.json new file mode 100644 index 0000000..b603c59 --- /dev/null +++ b/api/apib/dredd/data/logBudget.json @@ -0,0 +1,4 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb6"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:01:00.000Z"},"fraction":"BLUFOR","oldBudget":4535500,"newBudget":4195500,"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5ccf"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"fraction":"OPFOR","oldBudget":2384250,"newBudget":2324250,"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cce"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:01:00.000Z"},"fraction":"BLUFOR","oldBudget":4535500,"newBudget":4195500,"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb7"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"fraction":"OPFOR","oldBudget":2384250,"newBudget":2324250,"__v":0} diff --git a/api/apib/dredd/data/logFlag.json b/api/apib/dredd/data/logFlag.json new file mode 100644 index 0000000..c07b0e3 --- /dev/null +++ b/api/apib/dredd/data/logFlag.json @@ -0,0 +1,4 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb5"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:13:00.000Z"},"player":"ALASTOR","flagFraction":"OPFOR","capture":false,"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5ccc"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:12:00.000Z"},"player":"Wiesl","flagFraction":"OPFOR","capture":true,"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5ccd"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:13:00.000Z"},"player":"ALASTOR","flagFraction":"OPFOR","capture":false,"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb4"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:12:00.000Z"},"player":"Wiesl","flagFraction":"OPFOR","capture":true,"__v":0} diff --git a/api/apib/dredd/data/logKill.json b/api/apib/dredd/data/logKill.json new file mode 100644 index 0000000..ea0ac8c --- /dev/null +++ b/api/apib/dredd/data/logKill.json @@ -0,0 +1,8 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cac"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"shooter":null,"target":"Saxe","friendlyFire":false,"fraction":"NONE","__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cae"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:12:00.000Z"},"shooter":"Wiesl","target":"patze","friendlyFire":false,"fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cad"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"shooter":"Saxe","target":"Pumarang","friendlyFire":true,"fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5caf"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:12:00.000Z"},"shooter":"Wiesl","target":"Nicolas","friendlyFire":true,"fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc4"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"shooter":null,"target":"Saxe","friendlyFire":false,"fraction":"NONE","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc5"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"shooter":"Saxe","target":"Pumarang","friendlyFire":true,"fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc7"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:12:00.000Z"},"shooter":"Wiesl","target":"Nicolas","friendlyFire":true,"fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc6"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:12:00.000Z"},"shooter":"Wiesl","target":"patze","friendlyFire":false,"fraction":"BLUFOR","__v":0} diff --git a/api/apib/dredd/data/logPoints.json b/api/apib/dredd/data/logPoints.json new file mode 100644 index 0000000..38ac74c --- /dev/null +++ b/api/apib/dredd/data/logPoints.json @@ -0,0 +1,4 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cba"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:13:00.000Z"},"ptBlufor":1,"ptOpfor":0,"fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb9"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:10:00.000Z"},"ptBlufor":0,"ptOpfor":0,"fraction":"NONE","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cd1"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:10:00.000Z"},"ptBlufor":0,"ptOpfor":0,"fraction":"NONE","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cd2"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:13:00.000Z"},"ptBlufor":1,"ptOpfor":0,"fraction":"BLUFOR","__v":0} diff --git a/api/apib/dredd/data/logRespawn.json b/api/apib/dredd/data/logRespawn.json new file mode 100644 index 0000000..acc1f61 --- /dev/null +++ b/api/apib/dredd/data/logRespawn.json @@ -0,0 +1,2 @@ +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc9"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"player":"Pumarang","__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb1"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:04:00.000Z"},"player":"Pumarang","__v":0} diff --git a/api/apib/dredd/data/logRevive.json b/api/apib/dredd/data/logRevive.json new file mode 100644 index 0000000..f6765b4 --- /dev/null +++ b/api/apib/dredd/data/logRevive.json @@ -0,0 +1,4 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb3"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:35:00.000Z"},"stabilized":false,"medic":"Wiesl","patient":"Andi-de","fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5ccb"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:35:00.000Z"},"stabilized":false,"medic":"Wiesl","patient":"Andi-de","fraction":"BLUFOR","__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb2"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:35:00.000Z"},"stabilized":true,"medic":"ALASTOR","patient":"Bodochecker","fraction":"OPFOR","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cca"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:35:00.000Z"},"stabilized":true,"medic":"ALASTOR","patient":"Bodochecker","fraction":"OPFOR","__v":0} diff --git a/api/apib/dredd/data/logTransport.json b/api/apib/dredd/data/logTransport.json new file mode 100644 index 0000000..4facc38 --- /dev/null +++ b/api/apib/dredd/data/logTransport.json @@ -0,0 +1,2 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb8"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:31:00.000Z"},"driver":"Ponykloete","passenger":" Dominik","fraction":"BLUFOR","distance":8666,"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cd0"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:31:00.000Z"},"driver":"Ponykloete","passenger":" Dominik","fraction":"BLUFOR","distance":8666,"__v":0} diff --git a/api/apib/dredd/data/logVehicle.json b/api/apib/dredd/data/logVehicle.json new file mode 100644 index 0000000..1ea70ca --- /dev/null +++ b/api/apib/dredd/data/logVehicle.json @@ -0,0 +1,2 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cb0"},"war":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"time":{"$date":"2018-03-19T23:16:00.000Z"},"shooter":"Murda]X[","target":"Hunter-HMG","fraction":"OPFOR","__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc8"},"war":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"time":{"$date":"2018-03-19T23:16:00.000Z"},"shooter":"Murda]X[","target":"Hunter-HMG","fraction":"OPFOR","__v":0} diff --git a/api/apib/dredd/data/player.json b/api/apib/dredd/data/player.json new file mode 100644 index 0000000..ea82a47 --- /dev/null +++ b/api/apib/dredd/data/player.json @@ -0,0 +1,16 @@ +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca4"},"name":"Pumarang","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119805032149e+16,"respawn":1,"kill":0,"vehicle":0,"friendlyFire":0,"death":1,"revive":0,"flagTouch":0,"sort":-2,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca5"},"name":"Mercurat","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611982788425e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca6"},"name":"KalleK","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119797767603e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca7"},"name":"MAPster","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119800988213e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca8"},"name":"LyrikEmu","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611982189104e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca9"},"name":"Philipp","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119804179206e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5caa"},"name":"Wiesl","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611980596481e+16,"respawn":0,"kill":1,"vehicle":0,"friendlyFire":1,"death":0,"revive":1,"flagTouch":1,"sort":2,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cab"},"name":"Murda]X[","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119797112163e+16,"respawn":0,"kill":0,"vehicle":1,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbc"},"name":"Pumarang","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119805032149e+16,"respawn":1,"kill":0,"vehicle":0,"friendlyFire":0,"death":1,"revive":0,"flagTouch":0,"sort":-2,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbd"},"name":"Mercurat","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611982788425e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbe"},"name":"KalleK","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119797767603e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc1"},"name":"Philipp","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119804179206e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc0"},"name":"LyrikEmu","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611982189104e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc2"},"name":"Wiesl","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611980596481e+16,"respawn":0,"kill":1,"vehicle":0,"friendlyFire":1,"death":0,"revive":1,"flagTouch":1,"sort":2,"timestamp":{"$date":"2018-03-31T10:41:28.460Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.460Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc3"},"name":"Murda]X[","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119797112163e+16,"respawn":0,"kill":0,"vehicle":1,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.460Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.460Z"},"__v":0} +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbf"},"name":"MAPster","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119800988213e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0} diff --git a/api/apib/dredd/data/promotion.json b/api/apib/dredd/data/promotion.json new file mode 100644 index 0000000..a1075d1 --- /dev/null +++ b/api/apib/dredd/data/promotion.json @@ -0,0 +1 @@ +{"_id":{"$oid":"5abf50d9861d950f157c4a0a"},"userId":{"$oid":"5ab68d42f547ed304064e5f7"},"oldRankLvl":0,"newRankLvl":10,"confirmed":0,"proposer":{"$oid":"5abf5064861d950f157c4a09"},"timestamp":{"$date":"2018-03-31T09:11:53.364Z"},"updatedAt":{"$date":"2018-03-31T09:11:53.364Z"},"__v":0} diff --git a/api/apib/dredd/data/rank.json b/api/apib/dredd/data/rank.json new file mode 100644 index 0000000..e4a51d4 --- /dev/null +++ b/api/apib/dredd/data/rank.json @@ -0,0 +1,3 @@ +{"_id":{"$oid":"5abeb23995cf43205225710b"},"name":"Unteroffizier","fraction":"BLUFOR","level":10,"timestamp":{"$date":"2018-03-30T21:55:05.625Z"},"updatedAt":{"$date":"2018-03-30T21:55:05.625Z"},"__v":0} +{"_id":{"$oid":"5aba5504eadcce6332c6a775"},"name":"Gefreiter","fraction":"BLUFOR","level":0,"timestamp":{"$date":"2018-03-27T14:28:20.948Z"},"updatedAt":{"$date":"2018-03-27T14:28:20.948Z"},"__v":0} +{"_id":{"$oid":"5abeb1b995cf43205225710a"},"name":"General","fraction":"OPFOR","level":22,"timestamp":{"$date":"2018-03-30T21:52:57.204Z"},"updatedAt":{"$date":"2018-03-30T21:52:57.204Z"},"__v":0} diff --git a/api/apib/dredd/data/resource/decoration/5abd3dff6e6a0334d95b8ba0.png b/api/apib/dredd/data/resource/decoration/5abd3dff6e6a0334d95b8ba0.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/decoration/5abd3dff6e6a0334d95b8ba0.png differ diff --git a/api/apib/dredd/data/resource/decoration/5abeb420b987672bb1ede643.png b/api/apib/dredd/data/resource/decoration/5abeb420b987672bb1ede643.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/decoration/5abeb420b987672bb1ede643.png differ diff --git a/api/apib/dredd/data/resource/decoration/5abeb43cb987672bb1ede644.png b/api/apib/dredd/data/resource/decoration/5abeb43cb987672bb1ede644.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/decoration/5abeb43cb987672bb1ede644.png differ diff --git a/api/apib/dredd/data/resource/logs/5abf65ae3fc5fa349ffd5ca3/clean.log b/api/apib/dredd/data/resource/logs/5abf65ae3fc5fa349ffd5ca3/clean.log new file mode 100644 index 0000000..68e638b --- /dev/null +++ b/api/apib/dredd/data/resource/logs/5abf65ae3fc5fa349ffd5ca3/clean.log @@ -0,0 +1,34 @@ +2018/03/20, 20:05:43 "[OPT] (Budget) LOG: 0:00:00 --- Startbudget: NATO 4.5355e+006 - CSAT 4.22125e+006" + +2018/03/20, 20:06:45 "[OPT] (Budget) LOG: 0:01:02 --- NATO alt: 4.5355e+006 - neu: 4.1955e+006 - Differenz: -340000" + +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Saxe (WEST) von: Selbstverschulden." + +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Pumarang (WEST) von: Saxe (WEST)." + +2018/03/20, 20:10:13 "[OPT] (Budget) LOG: 0:04:30 --- CSAT alt: 2.38425e+006 - neu: 2.32425e+006 - Differenz: -60000" + +2018/03/20, 20:15:54 "[OPT] (Punkte) LOG: 0:10:11 --- Kein Dominator (NATO 0 | CSAT 0)" + +2018/03/20, 20:17:51 "[OPT] (Abschuss) LOG: 0:12:08 --- patze (EAST) von: Wiesl (WEST)." + +2018/03/20, 20:18:20 "[OPT] (Fahne) LOG: 0:12:37 --- CSAT Flagge erobert von Wiesl" + +2018/03/20, 20:18:38 "[OPT] (Abschuss) LOG: 0:12:55 --- Nicolas (WEST) von: Wiesl (WEST)." + +2018/03/20, 20:18:59 "[OPT] (Punkte) LOG: 0:13:16 --- NATO +1 (NATO 1 | CSAT 0)" + +2018/03/20, 20:19:38 "[OPT] (Fahne) LOG: 0:13:56 --- CSAT Flagge gesichert von ALASTOR" + +2018/03/20, 20:22:18 "[OPT] (Abschuss) LOG: 0:16:35 --- Fahrzeug: Hunter-HMG (OPT_NATO) von: Murda]X[ (EAST)." + +2018/03/20, 20:37:19 "[OPT] (Transport) LOG: 0:31:36 --- Dominik (WEST) wurde von Ponykloete (WEST) eingeflogen (8666.94 m)" + +2018/03/20, 20:41:27 "[OPT] (Revive) LOG: 0:35:44 --- Bodochecker (EAST) wurde von ALASTOR (EAST) stabilisiert." + +2018/03/20, 20:41:35 "[OPT] (Revive) LOG: 0:35:52 --- Andi-de (WEST) wurde von Wiesl (WEST) wiederbelebt." + +2018/03/20, 22:35:43 "[OPT] (Budget) LOG: 2:30:00 --- Endbudget: (NATO 1997000 | CSAT 512000)" + +2018/03/20, 22:35:43 "[OPT] (Punkte) LOG: 2:30:00 --- Endpunktestand: (NATO 34 | CSAT 25)" + diff --git a/api/apib/dredd/data/resource/logs/5abf65ae3fc5fa349ffd5ca3/war.log b/api/apib/dredd/data/resource/logs/5abf65ae3fc5fa349ffd5ca3/war.log new file mode 100644 index 0000000..2863e66 --- /dev/null +++ b/api/apib/dredd/data/resource/logs/5abf65ae3fc5fa349ffd5ca3/war.log @@ -0,0 +1,29 @@ +Error: ENOENT: no such file or directory, open ' +2018/03/20, 20:05:43 "[OPT] (Budget) LOG: 0:00:00 --- Startbudget: NATO 4.5355e+006 - CSAT 4.22125e+006" +2018/03/20, 20:06:45 "[OPT] (Budget) LOG: 0:01:02 --- NATO alt: 4.5355e+006 - neu: 4.1955e+006 - Differenz: -340000" +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Saxe (WEST) von: Selbstverschulden." +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Pumarang (WEST) von: Saxe (WEST)." +2018/03/20, 20:10:13 "[OPT] (Budget) LOG: 0:04:30 --- CSAT alt: 2.38425e+006 - neu: 2.32425e+006 - Differenz: -60000" +2018/03/20, 20:10:38 "[OPT] (Respawn) LOG: 0:04:55 --- Spieler: Pumarang - Kosten: 3000" +2018/03/20, 20:15:54 "[OPT] (Punkte) LOG: 0:10:11 --- Kein Dominator (NATO 0 | CSAT 0)" +2018/03/20, 20:17:51 "[OPT] (Abschuss) LOG: 0:12:08 --- patze (EAST) von: Wiesl (WEST)." +2018/03/20, 20:18:20 "[OPT] (Fahne) LOG: 0:12:37 --- CSAT Flagge erobert von Wiesl" +2018/03/20, 20:18:38 "[OPT] (Abschuss) LOG: 0:12:55 --- Nicolas (WEST) von: Wiesl (WEST)." +2018/03/20, 20:18:59 "[OPT] (Punkte) LOG: 0:13:16 --- NATO +1 (NATO 1 | CSAT 0)" +2018/03/20, 20:19:38 "[OPT] (Fahne) LOG: 0:13:56 --- CSAT Flagge gesichert von ALASTOR" +2018/03/20, 20:22:18 "[OPT] (Abschuss) LOG: 0:16:35 --- Fahrzeug: Hunter-HMG (OPT_NATO) von: Murda]X[ (EAST)." +2018/03/20, 20:37:19 "[OPT] (Transport) LOG: 0:31:36 --- Dominik (WEST) wurde von Ponykloete (WEST) eingeflogen (8666.94 m)" +2018/03/20, 20:41:27 "[OPT] (Revive) LOG: 0:35:44 --- Bodochecker (EAST) wurde von ALASTOR (EAST) stabilisiert." +2018/03/20, 20:41:35 "[OPT] (Revive) LOG: 0:35:52 --- Andi-de (WEST) wurde von Wiesl (WEST) wiederbelebt." +2018/03/20, 22:35:43 "[OPT] (Mission) LOG: 2:30:00 --- Missionzeit abgelaufen" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Pumarang (WEST), PUID 76561198050321485" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Mercurat (WEST), PUID 76561198278842491" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- KalleK (EAST), PUID 76561197977676036" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- MAPster (EAST), PUID 76561198009882133" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- LyrikEmu (WEST), PUID 76561198218910400" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Philipp (EAST), PUID 76561198041792069" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Wiesl (WEST), PUID 76561198059648090" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Murda]X[ (EAST), PUID 76561197971121630" +2018/03/20, 22:35:43 "[OPT] (Budget) LOG: 2:30:00 --- Endbudget: (NATO 1997000 | CSAT 512000)" +2018/03/20, 22:35:43 "[OPT] (Punkte) LOG: 2:30:00 --- Endpunktestand: (NATO 34 | CSAT 25)" +' diff --git a/api/apib/dredd/data/resource/logs/5abf65d83fc5fa349ffd5cbb/clean.log b/api/apib/dredd/data/resource/logs/5abf65d83fc5fa349ffd5cbb/clean.log new file mode 100644 index 0000000..68e638b --- /dev/null +++ b/api/apib/dredd/data/resource/logs/5abf65d83fc5fa349ffd5cbb/clean.log @@ -0,0 +1,34 @@ +2018/03/20, 20:05:43 "[OPT] (Budget) LOG: 0:00:00 --- Startbudget: NATO 4.5355e+006 - CSAT 4.22125e+006" + +2018/03/20, 20:06:45 "[OPT] (Budget) LOG: 0:01:02 --- NATO alt: 4.5355e+006 - neu: 4.1955e+006 - Differenz: -340000" + +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Saxe (WEST) von: Selbstverschulden." + +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Pumarang (WEST) von: Saxe (WEST)." + +2018/03/20, 20:10:13 "[OPT] (Budget) LOG: 0:04:30 --- CSAT alt: 2.38425e+006 - neu: 2.32425e+006 - Differenz: -60000" + +2018/03/20, 20:15:54 "[OPT] (Punkte) LOG: 0:10:11 --- Kein Dominator (NATO 0 | CSAT 0)" + +2018/03/20, 20:17:51 "[OPT] (Abschuss) LOG: 0:12:08 --- patze (EAST) von: Wiesl (WEST)." + +2018/03/20, 20:18:20 "[OPT] (Fahne) LOG: 0:12:37 --- CSAT Flagge erobert von Wiesl" + +2018/03/20, 20:18:38 "[OPT] (Abschuss) LOG: 0:12:55 --- Nicolas (WEST) von: Wiesl (WEST)." + +2018/03/20, 20:18:59 "[OPT] (Punkte) LOG: 0:13:16 --- NATO +1 (NATO 1 | CSAT 0)" + +2018/03/20, 20:19:38 "[OPT] (Fahne) LOG: 0:13:56 --- CSAT Flagge gesichert von ALASTOR" + +2018/03/20, 20:22:18 "[OPT] (Abschuss) LOG: 0:16:35 --- Fahrzeug: Hunter-HMG (OPT_NATO) von: Murda]X[ (EAST)." + +2018/03/20, 20:37:19 "[OPT] (Transport) LOG: 0:31:36 --- Dominik (WEST) wurde von Ponykloete (WEST) eingeflogen (8666.94 m)" + +2018/03/20, 20:41:27 "[OPT] (Revive) LOG: 0:35:44 --- Bodochecker (EAST) wurde von ALASTOR (EAST) stabilisiert." + +2018/03/20, 20:41:35 "[OPT] (Revive) LOG: 0:35:52 --- Andi-de (WEST) wurde von Wiesl (WEST) wiederbelebt." + +2018/03/20, 22:35:43 "[OPT] (Budget) LOG: 2:30:00 --- Endbudget: (NATO 1997000 | CSAT 512000)" + +2018/03/20, 22:35:43 "[OPT] (Punkte) LOG: 2:30:00 --- Endpunktestand: (NATO 34 | CSAT 25)" + diff --git a/api/apib/dredd/data/resource/logs/5abf65d83fc5fa349ffd5cbb/war.log b/api/apib/dredd/data/resource/logs/5abf65d83fc5fa349ffd5cbb/war.log new file mode 100644 index 0000000..2863e66 --- /dev/null +++ b/api/apib/dredd/data/resource/logs/5abf65d83fc5fa349ffd5cbb/war.log @@ -0,0 +1,29 @@ +Error: ENOENT: no such file or directory, open ' +2018/03/20, 20:05:43 "[OPT] (Budget) LOG: 0:00:00 --- Startbudget: NATO 4.5355e+006 - CSAT 4.22125e+006" +2018/03/20, 20:06:45 "[OPT] (Budget) LOG: 0:01:02 --- NATO alt: 4.5355e+006 - neu: 4.1955e+006 - Differenz: -340000" +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Saxe (WEST) von: Selbstverschulden." +2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Pumarang (WEST) von: Saxe (WEST)." +2018/03/20, 20:10:13 "[OPT] (Budget) LOG: 0:04:30 --- CSAT alt: 2.38425e+006 - neu: 2.32425e+006 - Differenz: -60000" +2018/03/20, 20:10:38 "[OPT] (Respawn) LOG: 0:04:55 --- Spieler: Pumarang - Kosten: 3000" +2018/03/20, 20:15:54 "[OPT] (Punkte) LOG: 0:10:11 --- Kein Dominator (NATO 0 | CSAT 0)" +2018/03/20, 20:17:51 "[OPT] (Abschuss) LOG: 0:12:08 --- patze (EAST) von: Wiesl (WEST)." +2018/03/20, 20:18:20 "[OPT] (Fahne) LOG: 0:12:37 --- CSAT Flagge erobert von Wiesl" +2018/03/20, 20:18:38 "[OPT] (Abschuss) LOG: 0:12:55 --- Nicolas (WEST) von: Wiesl (WEST)." +2018/03/20, 20:18:59 "[OPT] (Punkte) LOG: 0:13:16 --- NATO +1 (NATO 1 | CSAT 0)" +2018/03/20, 20:19:38 "[OPT] (Fahne) LOG: 0:13:56 --- CSAT Flagge gesichert von ALASTOR" +2018/03/20, 20:22:18 "[OPT] (Abschuss) LOG: 0:16:35 --- Fahrzeug: Hunter-HMG (OPT_NATO) von: Murda]X[ (EAST)." +2018/03/20, 20:37:19 "[OPT] (Transport) LOG: 0:31:36 --- Dominik (WEST) wurde von Ponykloete (WEST) eingeflogen (8666.94 m)" +2018/03/20, 20:41:27 "[OPT] (Revive) LOG: 0:35:44 --- Bodochecker (EAST) wurde von ALASTOR (EAST) stabilisiert." +2018/03/20, 20:41:35 "[OPT] (Revive) LOG: 0:35:52 --- Andi-de (WEST) wurde von Wiesl (WEST) wiederbelebt." +2018/03/20, 22:35:43 "[OPT] (Mission) LOG: 2:30:00 --- Missionzeit abgelaufen" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Pumarang (WEST), PUID 76561198050321485" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Mercurat (WEST), PUID 76561198278842491" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- KalleK (EAST), PUID 76561197977676036" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- MAPster (EAST), PUID 76561198009882133" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- LyrikEmu (WEST), PUID 76561198218910400" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Philipp (EAST), PUID 76561198041792069" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Wiesl (WEST), PUID 76561198059648090" +2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Murda]X[ (EAST), PUID 76561197971121630" +2018/03/20, 22:35:43 "[OPT] (Budget) LOG: 2:30:00 --- Endbudget: (NATO 1997000 | CSAT 512000)" +2018/03/20, 22:35:43 "[OPT] (Punkte) LOG: 2:30:00 --- Endpunktestand: (NATO 34 | CSAT 25)" +' diff --git a/api/apib/dredd/data/resource/rank/5aba5504eadcce6332c6a775.png b/api/apib/dredd/data/resource/rank/5aba5504eadcce6332c6a775.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/rank/5aba5504eadcce6332c6a775.png differ diff --git a/api/apib/dredd/data/resource/rank/5abeb1b995cf43205225710a.png b/api/apib/dredd/data/resource/rank/5abeb1b995cf43205225710a.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/rank/5abeb1b995cf43205225710a.png differ diff --git a/api/apib/dredd/data/resource/rank/5abeb23995cf43205225710b.png b/api/apib/dredd/data/resource/rank/5abeb23995cf43205225710b.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/rank/5abeb23995cf43205225710b.png differ diff --git a/api/apib/dredd/data/resource/squad/5aba54eaeadcce6332c6a774.png b/api/apib/dredd/data/resource/squad/5aba54eaeadcce6332c6a774.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/squad/5aba54eaeadcce6332c6a774.png differ diff --git a/api/apib/dredd/data/resource/squad/5abe166f8b7488392a623f12.png b/api/apib/dredd/data/resource/squad/5abe166f8b7488392a623f12.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/squad/5abe166f8b7488392a623f12.png differ diff --git a/api/apib/dredd/data/resource/squad/5abe16f98b7488392a623f17.png b/api/apib/dredd/data/resource/squad/5abe16f98b7488392a623f17.png new file mode 100644 index 0000000..e4e8dca Binary files /dev/null and b/api/apib/dredd/data/resource/squad/5abe16f98b7488392a623f17.png differ diff --git a/api/apib/dredd/data/squad.json b/api/apib/dredd/data/squad.json new file mode 100644 index 0000000..5ebfaf2 --- /dev/null +++ b/api/apib/dredd/data/squad.json @@ -0,0 +1,3 @@ +{"_id":{"$oid":"5aba54eaeadcce6332c6a774"},"sortingNumber":0,"name":"Alpha","fraction":"BLUFOR","timestamp":{"$date":"2018-03-27T14:27:54.399Z"},"updatedAt":{"$date":"2018-03-27T14:27:54.399Z"},"__v":0} +{"_id":{"$oid":"5abe166f8b7488392a623f12"},"sortingNumber":0,"name":"Führungsstab","fraction":"OPFOR","timestamp":{"$date":"2018-03-30T10:50:23.121Z"},"updatedAt":{"$date":"2018-03-30T10:50:23.121Z"},"__v":0} +{"_id":{"$oid":"5abe16f98b7488392a623f17"},"sortingNumber":4,"name":"Bravo","fraction":"BLUFOR","timestamp":{"$date":"2018-03-30T10:52:41.396Z"},"updatedAt":{"$date":"2018-03-30T10:52:41.396Z"},"__v":0} diff --git a/api/apib/dredd/data/user.json b/api/apib/dredd/data/user.json new file mode 100644 index 0000000..e84e3e5 --- /dev/null +++ b/api/apib/dredd/data/user.json @@ -0,0 +1,2 @@ +{"_id":{"$oid":"5ab68d42f547ed304064e5f7"},"rankLvl":0,"squadId":{"$oid":"5aba54eaeadcce6332c6a774"},"username":"hardiready","updatedAt":{"$date":"2018-03-27T14:28:04.533Z"},"__v":0} +{"_id":{"$oid":"5abd4780396bc0487068be0e"},"rankLvl":0,"squadId":null,"username":"KalleK","timestamp":{"$date":"2018-03-29T20:07:28.960Z"},"updatedAt":{"$date":"2018-03-29T20:07:28.960Z"},"__v":0} diff --git a/api/apib/dredd/data/war.json b/api/apib/dredd/data/war.json new file mode 100644 index 0000000..ec8d2ee --- /dev/null +++ b/api/apib/dredd/data/war.json @@ -0,0 +1,2 @@ +{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"playersBlufor":4,"playersOpfor":4,"budgetBlufor":4535500,"budgetOpfor":4221250,"endBudgetBlufor":997000,"endBudgetOpfor":512000,"title":"Battle #1","campaign":{"$oid":"5abd55ea9e30a76bfef747d6"},"date":{"$date":"2018-03-19T23:00:00.000Z"},"endDate":{"$date":"2018-03-20T01:30:00.000Z"},"ptBlufor":34,"ptOpfor":25,"timestamp":{"$date":"2018-03-31T10:41:28.451Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.451Z"},"__v":0} +{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"playersBlufor":4,"playersOpfor":4,"budgetBlufor":4535500,"budgetOpfor":4221250,"endBudgetBlufor":997000,"endBudgetOpfor":512000,"title":"Test Battle #0","campaign":{"$oid":"5abd55ea9e30a76bfef747d6"},"date":{"$date":"2018-03-19T23:00:00.000Z"},"endDate":{"$date":"2018-03-20T01:30:00.000Z"},"ptBlufor":34,"ptOpfor":25,"timestamp":{"$date":"2018-03-31T10:40:46.695Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.695Z"},"__v":0} diff --git a/api/apib/dredd/populate-data.sh b/api/apib/dredd/populate-data.sh new file mode 100755 index 0000000..47dc954 --- /dev/null +++ b/api/apib/dredd/populate-data.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +########### IMPORT EXPORT/SCRIPT FOR DREDD TEST DATA ############## +###-------------------------------------------------------------### +###------------------- HOW TO USE THIS FILE --------------------### +###-------------------------------------------------------------### +### 1. start express server with `npm run start-test` ### +### 2. import data by executing script: `./populate-data.sh` ### +### 3. change data in app as you need for tests ### +### 4. export data state with: `./populate-data.sh -m save` ### +################################################################### + +# execute script in its location folder +cd $(dirname $0) + +while getopts m:p:d: option +do +case "${option}" +in +m) MODE=${OPTARG};; +p) PORT=${OPTARG};; +d) DATABASE=${OPTARG};; +esac +done + +# array of available collection names +col=(app_user awarding campaign decoration logBudget logFlag logKill logPoints logRespawn logRevive logTransport logVehicle player promotion rank squad user war ) + +for i in "${col[@]}" +do + # provide date for restore process, if data import is needed + if [ "$MODE" == "save" ] + then + echo -e "$(date "+%Y-%m-%dT%T.%3N%z")\tTable: ${i}" + mongoexport --db ${DATABASE} --port ${PORT} --collection $i --out data/${i}.json; + else + mongoimport --db ${DATABASE} --port ${PORT} --collection $i --drop --file data/${i}.json + fi +done diff --git a/api/apib/statistics/campaigns.apib b/api/apib/statistics/campaigns.apib new file mode 100644 index 0000000..915aa26 --- /dev/null +++ b/api/apib/statistics/campaigns.apib @@ -0,0 +1,37 @@ +### Get Campaign [GET /campaigns/{id}] + +Get single campaign information + ++ Parameters + + id: `5abd55ea9e30a76bfef747d6` (string, required) - unique id of campaign + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Campaign, fixed-type) + +### Create Campaign [POST /campaigns] + +Create a new campaign + +**Permission: 3** + ++ Request Create new army member (application/json) + + + Attributes + + title: `Return To Kessel In A Schmelz` (string, required) - display name of the campaign + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (Campaign, fixed-type) + +### Delete Campaign [DELETE /campaigns/{id}] + +Delete a campaign + +**Permission: 3** + ++ Parameters + + id: `5abd58989e30a76bfef747e6` (string, required) - unique id of campaign + ++ Response 204 + diff --git a/api/apib/statistics/logs.apib b/api/apib/statistics/logs.apib new file mode 100644 index 0000000..86f1e60 --- /dev/null +++ b/api/apib/statistics/logs.apib @@ -0,0 +1,18 @@ +### Get War Logs [GET /logs/{warId}] + +Ge the combined log object, containing all events in collections, for a single war + ++ Parameters + + warId: `5abf65ae3fc5fa349ffd5ca3` (string, required) - unique id of the war + ++ Response 200 (application/json; charset=utf-8) + + + Attributes + + points (array[LogPoints], required) + + budget (array[LogBudget], required) + + respawn (array[LogRespawn], required) + + revive (array[LogRevive], required) + + kill (array[LogKill], required) + + vehicle (array[LogVehicle], required) + + transport (array[LogTransport], required) + + flag (array[LogFlag], required) diff --git a/api/apib/statistics/players.apib b/api/apib/statistics/players.apib new file mode 100644 index 0000000..033c691 --- /dev/null +++ b/api/apib/statistics/players.apib @@ -0,0 +1,34 @@ +### Get Player Highscore [GET /players/ranking/{campaignId}] + +List highscores for player statistics over all wars of a certain campaign. +Every highscore player object contains a field *sum*, representing its order number in the collection + ++ Parameters + + campaignId: `5abd55ea9e30a76bfef747d6` (string, required) - unique id of the campaign + ++ Response 200 (application/json; charset=utf-8) + + + Attributes + + kill (array[HighscorePlayer],required) - player highscore for kill + + death (array[HighscorePlayer],required) - player highscore for death + + friendlyFire (array[HighscorePlayer],required) - player highscore for friendly fire + + vehicle (array[HighscorePlayer],required) - player highscore for vehicle + + revive (array[HighscorePlayer],required) - player highscore for revive + + respawn (array[HighscorePlayer],required) - player highscore for respawn + + flagTouch (array[HighscorePlayer],required) - player highscore for flag captures + + +### Get Player Campaign Statistics [GET /players/single/{campaignId}/{playerSteamId}] + +Get statistics for a single player for all wars of a campaign he took part at + ++ Parameters + + campaignId: `5abd55ea9e30a76bfef747d6` (string, required) - unique id of the campaign + + playerSteamId: `76561198050321490` (string, required) - STEAM application unique user id of player + ++ Response 200 (application/json; charset=utf-8) + + + Attributes + + name: `Pumarang` (string, required) - latest used playername + + campaign (Campaign,required) - campaign reflected from request is + + players (array[WarPlayer],required) - collection of player instances in the campaign diff --git a/api/apib/statistics/wars.apib b/api/apib/statistics/wars.apib new file mode 100644 index 0000000..6ce40bb --- /dev/null +++ b/api/apib/statistics/wars.apib @@ -0,0 +1,89 @@ +### List Wars [GET /wars] + +List all wars, subordinate to their campaign + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[WarCampaign], fixed-type) + +### Get War [GET /wars/{id}] + +Retrieve single war data + ++ Parameters + + id: `5abf65ae3fc5fa349ffd5ca3` (string, required) - unique id of the war to fetch + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (WarWithPlayers, fixed-type) + + +### Create War [POST /wars] + +Create a new war + +**Permission: 3** + +*NOTE: First line of the log file sent should be NOT beginning of actual game logs! This might result in unparsable line.* + ++ Request (multipart/form-data; boundary=---BOUNDARY) + + -----BOUNDARY + Content-Disposition: form-data; name="title" + Content-Type: text/plain + + Battle XY + -----BOUNDARY + Content-Disposition: form-data; name="campaign" + Content-Type: text/plain + + 5abd55ea9e30a76bfef747d6 + -----BOUNDARY + Content-Disposition: form-data; name="log"; filename="war_2018_log.rpt" + Content-Type: text/plain + + \ + 2018/03/20, 20:05:43 "[OPT] (Budget) LOG: 0:00:00 --- Startbudget: NATO 4.5355e+006 - CSAT 4.22125e+006" + 2018/03/20, 20:06:45 "[OPT] (Budget) LOG: 0:01:02 --- NATO alt: 4.5355e+006 - neu: 4.1955e+006 - Differenz: -340000" + 2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Saxe (WEST) von: Selbstverschulden." + 2018/03/20, 20:10:11 "[OPT] (Abschuss) LOG: 0:04:28 --- Pumarang (WEST) von: Saxe (WEST)." + 2018/03/20, 20:10:13 "[OPT] (Budget) LOG: 0:04:30 --- CSAT alt: 2.38425e+006 - neu: 2.32425e+006 - Differenz: -60000" + 2018/03/20, 20:10:38 "[OPT] (Respawn) LOG: 0:04:55 --- Spieler: Pumarang - Kosten: 3000" + 2018/03/20, 20:15:54 "[OPT] (Punkte) LOG: 0:10:11 --- Kein Dominator (NATO 0 | CSAT 0)" + 2018/03/20, 20:17:51 "[OPT] (Abschuss) LOG: 0:12:08 --- patze (EAST) von: Wiesl (WEST)." + 2018/03/20, 20:18:20 "[OPT] (Fahne) LOG: 0:12:37 --- CSAT Flagge erobert von Wiesl" + 2018/03/20, 20:18:38 "[OPT] (Abschuss) LOG: 0:12:55 --- Nicolas (WEST) von: Wiesl (WEST)." + 2018/03/20, 20:18:59 "[OPT] (Punkte) LOG: 0:13:16 --- NATO +1 (NATO 1 | CSAT 0)" + 2018/03/20, 20:19:38 "[OPT] (Fahne) LOG: 0:13:56 --- CSAT Flagge gesichert von ALASTOR" + 2018/03/20, 20:22:18 "[OPT] (Abschuss) LOG: 0:16:35 --- Fahrzeug: Hunter-HMG (OPT_NATO) von: Murda]X[ (EAST)." + 2018/03/20, 20:37:19 "[OPT] (Transport) LOG: 0:31:36 --- Dominik (WEST) wurde von Ponykloete (WEST) eingeflogen (8666.94 m)" + 2018/03/20, 20:41:27 "[OPT] (Revive) LOG: 0:35:44 --- Bodochecker (EAST) wurde von ALASTOR (EAST) stabilisiert." + 2018/03/20, 20:41:35 "[OPT] (Revive) LOG: 0:35:52 --- Andi-de (WEST) wurde von Wiesl (WEST) wiederbelebt." + 2018/03/20, 22:35:43 "[OPT] (Mission) LOG: 2:30:00 --- Missionzeit abgelaufen" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Pumarang (WEST), PUID 76561198050321485" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Mercurat (WEST), PUID 76561198278842491" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- KalleK (EAST), PUID 76561197977676036" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- MAPster (EAST), PUID 76561198009882133" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- LyrikEmu (WEST), PUID 76561198218910400" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Philipp (EAST), PUID 76561198041792069" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Wiesl (WEST), PUID 76561198059648090" + 2018/03/20, 22:35:43 "[OPT] (Fraktionsuebersicht) LOG: 2:30:00 --- Murda]X[ (EAST), PUID 76561197971121630" + 2018/03/20, 22:35:43 "[OPT] (Budget) LOG: 2:30:00 --- Endbudget: (NATO 1997000 | CSAT 512000)" + 2018/03/20, 22:35:43 "[OPT] (Punkte) LOG: 2:30:00 --- Endpunktestand: (NATO 34 | CSAT 25)" + -----BOUNDARY-- + ++ Response 201 (application/json; charset=utf-8) + + + Attributes (War, fixed-type) + +### Delete War [DELETE /wars/{id}] + +Delete a war + +**Permission: 3** + ++ Parameters + + id: `5abf65d83fc5fa349ffd5cbb` (string, required) - unique id of the war + ++ Response 204 + diff --git a/api/config/api-url.js b/api/config/api-url.js index e8041c8..78ba32a 100644 --- a/api/config/api-url.js +++ b/api/config/api-url.js @@ -17,5 +17,5 @@ module.exports = { signUp: rootRoute + '/authenticate/signup', squads: rootRoute + '/squads', users: rootRoute + '/users', - wars: rootRoute + '/wars' + wars: rootRoute + '/wars', }; diff --git a/api/config/config.js b/api/config/config.js index 621e65f..8f61a99 100644 --- a/api/config/config.js +++ b/api/config/config.js @@ -1,5 +1,6 @@ module.exports = { port: 8091, + resourceLocation: __dirname + '/../resource', database: { uri: 'mongodb://localhost:27017/', @@ -7,17 +8,22 @@ module.exports = { }, prod: { - env: 'production' + env: 'production', }, dev: { - env: 'dev' + env: 'dev', }, test: { - port: 3001, db: 'cc-test', - env: 'test' - } - + port: 3001, + dredd: { + env: 'dreddTest', + resourceLocation: __dirname + '/../apib/dredd/data/tmp-resource', + }, + unit: { + env: 'unitTest', + }, + }, }; diff --git a/api/cron-job/cron.js b/api/cron-job/cron.js index b8282fd..7dc1f0a 100644 --- a/api/cron-job/cron.js +++ b/api/cron-job/cron.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const cron = require('cron'); const async = require('async'); @@ -19,8 +19,8 @@ const createAllSignatures = () => { // mock response const res = { locals: { - items: {} - } + items: {}, + }, }; // re-create signature image for each active user @@ -29,21 +29,21 @@ const createAllSignatures = () => { // mock next to execute callback const next = (err) => { if (!err || (err && err.message.startsWith('Fraction not defined'))) { - callback() + callback(); } else { error('\x1b[41m%s\x1b[0m', new Date().toLocaleString() - + ': Error in execution - UPDATE SIGNATURES: ' + err.message) + + ': Error in execution - UPDATE SIGNATURES: ' + err.message); } }; - signatureTool(user._id, res, next) + signatureTool(user._id, res, next); }, () => { if (err) { error('\x1b[41m%s\x1b[0m', new Date().toLocaleString() - + ': Error in execution - UPDATE SIGNATURES: ' + err.message) + + ': Error in execution - UPDATE SIGNATURES: ' + err.message); } logger('\x1b[35m%s\x1b[0m', new Date().toLocaleString() + ': finished successful - UPDATE SIGNATURES'); - }) + }); }); }; @@ -57,7 +57,7 @@ const createBackup = () => { logger('\x1b[32m%s\x1b[0m', stderr); logger('\x1b[35m%s\x1b[0m', new Date().toLocaleString() + ': cron job finished - CREATE BACKUP'); - }) + }); }; // Execute daily @ 02:30 AM @@ -69,5 +69,5 @@ const cronJobBackup = cron.job('00 00 04 * * mon,thu,sat', createBackup); module.exports = { cronJobSignature: cronJobSignature, cronJobBackup: cronJobBackup, - createAllSignatures: createAllSignatures + createAllSignatures: createAllSignatures, }; diff --git a/api/dredd.yml b/api/dredd.yml new file mode 100644 index 0000000..04ac236 --- /dev/null +++ b/api/dredd.yml @@ -0,0 +1,34 @@ +dry-run: null +hookfiles: null +language: nodejs +sandbox: false +server: npm run start-api-test +server-wait: 3 +init: false +custom: {} +names: false +only: [] +reporter: base +output: [] +header: ['X-Access-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1YWI2OGNlZWY1NDdlZDMwNDA2NGU1ZjYiLCJpYXQiOjE1MjIzNTMwNzAsImV4cCI6MTAyMzIyMzUzMDcwfQ.aC4TYkPc8gYcpdsYNnYcs8D8e6OPilrgSGZF6pI3g1w'] +sorted: false +user: null +inline-errors: false +details: false +method: [] +color: true +level: info +timestamp: false +silent: false +path: [] +hooks-worker-timeout: 5000 +hooks-worker-connect-timeout: 1500 +hooks-worker-connect-retry: 500 +hooks-worker-after-connect-wait: 100 +hooks-worker-term-timeout: 5000 +hooks-worker-term-retry: 500 +hooks-worker-handler-host: 127.0.0.1 +hooks-worker-handler-port: 61321 +config: ./dredd.yml +blueprint: ./apib/documentation.apib +endpoint: 'http://localhost:3001/api' diff --git a/api/middleware/auth-middleware.js b/api/middleware/auth-middleware.js index ca1e0de..1ffea19 100644 --- a/api/middleware/auth-middleware.js +++ b/api/middleware/auth-middleware.js @@ -1,17 +1,15 @@ -"use strict"; +'use strict'; const jwt = require('jsonwebtoken'); const config = require('../config/config'); const AppUser = require('../models/app-user'); const apiAuthentication = (req, res, next) => { - // check header or url parameters or post parameters for token const token = req.body.token || req.query.token || req.headers['x-access-token']; // decode token if (token) { - const secret = process.env.NODE_ENV === config.prod.env ? process.env.JWS_SECRET : 'dev-secret'; // verifies secret and checks exp @@ -25,7 +23,7 @@ const apiAuthentication = (req, res, next) => { if (err) { return res.status(403).send({ success: false, - message: 'token is not associated to any actual user' + message: 'token is not associated to any actual user', }); } req.user = item; @@ -33,16 +31,13 @@ const apiAuthentication = (req, res, next) => { }); } }); - } else { - // if there is no token // return an error return res.status(403).send({ success: false, - message: 'No token provided.' + message: 'No token provided.', }); - } }; diff --git a/api/middleware/error-response.js b/api/middleware/error-response.js index f8ee5b7..e6ad4c2 100644 --- a/api/middleware/error-response.js +++ b/api/middleware/error-response.js @@ -1,43 +1,43 @@ -/** This module provides middleware to respond with proper JSON error objects - * using NODE_ENV setting to production or development. In dev mode it send the stacktrace. - * - * You call the returned function with an app instance - * - * @author Johannes Konert - * @licence CC BY-SA 4.0 - * - * - * @module restapi/error-response - * @type {Function} - */ -"use strict"; -const logger = require('debug')('me2:error-response'); - -module.exports = (app) => { - // development error handler - // will print stacktrace as JSON response - if (app.get('env') === 'development') { - app.use(function (err, req, res, next) { - logger('Internal Error: ', err.stack); - res.status(err.status || 500); - res.json({ - error: { - message: err.message, - error: err.stack - } - }); - }); - } else { - // production error handler - // no stacktraces leaked to user - app.use(function (err, req, res, next) { - res.status(err.status || 500); - res.json({ - error: { - message: err.message, - error: {} - } - }); - }); - } -}; +/** This module provides middleware to respond with proper JSON error objects + * using NODE_ENV setting to production or development. In dev mode it send the stacktrace. + * + * You call the returned function with an app instance + * + * @author Johannes Konert + * @licence CC BY-SA 4.0 + * + * + * @module restapi/error-response + * @type {Function} + */ +'use strict'; +const logger = require('debug')('me2:error-response'); + +module.exports = (app) => { + // development error handler + // will print stacktrace as JSON response + if (app.get('env') === 'development') { + app.use(function(err, req, res, next) { + logger('Internal Error: ', err.stack); + res.status(err.status || 500); + res.json({ + error: { + message: err.message, + error: err.stack, + }, + }); + }); + } else { + // production error handler + // no stacktraces leaked to user + app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.json({ + error: { + message: err.message, + error: {}, + }, + }); + }); + } +}; diff --git a/api/middleware/filter-handler-mongo.js b/api/middleware/filter-handler-mongo.js index 9ae5878..96468df 100644 --- a/api/middleware/filter-handler-mongo.js +++ b/api/middleware/filter-handler-mongo.js @@ -1,104 +1,105 @@ -/** This module defines a express.Router() instance - * - supporting filter=key1,key2 - * - it sets res.locals.filter to a string "key1 key2" - * - calls next with error if a filter=key is given, but key does not exist (not raised on empty item arrays!) - * - * Note: it expects to be called before any data is fetched from DB - * Note: it sets an Error-Object to next with error.status set to HTTP status code 400 - * - * @author Johannes Konert - * @licence CC BY-SA 4.0 - * - * @module restapi/filter-middleware-mongo - * @type {Factory function returning an Router} - * @param Schema {Object} a MongooseSchema.path value or similar object with attributes representing the valid keys - * @param suppressId {Boolean} if true, the _id is not returned implicitly - */ - -// remember: in modules you have 3 variables given by CommonJS -// 1.) require() function -// 2.) module.exports -// 3.) exports (which is module.exports) -"use strict"; - -const express = require('express'); -const logger = require('debug')('middleware:filterware'); - -/** - * private helper function to filter Objects by given keys - * @param keys {Array} the keys from GET parameter filter - * @param schema [Object} containing the keys as attributes that are allowed - * @returns {Object or Error} either the filtered items or an Error object - */ -const limitFilterToSchema = (keys, schema) => { - if (!keys || !schema) { // empty arrays evaluate to false - return undefined; // means no filter at all - } - - let error = null; - const result = []; - // now for each given filter=key1,key2in the array check that the schema allows this key and store it in result - keys.forEach((key) => { - if (schema.hasOwnProperty(key)) { - result.push(key); - } else { - error = new Error('given key for filter does not exist in ressource: ' + key); - } - }); - return error ? error : result -}; - -/** - * closure function as factory returning the router - * - * @param Schema {Object} a MongooseSchema.path value or similar object with attributes representing the valid keys - * @param suppressId {Boolean} if true, the _id is not returned implicitly - * @returns {Router} - */ - -const createFilterRouter = (schema, supressID) => { - const router = express.Router(); - // the exported router with handler - router.use((req, res, next) => { - const filterString = req.query.filter; - let filterKeys = []; - let err = null; - - if (filterString !== undefined) { - filterKeys = filterString.split(','); - filterKeys.forEach((item, index, array) => { - array[index] = item.trim(); - }); - filterKeys = filterKeys.filter((item) => { - return item.length > 0; - }); - if (filterKeys.length === 0) { - err = new Error('given filter does not contain any keys'); - err.status = 400; - } else { - const result = limitFilterToSchema(filterKeys, schema); - if (result instanceof Error) { - err = result; - err.status = 400; - } else { - res.locals.filter = result.join(' '); // create a string with space as seperator - if (supressID) { - res.locals.filter = '-_id ' + res.locals.filter; - } - } - } - } - if (err) { - logger(err); - next(err) - } else { - if (res.locals.filter) { - logger('Successfully set filter to ' + res.locals.filter); - } - next() - } - }); - return router; -}; - -module.exports = createFilterRouter; +/** This module defines a express.Router() instance + * - supporting filter=key1,key2 + * - it sets res.locals.filter to a string "key1 key2" + * - calls next with error if a filter=key is given, but key does not exist (not raised on empty item arrays!) + * + * Note: it expects to be called before any data is fetched from DB + * Note: it sets an Error-Object to next with error.status set to HTTP status code 400 + * + * @author Johannes Konert + * @licence CC BY-SA 4.0 + * + * @module restapi/filter-middleware-mongo + * @type {Factory function returning an Router} + * @param Schema {Object} a MongooseSchema.path value or similar object with attributes representing the valid keys + * @param suppressId {Boolean} if true, the _id is not returned implicitly + */ + +// remember: in modules you have 3 variables given by CommonJS +// 1.) require() function +// 2.) module.exports +// 3.) exports (which is module.exports) +'use strict'; + +const express = require('express'); +const logger = require('debug')('middleware:filterware'); + +/** + * private helper function to filter Objects by given keys + * + * @param {Array} keys - the keys from GET parameter filter + * @param {Object} schema - containing the keys as attributes that are allowed + * @return {Object} either the filtered items or an Error object + */ +const limitFilterToSchema = (keys, schema) => { + if (!keys || !schema) { // empty arrays evaluate to false + return undefined; // means no filter at all + } + + let error = null; + const result = []; + // now for each given filter=key1,key2in the array check that the schema allows this key and store it in result + keys.forEach((key) => { + if (schema.hasOwnProperty(key)) { + result.push(key); + } else { + error = new Error('given key for filter does not exist in ressource: ' + key); + } + }); + return error ? error : result; +}; + +/** + * closure function as factory returning the router + * + * @param Schema {Object} a MongooseSchema.path value or similar object with attributes representing the valid keys + * @param suppressId {Boolean} if true, the _id is not returned implicitly + * @returns {Router} + */ + +const createFilterRouter = (schema, supressID) => { + const router = new express.Router(); + // the exported router with handler + router.use((req, res, next) => { + const filterString = req.query.filter; + let filterKeys = []; + let err = null; + + if (filterString !== undefined) { + filterKeys = filterString.split(','); + filterKeys.forEach((item, index, array) => { + array[index] = item.trim(); + }); + filterKeys = filterKeys.filter((item) => { + return item.length > 0; + }); + if (filterKeys.length === 0) { + err = new Error('given filter does not contain any keys'); + err.status = 400; + } else { + const result = limitFilterToSchema(filterKeys, schema); + if (result instanceof Error) { + err = result; + err.status = 400; + } else { + res.locals.filter = result.join(' '); // create a string with space as seperator + if (supressID) { + res.locals.filter = '-_id ' + res.locals.filter; + } + } + } + } + if (err) { + logger(err); + next(err); + } else { + if (res.locals.filter) { + logger('Successfully set filter to ' + res.locals.filter); + } + next(); + } + }); + return router; +}; + +module.exports = createFilterRouter; diff --git a/api/middleware/limitoffset-middleware-mongo.js b/api/middleware/limitoffset-middleware-mongo.js index 944ee3a..0d752fc 100644 --- a/api/middleware/limitoffset-middleware-mongo.js +++ b/api/middleware/limitoffset-middleware-mongo.js @@ -17,9 +17,10 @@ // 1.) require() function // 2.) module.exports // 3.) exports (which is module.exports) -"use strict"; +'use strict'; -const router = require('express').Router(); +const express = require('express'); +const router = new express.Router(); const logger = require('debug')('middleware:offsetlimit'); @@ -36,10 +37,9 @@ router.use((req, res, next) => { if (!isNaN(offsetString)) { offset = parseInt(offsetString); if (offset < 0) { - err = new Error('offset is negative') + err = new Error('offset is negative'); } - } - else { + } else { err = new Error('given offset is not a valid number ' + offsetString); } } @@ -47,22 +47,21 @@ router.use((req, res, next) => { if (!isNaN(limitString)) { limit = parseInt(limitString); if (limit < 1) { - err = new Error('limit is zero or negative') + err = new Error('limit is zero or negative'); } - } - else { + } else { err = new Error('given limit is not a valid number ' + limitString); } } if (err) { logger('problem occurred with limit/offset values'); err.status = 400; - next(err) + next(err); } else { res.locals.limitskip = {}; // mongoDB uses parameter object for skip/limit if (limit) res.locals.limitskip.limit = limit; if (offset) res.locals.limitskip.skip = offset; - next() + next(); } }); diff --git a/api/middleware/permission-check.js b/api/middleware/permission-check.js index a4990b5..43f6566 100644 --- a/api/middleware/permission-check.js +++ b/api/middleware/permission-check.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; let check = (requiredPermission, actualPermission, res, next) => { @@ -7,21 +7,21 @@ let check = (requiredPermission, actualPermission, res, next) => { } return res.status(403).send({ success: false, - message: 'permission denied' + message: 'permission denied', }); }; module.exports = { checkSql: (req, res, next) => { - check(1, req.user.permission, res, next) + check(1, req.user.permission, res, next); }, checkHl: (req, res, next) => { - check(2, req.user.permission, res, next) + check(2, req.user.permission, res, next); }, checkMT: (req, res, next) => { - check(3, req.user.permission, res, next) + check(3, req.user.permission, res, next); }, checkAdmin: (req, res, next) => { - check(4, req.user.permission, res, next) - } + check(4, req.user.permission, res, next); + }, }; diff --git a/api/middleware/request-checks.js b/api/middleware/request-checks.js index 67109ea..d421391 100644 --- a/api/middleware/request-checks.js +++ b/api/middleware/request-checks.js @@ -1,67 +1,67 @@ -/** This module defines a express.Router() instance - * - checking Accept-Version header to be 1.0 - * - body-data to be JSON on POST/PUT/PATCH - * - body to be not empty on POST/PUT/PATCH - * - Request accepts JSOn as reply content-type - * - * @author Johannes Konert - * @licence CC BY-SA 4.0 - * - * @module restapi/request-checks - * @type {Router} - */ - -// remember: in modules you have 3 variables given by CommonJS -// 1.) require() function -// 2.) module.exports -// 3.) exports (which is module.exports) -"use strict"; - -const router = require('express').Router(); - -// API-Version control. We use HTTP Header field Accept-Version instead of URL-part /v1/ -router.use((req, res, next) => { - // expect the Accept-Version header to be NOT set or being 1.0 - const versionWanted = req.get('Accept-Version'); - if (versionWanted !== undefined && versionWanted !== '1.0') { - // 406 Accept-* header cannot be fulfilled. - res.status(406).send('Accept-Version cannot be fulfilled').end(); - } else { - next(); // all OK, call next handler - } -}); - -// request type application/json check -router.use((req, res, next) => { - if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 && - (!(/multipart\/form-data/.test(req.get('Content-Type'))) && - !(/application\/json/.test(req.get('Content-Type'))))) { - // send error code 415: unsupported media type - res.status(415).send('wrong Content-Type'); // user has SEND the wrong type - } else if (!req.accepts('json')) { - // send 406 that response will be application/json and request does not support it by now as answer - // user has REQUESTED the wrong type - res.status(406).send('response of application/json only supported, please accept this'); - } - else { - next(); // let this request pass through as it is OK - } -}); - - -// request POST, PUT check that any content was send -router.use((req, res, next) => { - let err = undefined; - if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 && parseInt(req.get('Content-Length')) === 0) { - err = new Error("content in body is missing"); - err.status = 400; - next(err); - } else if ('PUT' === req.method && !(req.body.id || req.body._id)) { - err = new Error("content in body is missing field id"); - err.status = 400; - next(err); - } - next(); -}); - -module.exports = router; +/** This module defines a express.Router() instance + * - checking Accept-Version header to be 1.0 + * - body-data to be JSON on POST/PUT/PATCH + * - body to be not empty on POST/PUT/PATCH + * - Request accepts JSOn as reply content-type + * + * @author Johannes Konert + * @licence CC BY-SA 4.0 + * + * @module restapi/request-checks + * @type {Router} + */ + +// remember: in modules you have 3 variables given by CommonJS +// 1.) require() function +// 2.) module.exports +// 3.) exports (which is module.exports) +'use strict'; + +const express = require('express'); +const router = new express.Router(); + +// API-Version control. We use HTTP Header field Accept-Version instead of URL-part /v1/ +router.use((req, res, next) => { + // expect the Accept-Version header to be NOT set or being 1.0 + const versionWanted = req.get('Accept-Version'); + if (versionWanted !== undefined && versionWanted !== '1.0') { + // 406 Accept-* header cannot be fulfilled. + res.status(406).send('Accept-Version cannot be fulfilled').end(); + } else { + next(); // all OK, call next handler + } +}); + +// request type application/json check +router.use((req, res, next) => { + if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 && + (!(/multipart\/form-data/.test(req.get('Content-Type'))) && + !(/application\/json/.test(req.get('Content-Type'))))) { + // send error code 415: unsupported media type + res.status(415).send('wrong Content-Type'); // user has SEND the wrong type + } else if (!req.accepts('json')) { + // send 406 that response will be application/json and request does not support it by now as answer + // user has REQUESTED the wrong type + res.status(406).send('response of application/json only supported, please accept this'); + } else { + next(); // let this request pass through as it is OK + } +}); + + +// request POST, PUT check that any content was send +router.use((req, res, next) => { + let err = undefined; + if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 && parseInt(req.get('Content-Length')) === 0) { + err = new Error('content in body is missing'); + err.status = 400; + next(err); + } else if ('PUT' === req.method && !(req.body.id || req.body._id)) { + err = new Error('content in body is missing field id'); + err.status = 400; + next(err); + } + next(); +}); + +module.exports = router; diff --git a/api/middleware/resource-location.js b/api/middleware/resource-location.js new file mode 100644 index 0000000..b03d42e --- /dev/null +++ b/api/middleware/resource-location.js @@ -0,0 +1,12 @@ +'use strict'; + +const config = require('../config/config'); + +const resourceLocation = () => { + if (process.env.NODE_ENV === config.test.dredd.env) { + return config.test.dredd.resourceLocation; + } + return config.resourceLocation; +}; + +exports.resourceLocation = resourceLocation; diff --git a/api/middleware/router-handling.js b/api/middleware/router-handling.js index 367b6df..9d3b165 100644 --- a/api/middleware/router-handling.js +++ b/api/middleware/router-handling.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // HTTP status codes by name const codes = require('../routes/http-codes'); diff --git a/api/middleware/validators.js b/api/middleware/validators.js index d9a668c..8a26513 100644 --- a/api/middleware/validators.js +++ b/api/middleware/validators.js @@ -1,16 +1,21 @@ -"use strict"; +'use strict'; // HTTP status codes by name const codes = require('../routes/http-codes'); /** * check if id has valid UUID format + * + * @param {object} req + * @param {function} res + * @param {function} next + * @return {boolean} */ const idValidator = (req, res, next) => { const reqId = req.params.id; if (!reqId.match(/^[0-9a-fA-F]{24}$/)) { - const err = new Error("Invalid request id format"); + const err = new Error('Invalid request id format'); err.status = codes.notfound; return next(err); } diff --git a/api/models/app-user.js b/api/models/app-user.js index b83599d..af000aa 100644 --- a/api/models/app-user.js +++ b/api/models/app-user.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,36 +7,36 @@ const AppUserSchema = new Schema({ username: { type: String, required: true, - unique: true + unique: true, }, password: { type: String, - required: true + required: true, }, squad: { type: mongoose.Schema.Types.ObjectId, ref: 'Squad', - default: null + default: null, }, permission: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), + get: (v) => Math.round(v), + set: (v) => Math.round(v), min: 0, max: 4, - default: 0 + default: 0, }, secret: { type: String, - required: true + required: true, }, activated: { type: Boolean, - default: false - } + default: false, + }, }, { collection: 'app_user', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices AppUserSchema.index({timestamp: 1}); diff --git a/api/models/awarding.js b/api/models/awarding.js index 4a632a7..e94d3be 100644 --- a/api/models/awarding.js +++ b/api/models/awarding.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,39 +6,39 @@ const Schema = mongoose.Schema; const AwardingSchema = new Schema({ userId: { type: mongoose.Schema.Types.ObjectId, - ref: 'User' + ref: 'User', }, decorationId: { type: mongoose.Schema.Types.ObjectId, - ref: 'Decoration' + ref: 'Decoration', }, reason: { type: String, - required: true + required: true, }, proposer: { type: mongoose.Schema.Types.ObjectId, ref: 'AppUser', - required: true + required: true, }, confirmed: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), + get: (v) => Math.round(v), + set: (v) => Math.round(v), min: 0, max: 2, - default: 0 + default: 0, }, rejectReason: { - type: String + type: String, }, date: { type: Date, - default: Date.now() - } + default: Date.now(), + }, }, { collection: 'awarding', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices AwardingSchema.index({timestamp: 1}); diff --git a/api/models/campaign.js b/api/models/campaign.js index 405a0c1..ab4d9d5 100644 --- a/api/models/campaign.js +++ b/api/models/campaign.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,11 +6,11 @@ const Schema = mongoose.Schema; const CampaignSchema = new Schema({ title: { type: String, - required: true - } + required: true, + }, }, { collection: 'campaign', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices CampaignSchema.index({timestamp: 1}); diff --git a/api/models/decoration.js b/api/models/decoration.js index c0af942..5c6e2e2 100644 --- a/api/models/decoration.js +++ b/api/models/decoration.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,27 +6,27 @@ const Schema = mongoose.Schema; const DecorationSchema = new Schema({ name: { type: String, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR', 'GLOBAL'], - required: true + required: true, }, description: { type: String, - required: true + required: true, }, sortingNumber: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, - isMedal: {type: Boolean, required: true} + isMedal: {type: Boolean, required: true}, }, { collection: 'decoration', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices DecorationSchema.index({timestamp: 1}); diff --git a/api/models/logs/budget.js b/api/models/logs/budget.js index 46f93b1..479ddab 100644 --- a/api/models/logs/budget.js +++ b/api/models/logs/budget.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,31 +7,31 @@ const LogBudgetSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true + required: true, }, oldBudget: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, newBudget: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true - } + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, + }, }, { - collection: 'logBudget' + collection: 'logBudget', }); // optional more indices LogBudgetSchema.index({war: 1}); diff --git a/api/models/logs/flag.js b/api/models/logs/flag.js index 13a0eea..820bbfa 100644 --- a/api/models/logs/flag.js +++ b/api/models/logs/flag.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,27 +7,27 @@ const LogFlagSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, player: { type: String, - required: true + required: true, }, flagFraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true + required: true, }, capture: { type: Boolean, - required: true - } + required: true, + }, }, { - collection: 'logFlag' + collection: 'logFlag', }); // optional more indices LogFlagSchema.index({war: 1, player: 1}); diff --git a/api/models/logs/kill.js b/api/models/logs/kill.js index b48761e..29e76a3 100644 --- a/api/models/logs/kill.js +++ b/api/models/logs/kill.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,30 +7,30 @@ const LogKillSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, shooter: { - type: String + type: String, }, target: { type: String, - required: true + required: true, }, friendlyFire: { type: Boolean, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR', 'NONE'], - required: true - } + required: true, + }, }, { - collection: 'logKill' + collection: 'logKill', }); // optional more indices LogKillSchema.index({war: 1, shooter: 1, target: 1}); diff --git a/api/models/logs/points.js b/api/models/logs/points.js index 28aa39b..3ac06b8 100644 --- a/api/models/logs/points.js +++ b/api/models/logs/points.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,31 +7,31 @@ const LogKillSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, ptBlufor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, ptOpfor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR', 'NONE'], - required: true - } + required: true, + }, }, { - collection: 'logPoints' + collection: 'logPoints', }); // optional more indices LogKillSchema.index({war: 1, shooter: 1, target: 1}); diff --git a/api/models/logs/respawn.js b/api/models/logs/respawn.js index a79486a..8de2b57 100644 --- a/api/models/logs/respawn.js +++ b/api/models/logs/respawn.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,18 +7,18 @@ const LogRespawnSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, player: { type: String, - required: true - } + required: true, + }, }, { - collection: 'logRespawn' + collection: 'logRespawn', }); // optional more indices LogRespawnSchema.index({war: 1, player: 1}); diff --git a/api/models/logs/revive.js b/api/models/logs/revive.js index c5c9b10..a409ac6 100644 --- a/api/models/logs/revive.js +++ b/api/models/logs/revive.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,31 +7,31 @@ const LogReviveSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, medic: { type: String, - required: true + required: true, }, patient: { type: String, - required: true + required: true, }, stabilized: { type: Boolean, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true - } + required: true, + }, }, { - collection: 'logRevive' + collection: 'logRevive', }); // optional more indices LogReviveSchema.index({war: 1, medic: 1}); diff --git a/api/models/logs/transport.js b/api/models/logs/transport.js index 24998b3..dff8619 100644 --- a/api/models/logs/transport.js +++ b/api/models/logs/transport.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,33 +7,33 @@ const LogTransportSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, driver: { type: String, - required: true + required: true, }, passenger: { type: String, - required: true + required: true, }, distance: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true - } + required: true, + }, }, { - collection: 'logTransport' + collection: 'logTransport', }); // optional more indices LogTransportSchema.index({war: 1, driver: 1}); diff --git a/api/models/logs/vehicle.js b/api/models/logs/vehicle.js index 616f84c..8e9920e 100644 --- a/api/models/logs/vehicle.js +++ b/api/models/logs/vehicle.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,26 +7,26 @@ const LogVehicleKillSchema = new Schema({ war: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, time: { type: Date, - required: true + required: true, }, shooter: { - type: String + type: String, }, target: { type: String, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR', 'NONE'], - required: true - } + required: true, + }, }, { - collection: 'logVehicle' + collection: 'logVehicle', }); // optional more indices LogVehicleKillSchema.index({war: 1, shooter: 1, target: 1}); diff --git a/api/models/player.js b/api/models/player.js index 6741289..a91edf1 100644 --- a/api/models/player.js +++ b/api/models/player.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,73 +6,73 @@ const Schema = mongoose.Schema; const PlayerSchema = new Schema({ name: { type: String, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true + required: true, }, warId: { type: mongoose.Schema.Types.ObjectId, ref: 'War', - required: true + required: true, }, kill: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, vehicle: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, death: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, friendlyFire: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, revive: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, respawn: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, flagTouch: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, sort: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v) + get: (v) => Math.round(v), + set: (v) => Math.round(v), }, steamUUID: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v) - } + get: (v) => Math.round(v), + set: (v) => Math.round(v), + }, }, { collection: 'player', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices PlayerSchema.index({warId: 1}); diff --git a/api/models/promotion.js b/api/models/promotion.js index d0da9d0..16640c2 100644 --- a/api/models/promotion.js +++ b/api/models/promotion.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,39 +6,39 @@ const Schema = mongoose.Schema; const PromotionSchema = new Schema({ userId: { type: mongoose.Schema.Types.ObjectId, - ref: 'User' + ref: 'User', }, proposer: { type: mongoose.Schema.Types.ObjectId, ref: 'AppUser', - required: true + required: true, }, oldRankLvl: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, newRankLvl: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, }, confirmed: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), + get: (v) => Math.round(v), + set: (v) => Math.round(v), min: 0, max: 2, - required: true + required: true, }, rejectReason: { - type: String - } + type: String, + }, }, { collection: 'promotion', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices PromotionSchema.index({timestamp: 1}); diff --git a/api/models/rank.js b/api/models/rank.js index d14cbaa..bb83249 100644 --- a/api/models/rank.js +++ b/api/models/rank.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,22 +6,22 @@ const Schema = mongoose.Schema; const RankSchema = new Schema({ name: { type: String, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true + required: true, }, level: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - required: true - } + get: (v) => Math.round(v), + set: (v) => Math.round(v), + required: true, + }, }, { collection: 'rank', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices RankSchema.index({timestamp: 1}); diff --git a/api/models/squad.js b/api/models/squad.js index e427fd6..805a1b8 100644 --- a/api/models/squad.js +++ b/api/models/squad.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,22 +6,22 @@ const Schema = mongoose.Schema; const SquadSchema = new Schema({ name: { type: String, - required: true + required: true, }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR'], - required: true + required: true, }, sortingNumber: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 - } + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, + }, }, { collection: 'squad', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices SquadSchema.index({timestamp: 1}); diff --git a/api/models/user.js b/api/models/user.js index f36a75e..f63712a 100644 --- a/api/models/user.js +++ b/api/models/user.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -7,22 +7,22 @@ const UserSchema = new Schema({ username: { type: String, required: true, - unique: true + unique: true, }, rankLvl: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, squadId: { type: mongoose.Schema.Types.ObjectId, ref: 'Squad', - default: null - } + default: null, + }, }, { collection: 'user', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices UserSchema.index({timestamp: 1}); diff --git a/api/models/war.js b/api/models/war.js index e9a293b..ff342cd 100644 --- a/api/models/war.js +++ b/api/models/war.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const mongoose = require('mongoose'); const Schema = mongoose.Schema; @@ -6,7 +6,7 @@ const Schema = mongoose.Schema; const WarSchema = new Schema({ title: { type: String, - required: true + required: true, }, date: { type: Date, @@ -16,58 +16,58 @@ const WarSchema = new Schema({ }, ptBlufor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), + get: (v) => Math.round(v), + set: (v) => Math.round(v), }, ptOpfor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), + get: (v) => Math.round(v), + set: (v) => Math.round(v), }, playersBlufor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, playersOpfor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, campaign: { type: mongoose.Schema.Types.ObjectId, ref: 'Campaign', - required: true + required: true, }, budgetBlufor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, budgetOpfor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, endBudgetBlufor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, }, endBudgetOpfor: { type: Number, - get: v => Math.round(v), - set: v => Math.round(v), - default: 0 - } + get: (v) => Math.round(v), + set: (v) => Math.round(v), + default: 0, + }, }, { collection: 'war', - timestamps: {createdAt: 'timestamp'} + timestamps: {createdAt: 'timestamp'}, }); // optional more indices WarSchema.index({timestamp: 1}); diff --git a/api/package-lock.json b/api/package-lock.json index 71c0d75..33d5c16 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -3,6 +3,18 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -18,6 +30,170 @@ "negotiator": "0.6.1" } }, + "acorn": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", + "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", + "dev": true + }, + "acorn-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", + "dev": true, + "requires": { + "acorn": "2.7.0" + }, + "dependencies": { + "acorn": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "aglio": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/aglio/-/aglio-2.3.0.tgz", + "integrity": "sha1-n3Ri8BUgmWQVJ4oC0OILNuyWrcw=", + "dev": true, + "requires": { + "aglio-theme-olio": "1.6.3", + "chokidar": "1.7.0", + "cli-color": "1.2.0", + "drafter": "1.2.0", + "pretty-error": "1.2.0", + "serve-static": "1.13.1", + "socket.io": "1.7.4", + "yargs": "3.32.0" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "fsevents": "1.1.3", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "aglio-theme-olio": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/aglio-theme-olio/-/aglio-theme-olio-1.6.3.tgz", + "integrity": "sha1-kYZ558pNj7NjqS2vkAKt5IomUxk=", + "dev": true, + "requires": { + "coffee-script": "1.12.7", + "highlight.js": "8.9.1", + "jade": "1.11.0", + "less": "2.7.3", + "markdown-it": "4.4.0", + "markdown-it-anchor": "2.7.1", + "markdown-it-checkbox": "1.1.0", + "markdown-it-container": "1.0.0", + "markdown-it-emoji": "1.4.0", + "moment": "2.19.1", + "stylus": "0.51.1" + }, + "dependencies": { + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", + "dev": true + }, + "linkify-it": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", + "integrity": "sha1-B3NSbDF8j9E71TTuHRgP+Iq/iBo=", + "dev": true, + "requires": { + "uc.micro": "1.0.5" + } + }, + "markdown-it": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", + "integrity": "sha1-PfNz2+pYepp/7z5WMRtokI91xBQ=", + "dev": true, + "requires": { + "argparse": "1.0.10", + "entities": "1.1.1", + "linkify-it": "1.2.4", + "mdurl": "1.0.1", + "uc.micro": "1.0.5" + } + } + } + }, "ajv": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", @@ -36,6 +212,35 @@ } } }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amanda": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/amanda/-/amanda-0.5.1.tgz", + "integrity": "sha1-IAM3dsDksEPlNKhy4262xqvoQQM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, "ansi-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -45,6 +250,12 @@ "string-width": "2.1.1" } }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "dev": true + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -273,6 +484,12 @@ } } }, + "api-blueprint-http-formatter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/api-blueprint-http-formatter/-/api-blueprint-http-formatter-0.0.1.tgz", + "integrity": "sha1-Kn6zz4LewX2jYi/tt+oLLTBpybc=", + "dev": true + }, "append-field": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", @@ -293,6 +510,15 @@ } } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -345,6 +571,24 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" }, + "arraybuffer.slice": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", + "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=", + "dev": true + }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", @@ -407,6 +651,33 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -435,6 +706,24 @@ } } }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, "base64url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", @@ -464,6 +753,15 @@ "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, "bignumber.js": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", @@ -560,6 +858,12 @@ "readable-stream": "2.3.3" } }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "dev": true + }, "bluebird": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", @@ -602,6 +906,12 @@ } } }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, "boom": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", @@ -698,6 +1008,33 @@ "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz", "integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw=" }, + "buffer": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "dev": true, + "requires": { + "base64-js": "0.0.8", + "ieee754": "1.1.11", + "isarray": "1.0.0" + } + }, + "buffer-alloc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", + "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "0.1.1", + "buffer-fill": "0.1.1" + } + }, + "buffer-alloc-unsafe": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz", + "integrity": "sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo=", + "dev": true + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -713,6 +1050,12 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, + "buffer-fill": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-0.1.1.tgz", + "integrity": "sha512-YgBMBzdRLEfgxJIGu2wrvI2E03tMCFU1p7d1KhB4BOoMN0VxmTFjSyN5JtKt9z8Z9JajMHruI6SE25W96wNv7Q==", + "dev": true + }, "buffer-to-vinyl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz", @@ -803,6 +1146,48 @@ } } }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -845,6 +1230,24 @@ } } }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + }, + "dependencies": { + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + } + } + }, "chai": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", @@ -896,6 +1299,24 @@ } } }, + "character-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", + "integrity": "sha1-wN3kqxgnE7kZuXCVmhI+zBow/NY=", + "dev": true + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.0.tgz", @@ -978,6 +1399,12 @@ } } }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -1064,17 +1491,105 @@ } } }, + "clean-css": { + "version": "3.4.28", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", + "dev": true, + "requires": { + "commander": "2.8.1", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, "cli-boxes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, + "cli-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.2.0.tgz", + "integrity": "sha1-OlrnT9drYmevZm5p4q+70B3vNNE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1", + "d": "1.0.0", + "es5-ext": "0.10.41", + "es6-iterator": "2.0.3", + "memoizee": "0.4.12", + "timers-ext": "0.1.5" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + }, "clone": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=" }, + "clone-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.0.tgz", + "integrity": "sha1-6uCiQT9VwJQvgYwin+/OhF1/Oxw=", + "dev": true, + "requires": { + "is-regexp": "1.0.0", + "is-supported-regexp-flag": "1.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "1.0.0" + } + }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", @@ -1085,6 +1600,18 @@ "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=" }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "coffeescript": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", + "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1110,6 +1637,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, "combined-stream": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", @@ -1126,12 +1659,24 @@ "graceful-readlink": "1.0.1" } }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "dev": true }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1166,6 +1711,23 @@ "resolved": "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz", "integrity": "sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ=" }, + "constantinople": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", + "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=", + "dev": true, + "requires": { + "acorn": "2.7.0" + }, + "dependencies": { + "acorn": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", + "dev": true + } + } + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -1203,6 +1765,12 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1267,6 +1835,104 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, + "css": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", + "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=", + "dev": true, + "requires": { + "css-parse": "1.0.4", + "css-stringify": "1.0.5" + } + }, + "css-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=", + "dev": true + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "1.0.0", + "css-what": "2.1.0", + "domutils": "1.5.1", + "nth-check": "1.0.1" + } + }, + "css-stringify": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=", + "dev": true + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "csv": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/csv/-/csv-0.4.6.tgz", + "integrity": "sha1-jbrn3f26rmLB6ph8Pg+Kmsc3tz0=", + "dev": true, + "requires": { + "csv-generate": "0.0.6", + "csv-parse": "1.3.3", + "csv-stringify": "0.0.8", + "stream-transform": "0.1.2" + } + }, + "csv-generate": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-0.0.6.tgz", + "integrity": "sha1-l+TmOuRrIZEs2UdbwxRp0m9a3mY=", + "dev": true + }, + "csv-parse": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.3.3.tgz", + "integrity": "sha1-0c/YdDwvhJoKuy/VRNtWaV0ZpJA=", + "dev": true + }, + "csv-stringify": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-0.0.8.tgz", + "integrity": "sha1-Usw7PfwZd1jFWtMlqVvoUHH55Rs=", + "dev": true + }, + "curl-trace-parser": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/curl-trace-parser/-/curl-trace-parser-0.0.8.tgz", + "integrity": "sha1-hCD0iQ/ZmIIvtLSL/WZxI+ApNws=", + "dev": true, + "requires": { + "api-blueprint-http-formatter": "0.0.1", + "commander": "1.2.0", + "http-string-parser": "0.0.4" + }, + "dependencies": { + "commander": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.2.0.tgz", + "integrity": "sha1-/VcTv6FTx9bMWZN4patMRcU1Ap4=", + "dev": true, + "requires": { + "keypress": "0.1.0" + } + }, + "http-string-parser": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/http-string-parser/-/http-string-parser-0.0.4.tgz", + "integrity": "sha1-ayU441INQrNJoKxLcjTg45R2xbM=", + "dev": true + } + } + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -1275,6 +1941,21 @@ "array-find-index": "1.0.2" } }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.41" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -1301,6 +1982,12 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "deckardcain": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/deckardcain/-/deckardcain-0.3.4.tgz", + "integrity": "sha1-ZOlJ6xLHs0j1GpGJsHEPoKJPqVE=", + "dev": true + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -1323,6 +2010,15 @@ "vinyl-fs": "2.4.4" } }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "1.0.0" + } + }, "decompress-tar": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz", @@ -1468,11 +2164,23 @@ } } }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, "deep-extend": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", @@ -1482,6 +2190,37 @@ "is-descriptor": "1.0.2" } }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1492,6 +2231,23 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" }, + "deref": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/deref/-/deref-0.7.3.tgz", + "integrity": "sha512-9ROdWS8nWgz/uJxYWIDZyEAP+oANSl/pNQO27GFJWptVVocqBQ95iKmcboxjvjPQ0rn3IpJcA450hIJpznzVLg==", + "dev": true, + "requires": { + "deep-extend": "0.5.0" + }, + "dependencies": { + "deep-extend": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.0.tgz", + "integrity": "sha1-bvSgmwX5iw41jW2T1Mo8rsZnKAM=", + "dev": true + } + } + }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -1535,11 +2291,80 @@ "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", "dev": true }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, + "dom-converter": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", + "dev": true, + "requires": { + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, "dom-walk": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -1571,6 +2396,153 @@ "ware": "1.3.0" } }, + "drafter": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/drafter/-/drafter-1.2.0.tgz", + "integrity": "sha1-9NEeje4fJ/mkBIW4dAxENh6c+Fk=", + "dev": true, + "requires": { + "drafter.js": "2.6.7", + "protagonist": "1.6.8" + } + }, + "drafter.js": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/drafter.js/-/drafter.js-2.6.7.tgz", + "integrity": "sha1-WcQ6hYZSc0DLNb3cVBgFWfru8AE=", + "dev": true + }, + "drange": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.0.1.tgz", + "integrity": "sha512-PVkrAwra9MnIY6QIa9YMlEHkfbcikjK+W/X/O0BNXG14y3O8vqGhzvP8TKlu4sFCJn7V2raugY8SOjDXVHti0g==", + "dev": true + }, + "dredd": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/dredd/-/dredd-5.1.5.tgz", + "integrity": "sha512-Z8ihEYJjo6T26ys0fP3UbUhO4KHh9/oju7r+Uj+v2jcRhwBnKRWqxkkzKdDuZOnCPymRRgMIxQ44QuSG1onc9A==", + "dev": true, + "requires": { + "async": "2.6.0", + "caseless": "0.12.0", + "chai": "4.1.2", + "clone": "2.1.1", + "coffeescript": "1.12.7", + "cross-spawn": "6.0.5", + "dredd-transactions": "6.0.2", + "file": "0.2.2", + "fs-extra": "5.0.0", + "gavel": "1.1.1", + "glob": "7.1.2", + "html": "1.0.0", + "htmlencode": "0.0.4", + "inquirer": "3.3.0", + "js-yaml": "3.10.0", + "markdown-it": "8.4.1", + "optimist": "0.6.1", + "pitboss-ng": "0.3.3", + "proxyquire": "2.0.0", + "request": "2.83.0", + "spawn-args": "0.2.0", + "uuid": "3.2.1", + "which": "1.3.0", + "winston": "2.2.0" + }, + "dependencies": { + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "dev": true, + "requires": { + "assertion-error": "1.0.2", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" + } + }, + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.4", + "path-key": "2.0.1", + "semver": "5.5.0", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true + } + } + }, + "dredd-transactions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/dredd-transactions/-/dredd-transactions-6.0.2.tgz", + "integrity": "sha512-4abrX4zUktbs2OqhVpnp5ziizEfsNNxAz1nw9lP0mqyhmRSYUm4eacSVXqRY/74A9mzlQFdYxR7nZMI6bMVZ0Q==", + "dev": true, + "requires": { + "clone": "2.1.1", + "fury": "3.0.0-beta.6", + "fury-adapter-apib-parser": "0.10.0", + "fury-adapter-swagger": "0.18.0", + "uri-template": "1.0.1" + }, + "dependencies": { + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + } + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -1647,6 +2619,114 @@ "once": "1.4.0" } }, + "engine.io": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", + "integrity": "sha512-j1DWIcktw4hRwrv6nWx++5nFH2X64x16MAG2P0Lmi5Dvdfi3I+Jhc7JKJIdAmDJa+5aZ/imHV7dWRPy2Cqjh3A==", + "dev": true, + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "1.1.5" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "dev": true, + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "engine.io-client": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", + "integrity": "sha512-AYTgHyeVUPitsseqjoedjhYJapNVoSPShbZ+tEUX9/73jgZ/Z3sUlJf9oYgdEBBdVhupUpUqSxH0kBCXlQnmZg==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parsejson": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "1.1.5", + "xmlhttprequest-ssl": "1.5.3", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "optional": true, + "requires": { + "prr": "1.0.1" + } + }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", @@ -1655,11 +2735,55 @@ "is-arrayish": "0.2.1" } }, + "es5-ext": { + "version": "0.10.41", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.41.tgz", + "integrity": "sha512-MYK02wXfwTMie5TEJWPolgOsXEmz7wKCQaGzgmRjZOoV6VLG8I5dSv2bn6AOClXhK64gnSQTQ9W9MKvx87J4gw==", + "dev": true, + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "next-tick": "1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.41", + "es6-symbol": "3.1.1" + } + }, "es6-promise": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.41" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.41", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1670,11 +2794,186 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", + "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==", + "dev": true, + "requires": { + "ajv": "5.3.0", + "babel-code-frame": "6.26.0", + "chalk": "2.3.2", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.3.0", + "ignore": "3.3.7", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.11.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "eslint-config-google": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.9.1.tgz", + "integrity": "sha512-5A83D+lH0PA81QMESKbLJd/a3ic8tPZtwUmqNrxMRo54nfFaUvtt89q/+icQ+fd66c2xQHn0KyFkzJDoAUfpZA==", + "dev": true + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "5.5.3", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.41" + } + }, "event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", @@ -1897,6 +3196,25 @@ "is-extendable": "0.1.1" } }, + "external-editor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", + "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", + "dev": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.19", + "tmp": "0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + } + } + }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", @@ -1917,6 +3235,12 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, "fancy-log": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz", @@ -1936,6 +3260,12 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", @@ -1953,6 +3283,22 @@ "object-assign": "4.1.1" } }, + "file": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/file/-/file-0.2.2.tgz", + "integrity": "sha1-w9/Y+M81Na5FXCtCPC5SY112tNM=", + "dev": true + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, "file-type": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", @@ -1978,6 +3324,16 @@ "trim-repeated": "1.0.0" } }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "1.0.1", + "merge-descriptors": "1.0.1" + } + }, "fill-range": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", @@ -2044,6 +3400,18 @@ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=" }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, "for-each": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.2.tgz", @@ -2065,6 +3433,12 @@ "for-in": "1.0.2" } }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2080,6 +3454,12 @@ "mime-types": "2.1.17" } }, + "format-util": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz", + "integrity": "sha1-Ay3KShFiYqEsQ/TD7IVmQWxbLZU=", + "dev": true + }, "formidable": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", @@ -2111,6 +3491,27 @@ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "fs-extra": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", + "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2123,7 +3524,7 @@ "dev": true, "optional": true, "requires": { - "nan": "2.9.2", + "nan": "2.10.0", "node-pre-gyp": "0.6.39" }, "dependencies": { @@ -3020,6 +4421,106 @@ } } }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "fury": { + "version": "3.0.0-beta.6", + "resolved": "https://registry.npmjs.org/fury/-/fury-3.0.0-beta.6.tgz", + "integrity": "sha512-IjCU8srMfZv2SN075a0iCt+OdWmaSDaAv9+ev/degImwTmVbzy61Sx3sakI/G0tbhQs29szTVk/EwcoHf7ur5Q==", + "dev": true, + "requires": { + "minim": "0.20.4", + "minim-parse-result": "0.10.0" + } + }, + "fury-adapter-apib-parser": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/fury-adapter-apib-parser/-/fury-adapter-apib-parser-0.10.0.tgz", + "integrity": "sha512-nvKIiNZt452vnWEMTobgtd4qb8C5iLqoQCrXr0SCJOaILOzHQmdihipy6gjLtdM9MgyrKlOzkSBmSCL+wVPQOA==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "deckardcain": "0.3.4", + "drafter": "1.2.0", + "minim": "0.20.4" + } + }, + "fury-adapter-swagger": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/fury-adapter-swagger/-/fury-adapter-swagger-0.18.0.tgz", + "integrity": "sha1-EjHoe5qX2LY9ab+v7ZmzCl5OhNY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "js-yaml": "3.11.0", + "json-schema-faker": "0.5.0-rc11", + "lodash": "4.17.4", + "media-typer": "0.3.0", + "swagger-parser": "3.4.2", + "yaml-js": "0.2.3", + "z-schema": "3.19.1" + } + }, + "gavel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/gavel/-/gavel-1.1.1.tgz", + "integrity": "sha1-AXd9S+FsrpC6GZtjXv/GWtvQQP4=", + "dev": true, + "requires": { + "amanda": "0.5.1", + "async": "2.6.0", + "caseless": "0.12.0", + "clone": "2.1.2", + "commander": "2.15.1", + "curl-trace-parser": "0.0.8", + "deep-equal": "1.0.1", + "googlediff": "0.1.0", + "http-string-parser": "0.0.5", + "is-type": "0.0.1", + "json-pointer": "0.6.0", + "jsonlint": "git+https://git@github.com/josdejong/jsonlint.git#85a19d77126771f3177582e3d09c6ffae185d391", + "media-typer": "0.3.0", + "tv4": "1.3.0" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "jsonlint": { + "version": "git+https://git@github.com/josdejong/jsonlint.git#85a19d77126771f3177582e3d09c6ffae185d391", + "dev": true, + "requires": { + "JSV": "4.0.2", + "nomnom": "1.8.1" + } + } + } + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, "get-proxy": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz", @@ -3153,6 +4654,12 @@ "ini": "1.3.4" } }, + "globals": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.3.0.tgz", + "integrity": "sha512-kkpcKNlmQan9Z5ZmgqKH/SMbSmjxQ7QjyNqfXVc8VJcoBV2UEg+sxQD15GQofGRh2hfpwUb70VC31DR7Rq5Hdw==", + "dev": true + }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", @@ -3173,6 +4680,12 @@ "sparkles": "1.0.0" } }, + "googlediff": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/googlediff/-/googlediff-0.1.0.tgz", + "integrity": "sha1-mazwXMBiI+tmwpAI2B+bLRjCRT0=", + "dev": true + }, "got": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz", @@ -3336,6 +4849,35 @@ "ansi-regex": "2.1.1" } }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", @@ -3350,6 +4892,21 @@ "sparkles": "1.0.0" } }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "1.4.2" + } + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -3427,6 +4984,102 @@ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, + "hercule": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/hercule/-/hercule-4.1.1.tgz", + "integrity": "sha512-ws8KMjT6SZU8jbdq+w3/O0aSdEDxKCXyhYQkAKknvadhzcLf5Qw413laK0UjhWM9jxwCr3nYsbTYVYbOIWK5+g==", + "dev": true, + "requires": { + "async": "2.6.0", + "clone-regexp": "1.0.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "got": "8.3.0", + "isstream": "0.1.2", + "left-split": "1.0.0", + "lodash": "4.17.4", + "meow": "3.7.0", + "source-map": "0.6.1", + "through2": "2.0.3", + "through2-get": "0.1.0" + }, + "dependencies": { + "got": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz", + "integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "0.7.0", + "cacheable-request": "2.1.4", + "decompress-response": "3.3.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "into-stream": "3.1.0", + "is-retry-allowed": "1.1.0", + "isurl": "1.0.0", + "lowercase-keys": "1.0.0", + "mimic-response": "1.0.0", + "p-cancelable": "0.4.0", + "p-timeout": "2.0.1", + "pify": "3.0.0", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "url-parse-lax": "3.0.0", + "url-to-options": "1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "2.0.0" + } + } + } + }, + "highlight.js": { + "version": "8.9.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-8.9.1.tgz", + "integrity": "sha1-uKnFSTISqTkvAiK2SclhFJfr+4g=", + "dev": true + }, "hoek": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", @@ -3437,6 +5090,74 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" }, + "html": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/html/-/html-1.0.0.tgz", + "integrity": "sha1-pUT6nqVJK/s6LMqCEKEL57WvH2E=", + "dev": true, + "requires": { + "concat-stream": "1.6.0" + } + }, + "htmlencode": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/htmlencode/-/htmlencode-0.0.4.tgz", + "integrity": "sha1-9+LWr74YqHp45jujMI51N2Z0Dj8=", + "dev": true + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.1.0", + "domutils": "1.1.6", + "readable-stream": "1.0.34" + }, + "dependencies": { + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, "http-errors": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", @@ -3456,17 +5177,42 @@ "sshpk": "1.13.1" } }, + "http-string-parser": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/http-string-parser/-/http-string-parser-0.0.5.tgz", + "integrity": "sha1-jy2geB/gpuSAND9T0uz5OvhkYcg=", + "dev": true + }, "iconv-lite": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=" }, + "ieee754": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", + "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", + "dev": true + }, + "ignore": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, "imagemin": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-5.3.1.tgz", @@ -3510,6 +5256,12 @@ "repeating": "2.0.1" } }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3529,6 +5281,105 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.2", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "2.3.0", + "p-is-promise": "1.1.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, "ip-regex": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", @@ -3730,6 +5581,12 @@ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-odd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", @@ -3750,6 +5607,21 @@ } } }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", @@ -3759,6 +5631,12 @@ "path-is-inside": "1.0.2" } }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -3791,16 +5669,34 @@ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, "is-relative": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=" }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -3811,11 +5707,26 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-supported-regexp-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz", + "integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=", + "dev": true + }, "is-tar": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz", "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=" }, + "is-type": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz", + "integrity": "sha1-9lHYXDZdRJVdFKUdjXBh8/a0d5w=", + "dev": true, + "requires": { + "core-util-is": "1.0.2" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3869,6 +5780,42 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "1.4.1", + "is-object": "1.0.1" + } + }, + "jade": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", + "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=", + "dev": true, + "requires": { + "character-parser": "1.2.1", + "clean-css": "3.4.28", + "commander": "2.6.0", + "constantinople": "3.0.2", + "jstransformer": "0.0.2", + "mkdirp": "0.5.1", + "transformers": "2.1.0", + "uglify-js": "2.8.29", + "void-elements": "2.0.1", + "with": "4.0.3" + }, + "dependencies": { + "commander": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=", + "dev": true + } + } + }, "jimp": { "version": "0.2.28", "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz", @@ -3922,17 +5869,82 @@ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz", "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=" }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", + "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-pointer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.0.tgz", + "integrity": "sha1-jlAFUKaqxUZKRzN32leqbMIoKNc=", + "dev": true, + "requires": { + "foreach": "2.0.5" + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, + "json-schema-faker": { + "version": "0.5.0-rc11", + "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.0-rc11.tgz", + "integrity": "sha512-p0Kf2p0zx7so8LHXZIs7lAgKjcOIy+qyTAo9s1FkqUQmvS2MDaTfPGTqdXW3jjNg7wot1ZGpJPdY1M0te9lh3w==", + "dev": true, + "requires": { + "deref": "0.7.3", + "json-schema-ref-parser": "3.3.1", + "randexp": "0.4.9", + "tslib": "1.9.0" + } + }, + "json-schema-ref-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-3.3.1.tgz", + "integrity": "sha512-stQTMhec2R/p2L9dH4XXRlpNCP0mY8QrLd/9Kl+8SHJQmwHtE1nDfXH4wbsSM+GkJMl8t92yZbI0OIol432CIQ==", + "dev": true, + "requires": { + "call-me-maybe": "1.0.1", + "debug": "3.1.0", + "es6-promise": "4.2.4", + "js-yaml": "3.11.0", + "ono": "4.0.3", + "z-schema": "3.19.1" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true + } + } + }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", @@ -3946,6 +5958,12 @@ "jsonify": "0.0.0" } }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "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", @@ -3957,6 +5975,15 @@ "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", "dev": true }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", @@ -3992,6 +6019,16 @@ "verror": "1.10.0" } }, + "jstransformer": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", + "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=", + "dev": true, + "requires": { + "is-promise": "2.1.0", + "promise": "6.1.0" + } + }, "jwa": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", @@ -4018,6 +6055,21 @@ "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.0.3.tgz", "integrity": "sha512-WloXk3nyByx9FEB5WY7WFEXIZB/QA+zy7c2kJMjnZCebjepEyQcJzazgLiKcTS/ltZeEoeEQ1A1pau1fEDlnIA==" }, + "keypress": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=", + "dev": true + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4057,6 +6109,252 @@ "readable-stream": "2.3.3" } }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "left-split": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/left-split/-/left-split-1.0.0.tgz", + "integrity": "sha1-vsUUwjz7TJV6mXTt/aOFvFlyiAY=", + "dev": true + }, + "less": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", + "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", + "dev": true, + "requires": { + "errno": "0.1.7", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.4.1", + "mkdirp": "0.5.1", + "promise": "7.3.1", + "request": "2.81.0", + "source-map": "0.5.7" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "optional": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "optional": true + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true, + "optional": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "2.0.6" + } + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.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": "4.2.1", + "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", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "linkify-it": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", + "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", + "dev": true, + "requires": { + "uc.micro": "1.0.5" + } + }, "load-bmfont": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.3.0.tgz", @@ -4083,6 +6381,12 @@ "strip-bom": "2.0.0" } }, + "lockfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.3.tgz", + "integrity": "sha1-Jjj8OaAzHpysGgS3F5mTHJxQ33k=", + "dev": true + }, "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", @@ -4281,6 +6585,15 @@ "yallist": "2.1.2" } }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dev": true, + "requires": { + "es5-ext": "0.10.41" + } + }, "make-dir": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz", @@ -4322,11 +6635,84 @@ "object-visit": "1.0.1" } }, + "markdown-it": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz", + "integrity": "sha512-CzzqSSNkFRUf9vlWvhK1awpJreMRqdCrBvZ8DIoDWTOkESMIF741UPAhuAmbyWmdiFPA6WARNhnu2M6Nrhwa+A==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "entities": "1.1.1", + "linkify-it": "2.0.3", + "mdurl": "1.0.1", + "uc.micro": "1.0.5" + } + }, + "markdown-it-anchor": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-2.7.1.tgz", + "integrity": "sha1-Ny9n2npMRjKtDr5MlpFybv4lNCo=", + "dev": true, + "requires": { + "string": "3.3.3" + } + }, + "markdown-it-checkbox": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/markdown-it-checkbox/-/markdown-it-checkbox-1.1.0.tgz", + "integrity": "sha1-IM/5fzPXfRcvnc8bz8ks7MUzD6w=", + "dev": true, + "requires": { + "underscore": "1.8.3" + }, + "dependencies": { + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true + } + } + }, + "markdown-it-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-1.0.0.tgz", + "integrity": "sha1-0ugmnUZ8BWxsnva3sW8Smhm5820=", + "dev": true + }, + "markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=", + "dev": true + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoizee": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.12.tgz", + "integrity": "sha512-sprBu6nwxBWBvBOh5v2jcsGqiGLlL2xr2dLub3vR8dnE8YB17omwtm/0NSHl8jjNbcsJd5GMWJAnTSVe/O0Wfg==", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.41", + "es6-weak-map": "2.0.2", + "event-emitter": "0.3.5", + "is-promise": "2.1.0", + "lru-queue": "0.1.0", + "next-tick": "1.0.0", + "timers-ext": "0.1.5" + } + }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -4415,6 +6801,18 @@ "mime-db": "1.30.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "mimic-response": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", + "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=", + "dev": true + }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -4423,6 +6821,31 @@ "dom-walk": "0.1.1" } }, + "minim": { + "version": "0.20.4", + "resolved": "https://registry.npmjs.org/minim/-/minim-0.20.4.tgz", + "integrity": "sha1-ShFke+Uk2pIzour/+mSQ54WlqAA=", + "dev": true, + "requires": { + "lodash": "4.17.4", + "uptown": "1.0.1" + } + }, + "minim-api-description": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/minim-api-description/-/minim-api-description-0.8.0.tgz", + "integrity": "sha512-gDxqv0pHiFYRI1zllvjig1WbTdNh2L1q3RYY/mh0jb0bNl+fwmEGNo36qqiNuLi7OamJQZQ9gcLlE8mWxsg7AA==", + "dev": true + }, + "minim-parse-result": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/minim-parse-result/-/minim-parse-result-0.10.0.tgz", + "integrity": "sha512-6s9JTgM8wVZoE6KuJZrCBMzIf0pOFNCXsDcUNBCpSfc4aF1950ywOoQP2LyQPXbITao1SDLqJHQdZy2xXJjMYA==", + "dev": true, + "requires": { + "minim-api-description": "0.8.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -4541,6 +6964,12 @@ } } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "moment": { "version": "2.19.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.1.tgz", @@ -4571,6 +7000,217 @@ "require_optional": "1.0.1" } }, + "mongodb-memory-server": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-1.7.3.tgz", + "integrity": "sha512-4shE5rDEm7aUA1lNY7xA62MTZ8Z2iJN5ZuaBl+NWIyZ55YPUCoBiCdCMeYDkCSThrRu2v4yFDCtZ33u8wnJLvg==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "debug": "3.1.0", + "decompress": "4.2.0", + "fs-extra": "5.0.0", + "get-port": "3.2.0", + "getos": "3.1.0", + "lockfile": "1.0.3", + "md5-file": "3.2.3", + "mkdirp": "0.5.1", + "request": "2.85.0", + "request-promise": "4.2.2", + "tmp": "0.0.33", + "uuid": "3.2.1" + }, + "dependencies": { + "async": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.4.0.tgz", + "integrity": "sha1-SZAgDxjqW4N8LMT4wDGmmFw4VhE=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "dev": true, + "requires": { + "decompress-tar": "4.1.1", + "decompress-tarbz2": "4.1.1", + "decompress-targz": "4.1.1", + "decompress-unzip": "4.0.1", + "graceful-fs": "4.1.11", + "make-dir": "1.1.0", + "pify": "2.3.0", + "strip-dirs": "2.1.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "requires": { + "file-type": "5.2.0", + "is-stream": "1.1.0", + "tar-stream": "1.5.4" + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "requires": { + "decompress-tar": "4.1.1", + "file-type": "6.2.0", + "is-stream": "1.1.0", + "seek-bzip": "1.0.5", + "unbzip2-stream": "1.2.5" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "requires": { + "decompress-tar": "4.1.1", + "file-type": "5.2.0", + "is-stream": "1.1.0" + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "dev": true, + "requires": { + "file-type": "3.9.0", + "get-stream": "2.3.1", + "pify": "2.3.0", + "yauzl": "2.9.1" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + } + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + }, + "getos": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.1.0.tgz", + "integrity": "sha512-i9vrxtDu5DlLVFcrbqUqGWYlZN/zZ4pGMICCAcZoYsX3JA54nYp8r5EThw5K+m2q3wszkx4Th746JstspB0H4Q==", + "dev": true, + "requires": { + "async": "2.4.0" + } + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", + "dev": true + }, + "md5-file": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-3.2.3.tgz", + "integrity": "sha512-3Tkp1piAHaworfcCgH0jKbTvj1jWWFgbvh2cXaNCgHwyTCBxxvD1Y04rmfpvdPm1P4oXMOpm6+2H7sr7v9v8Fw==", + "dev": true, + "requires": { + "buffer-alloc": "1.1.0" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "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", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "requires": { + "is-natural-number": "4.0.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true + } + } + }, "mongoose": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.0.3.tgz", @@ -4728,10 +7368,16 @@ } } }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "nan": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.9.2.tgz", - "integrity": "sha512-ltW65co7f3PQWBDbqVvaU1WtFJUsNW7sWWm4HINhbMQIyVyzIeyZ8toX5TC5eeooE6piZoaEh4cZkueSKG3KYw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", "dev": true, "optional": true }, @@ -4774,11 +7420,29 @@ } } }, + "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 + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", + "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", + "dev": true + }, "node-sha1": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/node-sha1/-/node-sha1-1.0.1.tgz", @@ -4806,6 +7470,41 @@ "update-notifier": "2.3.0" } }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + } + } + }, "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -4834,6 +7533,25 @@ "remove-trailing-separator": "1.1.0" } }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "2.0.0", + "query-string": "5.1.1", + "sort-keys": "2.0.0" + }, + "dependencies": { + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + } + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -4842,6 +7560,15 @@ "path-key": "2.0.1" } }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "1.0.0" + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -4857,6 +7584,12 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -4985,6 +7718,59 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" }, + "ono": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.3.tgz", + "integrity": "sha512-7QIxG4UB00H7CR7fhXC/U7VhB5DK9wsYLwaYBui1JmQoXtLkhIBn3fbuk6FgAP+ctWeBsWVTM+R/bThvUZN+ww==", + "dev": true, + "requires": { + "format-util": "1.0.3" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.10", + "wordwrap": "0.0.3" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, "ordered-read-streams": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", @@ -4999,21 +7785,51 @@ "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-1.0.3.tgz", "integrity": "sha1-WRUzDZDs7VV9LZOKMcbdIU2cY60=" }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, + "p-cancelable": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.0.tgz", + "integrity": "sha512-/AodqPe1y/GYbhSlnMjxukLGQfQIgsmjSy2CXCNB96kg4ozKvmlovuHEKICToOO/yS3LLWgrWI1dFtFfrePS1g==", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, "p-pipe": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz", "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=" }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "1.0.0" + } + }, "package-json": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", @@ -5121,6 +7937,33 @@ "error-ex": "1.3.1" } }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -5176,6 +8019,12 @@ "pinkie-promise": "2.0.1" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pause-stream": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", @@ -5185,6 +8034,12 @@ "through": "2.3.8" } }, + "pct-encode": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pct-encode/-/pct-encode-1.0.2.tgz", + "integrity": "sha1-uZt7BE1r18OeSDmnqAEirXUVyqU=", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -5195,6 +8050,12 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "pidusage": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-1.1.5.tgz", + "integrity": "sha1-uMjTK9+vNiEsqedBAoh26jMhfmY=", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -5213,6 +8074,17 @@ "pinkie": "2.0.4" } }, + "pitboss-ng": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/pitboss-ng/-/pitboss-ng-0.3.3.tgz", + "integrity": "sha1-dB3nbNG5EOzMgVVl6TzWVdDnH3M=", + "dev": true, + "requires": { + "clone": "1.0.3", + "csv": "0.4.6", + "pidusage": "1.1.5" + } + }, "pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", @@ -5221,6 +8093,18 @@ "pngjs": "3.3.0" } }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", + "dev": true + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, "pngjs": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.3.0.tgz", @@ -5242,6 +8126,12 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", @@ -5252,6 +8142,16 @@ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, + "pretty-error": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-1.2.0.tgz", + "integrity": "sha1-8oBYQUvzTdLpk0liGTN+nSWlraU=", + "dev": true, + "requires": { + "renderkid": "1.0.0", + "utila": "0.4.0" + } + }, "process": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", @@ -5262,6 +8162,31 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, + "promise": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=", + "dev": true, + "requires": { + "asap": "1.0.0" + } + }, + "protagonist": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/protagonist/-/protagonist-1.6.8.tgz", + "integrity": "sha1-FtXWMW8bbU5JPslFBjnbw1UDvm4=", + "dev": true, + "optional": true, + "requires": { + "nan": "2.10.0" + } + }, "proxy-addr": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", @@ -5271,6 +8196,24 @@ "ipaddr.js": "1.5.2" } }, + "proxyquire": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.0.0.tgz", + "integrity": "sha512-TO9TAIz0mpa+SKddXsgCFatoe/KmHvoNVj2jDMC1kXE6kKn7/4CRpxvQ+0wAK9sbMT2FVO89qItlvnZMcFbJ2Q==", + "dev": true, + "requires": { + "fill-keys": "1.0.2", + "module-not-found-error": "1.0.1", + "resolve": "1.1.7" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, + "optional": true + }, "ps-tree": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", @@ -5309,6 +8252,27 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=" }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "0.2.0", + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, + "randexp": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.9.tgz", + "integrity": "sha512-maAX1cnBkzIZ89O4tSQUOF098xjGMC8N+9vuY/WfHwg87THw6odD2Br35donlj5e6KnB1SB0QBHhTQhhDHuTPQ==", + "dev": true, + "requires": { + "drange": "1.0.1", + "ret": "0.2.2" + } + }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", @@ -5452,6 +8416,12 @@ "strip-indent": "1.0.1" } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", @@ -5498,6 +8468,27 @@ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, + "renderkid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-1.0.0.tgz", + "integrity": "sha1-KeFsX2S+m91SmJtqYwrHmcc4FYs=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-converter": "0.1.4", + "htmlparser2": "3.3.0", + "strip-ansi": "3.0.1", + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", @@ -5565,6 +8556,45 @@ } } }, + "request-promise": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", + "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", + "dev": true, + "requires": { + "bluebird": "3.5.0", + "request-promise-core": "1.1.1", + "stealthy-require": "1.1.1", + "tough-cookie": "2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } + } + }, "require_optional": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", @@ -5574,6 +8604,12 @@ "semver": "5.4.1" } }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", @@ -5585,6 +8621,51 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + }, + "dependencies": { + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + } + } + }, + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -5593,6 +8674,30 @@ "glob": "7.1.2" } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -5784,11 +8889,26 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", @@ -5923,6 +9043,157 @@ "hoek": "4.2.0" } }, + "socket.io": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", + "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", + "dev": true, + "requires": { + "debug": "2.3.3", + "engine.io": "1.8.5", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.4", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", + "dev": true, + "requires": { + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "socket.io-client": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", + "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", + "dev": true, + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "1.8.5", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", + "dev": true, + "requires": { + "component-emitter": "1.1.2", + "debug": "2.2.0", + "isarray": "0.0.1", + "json3": "3.3.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=", + "dev": true + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -5953,6 +9224,12 @@ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=" }, + "spawn-args": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz", + "integrity": "sha1-+30L0dcP1DFr2ePew4nmX51jYbs=", + "dev": true + }, "spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", @@ -6010,6 +9287,12 @@ } } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "squeak": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz", @@ -6035,6 +9318,12 @@ "tweetnacl": "0.14.5" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, "stat-mode": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", @@ -6123,6 +9412,12 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", @@ -6159,11 +9454,29 @@ "stream-to": "0.2.2" } }, + "stream-transform": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.1.2.tgz", + "integrity": "sha1-fY5rTgOsR4F3j4x5UXUBv7B2Kp8=", + "dev": true + }, "streamsearch": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/string/-/string-3.3.3.tgz", + "integrity": "sha1-XqIRzZLSKOGEKUmQpsyXs2anfLA=", + "dev": true + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -6268,6 +9581,75 @@ "escape-string-regexp": "1.0.5" } }, + "stylus": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.51.1.tgz", + "integrity": "sha1-11xAXB2H1eAMpXWNMRzXk2Dw+5k=", + "dev": true, + "requires": { + "css-parse": "1.7.0", + "debug": "3.1.0", + "glob": "3.2.11", + "mkdirp": "0.3.5", + "sax": "0.5.8", + "source-map": "0.1.43" + }, + "dependencies": { + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", + "dev": true + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimatch": "0.3.0" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "dev": true + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, "sum-up": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz", @@ -6343,6 +9725,129 @@ } } }, + "swagger-methods": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-1.0.4.tgz", + "integrity": "sha512-xrKFLbrZ6VxRsg+M3uJozJtsEpNI/aPfZsOkoEjXw8vhAqdMIqwTYGj1f4dmUgvJvCdZhV5iArgtqXgs403ltg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "call-me-maybe": "1.0.1", + "debug": "3.1.0", + "es6-promise": "4.2.4", + "json-schema-ref-parser": "1.4.1", + "ono": "4.0.3", + "swagger-methods": "1.0.4", + "swagger-schema-official": "2.0.0-bab6bed", + "z-schema": "3.19.1" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true + }, + "json-schema-ref-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-1.4.1.tgz", + "integrity": "sha1-wMLkOL8HlnI7AkUbrovH3Qs3/tA=", + "dev": true, + "requires": { + "call-me-maybe": "1.0.1", + "debug": "2.6.9", + "es6-promise": "3.3.1", + "js-yaml": "3.11.0", + "ono": "2.2.5" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + }, + "ono": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/ono/-/ono-2.2.5.tgz", + "integrity": "sha1-2vCUiLURdNp6fkJ136sxtDj/oOM=", + "dev": true + } + } + } + } + }, + "swagger-schema-official": { + "version": "2.0.0-bab6bed", + "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", + "integrity": "sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0=", + "dev": true + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.3.0", + "ajv-keywords": "2.1.1", + "chalk": "2.3.2", + "lodash": "4.17.4", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "tar-stream": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", @@ -6377,6 +9882,12 @@ "execa": "0.7.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -6435,6 +9946,28 @@ } } }, + "through2-get": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/through2-get/-/through2-get-0.1.0.tgz", + "integrity": "sha512-hlySS8S0Xr75MJ8BvTKiGegiJD4V08lJVPO0qzFzx/1XJCkSbn9q2secwiYkoa6jvaHOwF5eAKOutdEXRnKGXg==", + "dev": true, + "requires": { + "lodash.get": "4.4.2", + "through2": "2.0.3" + }, + "dependencies": { + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + } + } + }, "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", @@ -6445,11 +9978,30 @@ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz", "integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=" }, + "timers-ext": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.5.tgz", + "integrity": "sha512-tsEStd7kmACHENhsUPaxb8Jf8/+GZZxyNFQbZD07HQOyooOa6At1rQqjffgvg7n+dxscQa9cjjMdWhJtsP2sxg==", + "dev": true, + "requires": { + "es5-ext": "0.10.41", + "next-tick": "1.0.0" + } + }, "tinycolor2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, "to-absolute-glob": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", @@ -6458,6 +10010,12 @@ "extend-shallow": "2.0.1" } }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -6599,6 +10157,68 @@ "punycode": "1.4.1" } }, + "transformers": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", + "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=", + "dev": true, + "requires": { + "css": "1.0.8", + "promise": "2.0.0", + "uglify-js": "2.2.5" + }, + "dependencies": { + "is-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=", + "dev": true + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "dev": true, + "requires": { + "wordwrap": "0.0.3" + } + }, + "promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=", + "dev": true, + "requires": { + "is-promise": "1.0.1" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "uglify-js": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=", + "dev": true, + "requires": { + "optimist": "0.3.7", + "source-map": "0.1.43" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, "trim": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", @@ -6617,17 +10237,38 @@ "escape-string-regexp": "1.0.5" } }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true + }, "tunnel-agent": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" }, + "tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=", + "dev": true + }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, "type-detect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", @@ -6648,6 +10289,66 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "uc.micro": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", + "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "unbzip2-stream": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", + "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "dev": true, + "requires": { + "buffer": "3.6.0", + "through": "2.3.8" + } + }, "undefsafe": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.1.tgz", @@ -6668,6 +10369,12 @@ } } }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -6712,6 +10419,12 @@ "crypto-random-string": "1.0.0" } }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -6822,6 +10535,24 @@ } } }, + "uptown": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uptown/-/uptown-1.0.1.tgz", + "integrity": "sha512-Ft4xdRpyPoY9zDQ3gwG64AyF4jXgB4M64Pgtj4gYF5GKJh5bMSeEL6vQ/nlqlreHv6pF8l+5DuoKuZebvRhHtw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "uri-template": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uri-template/-/uri-template-1.0.1.tgz", + "integrity": "sha1-FKklo35Nk/diVDKqEWsF5Qyuga0=", + "dev": true, + "requires": { + "pct-encode": "1.0.2" + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -6844,6 +10575,12 @@ "ip-regex": "1.0.3" } }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, "use": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", @@ -6934,6 +10671,12 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -6958,6 +10701,12 @@ "spdx-expression-parse": "1.0.4" } }, + "validator": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", + "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==", + "dev": true + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -7034,6 +10783,12 @@ } } }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, "ware": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz", @@ -7059,6 +10814,91 @@ "string-width": "2.1.1" } }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "winston": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.2.0.tgz", + "integrity": "sha1-LIU92Hq1UqjoSF1yy7+aIobwKbc=", + "dev": true, + "requires": { + "async": "1.0.0", + "colors": "1.0.3", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "pkginfo": "0.3.1", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true + } + } + }, + "with": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", + "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=", + "dev": true, + "requires": { + "acorn": "1.2.2", + "acorn-globals": "1.0.9" + }, + "dependencies": { + "acorn": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", + "dev": true + } + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, "wrap-fn": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz", @@ -7072,6 +10912,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, "write-file-atomic": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", @@ -7083,6 +10932,22 @@ "signal-exit": "3.0.2" } }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "dev": true, + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=", + "dev": true + }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", @@ -7119,16 +10984,88 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=" }, + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, + "yaml-js": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/yaml-js/-/yaml-js-0.2.3.tgz", + "integrity": "sha512-6xUQtVKl1qcd0EXtTEzUDVJy9Ji1fYa47LtkDtYKlIjhibPE9knNPmoRyf6SGREFHlOAUyDe9OdYqRP4DuSi5Q==", + "dev": true + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "os-locale": "1.4.0", + "string-width": "1.0.2", + "window-size": "0.1.4", + "y18n": "3.2.1" + }, + "dependencies": { + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true + } + } + }, "yauzl": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", @@ -7137,6 +11074,24 @@ "buffer-crc32": "0.2.13", "fd-slicer": "1.0.1" } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "z-schema": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.19.1.tgz", + "integrity": "sha512-jPNzqmOu3+AGbb4krDODqo4QBzwUGDVzyfGyy1HtWaUnafltQotatSpxxWd6Mp0iSZOUwHU5sqKYi+U8HsHMkg==", + "dev": true, + "requires": { + "commander": "2.8.1", + "lodash.get": "4.4.2", + "lodash.isequal": "4.5.0", + "validator": "9.4.1" + } } } } diff --git a/api/package.json b/api/package.json index 665e6bc..6f844b1 100644 --- a/api/package.json +++ b/api/package.json @@ -8,8 +8,15 @@ "scripts": { "start": "DEBUG='cc:*' NODE_ENV=production node server.js", "dev": "DEBUG='cc:*' NODE_ENV=dev nodemon server.js", + "eslint": "$(npm bin)/eslint", + "lint": "eslint '**/*.js'", "test": "mocha --require ./test/config/spec_helper.js", - "e2e": "NODE_ENV=test node server.js" + "start-test": "DEBUG='cc:*' NODE_ENV=unitTest node server.js", + "start-api-test": "rm -rf ./apib/dredd/data/tmp-resource && cp -r ./apib/dredd/data/resource ./apib/dredd/data/tmp-resource && DEBUG='cc:*' NODE_ENV=dreddTest node server.js", + "api:compile-docs": "$(npm bin)/hercule apib/dev-doc.apib -o apib/documentation.apib", + "api:publish-docs": "$(npm bin)/aglio --theme-variables streak --theme-full-width -i ./apib/documentation.apib -o ../public/api-docs.html", + "api:test-docs": "npm run api:docs && $(npm bin)/dredd", + "api:docs": "npm run api:compile-docs && npm run api:publish-docs" }, "dependencies": { "async": "^2.5.0", @@ -34,9 +41,15 @@ "supports-color": "^5.1.0" }, "devDependencies": { + "aglio": "^2.3.0", "chai": "^3.5.0", "chai-http": "^3.0.0", + "dredd": "^5.1.5", + "eslint": "^4.18.2", + "eslint-config-google": "^0.9.1", + "hercule": "^4.1.1", "mocha": "^3.5.3", + "mongodb-memory-server": "^1.7.3", "nodemon": "^1.14.12" } } diff --git a/api/routes/account.js b/api/routes/account.js index 016a4a6..687ae7e 100644 --- a/api/routes/account.js +++ b/api/routes/account.js @@ -1,8 +1,7 @@ -"use strict"; +'use strict'; // modules const express = require('express'); -const logger = require('debug')('cc:awardings'); // HTTP status codes by name const codes = require('./http-codes'); @@ -12,7 +11,7 @@ const routerHandling = require('../middleware/router-handling'); // Mongoose Model using mongoDB const AppUserModel = require('../models/app-user'); -const account = express.Router(); +const account = new express.Router(); account.route('/') .get((req, res, next) => { @@ -24,7 +23,7 @@ account.route('/') res.locals.items = items; res.locals.processed = true; next(); - }) + }); }) .all( routerHandling.httpMethodNotAllowed @@ -35,7 +34,8 @@ account.route('/:id') .patch((req, res, next) => { if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. @@ -50,25 +50,22 @@ account.route('/:id') AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}).populate('squad').exec((err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("appUser not found"); + } else if (!item) { + err = new Error('appUser not found'); err.status = codes.notfound; - } - else { + } else { res.locals.items = item; } next(err); - }) + }); }) .delete((req, res, next) => { AppUserModel.findByIdAndRemove(req.params.id, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; } // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler diff --git a/api/routes/authenticate.js b/api/routes/authenticate.js index ef0c2a1..f43a338 100644 --- a/api/routes/authenticate.js +++ b/api/routes/authenticate.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // modules const express = require('express'); @@ -6,7 +6,6 @@ const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const Q = require('q'); const _ = require('lodash'); -const logger = require('debug')('cc:authenticate'); // HTTP status codes by name const codes = require('./http-codes'); @@ -17,7 +16,7 @@ const routerHandling = require('../middleware/router-handling'); const AppUserModel = require('../models/app-user'); -const authenticate = express.Router(); +const authenticate = new express.Router(); // routes ********************** authenticate.route('/') @@ -62,7 +61,7 @@ let authCheck = (username, password, res) => { permission: user.permission, squad: user.squad, token: jwt.sign({sub: user._id}, secret, {expiresIn: diff * 60}), - tokenExpireDate: new Date(Date.now().valueOf() + diff * 60000 - 1000) + tokenExpireDate: new Date(Date.now().valueOf() + diff * 60000 - 1000), }); } else { // authentication failed @@ -79,7 +78,7 @@ authenticate.route('/signup') .post((req, res, next) => { create(req.body) .then(() => { - res.sendStatus(200); + res.send(201, {message: 'User successfully created'}); }) .catch((err) => { res.status(400).send(err); @@ -101,7 +100,7 @@ let create = (userParam) => { if (user) { // username already exists - deferred.reject(new Error("Username already exists")); + deferred.reject(new Error('Username already exists')); } else { createUser(); } diff --git a/api/routes/awardings.js b/api/routes/awardings.js index 61b15e0..2402632 100644 --- a/api/routes/awardings.js +++ b/api/routes/awardings.js @@ -1,8 +1,7 @@ -"use strict"; +'use strict'; // modules const express = require('express'); -const logger = require('debug')('cc:awardings'); // HTTP status codes by name const codes = require('./http-codes'); @@ -17,16 +16,10 @@ const AwardingModel = require('../models/awarding'); // result set for proposer(appUser) population const resultSet = { - '__v': 0, - 'updatedAt': 0, - 'timestamp': 0, - 'password': 0, - 'permission': 0, - 'secret': 0, - 'activated': 0 + '__v': 0, 'updatedAt': 0, 'timestamp': 0, 'password': 0, 'permission': 0, 'secret': 0, 'activated': 0, }; -const awarding = express.Router(); +const awarding = new express.Router(); // routes ********************** @@ -39,47 +32,30 @@ awarding.route('/') if (req.query.inProgress) { filter.confirmed = 0; } - if (req.query.simple) { - AwardingModel.find(filter, {}, {sort: {date: 'desc'}}, (err, items) => { - if (err) { - err.status = codes.servererror; - return next(err); - // with return before (or after) the next(err) we prevent that the code continues here after next(err) - // has finished. this saves an extra else {..} - } - // if the collection is empty we do not send empty arrays back. - if (items && items.length > 0) { - res.locals.items = items; - } - res.locals.processed = true; - next(); - }); - } else { - AwardingModel.find(filter, {}, {sort: {date: 'desc'}}) - .populate('decorationId').populate('proposer', resultSet).populate('userId').exec((err, items) => { - if (err) { - err.status = codes.servererror; - return next(err); - // with return before (or after) the next(err) we prevent that the code continues here after next(err) - // has finished. this saves an extra else {..} - } - let results = []; - if (req.query.fractFilter) { - for (let item of items) { - if (item.decorationId.fraction === req.query.fractFilter) { - results.push(item) - } - } - res.locals.items = results; + AwardingModel.find(filter, {}, {sort: {date: 'desc'}}) + .populate('decorationId').populate('proposer', resultSet) + .exec((err, items) => { + if (err) { + err.status = codes.servererror; + return next(err); + // with return before (or after) the next(err) we prevent that the code continues here + // after next(err) has finished. this saves an extra else {..} + } + let results = []; + if (req.query.fractFilter) { + for (let item of items) { + if (item.decorationId.fraction === req.query.fractFilter) { + results.push(item); + } + } + res.locals.items = results; + } else { + res.locals.items = items; + } - } else { - res.locals.items = items; - } - - res.locals.processed = true; - next(); - }); - } + res.locals.processed = true; + next(); + }); }) .post(apiAuthenticationMiddleware, checkHl, (req, res, next) => { @@ -99,16 +75,15 @@ awarding.route('/') }); }) - .all( - routerHandling.httpMethodNotAllowed - ); + .all(routerHandling.httpMethodNotAllowed); awarding.route('/:id') .patch(apiAuthenticationMiddleware, checkHl, (req, res, next) => { if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. @@ -122,25 +97,22 @@ awarding.route('/:id') AwardingModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; - } - else { + } else { res.locals.items = item; } next(err); - }) + }); }) .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => { AwardingModel.findByIdAndRemove(req.params.id, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; } // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler @@ -150,9 +122,7 @@ awarding.route('/:id') }); }) - .all( - routerHandling.httpMethodNotAllowed - ); + .all(routerHandling.httpMethodNotAllowed); // this middleware function can be used, if you like or remove it // it looks for object(s) in res.locals.items and if they exist, they are send to the client as json diff --git a/api/routes/campaigns.js b/api/routes/campaigns.js index d91df19..0cb9c85 100644 --- a/api/routes/campaigns.js +++ b/api/routes/campaigns.js @@ -1,8 +1,7 @@ -"use strict"; +'use strict'; // modules const express = require('express'); -const logger = require('debug')('cc:campaigns'); // HTTP status codes by name const codes = require('./http-codes'); @@ -18,7 +17,7 @@ const CampaignModel = require('../models/campaign'); const WarModel = require('../models/war'); -const campaigns = express.Router(); +const campaigns = new express.Router(); // routes ********************** campaigns.route('/') @@ -48,9 +47,8 @@ campaigns.route('/:id') if (err) { err.status = codes.servererror; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -64,17 +62,16 @@ campaigns.route('/:id') if (err) { err.status = codes.wrongrequest; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } WarModel.find({campaign: req.params.id}).remove().exec(); - + // TODO: remove all the war logs from fs here!!! res.locals.processed = true; next(); - }) + }); }) .all( diff --git a/api/routes/command.js b/api/routes/command.js index 11cbef9..39ba698 100644 --- a/api/routes/command.js +++ b/api/routes/command.js @@ -1,26 +1,12 @@ -"use strict"; +'use strict'; // modules const express = require('express'); -const logger = require('debug')('cc:command'); - -// HTTP status codes by name -const codes = require('./http-codes'); const routerHandling = require('../middleware/router-handling'); -const createAllSignatures = require('../cron-job/cron').createAllSignatures; const createSignature = require('../tools/signature-tool'); -const command = express.Router(); - -command.route('/createSignature') - .post((req, res, next) => { - createAllSignatures(); - }) - - .all( - routerHandling.httpMethodNotAllowed - ); +const command = new express.Router(); command.route('/createSignature/:id') .post((req, res, next) => { diff --git a/api/routes/decorations.js b/api/routes/decorations.js index 53ad131..2302217 100644 --- a/api/routes/decorations.js +++ b/api/routes/decorations.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // modules const fs = require('fs'); @@ -6,7 +6,6 @@ const express = require('express'); const multer = require('multer'); const storage = multer.memoryStorage(); const upload = multer({storage: storage}); -const logger = require('debug')('cc:decorations'); // HTTP status codes by name const codes = require('./http-codes'); @@ -16,31 +15,31 @@ const checkHl = require('../middleware/permission-check').checkHl; const routerHandling = require('../middleware/router-handling'); const idValidator = require('../middleware/validators').idValidator; +const resourceLocation = require('../middleware/resource-location').resourceLocation().concat('/decoration/'); // Mongoose Model using mongoDB const DecorationModel = require('../models/decoration'); const AwardingsModel = require('../models/awarding'); -const decoration = express.Router(); - +const decoration = new express.Router(); // routes ********************** decoration.route('/') .get((req, res, next) => { const filter = {}; if (req.query.fractFilter) { - filter.fraction = req.query.fractFilter.toUpperCase() + filter.fraction = req.query.fractFilter.toUpperCase(); } if (req.query.q) { - filter.name = {$regex: req.query.q, $options: 'i'} + filter.name = {$regex: req.query.q, $options: 'i'}; } DecorationModel.find(filter, {}, { sort: { fraction: 'asc', isMedal: 'asc', sortingNumber: 'asc', - name: 'asc' - } + name: 'asc', + }, }, (err, items) => { if (err) { err.status = codes.servererror; @@ -67,12 +66,13 @@ decoration.route('/') } res.status(codes.created); res.locals.items = decoration; - fs.appendFile(__dirname + '/../resource/decoration/' + decoration.id + '.png', new Buffer(req.file.buffer), + fs.appendFile(resourceLocation + decoration._id + '.png', + new Buffer(req.file.buffer), (err) => { if (err) next(err); }); next(); - }) + }); }) .all( @@ -85,9 +85,8 @@ decoration.route('/:id') if (err) { err.status = codes.servererror; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -99,7 +98,8 @@ decoration.route('/:id') .patch(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => { if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. @@ -110,7 +110,7 @@ decoration.route('/:id') req.body.$inc = {__v: 1}; if (req.file) { - const file = __dirname + '/../resource/decoration/' + req.body._id + '.png'; + const file = resourceLocation + req.params.id + '.png'; fs.unlink(file, (err) => { if (err) next(err); fs.appendFile(file, new Buffer(req.file.buffer), (err) => { @@ -124,41 +124,36 @@ decoration.route('/:id') DecorationModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; - } - else { + } else { res.locals.items = item; } next(err); - }) + }); }) .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => { - DecorationModel.findByIdAndRemove(req.params.id, (err, item) => { + const id = req.params.id; + DecorationModel.findByIdAndRemove(id, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; } // deleted all awardings linked to this decoration - AwardingsModel.find({decorationId: req.params.id}).remove().exec(); + AwardingsModel.find({decorationId: id}).remove().exec(); // delete graphic - fs.unlink(__dirname + '/../resource/decoration/' + req.params.id + '.png', + fs.unlink(resourceLocation.concat(id).concat('.png'), (err) => { - if (err) next(err); + // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler + res.locals.processed = true; + next(err); }); - - // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler - // user.use(..) - res.locals.processed = true; - next(err); // this works because err is in normal case undefined and that is the same as no parameter }); }) diff --git a/api/routes/http-codes.js b/api/routes/http-codes.js index 8e12bee..37f2337 100644 --- a/api/routes/http-codes.js +++ b/api/routes/http-codes.js @@ -1,21 +1,21 @@ -/** - * mini-module providing the HTTP Status codes - * # - * @author Johannes Konert - * @module http-codes - */ -"use strict"; -module.exports = { - success: 200, - created: 201, - nocontent: 204, - wrongrequest: 400, - unauthorized: 401, - forbidden: 403, - notfound: 404, - wrongmethod: 405, - conflict: 409, - wrongdatatyperequest: 406, - wrongmediasend: 415, - servererror: 500 -}; +/** + * mini-module providing the HTTP Status codes + * # + * @author Johannes Konert + * @module http-codes + */ +'use strict'; +module.exports = { + success: 200, + created: 201, + nocontent: 204, + wrongrequest: 400, + unauthorized: 401, + forbidden: 403, + notfound: 404, + wrongmethod: 405, + conflict: 409, + wrongdatatyperequest: 406, + wrongmediasend: 415, + servererror: 500, +}; diff --git a/api/routes/logs.js b/api/routes/logs.js index aafc229..e277a41 100644 --- a/api/routes/logs.js +++ b/api/routes/logs.js @@ -1,12 +1,10 @@ -"use strict"; +'use strict'; // modules const express = require('express'); const async = require('async'); -const logger = require('debug')('cc:logs'); const routerHandling = require('../middleware/router-handling'); -const decimalToTimeString = require('../tools/util').decimalToTimeString; // Mongoose Model using mongoDB const LogBudgetModel = require('../models/logs/budget'); @@ -18,20 +16,20 @@ const LogTransportModel = require('../models/logs/transport'); const LogFlagModel = require('../models/logs/flag'); const LogPointsModel = require('../models/logs/points'); -const logsRouter = express.Router(); +const logsRouter = new express.Router(); -function processLogRequest(model, filter, res, next) { +const processLogRequest = (model, filter, res, next) => { model.find(filter, {}, {sort: {time: 1}}, (err, log) => { if (err) return next(err); if (!log || log.length === 0) { const err = new Error('No logs found'); err.status = require('./http-codes').notfound; - return next(err) + return next(err); } res.locals.items = log; next(); - }) -} + }); +}; // routes ********************** logsRouter.route('/:warId') @@ -55,16 +53,15 @@ logsRouter.route('/:warId') kill: killObjects.exec.bind(killObjects), vehicle: killObjects.exec.bind(vehicleObjects), transport: transportObjects.exec.bind(transportObjects), - flag: flagObjects.exec.bind(flagObjects) + flag: flagObjects.exec.bind(flagObjects), }; - async.parallel(resources, function (error, results) { + async.parallel(resources, (error, results) => { if (error) { - res.status(500).send(error); - return; + res.status(500); } res.locals.items = results; - next(); + next(error); }); }) .all( diff --git a/api/routes/overview.js b/api/routes/overview.js index e41e001..54eb919 100644 --- a/api/routes/overview.js +++ b/api/routes/overview.js @@ -1,12 +1,10 @@ -"use strict"; +'use strict'; // modules const async = require('async'); const express = require('express'); -const logger = require('debug')('cc:overview'); // HTTP status codes by name -const codes = require('./http-codes'); const routerHandling = require('../middleware/router-handling'); // Mongoose Model using mongoDB @@ -14,27 +12,23 @@ const UserModel = require('../models/user'); const SquadModel = require('../models/squad'); const RankModel = require('../models/rank'); -const overview = express.Router(); +const overview = new express.Router(); // routes ********************** overview.route('/') .get((req, res, next) => { - let countOpfor = 0; - let countBlufor = 0; - const armyOverview = { - BLUFOR: { - squads: [] - }, - OPFOR: { - squads: [] - } - }; + const fractions = ['BLUFOR', 'OPFOR']; + const fractionMemberCount = [0, 0]; + const armyOverview = [ + {squads: []}, + {squads: []}, + ]; SquadModel.find({}, {'sortingNumber': 0, 'updatedAt': 0, 'timestamp': 0, '__v': 0}, { sort: { sortingNumber: 'asc', - name: 'asc' - } + name: 'asc', + }, }, (err, squads) => { if (err) { return next(err); @@ -44,7 +38,7 @@ overview.route('/') 'squadId': 0, 'updatedAt': 0, 'timestamp': 0, - '__v': 0 + '__v': 0, }, {sort: {rankLvl: 'desc', name: 'asc'}}, (err, users) => { const squadMembers = []; async.eachSeries(users, (user, callback) => { @@ -59,7 +53,7 @@ overview.route('/') usr.rank = rank.name; } delete usr.rankLvl; - squadMembers.push(usr) + squadMembers.push(usr); callback(); }); @@ -73,28 +67,29 @@ overview.route('/') const s = squad.toObject(); s.members = squadMembers; s.memberCount = squadMembers.length; - if (s.fraction === 'BLUFOR') { - delete s.fraction; - armyOverview.BLUFOR.squads.push(s); - countBlufor += s.members.length; - } - if (s.fraction === 'OPFOR') { - delete s.fraction; - armyOverview.OPFOR.squads.push(s); - countOpfor += s.members.length; + + for (let i = 0; i < fractions.length; i++) { + if (s.fraction === fractions[i]) { + delete s.fraction; + armyOverview[i].squads.push(s); + fractionMemberCount[i] += s.members.length; + break; + } } } callback(); }); }); - }, (err) => { if (err) { return next(err); } - armyOverview.BLUFOR.memberCount = countBlufor; - armyOverview.OPFOR.memberCount = countOpfor; + + for (let i = 0; i < fractions.length; i++) { + armyOverview[i].memberCount = fractionMemberCount[i]; + } + res.locals.items = armyOverview; res.locals.processed = true; next(); diff --git a/api/routes/players.js b/api/routes/players.js index e6d6527..744bf25 100644 --- a/api/routes/players.js +++ b/api/routes/players.js @@ -1,8 +1,7 @@ -"use strict"; +'use strict'; // modules const express = require('express'); -const logger = require('debug')('cc:players'); // HTTP status codes by name const codes = require('./http-codes'); @@ -17,7 +16,7 @@ const WarModel = require('../models/war'); // Util const isSteamUUID = require('../tools/util').isSteamUUID; -const campaignPlayer = express.Router(); +const campaignPlayer = new express.Router(); // routes ********************** campaignPlayer.route('/ranking/:campaignId') @@ -27,12 +26,12 @@ campaignPlayer.route('/ranking/:campaignId') const warIds = wars.map((obj) => { return obj._id; }); - PlayerModel.find({warId: {"$in": warIds}}, (err, items) => { + PlayerModel.find({warId: {'$in': warIds}}, (err, items) => { if (err) return next(err); if (!items || items.length === 0) { const err = new Error('No players for given campaignId'); err.status = codes.notfound; - return next(err) + return next(err); } const rankingItems = []; @@ -40,9 +39,10 @@ campaignPlayer.route('/ranking/:campaignId') // check only first player to have valid steamUUID - then decide if tracked by name or by ID const usesUUID = isSteamUUID(items[0].steamUUID); - new Set(items.map(usesUUID ? x => x.steamUUID : x => x.name)) - .forEach(player => { - const playerInstances = items.filter(usesUUID ? p => p.steamUUID === player : p => p.name === player); + new Set(items.map(usesUUID ? (x) => x.steamUUID : (x) => x.name)) + .forEach((player) => { + const playerInstances = items.filter( + usesUUID ? (p) => p.steamUUID === player : (p) => p.name === player); const resItem = { name: usesUUID ? playerInstances[playerInstances.length - 1].name : player, kill: 0, @@ -51,7 +51,7 @@ campaignPlayer.route('/ranking/:campaignId') friendlyFire: 0, revive: 0, respawn: 0, - flagTouch: 0 + flagTouch: 0, }; for (let i = 0; i < playerInstances.length; i++) { resItem.kill += playerInstances[i].kill; @@ -66,15 +66,15 @@ campaignPlayer.route('/ranking/:campaignId') rankingItems.push(resItem); }); - function getSortedField(fieldName) { + const getSortedField = (fieldName) => { let num = 1; - rankingItems.sort((a, b) => b[fieldName] - a[fieldName]) + rankingItems.sort((a, b) => b[fieldName] - a[fieldName]); const res = JSON.parse(JSON.stringify(rankingItems)); for (const entity of res) { entity.num = num++; } return res; - } + }; res.locals.items = { kill: getSortedField('kill'), @@ -83,11 +83,11 @@ campaignPlayer.route('/ranking/:campaignId') vehicle: getSortedField('vehicle'), revive: getSortedField('revive'), respawn: getSortedField('respawn'), - flagTouch: getSortedField('flagTouch') + flagTouch: getSortedField('flagTouch'), }; next(); - }) - }) + }); + }); }) .all( @@ -108,7 +108,7 @@ campaignPlayer.route('/single/:campaignId/:playerId') const playerId = req.params.playerId; const filter = {}; filter[isSteamUUID(playerId) ? 'steamUUID' : 'name'] = playerId; - filter['warId'] = {"$in": warIds}; + filter['warId'] = {'$in': warIds}; PlayerModel.find(filter) .populate('warId') @@ -117,17 +117,17 @@ campaignPlayer.route('/single/:campaignId/:playerId') if (!items || items.length === 0) { const err = new Error('Unknown player id'); err.status = codes.notfound; - return next(err) + return next(err); } res.locals.items = { name: items[items.length - 1].name, campaign: campaign, - players: items + players: items, }; next(); - }) - }) - }) + }); + }); + }); }) .all( diff --git a/api/routes/ranks.js b/api/routes/ranks.js index d5abe3c..390bb70 100644 --- a/api/routes/ranks.js +++ b/api/routes/ranks.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // modules const fs = require('fs'); @@ -6,7 +6,6 @@ const express = require('express'); const multer = require('multer'); const storage = multer.memoryStorage(); const upload = multer({storage: storage}); -const logger = require('debug')('cc:ranks'); // HTTP status codes by name const codes = require('./http-codes'); @@ -16,21 +15,22 @@ const checkHl = require('../middleware/permission-check').checkHl; const routerHandling = require('../middleware/router-handling'); const idValidator = require('../middleware/validators').idValidator; +const resourceLocation = require('../middleware/resource-location').resourceLocation().concat('/rank/'); // Mongoose Model using mongoDB const RankModel = require('../models/rank'); -const ranks = express.Router(); +const ranks = new express.Router(); // routes ********************** ranks.route('/') .get((req, res, next) => { const filter = {}; if (req.query.fractFilter) { - filter.fraction = req.query.fractFilter.toUpperCase() + filter.fraction = req.query.fractFilter.toUpperCase(); } if (req.query.q) { - filter.name = {$regex: req.query.q, $options: 'i'} + filter.name = {$regex: req.query.q, $options: 'i'}; } RankModel.find(filter, {}, {sort: {fraction: 'asc', level: 'asc'}}, (err, items) => { @@ -59,11 +59,10 @@ ranks.route('/') } res.status(codes.created); res.locals.items = rank; - fs.appendFile(__dirname + '/../resource/rank/' + rank.id + '.png', new Buffer(req.file.buffer), + fs.appendFile(resourceLocation + rank._id + '.png', new Buffer(req.file.buffer), (err) => { - if (err) next(err); + next(err); }); - next(); }); }) @@ -78,9 +77,8 @@ ranks.route('/:id') if (err) { err.status = codes.servererror; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -90,10 +88,10 @@ ranks.route('/:id') }) .patch(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => { - if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. @@ -104,7 +102,7 @@ ranks.route('/:id') req.body.$inc = {__v: 1}; if (req.file) { - const file = __dirname + '/../resource/rank/' + req.body._id + '.png'; + const file = resourceLocation + req.params.id + '.png'; fs.unlink(file, (err) => { if (err) next(err); fs.appendFile(file, new Buffer(req.file.buffer), @@ -119,32 +117,29 @@ ranks.route('/:id') RankModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; - } - else { + } else { res.locals.items = item; } next(err); - }) + }); }) .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => { RankModel.findByIdAndRemove(req.params.id, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; } // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler // user.use(..) res.locals.processed = true; next(err); // this works because err is in normal case undefined and that is the same as no parameter - }) + }); }) .all( diff --git a/api/routes/request.js b/api/routes/request.js index 8a111cb..17916b6 100644 --- a/api/routes/request.js +++ b/api/routes/request.js @@ -1,8 +1,7 @@ -"use strict"; +'use strict'; // modules const express = require('express'); -const logger = require('debug')('cc:awardings'); // HTTP status codes by name const codes = require('./http-codes'); @@ -26,10 +25,10 @@ const resultSet = { 'password': 0, 'permission': 0, 'secret': 0, - 'activated': 0 + 'activated': 0, }; -const request = express.Router(); +const request = new express.Router(); // routes ********************** @@ -59,7 +58,7 @@ request.route('/award') request.route('/promotion') .get((req, res, next) => { - // TODO: add SQL authentication + // TODO: add SQL authentication? const squadFilter = req.query.squadId; const fractFilter = req.query.fractFilter; const progressFilter = req.query.inProgress; @@ -81,7 +80,7 @@ request.route('/promotion') } let promotionFilter = { - userId: {"$in": userIds} + userId: {'$in': userIds}, }; if (progressFilter) { promotionFilter.confirmed = 0; @@ -101,9 +100,8 @@ request.route('/promotion') } res.locals.processed = true; next(); - }) + }); }); - }) .post(apiAuthenticationMiddleware, checkSql, (req, res, next) => { @@ -132,7 +130,8 @@ request.route('/promotion/:id') .patch(apiAuthenticationMiddleware, checkHl, (req, res, next) => { if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. @@ -146,23 +145,20 @@ request.route('/promotion/:id') PromotionModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; - } - else { + } else { if (item.confirmed === 1) { let updateUser = { _id: item.userId, - rankLvl: item.newRankLvl + rankLvl: item.newRankLvl, }; UserModel.findByIdAndUpdate(updateUser._id, updateUser, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("user not found"); + } else if (!item) { + err = new Error('user not found'); err.status = codes.notfound; } }); @@ -170,7 +166,7 @@ request.route('/promotion/:id') res.locals.items = item; } next(err); - }) + }); }) .all( routerHandling.httpMethodNotAllowed diff --git a/api/routes/signatures.js b/api/routes/signatures.js index fc23c97..955f31f 100644 --- a/api/routes/signatures.js +++ b/api/routes/signatures.js @@ -1,9 +1,8 @@ -"use strict"; +'use strict'; // modules const fs = require('fs'); const express = require('express'); -const logger = require('debug')('cc:signatures'); // HTTP status codes by name const codes = require('./http-codes'); @@ -12,16 +11,18 @@ const routerHandling = require('../middleware/router-handling'); const UserModel = require('../models/user'); -const signatures = express.Router(); +const signatures = new express.Router(); // routes ********************** +/** + * @deprecated + */ signatures.route('/:id') // does not use idValidator since it works by username .get((req, res, next) => { // decode UTF8-escape sequences (special characters) const uri = decodeURIComponent(req.params.id); UserModel.findOne({username: uri}, (err, user) => { - const emptyFile = 'resource/signature/0.png'; if (user === null) { res.sendFile(emptyFile, {root: __dirname + '/../'}); @@ -34,15 +35,13 @@ signatures.route('/:id') } else if (err.code === 'ENOENT') { res.sendFile(emptyFile, {root: __dirname + '/../'}); } else { - err = new Error("Internal server error"); + err = new Error('Internal server error'); err.status = codes.servererror; return next(err); } }); - } - - }) + }); }) .all( diff --git a/api/routes/squads.js b/api/routes/squads.js index 9a77027..80582ab 100644 --- a/api/routes/squads.js +++ b/api/routes/squads.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // modules const fs = require('fs'); @@ -6,7 +6,6 @@ const express = require('express'); const multer = require('multer'); const storage = multer.memoryStorage(); const upload = multer({storage: storage}); -const logger = require('debug')('cc:squads'); // HTTP status codes by name const codes = require('./http-codes'); @@ -16,21 +15,22 @@ const checkHl = require('../middleware/permission-check').checkHl; const routerHandling = require('../middleware/router-handling'); const idValidator = require('../middleware/validators').idValidator; +const resourceLocation = require('../middleware/resource-location').resourceLocation().concat('/squad/'); // Mongoose Model using mongoDB const SquadModel = require('../models/squad'); -const squads = express.Router(); +const squads = new express.Router(); // routes ********************** squads.route('/') .get((req, res, next) => { const filter = {}; if (req.query.fractFilter) { - filter.fraction = req.query.fractFilter.toUpperCase() + filter.fraction = req.query.fractFilter.toUpperCase(); } if (req.query.q) { - filter.name = {$regex: req.query.q, $options: 'i'} + filter.name = {$regex: req.query.q, $options: 'i'}; } SquadModel.find(filter, {}, {sort: {fraction: 'asc', sortingNumber: 'asc'}}, (err, items) => { if (err) { @@ -59,11 +59,11 @@ squads.route('/') } res.status(codes.created); res.locals.items = squad; - fs.appendFile(__dirname + '/../resource/squad/' + squad.id + '.png', new Buffer(req.file.buffer), (err) => { - if (err) next(err); - }); - next(); - }) + fs.appendFile(resourceLocation.concat(squad._id).concat('.png'), + new Buffer(req.file.buffer), (err) => { + next(err); + }); + }); } else { const err = new Error('no image file provided'); err.status = codes.wrongmediasend; @@ -81,9 +81,8 @@ squads.route('/:id') if (err) { err.status = codes.servererror; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -93,10 +92,10 @@ squads.route('/:id') }) .patch(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => { - if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. @@ -107,7 +106,8 @@ squads.route('/:id') req.body.$inc = {__v: 1}; if (req.file) { - const file = __dirname + '/../resource/squad/' + req.body._id + '.png'; + const file = resourceLocation.concat(req.params.id) + .concat('.png'); fs.unlink(file, (err) => { if (err) next(err); fs.appendFile(file, new Buffer(req.file.buffer), (err) => { @@ -121,37 +121,32 @@ squads.route('/:id') SquadModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; - } - else { + } else { res.locals.items = item; } next(err); - }) + }); }) .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => { SquadModel.findByIdAndRemove(req.params.id, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; } // delete graphic - fs.unlink(__dirname + '/../resource/squad/' + req.params.id + '.png', (err) => { - if (err) next(err); + fs.unlink(resourceLocation.concat(req.params.id) + .concat('.png'), (err) => { + // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler + res.locals.processed = true; + next(err); }); - - // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler - // user.use(..) - res.locals.processed = true; - next(err); // this works because err is in normal case undefined and that is the same as no parameter }); }) diff --git a/api/routes/users.js b/api/routes/users.js index 2bde05b..b5db459 100644 --- a/api/routes/users.js +++ b/api/routes/users.js @@ -1,9 +1,8 @@ -"use strict"; +'use strict'; // modules const express = require('express'); const fs = require('fs'); -const logger = require('debug')('me2u5:users'); // HTTP status codes by name const codes = require('./http-codes'); @@ -15,13 +14,14 @@ const offsetlimitMiddleware = require('../middleware/limitoffset-middleware-mong const filterHandlerCreator = require('../middleware/filter-handler-mongo'); const routerHandling = require('../middleware/router-handling'); const idValidator = require('../middleware/validators').idValidator; +const resourceLocation = require('../middleware/resource-location').resourceLocation().concat('/signature/'); // Mongoose Model using mongoDB const UserModel = require('../models/user'); const SquadModel = require('../models/squad'); const AwardingModel = require('../models/awarding'); -const users = express.Router(); +const users = new express.Router(); users.get('/', filterHandlerCreator(UserModel.schema.paths)); users.get('/', offsetlimitMiddleware); @@ -32,7 +32,7 @@ users.route('/') const userQuery = () => { UserModel.find(dbFilter, res.locals.filter, res.locals.limitskip) .populate('squadId') - .collation({locale: "en", strength: 2}) // case insensitive order + .collation({locale: 'en', strength: 2}) // case insensitive order .sort('username').exec((err, users) => { if (err) return next(err); if (users.length === 0) { @@ -45,19 +45,19 @@ users.route('/') res.locals.items = users; res.locals.processed = true; return next(); - }) - }) + }); + }); }; if (!req.query.q) req.query.q = ''; - const dbFilter = {username: {"$regex": req.query.q, "$options": "i"}}; - if (req.query.squadId) dbFilter["squadId"] = {"$eq": req.query.squadId}; + const dbFilter = {username: {'$regex': req.query.q, '$options': 'i'}}; + if (req.query.squadId) dbFilter['squadId'] = {'$eq': req.query.squadId}; // squad / fraction filter setup if (req.query.fractFilter && req.query.fractFilter !== 'UNASSIGNED' && !req.query.squadId) { SquadModel.find({'fraction': req.query.fractFilter}, {_id: 1}, (err, squads) => { - dbFilter['squadId'] = {$in: squads.map(squad => squad.id)}; + dbFilter['squadId'] = {$in: squads.map((squad) => squad.id)}; userQuery(); - }) + }); } else { if (req.query.fractFilter === 'UNASSIGNED') { dbFilter['squadId'] = {$eq: null}; @@ -80,7 +80,7 @@ users.route('/') res.locals.items = extUser; res.locals.processed = true; return next(); - }) + }); }); }) @@ -93,9 +93,8 @@ users.route('/:id') if (err) { err.status = codes.servererror; return next(err); - } - else if (!user) { - err = new Error("item not found"); + } else if (!user) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -105,77 +104,36 @@ users.route('/:id') }); }) - .patch(apiAuthenticationMiddleware, checkHl, (req, res, next) => { - if (!req.body || (req.body._id && req.body._id !== req.params.id)) { - // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); - err.status = codes.notfound; - next(err); - return; // prevent node to process this function further after next() has finished. - } - - // optional task 3: increment version manually as we do not use .save(.) - req.body.updatedAt = new Date(); - req.body.$inc = {__v: 1}; - - // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to - // reset attributes that are missing. - UserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { - if (err) { - err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); - err.status = codes.notfound; - } - UserModel.populate(item, {path: 'squadId'}, (err, extUser) => { - if (err) { - err.status = codes.servererror; - return next(err); - } - if (!user) { - res.locals.items = {}; - res.locals.processed = true; - return next(); - } - res.locals.items = extUser; - res.locals.processed = true; - return next(); - }) - }) - }) - .put(apiAuthenticationMiddleware, checkHl, (req, res, next) => { // first check that the given element id is the same as the URL id if (!req.body || req.body._id !== req.params.id) { // the URL does not fit the given element - var err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id); + let err = + new Error('id of PUT resource and send JSON body are not equal ' + req.params.id + ' ' + req.body._id); err.status = codes.notfound; next(err); return; // prevent node to process this function further after next() has finished. } // main difference of PUT and PATCH is that PUT expects all data in request: checked by using the schema const user = new UserModel(req.body); - UserModel.findById(req.params.id, req.body, {new: true}, function (err, item) { - // with parameter {new: true} the TweetNModel will return the new and changed object from the DB and not the - // old one. + UserModel.findById(req.params.id, req.body, {new: true}, (err, item) => { + // with parameter {new: true} the TweetNModel will return the new and changed object + // from the DB and not the old one. if (err) { err.status = codes.wrongrequest; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); - } - // check that version is still accurate - else if (user.__v !== item.__v) { - err = new Error("version outdated. Meanwhile update on item happened. Please GET resource again") + } else if (user.__v !== item.__v) { + // checked that version is still accurate + err = new Error('version outdated. Meanwhile update on item happened. Please GET resource again'); err.status = codes.conflict; return next(err); } // now update all fields in DB item with body data in variable video - for (var field in UserModel.schema.paths) { + for (let field in UserModel.schema.paths) { if ((field !== '_id') && (field !== '__v')) { // this includes undefined. is important to reset attributes that are missing in req.body item.set(field, user[field]); @@ -185,7 +143,7 @@ users.route('/:id') // update updatedAt and increase version item.updatedAt = new Date(); item.increment(); // this sets __v++ - item.save(function (err) { + item.save((err) => { if (!err) { res.locals.items = item; } else { @@ -197,18 +155,17 @@ users.route('/:id') res.locals.items = extUser; res.locals.processed = true; return next(); - }) + }); }); - }) + }); }) .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => { UserModel.findByIdAndRemove(req.params.id, (err, item) => { if (err) { err.status = codes.wrongrequest; - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; } @@ -216,12 +173,12 @@ users.route('/:id') AwardingModel.find({userId: req.params.id}).remove().exec(); // check if signature exists and delete compressed and uncompressed file - const fileMinified = __dirname + '/../resource/signature/' + req.params.id + '.png'; + const fileMinified = resourceLocation + req.params.id + '.png'; if (fs.existsSync(fileMinified)) { fs.unlink(fileMinified, (err) => { }); } - const file = __dirname + '/../resource/signature/big/' + req.params.id + '.png'; + const file = resourceLocation + 'big/' + req.params.id + '.png'; if (fs.existsSync(file)) { fs.unlink(file, (err) => { }); diff --git a/api/routes/wars.js b/api/routes/wars.js index 406312f..15d3e44 100644 --- a/api/routes/wars.js +++ b/api/routes/wars.js @@ -1,13 +1,12 @@ -"use strict"; +'use strict'; // modules const fs = require('fs'); -const mkdirp = require("mkdirp"); +const mkdirp = require('mkdirp'); const express = require('express'); const multer = require('multer'); const storage = multer.memoryStorage(); const upload = multer({storage: storage}); -const logger = require('debug')('cc:wars'); // HTTP status codes by name const codes = require('./http-codes'); @@ -18,6 +17,7 @@ const checkMT = require('../middleware/permission-check').checkMT; const routerHandling = require('../middleware/router-handling'); const idValidator = require('../middleware/validators').idValidator; +const resourceLocation = require('../middleware/resource-location').resourceLocation().concat('/logs/'); // log paser tool const parseWarLog = require('../tools/log-parse-tool'); @@ -35,7 +35,7 @@ const LogFlagModel = require('../models/logs/flag'); const LogBudgetModel = require('../models/logs/budget'); const LogPointsModel = require('../models/logs/points'); -const wars = express.Router(); +const wars = new express.Router(); // routes ********************** wars.route('/') @@ -53,7 +53,7 @@ wars.route('/') return next(err); } if (wars) { - campaigns.forEach(campaign => { + campaigns.forEach((campaign) => { let entry = {_id: campaign._id, title: campaign.title, wars: []}; wars.forEach((war) => { if (String(campaign._id) === String(war.campaign)) { @@ -70,7 +70,7 @@ wars.route('/') ) ; } - }) + }); }) .post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => { @@ -82,59 +82,57 @@ wars.route('/') if (err) { return next(err); } - const lineArray = file.toString().split("\n"); + const lineArray = file.toString().split('\n'); const statsResult = parseWarLog(lineArray, warBody); statsResult.war.save((err, war) => { if (err) { return next(err); } - PlayerModel.create(statsResult.players, function (err) { + PlayerModel.create(statsResult.players, (err) => { if (err) { return next(err); } - LogKillModel.create(statsResult.kills, function () { - LogVehicleKillModel.create(statsResult.vehicles, function () { - - LogRespawnModel.create(statsResult.respawn, function () { - LogReviveModel.create(statsResult.revive, function () { - LogFlagModel.create(statsResult.flag, function () { - LogBudgetModel.create(statsResult.budget, function () { - LogTransportModel.create(statsResult.transport, function () { - LogPointsModel.create(statsResult.points, function () { - const folderName = __dirname + '/../resource/logs/' + war._id; - mkdirp(folderName, function (err) { + LogKillModel.create(statsResult.kills, () => { + LogVehicleKillModel.create(statsResult.vehicles, () => { + LogRespawnModel.create(statsResult.respawn, () => { + LogReviveModel.create(statsResult.revive, () => { + LogFlagModel.create(statsResult.flag, () => { + LogBudgetModel.create(statsResult.budget, () => { + LogTransportModel.create(statsResult.transport, () => { + LogPointsModel.create(statsResult.points, () => { + const folderName = resourceLocation.concat(war._id); + mkdirp(folderName, (err) => { if (err) return next(err); // save clean log file const cleanFile = fs.createWriteStream(folderName + '/clean.log'); - statsResult.clean.forEach(cleanLine => { - cleanFile.write(cleanLine + '\n\n') + statsResult.clean.forEach((cleanLine) => { + cleanFile.write(cleanLine + '\n\n'); }); cleanFile.end(); // save raw log file const rawFile = fs.createWriteStream(folderName + '/war.log'); - lineArray.forEach(rawLine => { - rawFile.write(rawLine + '\n') + lineArray.forEach((rawLine) => { + rawFile.write(rawLine + '\n'); }); rawFile.end(); res.status(codes.created); res.locals.items = war; next(); - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); + }); }); - } else { const err = new Error('no Logfile provided'); err.status = codes.wrongmediasend; @@ -152,9 +150,8 @@ wars.route('/:id') if (err) { err.status = codes.servererror; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -168,7 +165,6 @@ wars.route('/:id') res.locals.items = responseObj; return next(); }); - }); }) @@ -177,9 +173,8 @@ wars.route('/:id') if (err) { err.status = codes.wrongrequest; return next(err); - } - else if (!item) { - err = new Error("item not found"); + } else if (!item) { + err = new Error('item not found'); err.status = codes.notfound; return next(err); } @@ -195,7 +190,7 @@ wars.route('/:id') LogPointsModel.find({war: item._id}).remove().exec(); // check if logfiles exist and delete from fs - const warDir = __dirname + '/../resource/logs/' + req.params.id; + const warDir = resourceLocation + req.params.id; if (fs.existsSync(warDir)) { const cleanLog = warDir + '/clean.log'; @@ -215,8 +210,7 @@ wars.route('/:id') // user.use(..) res.locals.processed = true; next(); - - }) + }); }) .all( diff --git a/api/server.js b/api/server.js index df91c08..0b7490c 100644 --- a/api/server.js +++ b/api/server.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const express = require('express'); const path = require('path'); @@ -6,13 +6,15 @@ const favicon = require('serve-favicon'); const bodyParser = require('body-parser'); const requestLogger = require('morgan'); +// logger const debug = require('debug'); const error = debug('cc:server:err'); const logger = debug('cc:server'); logger.log = console.log.bind(console); -const cors = require('cors') +const cors = require('cors'); const mongoose = require('mongoose'); +const {exec} = require('child_process'); // own modules const config = require('./config/config'); @@ -24,7 +26,6 @@ const checkAdmin = require('./middleware/permission-check').checkAdmin; const signatureCronJob = require('./cron-job/cron').cronJobSignature; const backupCronJob = require('./cron-job/cron').cronJobBackup; - // router modules const authenticateRouter = require('./routes/authenticate'); const accountRouter = require('./routes/account'); @@ -54,7 +55,7 @@ const app = express(); // setup CORS-middleware const corsOptions = { methods: ['GET'], - optionsSuccessStatus: 200 + optionsSuccessStatus: 200, }; app.use(cors(corsOptions)); @@ -73,7 +74,7 @@ app.use(urls.signatures, signatureRouter); if (process.env.NODE_ENV === config.dev.env) { // development logging app.use(requestLogger('dev')); -} else if (process.env.NODE_ENV !== config.test.env) { +} else if (process.env.NODE_ENV !== config.test.dredd.env && process.env.NODE_ENV !== config.test.unit.env) { // production logging, apache style app.use(requestLogger(':date[clf] :method :url :response-time ms :status')); } @@ -94,34 +95,62 @@ app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter); app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter); // send index.html on all different paths -app.use(function (req, res) { - res.sendFile("public/index.html", {root: __dirname + '/..'}); +app.use((req, res) => { + res.sendFile('public/index.html', {root: __dirname + '/..'}); }); // register error handlers errorResponseWare(app); // Start the server -if (process.env.NODE_ENV !== config.test.env) { +if (process.env.NODE_ENV === config.test.unit.env || process.env.NODE_ENV === config.test.dredd.env) { + const MongodbMemoryServer = require('mongodb-memory-server').default; + const mongoServer = new MongodbMemoryServer(); + mongoose.Promise = Promise; + mongoServer.getConnectionString().then((mongoUri) => { + mongoose.connect(mongoUri); + + mongoose.connection.on('error', (e) => { + if (e.message.code === 'ETIMEDOUT') { + error(e); + mongoose.connect(mongoUri); + } + error(e); + }); + + if (process.env.NODE_ENV === config.test.dredd.env) { + const mongoPortAndDB = mongoUri.replace('mongodb://localhost:', '').split('/'); + exec( + __dirname + '/apib/dredd/populate-data.sh' + .concat(' -p ').concat(mongoPortAndDB[0]) + .concat(' -d ').concat(mongoPortAndDB[1]), (err, stdout, stderr) => { + if (err) { + error(err.message); + } else { + logger('\x1b[32m%s\x1b[0m', stderr); + } + }); + } + + mongoose.connection.once('open', () => { + logger(`MongoDB successfully connected to ${mongoUri}`); + app.listen(config.test.port); + logger('Listening on port ' + config.test.port); + }); + }); +} else { const mongoosePromise = mongoose.connect(config.database.uri + config.database.db); mongoosePromise.then((db) => { app.listen(config.port, (err) => { if (err !== undefined) { error('Error on startup, ', err); - } - else { + } else { logger('Listening on port ' + config.port); signatureCronJob.start(); backupCronJob.start(); } }); - }) -} else { - const mongoosePromise = mongoose.connect(config.database.uri + config.test.db); - mongoosePromise.then((db) => { - app.listen(config.test.port); - logger('Listening on port ' + config.test.port); - }) + }); } module.exports = app; diff --git a/api/test/awardings.spec.js b/api/test/awardings.spec.js index 7fa81c2..10c0206 100644 --- a/api/test/awardings.spec.js +++ b/api/test/awardings.spec.js @@ -1,19 +1,20 @@ -let mongoose = require("mongoose"); let AwardingModel = require('../models/awarding'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Awardings', () => { - beforeEach((done) => { //Before each test we empty the database + beforeEach((done) => { // Before each test we empty the database AwardingModel.remove({}, (err) => { done(); }); @@ -38,7 +39,6 @@ describe('Awardings', () => { * Test the /POST awardings */ describe('/POST awardings', () => { - it('it should not POST an awarding without auth-token provided', (done) => { chai.request(server) .post(urls.awards) @@ -57,7 +57,6 @@ describe('Awardings', () => { * Test the /PATCH awardings */ describe('/PATCH awardings', () => { - it('it should not PATCH an awarding without auth-token provided', (done) => { chai.request(server) .patch(urls.awards + '/someId') @@ -70,7 +69,6 @@ describe('Awardings', () => { done(); }); }); - }); @@ -78,7 +76,6 @@ describe('Awardings', () => { * Test the /DELETE awardings */ describe('/DELETE awardings', () => { - it('it should not accept DELETE method without id in url', (done) => { chai.request(server) .delete(urls.awards) @@ -104,7 +101,5 @@ describe('Awardings', () => { done(); }); }); - }); - }); diff --git a/api/test/command.spec.js b/api/test/command.spec.js index 18a46c9..2552fc8 100644 --- a/api/test/command.spec.js +++ b/api/test/command.spec.js @@ -1,19 +1,20 @@ -let mongoose = require("mongoose"); let AwardingModel = require('../models/awarding'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Command', () => { - beforeEach((done) => { //Before each test we empty the database + beforeEach((done) => { // Before each test we empty the database AwardingModel.remove({}, (err) => { done(); }); @@ -24,7 +25,7 @@ describe('Command', () => { describe('/POST command to create signature', () => { it('it should not succeed without auth-token provided', (done) => { chai.request(server) - .post(urls.cmdCreateSig + "/someId") + .post(urls.cmdCreateSig + '/someId') .send({}) .end((err, res) => { res.should.have.status(codes.forbidden); @@ -35,5 +36,4 @@ describe('Command', () => { }); }); }); - }); diff --git a/api/test/config/spec_helper.js b/api/test/config/spec_helper.js index 430e88b..4420648 100644 --- a/api/test/config/spec_helper.js +++ b/api/test/config/spec_helper.js @@ -1,3 +1,3 @@ const config = require('../../config/config'); -process.env.NODE_ENV = config.test.env; +process.env.NODE_ENV = config.test.unit.env; diff --git a/api/test/content-tool/user-db-item-creator.js b/api/test/content-tool/user-db-item-creator.js index 26bcf6a..6e5e184 100644 --- a/api/test/content-tool/user-db-item-creator.js +++ b/api/test/content-tool/user-db-item-creator.js @@ -20,10 +20,11 @@ mongoose.connection.on('connected', () => { }); const createString = (possible, length) => { - let text = ""; + let text = ''; - for (let i = 0; i < length; i++) + for (let i = 0; i < length; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); + } return text; }; @@ -34,21 +35,19 @@ for (let i = 0; i < quantity; i++) { UserModel.create({ username: createString('abcdefghijklmnopqrstuvwxyz0123456789', 10), squadId: squadId, - rankLvl: Math.floor(Math.random() * 22) - }, function (err, user) { + rankLvl: Math.floor(Math.random() * 22), + }, (err, user) => { if (err) { console.log(err); } else { console.log('User created: ' + user); - } - - }) + }); } // If the Node process ends, close the Mongoose connection process.on('SIGINT', () => { - mongoose.connection.close(function () { + mongoose.connection.close(() => { console.log('Mongoose default connection disconnected through app termination'); process.exit(0); }); diff --git a/api/test/decorations.spec.js b/api/test/decorations.spec.js index e191bd0..84e7cc9 100644 --- a/api/test/decorations.spec.js +++ b/api/test/decorations.spec.js @@ -1,19 +1,20 @@ -let mongoose = require("mongoose"); let DecorationModel = require('../models/decoration'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Decorations', () => { - beforeEach((done) => { //Before each test we empty the database + beforeEach((done) => { // Before each test we empty the database DecorationModel.remove({}, (err) => { done(); }); @@ -38,7 +39,6 @@ describe('Decorations', () => { * Test the /POST decorations */ describe('/POST decorations', () => { - it('it should not POST a decoration without auth-token provided', (done) => { chai.request(server) .post(urls.decorations) @@ -57,7 +57,6 @@ describe('Decorations', () => { * Test the /PATCH decoration */ describe('/PATCH decorations', () => { - it('it should not PATCH a decoration without auth-token provided', (done) => { chai.request(server) .patch(urls.decorations + '/someId') @@ -70,7 +69,6 @@ describe('Decorations', () => { done(); }); }); - }); @@ -103,7 +101,5 @@ describe('Decorations', () => { done(); }); }); - }); - }); diff --git a/api/test/ranks.spec.js b/api/test/ranks.spec.js index edd0111..2518561 100644 --- a/api/test/ranks.spec.js +++ b/api/test/ranks.spec.js @@ -1,19 +1,20 @@ -let mongoose = require("mongoose"); let RankModel = require('../models/rank'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Ranks', () => { - beforeEach((done) => { //Before each test we empty the database + beforeEach((done) => { // Before each test we empty the database RankModel.remove({}, (err) => { done(); }); @@ -38,7 +39,6 @@ describe('Ranks', () => { * Test the /POST ranks */ describe('/POST ranks', () => { - it('it should not POST a rank without auth-token provided', (done) => { chai.request(server) .post(urls.ranks) @@ -51,13 +51,12 @@ describe('Ranks', () => { done(); }); }); - }) + }); /* * Test the /PATCH rank */ describe('/PATCH ranks', () => { - it('it should not PATCH a rank without auth-token provided', (done) => { chai.request(server) .patch(urls.ranks + '/someId') @@ -70,7 +69,6 @@ describe('Ranks', () => { done(); }); }); - }); @@ -104,7 +102,5 @@ describe('Ranks', () => { done(); }); }); - }); - }); diff --git a/api/test/squads.spec.js b/api/test/squads.spec.js index ebc149a..cf776b8 100644 --- a/api/test/squads.spec.js +++ b/api/test/squads.spec.js @@ -1,19 +1,20 @@ -let mongoose = require("mongoose"); let SquadModel = require('../models/squad'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Squads', () => { - beforeEach((done) => { //Before each test we empty the database + beforeEach((done) => { // Before each test we empty the database SquadModel.remove({}, (err) => { done(); }); @@ -38,7 +39,6 @@ describe('Squads', () => { * Test the /POST squad */ describe('/POST squads', () => { - it('it should not POST a squad without auth-token provided', (done) => { chai.request(server) .post(urls.squads) @@ -57,7 +57,6 @@ describe('Squads', () => { * Test the /PATCH squad */ describe('/PATCH squads', () => { - it('it should not PATCH a squad without auth-token provided', (done) => { chai.request(server) .patch(urls.squads + '/someId') @@ -70,7 +69,6 @@ describe('Squads', () => { done(); }); }); - }); @@ -103,7 +101,5 @@ describe('Squads', () => { done(); }); }); - }); - }); diff --git a/api/test/users.spec.js b/api/test/users.spec.js index bfa5385..432b8a6 100644 --- a/api/test/users.spec.js +++ b/api/test/users.spec.js @@ -1,20 +1,20 @@ -let mongoose = require("mongoose"); let UserModel = require('../models/user'); -let AppUserModel = require('../models/app-user'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Users', () => { - beforeEach((done) => { //Before each test we empty the database + beforeEach((done) => { // Before each test we empty the database UserModel.remove({}, (err) => { done(); }); @@ -39,7 +39,6 @@ describe('Users', () => { * Test the /POST route */ describe('/POST users', () => { - // let token; // // before(function (done) { @@ -103,14 +102,13 @@ describe('Users', () => { }); /* - * Test the /PATCH route + * Test the /PUT route */ - describe('/PATCH users', () => { - - it('it should not PATCH a user without auth-token provided', (done) => { + describe('/PUT users', () => { + it('it should not PUT a user without auth-token provided', (done) => { chai.request(server) - .patch(urls.users + '/someId') - .send({}) + .put(urls.users + '/someId') + .send({_id: 'someId'}) .end((err, res) => { res.should.have.status(codes.forbidden); res.body.should.be.a('object'); @@ -119,7 +117,6 @@ describe('Users', () => { done(); }); }); - }); @@ -152,7 +149,5 @@ describe('Users', () => { done(); }); }); - }); - }); diff --git a/api/test/wars.spec.js b/api/test/wars.spec.js index 3b9a852..4a164e8 100644 --- a/api/test/wars.spec.js +++ b/api/test/wars.spec.js @@ -1,19 +1,18 @@ -let mongoose = require("mongoose"); -let AwardingModel = require('../models/awarding'); let urls = require('../config/api-url'); let codes = require('../routes/http-codes'); -//Require the dev-dependencies +// Require the dev-dependencies let chai = require('chai'); let chaiHttp = require('chai-http'); let server = require('../server'); -let should = chai.should(); + +// chai methods +require('chai').should(); chai.use(chaiHttp); -//Our parent block +// Our parent block describe('Wars', () => { - /* * Test the /GET awardings */ @@ -34,7 +33,6 @@ describe('Wars', () => { * Test the /POST awardings */ describe('/POST wars', () => { - it('it should not POST a war without auth-token provided', (done) => { chai.request(server) .post(urls.wars) @@ -53,7 +51,6 @@ describe('Wars', () => { * Test the /DELETE awardings */ describe('/DELETE wars', () => { - it('it should not accept DELETE method without id in url', (done) => { chai.request(server) .delete(urls.wars) @@ -79,7 +76,5 @@ describe('Wars', () => { done(); }); }); - }); - }); diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 6dce64f..9cc1772 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -5,7 +5,6 @@ const playerArrayContains = require('./util').playerArrayContains; const WHITESPACE = ' '; const parseWarLog = (lineArray, war) => { - const NAME_TOO_LONG_ERROR = 'Error: ENAMETOOLONG: name too long, open \''; const stats = { @@ -19,7 +18,7 @@ const parseWarLog = (lineArray, war) => { revive: [], flag: [], transport: [], - players: [] + players: [], }; const vehicleBlacklist = [ @@ -29,7 +28,7 @@ const parseWarLog = (lineArray, war) => { 'Qilin (Unbewaffnet)', 'Qilin (Bewaffnet)', 'Ifrit', 'Tempest-Transporter', 'Tempest-Transporter (abgedeckt)', 'Tempest SanitÀtsfahrzeug', 'Remote Designator [CSAT]', 'UBF Saif', - 'Quad Bike', 'HuntIR' + 'Quad Bike', 'HuntIR', ]; const addPlayerIfNotExists = (inputPlayer, steamUUID) => { @@ -41,7 +40,7 @@ const parseWarLog = (lineArray, war) => { } }; - lineArray.some(line => { + lineArray.some((line) => { /** * sanitize nameTooLongError coming up in first line */ @@ -49,10 +48,10 @@ const parseWarLog = (lineArray, war) => { line = line.substring(line.indexOf(NAME_TOO_LONG_ERROR) + NAME_TOO_LONG_ERROR.length); } - /** - * KILLS & VEHICLE KILLS - */ if (line.includes('(Abschuss)')) { + /** + * KILLS & VEHICLE KILLS + */ stats.clean.push(line); const shooterString = line.substring(line.lastIndexOf(' von: ') + 6, line.lastIndexOf('."')); @@ -67,8 +66,8 @@ const parseWarLog = (lineArray, war) => { time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]), shooter: shooter ? shooter.name : null, target: target ? target.name : null, - fraction: shooter ? shooter.fraction : 'NONE' - }) + fraction: shooter ? shooter.fraction : 'NONE', + }); } } else { const targetString = line.substring(line.lastIndexOf(' --- ') + 5, line.lastIndexOf(' von:')); @@ -79,15 +78,13 @@ const parseWarLog = (lineArray, war) => { shooter: shooter ? shooter.name : null, target: target ? target.name : null, friendlyFire: shooter ? target.fraction === shooter.fraction : false, - fraction: shooter ? shooter.fraction : 'NONE' + fraction: shooter ? shooter.fraction : 'NONE', }); } - } - - /** - * BUDGET - */ - else if (line.includes('(Budget)')) { + } else if (line.includes('(Budget)')) { + /** + * BUDGET + */ stats.clean.push(line); const budg = line.split(WHITESPACE); if (line.includes('Startbudget')) { @@ -95,9 +92,8 @@ const parseWarLog = (lineArray, war) => { stats.war['budgetOpfor'] = transformMoneyString(budg[12].slice(0, -1)); // this date needs to be assigned in first place !important - const dateString = budg[0].slice(0, -1).split('/').map(s => parseInt(s)); + const dateString = budg[0].slice(0, -1).split('/').map((s) => parseInt(s)); stats.war.date = new Date(dateString[0], dateString[1] - 1, dateString[2]); - } else if (line.includes('Endbudget')) { stats.war['endBudgetBlufor'] = transformMoneyString(budg[9].substr(1)); stats.war['endBudgetOpfor'] = transformMoneyString(budg[12].slice(0, -1)); @@ -105,12 +101,10 @@ const parseWarLog = (lineArray, war) => { } else { stats.budget.push(getBudgetEntry(budg, war._id, war.date)); } - } - - /** - * FLAG - */ - else if (line.includes('(Fahne)') && !line.includes('Dominator')) { + } else if (line.includes('(Fahne)') && !line.includes('Dominator')) { + /** + * FLAG + */ stats.clean.push(line); const playerName = line.substring(line.lastIndexOf('rt von ') + 7).slice(0, -2); const flagFraction = line.includes('NATO Flagge') ? 'BLUFOR' : 'OPFOR'; @@ -121,14 +115,12 @@ const parseWarLog = (lineArray, war) => { time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]), player: playerName, flagFraction: flagFraction, - capture: capture + capture: capture, }); - } - - /** - * POINTS - */ - else if (line.includes('(Punkte)')) { + } else if (line.includes('(Punkte)')) { + /** + * POINTS + */ stats.clean.push(line); const pt = line.split(WHITESPACE); @@ -138,23 +130,19 @@ const parseWarLog = (lineArray, war) => { // EXIT LOOP return true; } else { - stats.points.push(getPointsEntry(pt, line, war._id, war.date)) + stats.points.push(getPointsEntry(pt, line, war._id, war.date)); } - } - - /** - * RESPAWN - */ - else if (line.includes('(Respawn)')) { + } else if (line.includes('(Respawn)')) { + /** + * RESPAWN + */ const resp = line.split(WHITESPACE); const playerName = line.substring(line.lastIndexOf('Spieler:') + 9, line.lastIndexOf('- Kosten') - 1); stats.respawn.push(getRespawnEntry(resp, playerName, war._id, war.date)); - } - - /** - * REVIVE - */ - else if (line.includes('(Revive)')) { + } else if (line.includes('(Revive)')) { + /** + * REVIVE + */ stats.clean.push(line); const stabilized = !!line.includes('stabilisiert."'); const medicName = line.substring(line.lastIndexOf('wurde von ') + 10, @@ -169,14 +157,12 @@ const parseWarLog = (lineArray, war) => { stabilized: stabilized, medic: medic.name, patient: patient.name, - fraction: medic.fraction + fraction: medic.fraction, }); - } - - /** - * TRANSPORT - */ - else if (line.includes('(Transport)')) { + } else if (line.includes('(Transport)')) { + /** + * TRANSPORT + */ stats.clean.push(line); const driverString = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(' eingeflogen')); const driver = getPlayerAndFractionFromString(driverString); @@ -190,35 +176,35 @@ const parseWarLog = (lineArray, war) => { driver: driver ? driver.name : null, passenger: passenger ? passenger.name : null, fraction: driver ? driver.fraction : 'NONE', - distance: distance + distance: distance, }); - } - - /** - * PLAYERS - */ - else if (line.includes('(Fraktionsuebersicht)')) { + } else if (line.includes('(Fraktionsuebersicht)')) { + /** + * PLAYERS + */ const playerString = line.substring(line.lastIndexOf('--- ') + 4, line.lastIndexOf(', PUID')); const playerUUID = line.substring(line.lastIndexOf('PUID ') + 5, line.lastIndexOf('"')); - addPlayerIfNotExists(playerString, playerUUID) + addPlayerIfNotExists(playerString, playerUUID); } }); for (let i = 0; i < stats.players.length; i++) { const playerName = stats.players[i].name; - stats.players[i]['respawn'] = stats.respawn.filter(res => res.player === playerName).length; - stats.players[i]['kill'] = stats.kills.filter(kill => kill.shooter === playerName && !kill.friendlyFire).length; - stats.players[i]['vehicle'] = stats.vehicles.filter(vehicle => vehicle.shooter === playerName && vehicleBlacklist.indexOf(vehicle.target) < 0).length; - stats.players[i]['friendlyFire'] = stats.kills.filter(kill => kill.shooter === playerName && kill.friendlyFire).length; - stats.players[i]['death'] = stats.kills.filter(kill => kill.target === playerName).length; - stats.players[i]['revive'] = stats.revive.filter(rev => rev.medic === playerName && !rev.stabilized).length; - stats.players[i]['flagTouch'] = stats.flag.filter(flag => flag.player === playerName).length; + stats.players[i]['respawn'] = stats.respawn.filter((res) => res.player === playerName).length; + stats.players[i]['kill'] = stats.kills.filter((kill) => kill.shooter === playerName && !kill.friendlyFire).length; + stats.players[i]['vehicle'] = stats.vehicles.filter( + (vehicle) => vehicle.shooter === playerName && vehicleBlacklist.indexOf(vehicle.target) < 0).length; + stats.players[i]['friendlyFire'] = stats.kills.filter( + (kill) => kill.shooter === playerName && kill.friendlyFire).length; + stats.players[i]['death'] = stats.kills.filter((kill) => kill.target === playerName).length; + stats.players[i]['revive'] = stats.revive.filter((rev) => rev.medic === playerName && !rev.stabilized).length; + stats.players[i]['flagTouch'] = stats.flag.filter((flag) => flag.player === playerName).length; stats.players[i]['sort'] = stats.players[i]['kill'] + stats.players[i]['revive'] + stats.players[i]['flagTouch'] - - stats.players[i]['friendlyFire'] - stats.players[i]['death'] - stats.players[i]['respawn'] + - stats.players[i]['friendlyFire'] - stats.players[i]['death'] - stats.players[i]['respawn']; } - stats.war.playersBlufor = stats.players.filter(player => player.fraction === 'BLUFOR').length; - stats.war.playersOpfor = stats.players.filter(player => player.fraction === 'OPFOR').length; + stats.war.playersBlufor = stats.players.filter((player) => player.fraction === 'BLUFOR').length; + stats.war.playersOpfor = stats.players.filter((player) => player.fraction === 'OPFOR').length; return stats; }; @@ -227,8 +213,8 @@ const getRespawnEntry = (respawn, playerName, warId, warDate) => { return { war: warId, time: getFullTimeDate(warDate, respawn[5]), - player: playerName - } + player: playerName, + }; }; const getPointsEntry = (pt, line, warId, warDate) => { @@ -237,8 +223,8 @@ const getPointsEntry = (pt, line, warId, warDate) => { time: getFullTimeDate(warDate, pt[5]), ptBlufor: parseInt(pt[10]), ptOpfor: parseInt(pt[13].slice(0, -3)), - fraction: line.includes('Kein Dominator') ? 'NONE' : line.includes('NATO +1') ? 'BLUFOR' : 'OPFOR' - } + fraction: line.includes('Kein Dominator') ? 'NONE' : line.includes('NATO +1') ? 'BLUFOR' : 'OPFOR', + }; }; const getBudgetEntry = (budg, warId, warDate) => { @@ -247,13 +233,16 @@ const getBudgetEntry = (budg, warId, warDate) => { time: getFullTimeDate(warDate, budg[5]), fraction: budg[7] === 'NATO' ? 'BLUFOR' : 'OPFOR', oldBudget: transformMoneyString(budg[9]), - newBudget: transformMoneyString(budg[12]) - } + newBudget: transformMoneyString(budg[12]), + }; }; const getPlayerAndFractionFromString = (nameAndFractionString) => { const nameArray = nameAndFractionString.split(WHITESPACE); - const fraction = nameArray[nameArray.length - 1] !== '(ENEMY)' ? nameArray[nameArray.length - 1] === '(WEST)' ? 'BLUFOR' : 'OPFOR' : undefined; + const fraction = nameArray[nameArray.length - 1] !== '(ENEMY)' ? + nameArray[nameArray.length - 1] === '(WEST)' ? + 'BLUFOR' : 'OPFOR' : + undefined; const name = nameAndFractionString.substring(0, nameAndFractionString.indexOf(nameArray[nameArray.length - 1]) - 1); // do not return player for 'Selbstverschulden' or 'Error: No unit' if (name && name !== 'Error: No unit') { diff --git a/api/tools/signature-tool.js b/api/tools/signature-tool.js index f6d6ce4..8fe9b7e 100644 --- a/api/tools/signature-tool.js +++ b/api/tools/signature-tool.js @@ -1,10 +1,10 @@ -"use strict"; +'use strict'; // modules used for graphic manipulation const jimp = require('jimp'); const imagemin = require('imagemin'); const imageminpngquant = require('imagemin-pngquant'); -const SHA1 = require('node-sha1'); +const sha1 = require('node-sha1'); const async = require('async'); // Mongoose Model using mongoDB @@ -17,11 +17,10 @@ const codes = require('../routes/http-codes'); // standard input/output file extension const fileExt = '.png'; -const resourceDir = __dirname + '/../resource/'; +const resourceDir = require('../middleware/resource-location').resourceLocation().concat('/'); let createSignature = (userId, res, next) => { - let loadedImage; let user; @@ -46,7 +45,7 @@ let createSignature = (userId, res, next) => { if (!platePath) { throw new Error('Fraction not defined for user with id ' + userId); } - return jimp.read(platePath) + return jimp.read(platePath); }) .then((image) => { loadedImage = image; @@ -54,7 +53,7 @@ let createSignature = (userId, res, next) => { return jimp.loadFont(__dirname + '/font/DEVAJU_SANS_19.fnt'); }) .then((font) => { - loadedImage.print(font, 128, 8, user.username) + loadedImage.print(font, 128, 8, user.username); }) .then(() => { return jimp.loadFont(__dirname + '/font/DEJAVU_SANS_13.fnt'); @@ -64,11 +63,14 @@ let createSignature = (userId, res, next) => { return font; }) .then((font) => { - let rankH, rankW, rankX, rankY; + let rankH; + let rankW; + let rankX; + let rankY; RankModel.findOne({'level': user.rankLvl, 'fraction': user.squadId.fraction}, (err, result) => { if (err) { - return next(err) + return next(err); } if (result) { @@ -89,21 +91,21 @@ let createSignature = (userId, res, next) => { rankImage.resize(rankW, rankH); loadedImage .print(font, 128, 55, result.name) - .composite(rankImage, rankX, rankY) + .composite(rankImage, rankX, rankY); }) .then(() => { addDecorationsAndSave(userId, loadedImage, res, next); - }) + }); } else { // user has not any assignable rank in his fraction at this point, // e.g. assigned rank has been deleted or switched fraction so rankLvl is not defined addDecorationsAndSave(userId, loadedImage, res, next); } - }) + }); }) .catch((err) => { next(err); - }) + }); }; @@ -111,10 +113,10 @@ let createSignature = (userId, res, next) => { * query decorations according to user id and * add all graphics into given image * - * @param userId - * @param loadedImage - background image - * @param res - * @param next + * @param {number} userId + * @param {Object} loadedImage - background image + * @param {function} res + * @param {function} next */ let addDecorationsAndSave = (userId, loadedImage, res, next) => { const medalW = 21; @@ -128,15 +130,14 @@ let addDecorationsAndSave = (userId, loadedImage, res, next) => { AwardingModel.find({ 'userId': userId, - 'confirmed': 1 + 'confirmed': 1, }, ['decorationId', 'date']).populate('decorationId', ['isMedal', 'fraction']) .exec((err, awardings) => { if (err) { return next(err); } if (awardings.length > 0) { - - //TODO: simplify this sorting hell + // TODO: simplify this sorting hell awardings.sort((a1, a2) => { if (!a1.decorationId.isMedal && !a2.decorationId.isMedal) { if (a1.decorationId.fraction === a2.decorationId.fraction) { @@ -181,29 +182,30 @@ let addDecorationsAndSave = (userId, loadedImage, res, next) => { // use synchronized call to keep correct order of decorations async.eachSeries(awardings, (award, callback) => { - jimp.read(resourceDir + 'decoration/' + award.decorationId._id + fileExt).then((decorationImage) => { - if (award.decorationId.isMedal) { - decorationImage.resize(medalW, medalH); - loadedImage.composite(decorationImage, medalPx, medalPy); - if (medalPy === 5) { - medalPx = medalPx - 1 - medalW; - } else { - medalPx = medalPx + 1 + medalW; - } - if (medalPx <= 300) { - medalPy = medalPy + 3 + medalH; - } - } else { - decorationImage.resize(ribbonW, ribbonH); - loadedImage.composite(decorationImage, ribbonPx, ribbonPy); - ribbonPx = ribbonPx - 2 - ribbonW; - if (ribbonPx <= 154) { - ribbonPy = ribbonPy - 3 - ribbonH; - ribbonPx = 598; - } - } - callback(); - }) + jimp.read(resourceDir + 'decoration/' + award.decorationId._id + fileExt) + .then((decorationImage) => { + if (award.decorationId.isMedal) { + decorationImage.resize(medalW, medalH); + loadedImage.composite(decorationImage, medalPx, medalPy); + if (medalPy === 5) { + medalPx = medalPx - 1 - medalW; + } else { + medalPx = medalPx + 1 + medalW; + } + if (medalPx <= 300) { + medalPy = medalPy + 3 + medalH; + } + } else { + decorationImage.resize(ribbonW, ribbonH); + loadedImage.composite(decorationImage, ribbonPx, ribbonPy); + ribbonPx = ribbonPx - 2 - ribbonW; + if (ribbonPx <= 154) { + ribbonPy = ribbonPy - 3 - ribbonH; + ribbonPx = 598; + } + } + callback(); + }); }, (err) => { if (err) { throw err; @@ -214,18 +216,17 @@ let addDecorationsAndSave = (userId, loadedImage, res, next) => { compareImagesAndSave(loadedImage, userId, res, next); } } - ) + ); }; let compareImagesAndSave = (generatedImage, userId, res, next) => { - return jimp.read(resourceDir + 'signature/big/' + userId + fileExt) .then((oldImage) => { // compare hashes of image map to recognize difference - const sig1 = SHA1(generatedImage.bitmap.data); - const sig2 = SHA1(oldImage.bitmap.data); + const sig1 = sha1(generatedImage.bitmap.data); + const sig2 = sha1(oldImage.bitmap.data); if (sig1 !== sig2) { - saveJimpImageAndCompress(generatedImage, userId, res, next) + saveJimpImageAndCompress(generatedImage, userId, res, next); } else { res.locals.items = {status: 'nothing to do'}; next(); @@ -233,33 +234,31 @@ let compareImagesAndSave = (generatedImage, userId, res, next) => { }) .catch((err) => { saveJimpImageAndCompress(generatedImage, userId, res, next); - }) - + }); }; /** - * * Write Jimp image to file system * Gets minified after 3 seconds timeout * - * @param image - Jimp image - * @param userId - user id of signature owner - * @param res - express response object - * @param next - express next-function + * @param {Object} image - Jimp image + * @param {number} userId - user id of signature owner + * @param {function} res - express response object + * @param {function} next - express next-function */ let saveJimpImageAndCompress = (image, userId, res, next) => { image.write(resourceDir + 'signature/big/' + userId + fileExt); setTimeout(() => { imagemin([resourceDir + 'signature/big/' + userId + fileExt], resourceDir + 'signature/', { plugins: [ - imageminpngquant({quality: '65-80'}) - ] + imageminpngquant({quality: '65-80'}), + ], }).then((files) => { res.locals.items = {status: 'success'}; return next(); }).catch((error) => { - console.log(error) - }) + console.log(error); + }); }, 3000); }; diff --git a/api/tools/util.js b/api/tools/util.js index d631c27..155ac34 100644 --- a/api/tools/util.js +++ b/api/tools/util.js @@ -1,8 +1,8 @@ -"use strict"; +'use strict'; const isSteamUUID = (input) => { - const steamUIDPattern = new RegExp("[0-9]{17}"); - return steamUIDPattern.test(input) + const steamUIDPattern = new RegExp('[0-9]{17}'); + return steamUIDPattern.test(input); }; const sortCollectionBy = (collection, key) => { @@ -17,7 +17,9 @@ const sortCollectionBy = (collection, key) => { }; const playerArrayContains = (arr, item) => { - let i = 0, count = arr.length, matchFound = false; + let i = 0; + let count = arr.length; + let matchFound = false; for (; i < count; i++) { if (arr[i].name === item.name && arr[i].fraction === item.fraction) { @@ -39,9 +41,9 @@ const timeStringToDecimal = (timeString) => { const decimalToTimeString = (decimal) => { - const hours = parseInt(decimal.toString().split(".")[0]); + const hours = parseInt(decimal.toString().split('.')[0]); const minutesFloat = ((decimal % 1) * 3600) / 60; - const minutes = parseInt(minutesFloat.toString().split(".")[0]); + const minutes = parseInt(minutesFloat.toString().split('.')[0]); const seconds = Math.round((minutesFloat - parseInt(minutes)) * 60); return (hours < 10 ? '0' + hours : hours) + ':' + diff --git a/backup/backup.sh b/backup/backup.sh index afcb910..1f82242 100755 --- a/backup/backup.sh +++ b/backup/backup.sh @@ -4,7 +4,7 @@ cd $(dirname $0) # array of available collection names -col=(app_user awarding campaign decoration logBudget logFlag logKill logPoints logRespawn logRevive logTransport player promotion rank squad user war ) +col=(app_user awarding campaign decoration logBudget logFlag logKill logPoints logRespawn logRevive logTransport logVehicle player promotion rank squad user war ) if [ -z "$1" ] then diff --git a/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml b/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml index aa3b95e..c75b1af 100644 --- a/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml +++ b/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml @@ -1,4 +1,5 @@ - + + \ No newline at end of file + diff --git a/package-lock.json b/package-lock.json index 66b8361..62fefdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "opt-cc", - "version": "1.6.12", + "version": "1.7.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cc077e9..59608ba 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,22 @@ { "name": "opt-cc", - "version": "1.7.1", + "version": "1.7.2", "author": "Florian Hartwich ", "private": true, "scripts": { "start": "npm run deploy-static-prod && npm start --prefix ./api", "dev": "npm run deploy-static && npm run dev --prefix ./api", - "deploy-static": "cd ./static && $(npm bin)/ng build && ln -s ../api/resource/ ../public/resource", - "deploy-static:prod": "cd ./static && $(npm bin)/ng build --prod --aot && ln -s ../api/resource/ ../public/resource", + "deploy-static": "npm run build --prefix=static && npm run deploy-static:link-resource && npm run deploy-static:api-docs", + "deploy-static:prod": "npm run build:prod --prefix=static && npm run deploy-static:link-resource && npm run deploy-static:api-docs", + "deploy-static:link-resource": "ln -s ../api/resource/ public/resource", + "deploy-static:api-docs": "npm run api:docs --prefix=api", "postinstall": "npm install --prefix ./static && npm install --prefix ./api", - "mongodb": "mkdir -p mongodb-data && mongod --dbpath ./mongodb-data", + "lint": "npm run lint --prefix=api && npm run lint --prefix=static", "test": "npm test --prefix ./api", - "e2e": "npm run deploy-static && concurrently \"npm run e2e --prefix ./api\" \"wait-on -t 60000 http://localhost:3001/ && npm run e2e --prefix ./static\" --success first --kill-others", - "start-e2e": "npm run deploy-static && npm run e2e --prefix ./api", - "test-e2e": "npm run e2e --prefix ./static" + "e2e": "npm run deploy-static && concurrently \"npm run start-test --prefix ./api\" \"wait-on -t 60000 http://localhost:3001/ && npm run e2e --prefix ./static\" --success first --kill-others", + "start-e2e": "npm run deploy-static && npm run start-test --prefix ./api", + "test-e2e": "npm run e2e --prefix ./static", + "test-api": "npm run api:test-docs --prefix ./api" }, "dependencies": {}, "devDependencies": { diff --git a/static/package-lock.json b/static/package-lock.json index ea9bd46..04bda7c 100644 --- a/static/package-lock.json +++ b/static/package-lock.json @@ -1183,7 +1183,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -3003,6 +3002,11 @@ "schema-utils": "0.3.0" } }, + "file-saver": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.8.tgz", + "integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==" + }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -3188,795 +3192,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "optional": true, - "requires": { - "nan": "2.7.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.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": "4.2.1", - "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.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - } - } - }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", diff --git a/static/package.json b/static/package.json index 10057fe..3470c14 100644 --- a/static/package.json +++ b/static/package.json @@ -5,8 +5,11 @@ "private": true, "angular-cli": {}, "scripts": { - "ng": "ng", + "ng": "$(npm bin)/ng", + "build": "ng build", + "build:prod": "ng build --no-progress --prod --aot", "start": "ng serve", + "lint": "ng lint", "test": "ng test", "pree2e": "webdriver-manager update --standalone false --gecko false", "e2e": "ng e2e --serve=false" @@ -27,6 +30,7 @@ "@swimlane/ngx-datatable": "^11.0.4", "bootstrap": "^3.3.7", "d3": "^4.11.0", + "file-saver": "^1.3.8", "jquery": "^3.1.0", "jquery-ui": "^1.12.0", "jquery-ui-bundle": "^1.11.4", diff --git a/static/src/app/app.component.css b/static/src/app/app.component.css index 7bb12bc..cf1b8b8 100644 --- a/static/src/app/app.component.css +++ b/static/src/app/app.component.css @@ -38,6 +38,26 @@ li { color: #7e7d64; } +#scrollTopBtn { + position: fixed; /* Fixed/sticky position */ + bottom: 20px; + right: 30px; + z-index: 99; + border: none; + outline: none; + background-color: #101010; + color: white; + font-weight: bolder; + cursor: pointer; + padding: 7px 25px 10px 25px; + border-radius: 20px; + font-size: 22px; +} + +#scrollTopBtn:hover { + background-color: rgba(25, 142, 25, 1); +} + .unprocessed { -webkit-animation-name: color-blink; /* Safari 4.0 - 8.0 */ -webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */ diff --git a/static/src/app/app.component.html b/static/src/app/app.component.html index 6d4433a..045a2a6 100644 --- a/static/src/app/app.component.html +++ b/static/src/app/app.component.html @@ -86,7 +86,10 @@ + + +
diff --git a/static/src/app/app.component.ts b/static/src/app/app.component.ts index 4e520f0..efc736c 100644 --- a/static/src/app/app.component.ts +++ b/static/src/app/app.component.ts @@ -1,9 +1,10 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, HostListener, Inject, OnInit} from '@angular/core'; import {NavigationEnd, NavigationStart, Router} from '@angular/router'; import {LoginService} from './services/app-user-service/login-service'; import {PromotionService} from './services/army-management/promotion.service'; import {AwardingService} from './services/army-management/awarding.service'; import {RouteConfig} from './app.config'; +import {DOCUMENT} from '@angular/common'; declare function require(url: string); @@ -18,22 +19,38 @@ export class AppComponent implements OnInit { loading = false; - version = 'v' + require('./../../../package.json').version; + scrollTopVisible = false; + + scrollBtnVisibleVal = 100; + + version = 'v'.concat(require('./../../../package.json').version); constructor(public loginService: LoginService, private promotionService: PromotionService, private awardingService: AwardingService, - private router: Router) { + private router: Router, + @Inject(DOCUMENT) private document) { router.events.subscribe(event => { if (event instanceof NavigationStart) { this.loading = true; } if (event instanceof NavigationEnd) { this.loading = false; + // scroll to top on route from army overview to user detail and back + if (router.url.includes('overview')) { + this.scrollToTop(); + } } }); } + @HostListener('window:scroll', []) + onWindowScroll() { + this.scrollTopVisible = document.body.scrollTop > this.scrollBtnVisibleVal + || document.documentElement.scrollTop > this.scrollBtnVisibleVal; + } + + ngOnInit() { if (this.loginService.hasPermission(2)) { const fraction = this.loginService.getCurrentUser().squad.fraction; @@ -48,5 +65,10 @@ export class AppComponent implements OnInit { return false; } + scrollToTop() { + this.document.body.scrollTop = 0; // For Safari + this.document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera + } + } diff --git a/static/src/app/army/army.component.html b/static/src/app/army/army.component.html index 1baffa1..dce015e 100644 --- a/static/src/app/army/army.component.html +++ b/static/src/app/army/army.component.html @@ -3,7 +3,7 @@

{{fraction.BLUFOR}}

-
+
@@ -27,12 +27,12 @@
-
Armeemitglieder: {{army.BLUFOR.memberCount}}
+
Armeemitglieder: {{army[0].memberCount}}

{{fraction.OPFOR}}

-
+
@@ -56,7 +56,7 @@
-
Armeemitglieder: {{army.OPFOR.memberCount}}
+
Armeemitglieder: {{army[1].memberCount}}
diff --git a/static/src/app/army/army.component.ts b/static/src/app/army/army.component.ts index e22ef7d..cb51b89 100644 --- a/static/src/app/army/army.component.ts +++ b/static/src/app/army/army.component.ts @@ -15,7 +15,7 @@ import {CSSHelpers} from '../global.helpers'; }) export class ArmyComponent implements OnInit, OnDestroy { - army: Army = {BLUFOR: {squads: [], memberCount: 0}, OPFOR: {squads: [], memberCount: 0}}; + army: Army[] = [{}, {}]; readonly fraction = Fraction; diff --git a/static/src/app/models/model-interfaces.ts b/static/src/app/models/model-interfaces.ts index 1a52f36..20cb379 100644 --- a/static/src/app/models/model-interfaces.ts +++ b/static/src/app/models/model-interfaces.ts @@ -103,32 +103,19 @@ export interface Decoration { isMedal?: boolean; } -export interface Army { - BLUFOR: { - squads: { - _id, - name, - memberCount, - members: { - _id, - username, - rank - }[], - }[], - memberCount - }; - OPFOR: { - squads: { - _id, - name, - memberCount, - members: { - _id, - username, - rank - }[], - }[], - memberCount +export interface ArmySquad { + _id?: string; + name?: string; + memberCount?: number; + members?: { + _id, + username, + rank }; } +export interface Army { + squads?: ArmySquad[]; + memberCount?: number; +} + diff --git a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts index 416f751..9e206bf 100644 --- a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts @@ -31,7 +31,7 @@ export class CampaignPlayerDetailComponent implements OnInit { yAxisKill = 'Kills'; yAxisFriendlyFire = 'FriendlyFire'; - yAxisVehicleKill = 'Farzeug-Kills'; + yAxisVehicleKill = 'Fahrzeug-Kills'; yAxisDeath = 'Tode'; yAxisRespawn = 'Respawn'; yAxisRevive = 'Revive'; @@ -96,12 +96,13 @@ export class CampaignPlayerDetailComponent implements OnInit { this.reviveData = this.assignData(this.yAxisRevive, 'revive'); this.captureData = this.assignData(this.yAxisCapture, 'flagTouch'); - this.kdRatio = parseFloat((this.totalKills / (this.totalDeath === 0 ? 1 : this.totalDeath)).toFixed(2)); + const totalDeathDiv = this.totalDeath === 0 ? 1 : this.totalDeath; + this.kdRatio = parseFloat((this.totalKills / totalDeathDiv).toFixed(2)); if (this.kdRatio > 1) { this.maxKd = this.kdRatio * 1.7; } - this.respawnDeathRatio = parseFloat((this.totalRespawn / (this.totalDeath === 0 ? 1 : this.totalDeath)).toFixed(2)); + this.respawnDeathRatio = parseFloat((this.totalRespawn / totalDeathDiv).toFixed(2)); this.sumData = [ { diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html index 6d16c41..f7ddd5a 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html @@ -10,7 +10,7 @@ [columnMode]="'force'" [scrollbarV]="true" [selectionType]="'single'"> - + @@ -18,18 +18,18 @@ - + {{value === 'BLUFOR' ? fraction.BLUFOR : fraction.OPFOR}} - - - - - - - + + + + + + + diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts index e060b5e..fd4455c 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts @@ -2,6 +2,7 @@ import {Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleCha import {War} from '../../../models/model-interfaces'; import {Fraction} from '../../../utils/fraction.enum'; import {PlayerUtils} from '../../../utils/player-utils'; +import {saveAs} from 'file-saver/FileSaver'; @Component({ selector: 'cc-scoreboard', @@ -18,6 +19,8 @@ export class ScoreboardComponent implements OnChanges { @Output() playerTabSwitch = new EventEmitter(); + tableHead = ['Spieler', 'Fraktion', 'Kills', 'FriendlyFire', 'Fahrzeug', 'Revive', 'Eroberung', 'Tod', 'Respawn']; + isSteamUUID = PlayerUtils.isSteamUUID; cellHeight = 40; @@ -63,4 +66,31 @@ export class ScoreboardComponent implements OnChanges { } } + exportCSV() { + let csvOut = ''; + for (let i = 0; i < this.tableHead.length; i++) { + csvOut += this.tableHead[i]; + if (i !== this.tableHead.length - 1) { + csvOut += ','; + } + } + + for (let j = 0; j < this.war.players.length; j++) { + const player = this.war.players[j]; + csvOut += '\r\n'; + csvOut += '"' + player.name + '",'; + csvOut += player.fraction + ','; + csvOut += player.kill + ','; + csvOut += player.friendlyFire + ','; + csvOut += player.vehicle + ','; + csvOut += player.revive + ','; + csvOut += player.flagTouch + ','; + csvOut += player.death + ','; + csvOut += player.respawn; + } + + const blob = new Blob([csvOut], {type: 'text/plain'}); + saveAs(blob, this.war.title.toLowerCase().replace(' ', '_').concat('.csv')); + } + } diff --git a/static/src/app/statistic/war-detail/war-detail.component.css b/static/src/app/statistic/war-detail/war-detail.component.css index 9e60f76..c656ac1 100644 --- a/static/src/app/statistic/war-detail/war-detail.component.css +++ b/static/src/app/statistic/war-detail/war-detail.component.css @@ -10,6 +10,15 @@ margin-bottom: 10px; } +form.tab-control { + padding: 10px; +} + +span.tab-control { + margin: 4px 67px; + padding: 4px 16px; +} + .war-header { border-bottom: thin solid lightgrey; } @@ -34,6 +43,10 @@ color: #f5f5f5; } +.nav-tabs > li:last-child { + margin-left: 70px; +} + .nav-link { cursor: pointer !important; color: #FFF !important; diff --git a/static/src/app/statistic/war-detail/war-detail.component.html b/static/src/app/statistic/war-detail/war-detail.component.html index e5bcd5c..44773fc 100644 --- a/static/src/app/statistic/war-detail/war-detail.component.html +++ b/static/src/app/statistic/war-detail/war-detail.component.html @@ -24,29 +24,9 @@
- Logfile - anzeigen -
- - - -
-
+ + Logfile anzeigen +
@@ -60,12 +40,40 @@ +
  • +
    +
    + + + +
    + + Download CSV + +
    +
  • diff --git a/static/src/app/statistic/war-detail/war-detail.component.ts b/static/src/app/statistic/war-detail/war-detail.component.ts index 60cee6b..688a2a6 100644 --- a/static/src/app/statistic/war-detail/war-detail.component.ts +++ b/static/src/app/statistic/war-detail/war-detail.component.ts @@ -1,10 +1,11 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnInit, ViewChild} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {WarService} from '../../services/logs/war.service'; import {War} from '../../models/model-interfaces'; import {ChartUtils} from '../../utils/chart-utils'; import {Fraction} from '../../utils/fraction.enum'; import {LogsService} from '../../services/logs/logs.service'; +import {ScoreboardComponent} from './scoreboard/scoreboard.component'; @Component({ @@ -18,6 +19,8 @@ export class WarDetailComponent implements OnInit { war: War; + @ViewChild('scoreboard') scoreBoardComponent: ScoreboardComponent; + logData; singlePlayerView: number; @@ -81,5 +84,4 @@ export class WarDetailComponent implements OnInit { filterPlayersByFraction(fraction?: string) { this.fractionFilterSelected = fraction; } - }