Compare commits
2 Commits
master
...
feature/pl
Author | SHA1 | Date |
---|---|---|
HardiReady | e848ee1b66 | |
HardiReady | 45c16e2bdf |
|
@ -4,7 +4,6 @@
|
||||||
dist/
|
dist/
|
||||||
tmp/
|
tmp/
|
||||||
etc/
|
etc/
|
||||||
server/apib/documentation.apib
|
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
node_modules
|
node_modules
|
||||||
|
@ -45,11 +44,10 @@ Thumbs.db
|
||||||
.directory
|
.directory
|
||||||
|
|
||||||
# Internal Data
|
# Internal Data
|
||||||
/public/
|
public/
|
||||||
server/resource/
|
mongodb-data/
|
||||||
server/apib/dredd/data/tmp-resource
|
resource/
|
||||||
backup/
|
backup/
|
||||||
!backup.sh
|
|
||||||
|
|
||||||
# System
|
# System
|
||||||
.npm/
|
.npm/
|
||||||
|
@ -59,3 +57,4 @@ backup/
|
||||||
.cache/motd.legal-displayed
|
.cache/motd.legal-displayed
|
||||||
.profile
|
.profile
|
||||||
.ssh/
|
.ssh/
|
||||||
|
|
||||||
|
|
38
README.md
38
README.md
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
# Operation Pandora Trigger Commandcenter
|
# Operation Pandora Trigger Commandcenter
|
||||||
|
|
||||||
A [MEAN Stack](http://mean.io/) application created for [https://www.opt4.net](https://www.opt4.net) Arma3 Community
|
A [MEAN Application](http://mean.io/) created for [operation-pandora.com](https://www.operation-pandora.com) Arma3 Community
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
@ -14,25 +14,27 @@ All steps described here are working with a Debian based Linux system
|
||||||
|
|
||||||
Run the installation script located in the docs folder:
|
Run the installation script located in the docs folder:
|
||||||
|
|
||||||
```text
|
./docs/opt-cc-environment/3rd-party-install
|
||||||
./docs/opt-cc-environment/3rd-party-install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
It installs NPM, Node and MongoDB on latest versions.
|
It installs NPM, Node and MongoDB on latest versions.
|
||||||
In addition, it sets up the mongo deamon to start up automatically with the system.
|
In addition, it sets up the mongo deamon to start up automatically with the system.
|
||||||
|
|
||||||
#### Setup for Production
|
#### Setup for Production
|
||||||
|
|
||||||
**NOTE:** It his highly recommended **not** to run the following steps as _root_ user!
|
**NOTE:** It his highly recommended not to run the following steps as _root_ user!
|
||||||
|
|
||||||
|
Before triggering the environment execution run
|
||||||
|
|
||||||
|
npm install
|
||||||
|
|
||||||
|
inside the main folder, to process all needed npm package installations for the program execution.
|
||||||
|
|
||||||
For production setup run the script, described in _Setup for development_, adding the parameter `prod`
|
For production setup run the script, described in _Setup for development_, adding the parameter `prod`
|
||||||
|
|
||||||
```text
|
./docs/opt-cc-environment/3rd-party-install 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.
|
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.
|
Run the `sudo` command printed as last output to configure the `pm2` process for automatic start on the system, as the current user.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
@ -41,25 +43,19 @@ Run the `sudo` command printed as last output to configure the `pm2` process for
|
||||||
|
|
||||||
Before triggering the environment execution run
|
Before triggering the environment execution run
|
||||||
|
|
||||||
```text
|
npm install
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
inside the main folder, to process all needed npm package installations for the program execution.
|
inside the main folder, to process all needed npm package installations for the program execution.
|
||||||
|
|
||||||
To compile the Angular code and afterwards start the Express server with `nodemon` for development purpose run
|
To compile the Angular code and afterwards start the Express server with `nodemon` for development purpose run
|
||||||
|
|
||||||
```text
|
npm run dev
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Any changes on `server` code will trigger an automatic restart of the Express server.
|
Any changes on `api` code will trigger an automatic restart of the Express server.
|
||||||
|
|
||||||
Changes on `static` code can be submitted with
|
Changes on `static` code can be submitted with
|
||||||
|
|
||||||
```text
|
npm run deploy-static
|
||||||
npm run deploy-static
|
|
||||||
```
|
|
||||||
|
|
||||||
The page must be reloaded after this build step is finished, in order to make changes visible.
|
The page must be reloaded after this build step is finished, in order to make changes visible.
|
||||||
|
|
||||||
|
@ -69,10 +65,10 @@ _TODO_
|
||||||
## License Information
|
## License Information
|
||||||
|
|
||||||
|
|
||||||
### NodeJS Express Server (`/server`)
|
### Express API (`/api`)
|
||||||
published under [CC BY-SA 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt) \
|
published under [CC BY-SA 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt) \
|
||||||
Main concept for API Server, pagination and MongoDB usage by [Prof. Dr.-Ing. Johannes Konert](https://prof.beuth-hochschule.de/konert/) \
|
Main concept for API Server, pagination and MongoDB usage by [Prof. Dr.-Ing. Johannes Konert](https://prof.beuth-hochschule.de/konert/) \
|
||||||
All endpoints, signature image builder and Arma3 RPT-Log parsing by [Florian Hartwich](https://de.linkedin.com/in/florian-hartwich-b67b02125)
|
All endpoints, signature image builder and Arma3 RPT-Log parsing by [Florian Hartwich](https://de.linkedin.com/in/florian-hartwich-b67b02125)
|
||||||
|
|
||||||
### Angular 6 Frontend (`/static`)
|
### Angular 5 Frontend (`/static`)
|
||||||
published under [MIT License](https://opensource.org/licenses/MIT)
|
published under [MIT License](https://opensource.org/licenses/MIT)
|
||||||
|
|
|
@ -15,8 +15,7 @@ module.exports = {
|
||||||
request: rootRoute + '/request',
|
request: rootRoute + '/request',
|
||||||
signatures: '/signatures',
|
signatures: '/signatures',
|
||||||
signUp: rootRoute + '/authenticate/signup',
|
signUp: rootRoute + '/authenticate/signup',
|
||||||
slotting: rootRoute + '/slotting',
|
|
||||||
squads: rootRoute + '/squads',
|
squads: rootRoute + '/squads',
|
||||||
users: rootRoute + '/users',
|
users: rootRoute + '/users',
|
||||||
wars: rootRoute + '/wars',
|
wars: rootRoute + '/wars'
|
||||||
};
|
};
|
|
@ -0,0 +1,23 @@
|
||||||
|
module.exports = {
|
||||||
|
port: 8091,
|
||||||
|
|
||||||
|
database: {
|
||||||
|
uri: 'mongodb://localhost:27017/',
|
||||||
|
db: 'cc',
|
||||||
|
},
|
||||||
|
|
||||||
|
prod: {
|
||||||
|
env: 'production'
|
||||||
|
},
|
||||||
|
|
||||||
|
dev: {
|
||||||
|
env: 'dev'
|
||||||
|
},
|
||||||
|
|
||||||
|
test: {
|
||||||
|
port: 3001,
|
||||||
|
db: 'cc-test',
|
||||||
|
env: 'test'
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const cron = require('cron');
|
const cron = require('cron');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -19,8 +19,8 @@ const createAllSignatures = () => {
|
||||||
// mock response
|
// mock response
|
||||||
const res = {
|
const res = {
|
||||||
locals: {
|
locals: {
|
||||||
items: {},
|
items: {}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// re-create signature image for each active user
|
// re-create signature image for each active user
|
||||||
|
@ -29,21 +29,21 @@ const createAllSignatures = () => {
|
||||||
// mock next to execute callback
|
// mock next to execute callback
|
||||||
const next = (err) => {
|
const next = (err) => {
|
||||||
if (!err || (err && err.message.startsWith('Fraction not defined'))) {
|
if (!err || (err && err.message.startsWith('Fraction not defined'))) {
|
||||||
callback();
|
callback()
|
||||||
} else {
|
} else {
|
||||||
error('\x1b[41m%s\x1b[0m', new Date().toLocaleString()
|
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) {
|
if (err) {
|
||||||
error('\x1b[41m%s\x1b[0m', new Date().toLocaleString()
|
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()
|
logger('\x1b[35m%s\x1b[0m', new Date().toLocaleString()
|
||||||
+ ': finished successful - UPDATE SIGNATURES');
|
+ ': finished successful - UPDATE SIGNATURES');
|
||||||
});
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,10 +54,10 @@ const createBackup = () => {
|
||||||
if (err) {
|
if (err) {
|
||||||
error(err.message);
|
error(err.message);
|
||||||
}
|
}
|
||||||
logger('\x1b[32m%s\x1b[0m', stderr);
|
logger('\x1b[32m%s\x1b[0m',stderr);
|
||||||
logger('\x1b[35m%s\x1b[0m', new Date().toLocaleString()
|
logger('\x1b[35m%s\x1b[0m', new Date().toLocaleString()
|
||||||
+ ': cron job finished - CREATE BACKUP');
|
+ ': cron job finished - CREATE BACKUP');
|
||||||
});
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute daily @ 02:30 AM
|
// Execute daily @ 02:30 AM
|
||||||
|
@ -69,5 +69,5 @@ const cronJobBackup = cron.job('00 00 04 * * mon,thu,sat', createBackup);
|
||||||
module.exports = {
|
module.exports = {
|
||||||
cronJobSignature: cronJobSignature,
|
cronJobSignature: cronJobSignature,
|
||||||
cronJobBackup: cronJobBackup,
|
cronJobBackup: cronJobBackup,
|
||||||
createAllSignatures: createAllSignatures,
|
createAllSignatures: createAllSignatures
|
||||||
};
|
};
|
|
@ -1,15 +1,17 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const config = require('../config/config');
|
const config = require('../config/config');
|
||||||
const AppUser = require('../models/app-user');
|
const AppUser = require('../models/app-user');
|
||||||
|
|
||||||
const apiAuthentication = (req, res, next) => {
|
const apiAuthentication = (req, res, next) => {
|
||||||
|
|
||||||
// check header or url parameters or post parameters for token
|
// check header or url parameters or post parameters for token
|
||||||
const token = req.body.token || req.query.token || req.headers['x-access-token'];
|
const token = req.body.token || req.query.token || req.headers['x-access-token'];
|
||||||
|
|
||||||
// decode token
|
// decode token
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|
||||||
const secret = process.env.NODE_ENV === config.prod.env ? process.env.JWS_SECRET : 'dev-secret';
|
const secret = process.env.NODE_ENV === config.prod.env ? process.env.JWS_SECRET : 'dev-secret';
|
||||||
|
|
||||||
// verifies secret and checks exp
|
// verifies secret and checks exp
|
||||||
|
@ -23,7 +25,7 @@ const apiAuthentication = (req, res, next) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(403).send({
|
return res.status(403).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'token is not associated to any actual user',
|
message: 'token is not associated to any actual user'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
req.user = item;
|
req.user = item;
|
||||||
|
@ -31,13 +33,16 @@ const apiAuthentication = (req, res, next) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// if there is no token
|
// if there is no token
|
||||||
// return an error
|
// return an error
|
||||||
return res.status(403).send({
|
return res.status(403).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'No token provided.',
|
message: 'No token provided.'
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,33 +10,33 @@
|
||||||
* @module restapi/error-response
|
* @module restapi/error-response
|
||||||
* @type {Function}
|
* @type {Function}
|
||||||
*/
|
*/
|
||||||
'use strict';
|
"use strict";
|
||||||
const logger = require('debug')('me2:error-response');
|
const logger = require('debug')('me2:error-response');
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
// development error handler
|
// development error handler
|
||||||
// will print stacktrace as JSON response
|
// will print stacktrace as JSON response
|
||||||
if (app.get('env') === 'development') {
|
if (app.get('env') === 'development') {
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function (err, req, res, next) {
|
||||||
logger('Internal Error: ', err.stack);
|
logger('Internal Error: ', err.stack);
|
||||||
res.status(err.status || 500);
|
res.status(err.status || 500);
|
||||||
res.json({
|
res.json({
|
||||||
error: {
|
error: {
|
||||||
message: err.message,
|
message: err.message,
|
||||||
error: err.stack,
|
error: err.stack
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// production error handler
|
// production error handler
|
||||||
// no stacktraces leaked to user
|
// no stacktraces leaked to user
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function (err, req, res, next) {
|
||||||
res.status(err.status || 500);
|
res.status(err.status || 500);
|
||||||
res.json({
|
res.json({
|
||||||
error: {
|
error: {
|
||||||
message: err.message,
|
message: err.message,
|
||||||
error: {},
|
error: {}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -19,17 +19,16 @@
|
||||||
// 1.) require() function
|
// 1.) require() function
|
||||||
// 2.) module.exports
|
// 2.) module.exports
|
||||||
// 3.) exports (which is module.exports)
|
// 3.) exports (which is module.exports)
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const logger = require('debug')('middleware:filterware');
|
const logger = require('debug')('middleware:filterware');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* private helper function to filter Objects by given keys
|
* private helper function to filter Objects by given keys
|
||||||
*
|
* @param keys {Array} the keys from GET parameter filter
|
||||||
* @param {Array} keys - the keys from GET parameter filter
|
* @param schema [Object} containing the keys as attributes that are allowed
|
||||||
* @param {Object} schema - containing the keys as attributes that are allowed
|
* @returns {Object or Error} either the filtered items or an Error object
|
||||||
* @return {Object} either the filtered items or an Error object
|
|
||||||
*/
|
*/
|
||||||
const limitFilterToSchema = (keys, schema) => {
|
const limitFilterToSchema = (keys, schema) => {
|
||||||
if (!keys || !schema) { // empty arrays evaluate to false
|
if (!keys || !schema) { // empty arrays evaluate to false
|
||||||
|
@ -46,7 +45,7 @@ const limitFilterToSchema = (keys, schema) => {
|
||||||
error = new Error('given key for filter does not exist in ressource: ' + key);
|
error = new Error('given key for filter does not exist in ressource: ' + key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return error ? error : result;
|
return error ? error : result
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,7 +57,7 @@ const limitFilterToSchema = (keys, schema) => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const createFilterRouter = (schema, supressID) => {
|
const createFilterRouter = (schema, supressID) => {
|
||||||
const router = new express.Router();
|
const router = express.Router();
|
||||||
// the exported router with handler
|
// the exported router with handler
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
const filterString = req.query.filter;
|
const filterString = req.query.filter;
|
||||||
|
@ -91,12 +90,12 @@ const createFilterRouter = (schema, supressID) => {
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
logger(err);
|
logger(err);
|
||||||
next(err);
|
next(err)
|
||||||
} else {
|
} else {
|
||||||
if (res.locals.filter) {
|
if (res.locals.filter) {
|
||||||
logger('Successfully set filter to ' + res.locals.filter);
|
logger('Successfully set filter to ' + res.locals.filter);
|
||||||
}
|
}
|
||||||
next();
|
next()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return router;
|
return router;
|
|
@ -17,10 +17,9 @@
|
||||||
// 1.) require() function
|
// 1.) require() function
|
||||||
// 2.) module.exports
|
// 2.) module.exports
|
||||||
// 3.) exports (which is module.exports)
|
// 3.) exports (which is module.exports)
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const express = require('express');
|
const router = require('express').Router();
|
||||||
const router = new express.Router();
|
|
||||||
const logger = require('debug')('middleware:offsetlimit');
|
const logger = require('debug')('middleware:offsetlimit');
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,9 +36,10 @@ router.use((req, res, next) => {
|
||||||
if (!isNaN(offsetString)) {
|
if (!isNaN(offsetString)) {
|
||||||
offset = parseInt(offsetString);
|
offset = parseInt(offsetString);
|
||||||
if (offset < 0) {
|
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);
|
err = new Error('given offset is not a valid number ' + offsetString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,21 +47,22 @@ router.use((req, res, next) => {
|
||||||
if (!isNaN(limitString)) {
|
if (!isNaN(limitString)) {
|
||||||
limit = parseInt(limitString);
|
limit = parseInt(limitString);
|
||||||
if (limit < 1) {
|
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);
|
err = new Error('given limit is not a valid number ' + limitString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
logger('problem occurred with limit/offset values');
|
logger('problem occurred with limit/offset values');
|
||||||
err.status = 400;
|
err.status = 400;
|
||||||
next(err);
|
next(err)
|
||||||
} else {
|
} else {
|
||||||
res.locals.limitskip = {}; // mongoDB uses parameter object for skip/limit
|
res.locals.limitskip = {}; // mongoDB uses parameter object for skip/limit
|
||||||
if (limit) res.locals.limitskip.limit = limit;
|
if (limit) res.locals.limitskip.limit = limit;
|
||||||
if (offset) res.locals.limitskip.skip = offset;
|
if (offset) res.locals.limitskip.skip = offset;
|
||||||
next();
|
next()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
|
let check = (requiredPermission, actualPermission, res, next) => {
|
||||||
|
if (actualPermission >= requiredPermission) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
return res.status(403).send({
|
||||||
|
success: false,
|
||||||
|
message: 'permission denied'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
checkSql: (req, res, next) => { check(1, req.user.permission, res, next) },
|
||||||
|
checkHl: (req, res, next) => { check(2, req.user.permission, res, next) },
|
||||||
|
checkMT: (req, res, next) => { check(3, req.user.permission, res, next) },
|
||||||
|
checkAdmin: (req, res, next) => { check(4, req.user.permission, res, next) }
|
||||||
|
};
|
|
@ -15,10 +15,9 @@
|
||||||
// 1.) require() function
|
// 1.) require() function
|
||||||
// 2.) module.exports
|
// 2.) module.exports
|
||||||
// 3.) exports (which is module.exports)
|
// 3.) exports (which is module.exports)
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const express = require('express');
|
const router = require('express').Router();
|
||||||
const router = new express.Router();
|
|
||||||
|
|
||||||
// API-Version control. We use HTTP Header field Accept-Version instead of URL-part /v1/
|
// API-Version control. We use HTTP Header field Accept-Version instead of URL-part /v1/
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
|
@ -35,15 +34,16 @@ router.use((req, res, next) => {
|
||||||
// request type application/json check
|
// request type application/json check
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 &&
|
if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 &&
|
||||||
(!(/multipart\/form-data/.test(req.get('Content-Type'))) &&
|
(!( /multipart\/form-data/.test(req.get('Content-Type'))) &&
|
||||||
!(/application\/json/.test(req.get('Content-Type'))))) {
|
!( /application\/json/.test(req.get('Content-Type'))))) {
|
||||||
// send error code 415: unsupported media type
|
// send error code 415: unsupported media type
|
||||||
res.status(415).send('wrong Content-Type'); // user has SEND the wrong type
|
res.status(415).send('wrong Content-Type'); // user has SEND the wrong type
|
||||||
} else if (!req.accepts('json')) {
|
} else if (!req.accepts('json')) {
|
||||||
// send 406 that response will be application/json and request does not support it by now as answer
|
// send 406 that response will be application/json and request does not support it by now as answer
|
||||||
// user has REQUESTED the wrong type
|
// user has REQUESTED the wrong type
|
||||||
res.status(406).send('response of application/json only supported, please accept this');
|
res.status(406).send('response of application/json only supported, please accept this');
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
next(); // let this request pass through as it is OK
|
next(); // let this request pass through as it is OK
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -53,11 +53,11 @@ router.use((req, res, next) => {
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
let err = undefined;
|
let err = undefined;
|
||||||
if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 && parseInt(req.get('Content-Length')) === 0) {
|
if (['POST', 'PUT', 'PATCH'].indexOf(req.method) > -1 && parseInt(req.get('Content-Length')) === 0) {
|
||||||
err = new Error('content in body is missing');
|
err = new Error("content in body is missing");
|
||||||
err.status = 400;
|
err.status = 400;
|
||||||
next(err);
|
next(err);
|
||||||
} else if ('PUT' === req.method && !(req.body.id || req.body._id)) {
|
} else if ('PUT' === req.method && !(req.body.id || req.body._id)) {
|
||||||
err = new Error('content in body is missing field id');
|
err = new Error("content in body is missing field id");
|
||||||
err.status = 400;
|
err.status = 400;
|
||||||
next(err);
|
next(err);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
// HTTP status codes by name
|
// HTTP status codes by name
|
||||||
const codes = require('../routes/http-codes');
|
const codes = require('../routes/http-codes');
|
|
@ -0,0 +1,20 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('../routes/http-codes');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if id has valid UUID format
|
||||||
|
*/
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.idValidator = idValidator;
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,36 +7,36 @@ const AppUserSchema = new Schema({
|
||||||
username: {
|
username: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
unique: true,
|
unique: true
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
squad: {
|
squad: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'Squad',
|
ref: 'Squad',
|
||||||
default: null,
|
default: null
|
||||||
},
|
},
|
||||||
permission: {
|
permission: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 4,
|
max: 4,
|
||||||
default: 0,
|
default: 0
|
||||||
},
|
},
|
||||||
secret: {
|
secret: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
activated: {
|
activated: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'app_user',
|
collection: 'app_user',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
AppUserSchema.index({timestamp: 1});
|
AppUserSchema.index({timestamp: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -6,39 +6,36 @@ const Schema = mongoose.Schema;
|
||||||
const AwardingSchema = new Schema({
|
const AwardingSchema = new Schema({
|
||||||
userId: {
|
userId: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'User',
|
ref: 'User'
|
||||||
},
|
},
|
||||||
decorationId: {
|
decorationId: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'Decoration',
|
ref: 'Decoration'
|
||||||
},
|
},
|
||||||
reason: {
|
reason: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
proposer: {
|
proposer: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'AppUser',
|
ref: 'AppUser',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
confirmed: {
|
confirmed: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 2,
|
max: 2,
|
||||||
default: 0,
|
default: 0
|
||||||
},
|
|
||||||
rejectReason: {
|
|
||||||
type: String,
|
|
||||||
},
|
},
|
||||||
date: {
|
date: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: Date.now(),
|
default: Date.now()
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'awarding',
|
collection: 'awarding',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
AwardingSchema.index({timestamp: 1});
|
AwardingSchema.index({timestamp: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -6,11 +6,11 @@ const Schema = mongoose.Schema;
|
||||||
const CampaignSchema = new Schema({
|
const CampaignSchema = new Schema({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'campaign',
|
collection: 'campaign',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
CampaignSchema.index({timestamp: 1});
|
CampaignSchema.index({timestamp: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -6,27 +6,27 @@ const Schema = mongoose.Schema;
|
||||||
const DecorationSchema = new Schema({
|
const DecorationSchema = new Schema({
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR', 'ARF', 'SWORD', 'GLOBAL'],
|
enum: ['BLUFOR', 'OPFOR', 'GLOBAL'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
sortingNumber: {
|
sortingNumber: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
default: 0,
|
default: 0
|
||||||
},
|
},
|
||||||
isMedal: {type: Boolean, required: true},
|
isMedal: {type: Boolean, required: true}
|
||||||
}, {
|
}, {
|
||||||
collection: 'decoration',
|
collection: 'decoration',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
DecorationSchema.index({timestamp: 1});
|
DecorationSchema.index({timestamp: 1});
|
|
@ -0,0 +1,39 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const LogBudgetSchema = new Schema({
|
||||||
|
war: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
ref: 'War',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
type: Date,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
fraction: {
|
||||||
|
type: String,
|
||||||
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
oldBudget: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
collection: 'logBudget'
|
||||||
|
});
|
||||||
|
// optional more indices
|
||||||
|
LogBudgetSchema.index({war: 1});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('LogBudget', LogBudgetSchema);
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,28 +7,27 @@ const LogFlagSchema = new Schema({
|
||||||
war: {
|
war: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'War',
|
ref: 'War',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
player: {
|
player: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
flagFraction: {
|
flagFraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR'],
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
capture: {
|
capture: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'logFlag',
|
collection: 'logFlag'
|
||||||
versionKey: false,
|
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
LogFlagSchema.index({war: 1, player: 1});
|
LogFlagSchema.index({war: 1, player: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,40 +7,30 @@ const LogKillSchema = new Schema({
|
||||||
war: {
|
war: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'War',
|
ref: 'War',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
shooter: {
|
shooter: {
|
||||||
type: String,
|
type: String
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
friendlyFire: {
|
friendlyFire: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true
|
||||||
},
|
|
||||||
magazine: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
shooterVehicle: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
targetVehicle: {
|
|
||||||
type: String,
|
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR', 'NONE'],
|
enum: ['BLUFOR', 'OPFOR', 'NONE'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'logKill',
|
collection: 'logKill'
|
||||||
versionKey: false,
|
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
LogKillSchema.index({war: 1, shooter: 1, target: 1});
|
LogKillSchema.index({war: 1, shooter: 1, target: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,32 +7,31 @@ const LogKillSchema = new Schema({
|
||||||
war: {
|
war: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'War',
|
ref: 'War',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
ptBlufor: {
|
ptBlufor: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
ptOpfor: {
|
ptOpfor: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR', 'NONE'],
|
enum: ['BLUFOR', 'OPFOR', 'NONE'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'logPoints',
|
collection: 'logPoints'
|
||||||
versionKey: false,
|
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
LogKillSchema.index({war: 1, shooter: 1, target: 1});
|
LogKillSchema.index({war: 1, shooter: 1, target: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,19 +7,18 @@ const LogRespawnSchema = new Schema({
|
||||||
war: {
|
war: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'War',
|
ref: 'War',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
player: {
|
player: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'logRespawn',
|
collection: 'logRespawn'
|
||||||
versionKey: false,
|
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
LogRespawnSchema.index({war: 1, player: 1});
|
LogRespawnSchema.index({war: 1, player: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,32 +7,31 @@ const LogReviveSchema = new Schema({
|
||||||
war: {
|
war: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'War',
|
ref: 'War',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
medic: {
|
medic: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
patient: {
|
patient: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
stabilized: {
|
stabilized: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR'],
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'logRevive',
|
collection: 'logRevive'
|
||||||
versionKey: false,
|
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
LogReviveSchema.index({war: 1, medic: 1});
|
LogReviveSchema.index({war: 1, medic: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,36 +7,35 @@ const LogTransportSchema = new Schema({
|
||||||
war: {
|
war: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'War',
|
ref: 'War',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Date,
|
type: Date,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
driver: {
|
driver: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
passenger: {
|
passenger: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
distance: {
|
distance: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR'],
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'logTransport',
|
collection: 'logTransport'
|
||||||
versionKey: false,
|
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
LogTransportSchema.index({war: 1, driver: 1});
|
LogTransportSchema.index({war: 1});
|
||||||
|
|
||||||
module.exports = mongoose.model('LogTransport', LogTransportSchema);
|
module.exports = mongoose.model('LogTransport', LogTransportSchema);
|
|
@ -0,0 +1,69 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const PlayerSchema = new Schema({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
fraction: {
|
||||||
|
type: String,
|
||||||
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
warId: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
ref: 'War',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
kill: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
},
|
||||||
|
friendlyFire: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
},
|
||||||
|
respawn: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
},
|
||||||
|
sort: {
|
||||||
|
type: Number,
|
||||||
|
get: v => Math.round(v),
|
||||||
|
set: v => Math.round(v)
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
collection: 'player',
|
||||||
|
timestamps: {createdAt: 'timestamp'}
|
||||||
|
});
|
||||||
|
// optional more indices
|
||||||
|
PlayerSchema.index({timestamp: 1});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Player', PlayerSchema);
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -6,39 +6,36 @@ const Schema = mongoose.Schema;
|
||||||
const PromotionSchema = new Schema({
|
const PromotionSchema = new Schema({
|
||||||
userId: {
|
userId: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'User',
|
ref: 'User'
|
||||||
},
|
},
|
||||||
proposer: {
|
proposer: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'AppUser',
|
ref: 'AppUser',
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
oldRankLvl: {
|
oldRankLvl: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
newRankLvl: {
|
newRankLvl: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
confirmed: {
|
confirmed: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 2,
|
max: 2,
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
rejectReason: {
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
}, {
|
}, {
|
||||||
collection: 'promotion',
|
collection: 'promotion',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
PromotionSchema.index({timestamp: 1});
|
PromotionSchema.index({timestamp: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -6,22 +6,22 @@ const Schema = mongoose.Schema;
|
||||||
const RankSchema = new Schema({
|
const RankSchema = new Schema({
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR'],
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
level: {
|
level: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'rank',
|
collection: 'rank',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
RankSchema.index({timestamp: 1});
|
RankSchema.index({timestamp: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -6,22 +6,22 @@ const Schema = mongoose.Schema;
|
||||||
const SquadSchema = new Schema({
|
const SquadSchema = new Schema({
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
fraction: {
|
fraction: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['BLUFOR', 'OPFOR'],
|
enum: ['BLUFOR', 'OPFOR'],
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
sortingNumber: {
|
sortingNumber: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
default: 0,
|
default: 0
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'squad',
|
collection: 'squad',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
SquadSchema.index({timestamp: 1});
|
SquadSchema.index({timestamp: 1});
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
@ -7,22 +7,22 @@ const UserSchema = new Schema({
|
||||||
username: {
|
username: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
unique: true,
|
unique: true
|
||||||
},
|
},
|
||||||
rankLvl: {
|
rankLvl: {
|
||||||
type: Number,
|
type: Number,
|
||||||
get: (v) => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: (v) => Math.round(v),
|
set: v => Math.round(v),
|
||||||
default: 0,
|
default: 0
|
||||||
},
|
},
|
||||||
squadId: {
|
squadId: {
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'Squad',
|
ref: 'Squad',
|
||||||
default: null,
|
default: null
|
||||||
},
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'user',
|
collection: 'user',
|
||||||
timestamps: {createdAt: 'timestamp'},
|
timestamps: {createdAt: 'timestamp'}
|
||||||
});
|
});
|
||||||
// optional more indices
|
// optional more indices
|
||||||
UserSchema.index({timestamp: 1});
|
UserSchema.index({timestamp: 1});
|
|
@ -0,0 +1,75 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const WarSchema = new Schema({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
endDate : {
|
||||||
|
type: Date,
|
||||||
|
},
|
||||||
|
ptBlufor: {
|
||||||
|
type: Number,
|
||||||
|
get: v => Math.round(v),
|
||||||
|
set: v => Math.round(v),
|
||||||
|
},
|
||||||
|
ptOpfor: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
},
|
||||||
|
playersOpfor: {
|
||||||
|
type: Number,
|
||||||
|
get: v => Math.round(v),
|
||||||
|
set: v => Math.round(v),
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
campaign: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
ref: 'Campaign',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
budgetBlufor: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
},
|
||||||
|
endBudgetBlufor: {
|
||||||
|
type: Number,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
collection: 'war',
|
||||||
|
timestamps: {createdAt: 'timestamp'}
|
||||||
|
});
|
||||||
|
// optional more indices
|
||||||
|
WarSchema.index({timestamp: 1});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('War', WarSchema);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"name": "opt-cc-api",
|
||||||
|
"licence": "CC BY-SA 4.0",
|
||||||
|
"description": "RESTful API for Operation Pandora Trigger Command Center, includes signature generator",
|
||||||
|
"main": "server.js",
|
||||||
|
"author": "Florian Hartwich <hardi@noarch.de>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "DEBUG='cc:*' NODE_ENV=production node server.js",
|
||||||
|
"dev": "DEBUG='cc:*' NODE_ENV=dev nodemon server.js",
|
||||||
|
"test": "mocha --require ./test/config/spec_helper.js",
|
||||||
|
"e2e": "NODE_ENV=test node server.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"async": "^2.5.0",
|
||||||
|
"bcryptjs": "^2.4.3",
|
||||||
|
"body-parser": "~1.13.2",
|
||||||
|
"cors": "^2.8.4",
|
||||||
|
"cron": "^1.3.0",
|
||||||
|
"debug": "^3.1.0",
|
||||||
|
"express": "^4.16.2",
|
||||||
|
"imagemin": "^5.2.2",
|
||||||
|
"imagemin-pngquant": "^5.0.0",
|
||||||
|
"jimp": "^0.2.27",
|
||||||
|
"jsonwebtoken": "^7.4.3",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"mongoose": "^5.0.3",
|
||||||
|
"morgan": "~1.6.1",
|
||||||
|
"multer": "^1.3.0",
|
||||||
|
"node-sha1": "^1.0.1",
|
||||||
|
"q": "^1.5.0",
|
||||||
|
"serve-favicon": "~2.3.0",
|
||||||
|
"supports-color": "^5.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^3.5.0",
|
||||||
|
"chai-http": "^3.0.0",
|
||||||
|
"mocha": "^3.5.3",
|
||||||
|
"nodemon": "^1.14.12"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:awardings');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const AppUserModel = require('../models/app-user');
|
||||||
|
|
||||||
|
const account = express.Router();
|
||||||
|
|
||||||
|
account.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
AppUserModel.find({}, {}, {sort: {username: 1}}).populate('squad').exec((err, items) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = items;
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
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);
|
||||||
|
err.status = codes.notfound;
|
||||||
|
next(err);
|
||||||
|
return; // prevent node to process this function further after next() has finished.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
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(
|
||||||
|
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
|
||||||
|
account.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = account;
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
// modules
|
// modules
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
@ -6,6 +6,7 @@ const jwt = require('jsonwebtoken');
|
||||||
const bcrypt = require('bcryptjs');
|
const bcrypt = require('bcryptjs');
|
||||||
const Q = require('q');
|
const Q = require('q');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const logger = require('debug')('cc:authenticate');
|
||||||
|
|
||||||
// HTTP status codes by name
|
// HTTP status codes by name
|
||||||
const codes = require('./http-codes');
|
const codes = require('./http-codes');
|
||||||
|
@ -16,7 +17,7 @@ const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
const AppUserModel = require('../models/app-user');
|
const AppUserModel = require('../models/app-user');
|
||||||
|
|
||||||
const authenticate = new express.Router();
|
const authenticate = express.Router();
|
||||||
|
|
||||||
// routes **********************
|
// routes **********************
|
||||||
authenticate.route('/')
|
authenticate.route('/')
|
||||||
|
@ -46,7 +47,7 @@ let authCheck = (username, password, res) => {
|
||||||
AppUserModel.findOne({username: username.toLowerCase()}).populate('squad').exec((err, user) => {
|
AppUserModel.findOne({username: username.toLowerCase()}).populate('squad').exec((err, user) => {
|
||||||
if (err) deferred.reject(err.name + ': ' + err.message);
|
if (err) deferred.reject(err.name + ': ' + err.message);
|
||||||
|
|
||||||
const diff = 28 * 60 * 24; // time till expiration [minutes]
|
const diff = 7 * 60 * 24; // time till expiration [minutes]
|
||||||
|
|
||||||
if (user && !user.activated) {
|
if (user && !user.activated) {
|
||||||
res.status(codes.unauthorized).send('Account is not yet activated');
|
res.status(codes.unauthorized).send('Account is not yet activated');
|
||||||
|
@ -61,7 +62,7 @@ let authCheck = (username, password, res) => {
|
||||||
permission: user.permission,
|
permission: user.permission,
|
||||||
squad: user.squad,
|
squad: user.squad,
|
||||||
token: jwt.sign({sub: user._id}, secret, {expiresIn: diff * 60}),
|
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 {
|
} else {
|
||||||
// authentication failed
|
// authentication failed
|
||||||
|
@ -78,10 +79,10 @@ authenticate.route('/signup')
|
||||||
.post((req, res, next) => {
|
.post((req, res, next) => {
|
||||||
create(req.body)
|
create(req.body)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
res.status(codes.created).send({message: 'User successfully created'});
|
res.sendStatus(200);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
res.status(codes.wrongrequest).send(err);
|
res.status(400).send(err);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ let create = (userParam) => {
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
// username already exists
|
// username already exists
|
||||||
deferred.reject(new Error('Username already exists'));
|
deferred.reject(new Error("Username already exists"));
|
||||||
} else {
|
} else {
|
||||||
createUser();
|
createUser();
|
||||||
}
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:awardings');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
const awarding = express.Router();
|
||||||
|
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
awarding.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {};
|
||||||
|
if (req.query.userId) {
|
||||||
|
filter.userId = req.query.userId;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
res.locals.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
|
||||||
|
const award = new AwardingModel(req.body);
|
||||||
|
award.confirmed = 1;
|
||||||
|
award.proposer = req.user._id;
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
award.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = award;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.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);
|
||||||
|
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.
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
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(
|
||||||
|
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
|
||||||
|
awarding.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = awarding;
|
|
@ -0,0 +1,88 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:campaigns');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkMT = require('../middleware/permission-check').checkMT;
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const idValidator = require('../middleware/validators').idValidator;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const CampaignModel = require('../models/campaign');
|
||||||
|
const WarModel = require('../models/war');
|
||||||
|
|
||||||
|
|
||||||
|
const campaigns = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
campaigns.route('/')
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkMT, (req, res, next) => {
|
||||||
|
const campaign = new CampaignModel(req.body);
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
campaign.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = campaign;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
campaigns.route('/:id')
|
||||||
|
.get(idValidator, (req, res, next) => {
|
||||||
|
CampaignModel.findById(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = item;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.delete((req, res, next) => {
|
||||||
|
CampaignModel.findByIdAndRemove(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
WarModel.find({campaign: req.params.id}).remove().exec();
|
||||||
|
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.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
|
||||||
|
campaigns.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = campaigns;
|
|
@ -0,0 +1,41 @@
|
||||||
|
"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
|
||||||
|
);
|
||||||
|
|
||||||
|
command.route('/createSignature/:id')
|
||||||
|
.post((req, res, next) => {
|
||||||
|
const userId = req.params.id;
|
||||||
|
createSignature(userId, res, next);
|
||||||
|
})
|
||||||
|
|
||||||
|
.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
|
||||||
|
command.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = command;
|
|
@ -0,0 +1,165 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const fs = require('fs');
|
||||||
|
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');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const idValidator = require('../middleware/validators').idValidator;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const DecorationModel = require('../models/decoration');
|
||||||
|
const AwardingsModel = require('../models/awarding');
|
||||||
|
|
||||||
|
const decoration = express.Router();
|
||||||
|
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
decoration.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {};
|
||||||
|
if (req.query.fractFilter) {
|
||||||
|
filter.fraction = req.query.fractFilter.toUpperCase()
|
||||||
|
}
|
||||||
|
if (req.query.q) {
|
||||||
|
filter.name = {$regex: req.query.q, $options: 'i'}
|
||||||
|
}
|
||||||
|
DecorationModel.find(filter, {}, {sort: {fraction: 'asc', isMedal: 'asc', sortingNumber: 'asc', name: 'asc'}}, (err, items) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
if (items && items.length > 0) {
|
||||||
|
res.locals.items = items;
|
||||||
|
} else {
|
||||||
|
res.locals.items = [];
|
||||||
|
}
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => {
|
||||||
|
const decoration = new DecorationModel(req.body);
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
decoration.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = decoration;
|
||||||
|
fs.appendFile(__dirname + '/../resource/decoration/' + decoration.id + '.png', new Buffer(req.file.buffer),
|
||||||
|
(err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
decoration.route('/:id')
|
||||||
|
.get(idValidator, (req, res, next) => {
|
||||||
|
DecorationModel.findById(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = item;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.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);
|
||||||
|
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};
|
||||||
|
|
||||||
|
if (req.file) {
|
||||||
|
const file = __dirname + '/../resource/decoration/' + req.body._id + '.png';
|
||||||
|
fs.unlink(file, (err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
fs.appendFile(file, new Buffer(req.file.buffer), (err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.locals.items = item;
|
||||||
|
}
|
||||||
|
next(err);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
|
||||||
|
DecorationModel.findByIdAndRemove(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
|
||||||
|
// delete graphic
|
||||||
|
fs.unlink(__dirname + '/../resource/decoration/' + req.params.id + '.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 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(
|
||||||
|
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
|
||||||
|
decoration.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = decoration;
|
|
@ -4,7 +4,7 @@
|
||||||
* @author Johannes Konert
|
* @author Johannes Konert
|
||||||
* @module http-codes
|
* @module http-codes
|
||||||
*/
|
*/
|
||||||
'use strict';
|
"use strict";
|
||||||
module.exports = {
|
module.exports = {
|
||||||
success: 200,
|
success: 200,
|
||||||
created: 201,
|
created: 201,
|
||||||
|
@ -17,5 +17,5 @@ module.exports = {
|
||||||
conflict: 409,
|
conflict: 409,
|
||||||
wrongdatatyperequest: 406,
|
wrongdatatyperequest: 406,
|
||||||
wrongmediasend: 415,
|
wrongmediasend: 415,
|
||||||
servererror: 500,
|
servererror: 500
|
||||||
};
|
};
|
|
@ -0,0 +1,156 @@
|
||||||
|
"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');
|
||||||
|
const LogRespawnModel = require('../models/logs/respawn');
|
||||||
|
const LogReviveModel = require('../models/logs/revive');
|
||||||
|
const LogKillModel = require('../models/logs/kill');
|
||||||
|
const LogTransportModel = require('../models/logs/transport');
|
||||||
|
const LogFlagModel = require('../models/logs/flag');
|
||||||
|
const LogPointsModel = require('../models/logs/points');
|
||||||
|
|
||||||
|
const logsRouter = express.Router();
|
||||||
|
|
||||||
|
function 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)
|
||||||
|
}
|
||||||
|
res.locals.items = log;
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
logsRouter.route('/:warId')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
const sort = {sort: {time: 1}};
|
||||||
|
|
||||||
|
const pointsObjects = LogPointsModel.find(filter, {}, sort);
|
||||||
|
const budgetObjects = LogBudgetModel.find(filter, {}, sort);
|
||||||
|
const respawnObjects = LogRespawnModel.find(filter, {}, sort);
|
||||||
|
const reviveObjects = LogReviveModel.find(filter, {}, sort);
|
||||||
|
const killObjects = LogKillModel.find(filter, {}, sort);
|
||||||
|
const transportObjects = LogTransportModel.find(filter, {}, sort);
|
||||||
|
const flagObjects = LogFlagModel.find(filter, {}, sort);
|
||||||
|
const resources = {
|
||||||
|
points: pointsObjects.exec.bind(pointsObjects),
|
||||||
|
budget: budgetObjects.exec.bind(budgetObjects),
|
||||||
|
respawn: respawnObjects.exec.bind(respawnObjects),
|
||||||
|
revive: reviveObjects.exec.bind(reviveObjects),
|
||||||
|
kill: killObjects.exec.bind(killObjects),
|
||||||
|
transport: transportObjects.exec.bind(transportObjects),
|
||||||
|
flag: flagObjects.exec.bind(flagObjects)
|
||||||
|
};
|
||||||
|
|
||||||
|
async.parallel(resources, function (error, results){
|
||||||
|
if (error) {
|
||||||
|
res.status(500).send(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.locals.items = results;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/budget')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.fraction) filter['fraction'] = req.query.fraction;
|
||||||
|
processLogRequest(LogBudgetModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/respawn')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.player) filter['player'] = req.query.player;
|
||||||
|
processLogRequest(LogRespawnModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/revive')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.medic) filter['medic'] = req.query.medic;
|
||||||
|
if (req.query.patient) filter['patient'] = req.query.patient;
|
||||||
|
if (req.query.stabilized) filter['stabilized'] = true;
|
||||||
|
if (req.query.revive) filter['stabilized'] = false;
|
||||||
|
if (req.query.fraction) filter['fraction'] = req.query.fraction;
|
||||||
|
processLogRequest(LogReviveModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/kills')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.shooter) filter['shooter'] = req.query.shooter;
|
||||||
|
if (req.query.target) filter['target'] = req.query.target;
|
||||||
|
if (req.query.friendlyFire) filter['friendlyFire'] = true;
|
||||||
|
if (req.query.noFriendlyFire) filter['friendlyFire'] = false;
|
||||||
|
if (req.query.fraction) filter['fraction'] = req.query.fraction;
|
||||||
|
processLogRequest(LogKillModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/transport')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.driver) filter['driver'] = req.query.driver;
|
||||||
|
if (req.query.passenger) filter['passenger'] = req.query.passenger;
|
||||||
|
if (req.query.fraction) filter['fraction'] = req.query.fraction;
|
||||||
|
processLogRequest(LogTransportModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/flag')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.player) filter['player'] = req.query.player;
|
||||||
|
if (req.query.capture) filter['capture'] = true;
|
||||||
|
if (req.query.defend) filter['capture'] = false;
|
||||||
|
if (req.query.fraction) filter['fraction'] = req.query.fraction;
|
||||||
|
processLogRequest(LogFlagModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.route('/:warId/points')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {war: req.params.warId};
|
||||||
|
if (req.query.fraction) filter['fraction'] = req.query.fraction;
|
||||||
|
processLogRequest(LogPointsModel, filter, res, next);
|
||||||
|
})
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
logsRouter.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = logsRouter;
|
|
@ -0,0 +1,113 @@
|
||||||
|
"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
|
||||||
|
const UserModel = require('../models/user');
|
||||||
|
const SquadModel = require('../models/squad');
|
||||||
|
const RankModel = require('../models/rank');
|
||||||
|
|
||||||
|
const overview = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
overview.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
let countOpfor = 0;
|
||||||
|
let countBlufor = 0;
|
||||||
|
const armyOverview = {
|
||||||
|
BLUFOR: {
|
||||||
|
squads: []
|
||||||
|
},
|
||||||
|
OPFOR: {
|
||||||
|
squads: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SquadModel.find({}, {'sortingNumber': 0, 'updatedAt': 0, 'timestamp': 0, '__v': 0}, {
|
||||||
|
sort: {
|
||||||
|
sortingNumber: 'asc',
|
||||||
|
name: 'asc'
|
||||||
|
}
|
||||||
|
}, (err, squads) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
async.eachSeries(squads, (squad, callback) => {
|
||||||
|
UserModel.find({squadId: squad._id}, {
|
||||||
|
'squadId': 0,
|
||||||
|
'updatedAt': 0,
|
||||||
|
'timestamp': 0,
|
||||||
|
'__v': 0
|
||||||
|
}, {sort: {rankLvl: 'desc', name: 'asc'}}, (err, users) => {
|
||||||
|
const squadMembers = [];
|
||||||
|
async.eachSeries(users, (user, callback) => {
|
||||||
|
const usr = user.toObject();
|
||||||
|
RankModel.findOne({level: user.rankLvl, fraction: squad.fraction}, (err, rank) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// not defined if rank was deleted / rankLvl not available for fraction
|
||||||
|
if (rank) {
|
||||||
|
usr.rank = rank.name;
|
||||||
|
}
|
||||||
|
delete usr.rankLvl;
|
||||||
|
squadMembers.push(usr)
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}, (err) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not return empty squads
|
||||||
|
if (squadMembers.length > 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, (err) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
armyOverview.BLUFOR.memberCount = countBlufor;
|
||||||
|
armyOverview.OPFOR.memberCount = countOpfor;
|
||||||
|
res.locals.items = armyOverview;
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
overview.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = overview;
|
|
@ -0,0 +1,114 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:players');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const CampaignModel = require('../models/campaign');
|
||||||
|
const PlayerModel = require('../models/player');
|
||||||
|
const WarModel = require('../models/war');
|
||||||
|
|
||||||
|
const campaignPlayer = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
campaignPlayer.route('/ranking/:campaignId')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
WarModel.find({campaign: req.params.campaignId}, '_id', (err, wars) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
const warIds = wars.map((obj) => {
|
||||||
|
return obj._id;
|
||||||
|
});
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rankingItems = [];
|
||||||
|
new Set(items.map(x => x.name)).forEach(playerName => {
|
||||||
|
const playerInstances = items.filter(p => p.name === playerName);
|
||||||
|
const resItem = {name: playerName, kill: 0, death: 0, friendlyFire: 0, revive: 0, respawn: 0, flagTouch: 0};
|
||||||
|
for (let i = 0; i < playerInstances.length; i++) {
|
||||||
|
resItem.kill += playerInstances[i].kill;
|
||||||
|
resItem.death += playerInstances[i].death;
|
||||||
|
resItem.friendlyFire += playerInstances[i].friendlyFire;
|
||||||
|
resItem.revive += playerInstances[i].revive;
|
||||||
|
resItem.respawn += playerInstances[i].respawn;
|
||||||
|
resItem.flagTouch += playerInstances[i].flagTouch;
|
||||||
|
}
|
||||||
|
resItem.fraction = playerInstances[playerInstances.length - 1].fraction;
|
||||||
|
rankingItems.push(resItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
function getSortedField(fieldName) {
|
||||||
|
let num = 1;
|
||||||
|
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'),
|
||||||
|
death: getSortedField('death'),
|
||||||
|
friendlyFire: getSortedField('friendlyFire'),
|
||||||
|
revive: getSortedField('revive'),
|
||||||
|
respawn: getSortedField('respawn'),
|
||||||
|
flagTouch: getSortedField('flagTouch')
|
||||||
|
};
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
campaignPlayer.route('/single/:campaignId/:playerName')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
CampaignModel.findById(req.params.campaignId, (err, campaign) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
WarModel.find({campaign: req.params.campaignId}, '_id', (err, wars) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
const warIds = wars.map((obj) => {
|
||||||
|
return obj._id;
|
||||||
|
});
|
||||||
|
PlayerModel.find({name: req.params.playerName, warId: {"$in": warIds}})
|
||||||
|
.populate('warId')
|
||||||
|
.exec((err, items) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
if (!items || items.length === 0) {
|
||||||
|
const err = new Error('Unknown player name');
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err)
|
||||||
|
}
|
||||||
|
res.locals.items = {
|
||||||
|
name: req.params.playerName,
|
||||||
|
campaign: campaign,
|
||||||
|
players: items
|
||||||
|
};
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
campaignPlayer.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = campaignPlayer;
|
|
@ -0,0 +1,158 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const fs = require('fs');
|
||||||
|
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');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const idValidator = require('../middleware/validators').idValidator;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const RankModel = require('../models/rank');
|
||||||
|
|
||||||
|
const ranks = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
ranks.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {};
|
||||||
|
if (req.query.fractFilter) {
|
||||||
|
filter.fraction = req.query.fractFilter.toUpperCase()
|
||||||
|
}
|
||||||
|
if (req.query.q) {
|
||||||
|
filter.name = {$regex: req.query.q, $options: 'i'}
|
||||||
|
}
|
||||||
|
|
||||||
|
RankModel.find(filter, {}, {sort: {fraction: 'asc', level: 'asc'}}, (err, items) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items && items.length > 0) {
|
||||||
|
res.locals.items = items;
|
||||||
|
} else {
|
||||||
|
res.locals.items = [];
|
||||||
|
}
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => {
|
||||||
|
const rank = new RankModel(req.body);
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
rank.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = rank;
|
||||||
|
fs.appendFile(__dirname + '/../resource/rank/' + rank.id + '.png', new Buffer(req.file.buffer),
|
||||||
|
(err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ranks.route('/:id')
|
||||||
|
.get(idValidator, (req, res, next) => {
|
||||||
|
RankModel.findById(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = item;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.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);
|
||||||
|
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};
|
||||||
|
|
||||||
|
if (req.file) {
|
||||||
|
const file = __dirname + '/../resource/rank/' + req.body._id + '.png';
|
||||||
|
fs.unlink(file, (err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
fs.appendFile(file, new Buffer(req.file.buffer),
|
||||||
|
(err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
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(
|
||||||
|
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
|
||||||
|
ranks.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = ranks;
|
|
@ -0,0 +1,183 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:awardings');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkSql = require('../middleware/permission-check').checkSql;
|
||||||
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const UserModel = require('../models/user');
|
||||||
|
const AwardingModel = require('../models/awarding');
|
||||||
|
const PromotionModel = require('../models/promotion');
|
||||||
|
|
||||||
|
// result set for proposer(appUser) population
|
||||||
|
const resultSet = {
|
||||||
|
'__v': 0,
|
||||||
|
'updatedAt': 0,
|
||||||
|
'timestamp': 0,
|
||||||
|
'password': 0,
|
||||||
|
'permission': 0,
|
||||||
|
'secret': 0,
|
||||||
|
'activated': 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = express.Router();
|
||||||
|
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
request.route('/award')
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkSql, (req, res, next) => {
|
||||||
|
const award = new AwardingModel(req.body);
|
||||||
|
award.confirmed = 0;
|
||||||
|
award.proposer = req.user._id;
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
award.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = award;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
request.route('/promotion')
|
||||||
|
|
||||||
|
.get((req, res, next) => {
|
||||||
|
// TODO: add SQL authentication
|
||||||
|
const squadFilter = req.query.squadId;
|
||||||
|
const fractFilter = req.query.fractFilter;
|
||||||
|
const progressFilter = req.query.inProgress;
|
||||||
|
let filter;
|
||||||
|
if (squadFilter) {
|
||||||
|
filter = {squadId: squadFilter};
|
||||||
|
}
|
||||||
|
let userIds = [];
|
||||||
|
UserModel.find(filter).populate('squadId').exec((err, items) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let item of items) {
|
||||||
|
if (!fractFilter || (fractFilter && item.squadId && item.squadId.fraction === fractFilter)) {
|
||||||
|
userIds.push(item._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let promotionFilter = {
|
||||||
|
userId: {"$in": userIds}
|
||||||
|
};
|
||||||
|
if (progressFilter) {
|
||||||
|
promotionFilter.confirmed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PromotionModel.find(promotionFilter, {}, {sort: {timestamp: 'desc'}})
|
||||||
|
.populate('userId').populate('proposer', resultSet).exec((err, items) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items && items.length > 0) {
|
||||||
|
res.locals.items = items;
|
||||||
|
} else {
|
||||||
|
res.locals.items = [];
|
||||||
|
}
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkSql, (req, res, next) => {
|
||||||
|
const promotion = new PromotionModel(req.body);
|
||||||
|
promotion.confirmed = 0;
|
||||||
|
promotion.proposer = req.user._id;
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
promotion.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = promotion;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
err.status = codes.notfound;
|
||||||
|
next(err);
|
||||||
|
return; // prevent node to process this function further after next() has finished.
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (item.confirmed === 1) {
|
||||||
|
let updateUser = {
|
||||||
|
_id: item.userId,
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
res.locals.items = item;
|
||||||
|
}
|
||||||
|
next(err);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.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
|
||||||
|
request.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = request;
|
|
@ -0,0 +1,58 @@
|
||||||
|
"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');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
const UserModel = require('../models/user');
|
||||||
|
|
||||||
|
const signatures = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
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 + '/../'});
|
||||||
|
} else {
|
||||||
|
const file = 'resource/signature/' + user._id + '.png';
|
||||||
|
|
||||||
|
fs.stat(__dirname + '/../' + file, (err, stat) => {
|
||||||
|
if (err === null) {
|
||||||
|
res.sendFile(file, {root: __dirname + '/../'});
|
||||||
|
} else if (err.code === 'ENOENT') {
|
||||||
|
res.sendFile(emptyFile, {root: __dirname + '/../'});
|
||||||
|
} else {
|
||||||
|
err = new Error("Internal server error");
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.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
|
||||||
|
signatures.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = signatures;
|
|
@ -0,0 +1,164 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const fs = require('fs');
|
||||||
|
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');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const idValidator = require('../middleware/validators').idValidator;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const SquadModel = require('../models/squad');
|
||||||
|
|
||||||
|
const squads = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
squads.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const filter = {};
|
||||||
|
if (req.query.fractFilter) {
|
||||||
|
filter.fraction = req.query.fractFilter.toUpperCase()
|
||||||
|
}
|
||||||
|
if (req.query.q) {
|
||||||
|
filter.name = {$regex: req.query.q, $options: 'i'}
|
||||||
|
}
|
||||||
|
SquadModel.find(filter, {}, {sort: {fraction: 'asc', sortingNumber: 'asc'}}, (err, items) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
if (items) {
|
||||||
|
res.locals.items = items;
|
||||||
|
} else {
|
||||||
|
res.locals.items = [];
|
||||||
|
}
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => {
|
||||||
|
const squad = new SquadModel(req.body);
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
if (req.file) {
|
||||||
|
squad.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const err = new Error('no image file provided');
|
||||||
|
err.status = codes.wrongmediasend;
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
squads.route('/:id')
|
||||||
|
.get(idValidator, (req, res, next) => {
|
||||||
|
SquadModel.findById(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = item;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.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);
|
||||||
|
err.status = codes.notfound;
|
||||||
|
next(err);
|
||||||
|
return; // prevent node to process this function further after next() has finished.
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment version manually as we do not use .save(.)
|
||||||
|
req.body.updatedAt = new Date();
|
||||||
|
req.body.$inc = {__v: 1};
|
||||||
|
|
||||||
|
if (req.file) {
|
||||||
|
const file = __dirname + '/../resource/squad/' + req.body._id + '.png';
|
||||||
|
fs.unlink(file, (err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
fs.appendFile(file, new Buffer(req.file.buffer), (err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete graphic
|
||||||
|
fs.unlink(__dirname + '/../resource/squad/' + req.params.id + '.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 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(
|
||||||
|
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
|
||||||
|
squads.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = squads;
|
|
@ -0,0 +1,243 @@
|
||||||
|
"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');
|
||||||
|
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
|
||||||
|
const offsetlimitMiddleware = require('../middleware/limitoffset-middleware-mongo');
|
||||||
|
const filterHandlerCreator = require('../middleware/filter-handler-mongo');
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const idValidator = require('../middleware/validators').idValidator;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const UserModel = require('../models/user');
|
||||||
|
const SquadModel = require('../models/squad');
|
||||||
|
const AwardingModel = require('../models/awarding');
|
||||||
|
|
||||||
|
const users = express.Router();
|
||||||
|
|
||||||
|
users.get('/', filterHandlerCreator(UserModel.schema.paths));
|
||||||
|
users.get('/', offsetlimitMiddleware);
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
users.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const userQuery = () => {
|
||||||
|
UserModel.find(dbFilter, res.locals.filter, res.locals.limitskip)
|
||||||
|
.populate('squadId')
|
||||||
|
.collation({locale: "en", strength: 2}) // case insensitive order
|
||||||
|
.sort('username').exec((err, users) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
if (users.length === 0) {
|
||||||
|
res.locals.items = users;
|
||||||
|
res.locals.processed = true;
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
UserModel.count(dbFilter, (err, totalCount) => {
|
||||||
|
res.set('x-total-count', totalCount);
|
||||||
|
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};
|
||||||
|
// 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)};
|
||||||
|
userQuery();
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (req.query.fractFilter === 'UNASSIGNED') {
|
||||||
|
dbFilter['squadId'] = {$eq: null};
|
||||||
|
}
|
||||||
|
userQuery();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
|
||||||
|
const user = new UserModel(req.body);
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
user.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
|
||||||
|
UserModel.populate(user, {path: 'squadId'}, (err, extUser) => {
|
||||||
|
res.locals.items = extUser;
|
||||||
|
res.locals.processed = true;
|
||||||
|
return next();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(routerHandling.httpMethodNotAllowed);
|
||||||
|
|
||||||
|
|
||||||
|
users.route('/:id')
|
||||||
|
.get(idValidator, (req, res, next) => {
|
||||||
|
UserModel.findById(req.params.id).populate('squadId').exec((err, user) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!user) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = user;
|
||||||
|
res.locals.processed = true;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.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);
|
||||||
|
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.
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
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")
|
||||||
|
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) {
|
||||||
|
if ((field !== '_id') && (field !== '__v')) {
|
||||||
|
// this includes undefined. is important to reset attributes that are missing in req.body
|
||||||
|
item.set(field, user[field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update updatedAt and increase version
|
||||||
|
item.updatedAt = new Date();
|
||||||
|
item.increment(); // this sets __v++
|
||||||
|
item.save(function (err) {
|
||||||
|
if (!err) {
|
||||||
|
res.locals.items = item;
|
||||||
|
} else {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel.populate(item, {path: 'squadId'}, (err, extUser) => {
|
||||||
|
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");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleted all awardings linked to this user
|
||||||
|
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';
|
||||||
|
if (fs.existsSync(fileMinified)) {
|
||||||
|
fs.unlink(fileMinified, (err) => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const file = __dirname + '/../resource/signature/big/' + req.params.id + '.png';
|
||||||
|
if (fs.existsSync(file)) {
|
||||||
|
fs.unlink(file, (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
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.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
|
||||||
|
users.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = users;
|
|
@ -0,0 +1,225 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const fs = require('fs');
|
||||||
|
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');
|
||||||
|
|
||||||
|
// access check
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkMT = require('../middleware/permission-check').checkMT;
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const idValidator = require('../middleware/validators').idValidator;
|
||||||
|
|
||||||
|
// log paser tool
|
||||||
|
const parseWarLog = require('../tools/log-parse-tool');
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const CampaignModel = require('../models/campaign');
|
||||||
|
const WarModel = require('../models/war');
|
||||||
|
const PlayerModel = require('../models/player');
|
||||||
|
const LogKillModel = require('../models/logs/kill');
|
||||||
|
const LogRespawnModel = require('../models/logs/respawn');
|
||||||
|
const LogReviveModel = require('../models/logs/revive');
|
||||||
|
const LogTransportModel = require('../models/logs/transport');
|
||||||
|
const LogFlagModel = require('../models/logs/flag');
|
||||||
|
const LogBudgetModel = require('../models/logs/budget');
|
||||||
|
const LogPointsModel = require('../models/logs/points');
|
||||||
|
|
||||||
|
const wars = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
wars.route('/')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
let result = [];
|
||||||
|
CampaignModel.find({}, {}, {sort: {timestamp: 'desc'}}, (err, campaigns) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
if (campaigns) {
|
||||||
|
WarModel.find({}, {}, {sort: {date: 'desc'}}, (err, wars) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
if (wars) {
|
||||||
|
campaigns.forEach(campaign => {
|
||||||
|
let entry = {_id: campaign._id, title: campaign.title, wars: []};
|
||||||
|
wars.forEach((war) => {
|
||||||
|
if (String(campaign._id) === String(war.campaign)) {
|
||||||
|
entry.wars.push(war);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
result.push(entry);
|
||||||
|
});
|
||||||
|
res.locals.items = result;
|
||||||
|
}
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => {
|
||||||
|
const body = req.body;
|
||||||
|
const warBody = new WarModel(body);
|
||||||
|
|
||||||
|
if (req.file) {
|
||||||
|
fs.readFile(req.file.buffer, (file, err) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
LogKillModel.create(statsResult.kills, 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) {
|
||||||
|
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')
|
||||||
|
});
|
||||||
|
cleanFile.end();
|
||||||
|
|
||||||
|
// save raw log file
|
||||||
|
const rawFile = fs.createWriteStream(folderName + '/war.log');
|
||||||
|
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;
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
wars.route('/:id')
|
||||||
|
.get(idValidator, (req, res, next) => {
|
||||||
|
WarModel.findById(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
PlayerModel.find({warId: item._id}, {}, {sort: {kill: 'desc'}}, (err, items) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseObj = item.toObject();
|
||||||
|
responseObj.players = items;
|
||||||
|
res.locals.items = responseObj;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.delete(apiAuthenticationMiddleware, checkMT, (req, res, next) => {
|
||||||
|
WarModel.findByIdAndRemove(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete linked appearances
|
||||||
|
PlayerModel.find({warId: item._id}).remove().exec();
|
||||||
|
LogKillModel.find({war: item._id}).remove().exec();
|
||||||
|
LogRespawnModel.find({war: item._id}).remove().exec();
|
||||||
|
LogReviveModel.find({war: item._id}).remove().exec();
|
||||||
|
LogFlagModel.find({war: item._id}).remove().exec();
|
||||||
|
LogBudgetModel.find({war: item._id}).remove().exec();
|
||||||
|
LogTransportModel.find({war: item._id}).remove().exec();
|
||||||
|
LogPointsModel.find({war: item._id}).remove().exec();
|
||||||
|
|
||||||
|
// check if logfiles exist and delete from fs
|
||||||
|
const warDir = __dirname + '/../resource/logs/' + req.params.id;
|
||||||
|
|
||||||
|
if (fs.existsSync(warDir)) {
|
||||||
|
const cleanLog = warDir + '/clean.log';
|
||||||
|
if (fs.existsSync(cleanLog)) {
|
||||||
|
fs.unlink(cleanLog, (err) => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const sourceLog = warDir + '/war.log';
|
||||||
|
if (fs.existsSync(sourceLog)) {
|
||||||
|
fs.unlink(sourceLog, (err) => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fs.rmdir(warDir, (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();
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.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
|
||||||
|
wars.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = wars;
|
|
@ -0,0 +1,127 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
const favicon = require('serve-favicon');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const requestLogger = require('morgan');
|
||||||
|
|
||||||
|
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 mongoose = require('mongoose');
|
||||||
|
|
||||||
|
// own modules
|
||||||
|
const config = require('./config/config');
|
||||||
|
const urls = require('./config/api-url');
|
||||||
|
const restAPIchecks = require('./middleware/request-checks.js');
|
||||||
|
const errorResponseWare = require('./middleware/error-response');
|
||||||
|
const apiAuthenticationMiddleware = require('./middleware/auth-middleware');
|
||||||
|
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');
|
||||||
|
const overviewRouter = require('./routes/overview');
|
||||||
|
const userRouter = require('./routes/users');
|
||||||
|
const squadRouter = require('./routes/squads');
|
||||||
|
const rankRouter = require('./routes/ranks');
|
||||||
|
const decorationRouter = require('./routes/decorations');
|
||||||
|
const awardingRouter = require('./routes/awardings');
|
||||||
|
const requestRouter = require('./routes/request');
|
||||||
|
const playerRouter = require('./routes/players');
|
||||||
|
const signatureRouter = require('./routes/signatures');
|
||||||
|
const commandRouter = require('./routes/command');
|
||||||
|
const campaignRouter = require('./routes/campaigns');
|
||||||
|
const warRouter = require('./routes/wars');
|
||||||
|
const logRouter = require('./routes/logs');
|
||||||
|
|
||||||
|
// Configuration ***********************************
|
||||||
|
// mongoose promise setup
|
||||||
|
mongoose.Promise = global.Promise;
|
||||||
|
|
||||||
|
// app creation
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
// Middlewares *************************************************
|
||||||
|
|
||||||
|
// setup CORS-middleware
|
||||||
|
const corsOptions = {
|
||||||
|
methods: ['GET'],
|
||||||
|
optionsSuccessStatus: 200
|
||||||
|
};
|
||||||
|
app.use(cors(corsOptions));
|
||||||
|
|
||||||
|
app.use(favicon(path.join(__dirname + '/..', 'public', 'favicon.ico')));
|
||||||
|
app.use(express.static(path.join(__dirname + '/..', 'public')));
|
||||||
|
app.use(bodyParser.json({limit: '10mb'}));
|
||||||
|
app.use(bodyParser.urlencoded({limit: '10mb', extended: true}));
|
||||||
|
|
||||||
|
// API request checks for API-version and JSON etc.
|
||||||
|
app.use(restAPIchecks);
|
||||||
|
|
||||||
|
// Routes ******************************************************
|
||||||
|
app.use(urls.signatures, signatureRouter);
|
||||||
|
|
||||||
|
// initialize logging at this point to exclude /signature requests
|
||||||
|
if (process.env.NODE_ENV === config.dev.env) {
|
||||||
|
// development logging
|
||||||
|
app.use(requestLogger('dev'));
|
||||||
|
} else if (process.env.NODE_ENV !== config.test.env) {
|
||||||
|
// production logging, apache style
|
||||||
|
app.use(requestLogger(':date[clf] :method :url :response-time ms :status'));
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(urls.auth, authenticateRouter);
|
||||||
|
app.use(urls.overview, overviewRouter);
|
||||||
|
app.use(urls.users, userRouter);
|
||||||
|
app.use(urls.squads, squadRouter);
|
||||||
|
app.use(urls.ranks, rankRouter);
|
||||||
|
app.use(urls.decorations, decorationRouter);
|
||||||
|
app.use(urls.request, requestRouter);
|
||||||
|
app.use(urls.awards, awardingRouter);
|
||||||
|
app.use(urls.wars, warRouter);
|
||||||
|
app.use(urls.players, playerRouter);
|
||||||
|
app.use(urls.campaigns, campaignRouter);
|
||||||
|
app.use(urls.logs, logRouter);
|
||||||
|
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 + '/..'});
|
||||||
|
});
|
||||||
|
|
||||||
|
// register error handlers
|
||||||
|
errorResponseWare(app);
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
if (process.env.NODE_ENV !== config.test.env) {
|
||||||
|
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 {
|
||||||
|
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;
|
|
@ -0,0 +1,110 @@
|
||||||
|
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
|
||||||
|
let chai = require('chai');
|
||||||
|
let chaiHttp = require('chai-http');
|
||||||
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
//Our parent block
|
||||||
|
describe('Awardings', () => {
|
||||||
|
beforeEach((done) => { //Before each test we empty the database
|
||||||
|
AwardingModel.remove({}, (err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
* Test the /GET awardings
|
||||||
|
*/
|
||||||
|
describe('/GET awardings', () => {
|
||||||
|
it('it should GET all awardings', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.get(urls.awards)
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.success);
|
||||||
|
res.body.should.be.a('array');
|
||||||
|
res.body.length.should.be.eql(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.wrongmethod);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('error').property('message')
|
||||||
|
.eql('this method is not allowed at ' + urls.awards);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should not DELETE an awarding without auth-token provided', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.awards + '/someId')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
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
|
||||||
|
let chai = require('chai');
|
||||||
|
let chaiHttp = require('chai-http');
|
||||||
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
//Our parent block
|
||||||
|
describe('Command', () => {
|
||||||
|
beforeEach((done) => { //Before each test we empty the database
|
||||||
|
AwardingModel.remove({}, (err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
* Test the /GET awardings
|
||||||
|
*/
|
||||||
|
describe('/POST command to create signature', () => {
|
||||||
|
it('it should not succeed without auth-token provided', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.post(urls.cmdCreateSig + "/someId")
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,3 +1,3 @@
|
||||||
const config = require('../../config/config');
|
const config = require('../../config/config');
|
||||||
|
|
||||||
process.env.NODE_ENV = config.test.unit.env;
|
process.env.NODE_ENV = config.test.env;
|
|
@ -20,11 +20,10 @@ mongoose.connection.on('connected', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const createString = (possible, length) => {
|
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));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
@ -35,19 +34,21 @@ for (let i = 0; i < quantity; i++) {
|
||||||
UserModel.create({
|
UserModel.create({
|
||||||
username: createString('abcdefghijklmnopqrstuvwxyz0123456789', 10),
|
username: createString('abcdefghijklmnopqrstuvwxyz0123456789', 10),
|
||||||
squadId: squadId,
|
squadId: squadId,
|
||||||
rankLvl: Math.floor(Math.random() * 22),
|
rankLvl: Math.floor(Math.random() * 22)
|
||||||
}, (err, user) => {
|
}, function (err, user) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
} else {
|
} else {
|
||||||
console.log('User created: ' + user);
|
console.log('User created: ' + user);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the Node process ends, close the Mongoose connection
|
// If the Node process ends, close the Mongoose connection
|
||||||
process.on('SIGINT', () => {
|
process.on('SIGINT', () => {
|
||||||
mongoose.connection.close(() => {
|
mongoose.connection.close(function () {
|
||||||
console.log('Mongoose default connection disconnected through app termination');
|
console.log('Mongoose default connection disconnected through app termination');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
|
@ -0,0 +1,109 @@
|
||||||
|
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
|
||||||
|
let chai = require('chai');
|
||||||
|
let chaiHttp = require('chai-http');
|
||||||
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
//Our parent block
|
||||||
|
describe('Decorations', () => {
|
||||||
|
beforeEach((done) => { //Before each test we empty the database
|
||||||
|
DecorationModel.remove({}, (err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
* Test the /GET decorations
|
||||||
|
*/
|
||||||
|
describe('/GET decorations', () => {
|
||||||
|
it('it should GET all the decorations', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.get(urls.decorations)
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.success);
|
||||||
|
res.body.should.be.a('array');
|
||||||
|
res.body.length.should.be.eql(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the /DELETE decorations
|
||||||
|
*/
|
||||||
|
describe('/DELETE decorations', () => {
|
||||||
|
it('it should not accept DELETE method without id in url', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.decorations)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.wrongmethod);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('error').property('message')
|
||||||
|
.eql('this method is not allowed at ' + urls.decorations);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should not DELETE a decoration without auth-token provided', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.decorations + '/someId')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,110 @@
|
||||||
|
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
|
||||||
|
let chai = require('chai');
|
||||||
|
let chaiHttp = require('chai-http');
|
||||||
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
//Our parent block
|
||||||
|
describe('Ranks', () => {
|
||||||
|
beforeEach((done) => { //Before each test we empty the database
|
||||||
|
RankModel.remove({}, (err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
* Test the /GET ranks
|
||||||
|
*/
|
||||||
|
describe('/GET ranks', () => {
|
||||||
|
it('it should GET all the ranks', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.get(urls.ranks)
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.success);
|
||||||
|
res.body.should.be.a('array');
|
||||||
|
res.body.length.should.be.eql(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
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')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the /DELETE rank
|
||||||
|
*/
|
||||||
|
describe('/DELETE ranks', () => {
|
||||||
|
it('it should not accept DELETE method without id in url', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.ranks)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.wrongmethod);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('error').property('message')
|
||||||
|
.eql('this method is not allowed at ' + urls.ranks);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('it should not DELETE a rank without auth-token provided', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.ranks + '/someId')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,109 @@
|
||||||
|
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
|
||||||
|
let chai = require('chai');
|
||||||
|
let chaiHttp = require('chai-http');
|
||||||
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
//Our parent block
|
||||||
|
describe('Squads', () => {
|
||||||
|
beforeEach((done) => { //Before each test we empty the database
|
||||||
|
SquadModel.remove({}, (err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
* Test the /GET route
|
||||||
|
*/
|
||||||
|
describe('/GET squads', () => {
|
||||||
|
it('it should GET all the squads', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.get(urls.squads)
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.success);
|
||||||
|
res.body.should.be.a('array');
|
||||||
|
res.body.length.should.be.eql(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the /DELETE squad
|
||||||
|
*/
|
||||||
|
describe('/DELETE squads', () => {
|
||||||
|
it('it should not accept DELETE method without id in url', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.squads)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.wrongmethod);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('error').property('message')
|
||||||
|
.eql('this method is not allowed at ' + urls.squads);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should not DELETE a squad without auth-token provided', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.squads + '/someId')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,21 +1,21 @@
|
||||||
|
let mongoose = require("mongoose");
|
||||||
let UserModel = require('../models/user');
|
let UserModel = require('../models/user');
|
||||||
|
let AppUserModel = require('../models/app-user');
|
||||||
let urls = require('../config/api-url');
|
let urls = require('../config/api-url');
|
||||||
let codes = require('../routes/http-codes');
|
let codes = require('../routes/http-codes');
|
||||||
|
|
||||||
|
|
||||||
// Require the dev-dependencies
|
//Require the dev-dependencies
|
||||||
let chai = require('chai');
|
let chai = require('chai');
|
||||||
let chaiHttp = require('chai-http');
|
let chaiHttp = require('chai-http');
|
||||||
let server = require('../server');
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
// chai methods
|
|
||||||
require('chai').should();
|
|
||||||
|
|
||||||
chai.use(chaiHttp);
|
chai.use(chaiHttp);
|
||||||
// Our parent block
|
//Our parent block
|
||||||
describe('Users', () => {
|
describe('Users', () => {
|
||||||
beforeEach((done) => { // Before each test we empty the database
|
beforeEach((done) => { //Before each test we empty the database
|
||||||
UserModel.deleteMany({}, (err) => {
|
UserModel.remove({}, (err) => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -39,6 +39,7 @@ describe('Users', () => {
|
||||||
* Test the /POST route
|
* Test the /POST route
|
||||||
*/
|
*/
|
||||||
describe('/POST users', () => {
|
describe('/POST users', () => {
|
||||||
|
|
||||||
// let token;
|
// let token;
|
||||||
//
|
//
|
||||||
// before(function (done) {
|
// before(function (done) {
|
||||||
|
@ -102,13 +103,14 @@ describe('Users', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test the /PUT route
|
* Test the /PATCH route
|
||||||
*/
|
*/
|
||||||
describe('/PUT users', () => {
|
describe('/PATCH users', () => {
|
||||||
it('it should not PUT a user without auth-token provided', (done) => {
|
|
||||||
|
it('it should not PATCH a user without auth-token provided', (done) => {
|
||||||
chai.request(server)
|
chai.request(server)
|
||||||
.put(urls.users + '/someId')
|
.patch(urls.users + '/someId')
|
||||||
.send({_id: 'someId'})
|
.send({})
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
res.should.have.status(codes.forbidden);
|
res.should.have.status(codes.forbidden);
|
||||||
res.body.should.be.a('object');
|
res.body.should.be.a('object');
|
||||||
|
@ -117,6 +119,7 @@ describe('Users', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,5 +152,7 @@ describe('Users', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -0,0 +1,85 @@
|
||||||
|
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
|
||||||
|
let chai = require('chai');
|
||||||
|
let chaiHttp = require('chai-http');
|
||||||
|
let server = require('../server');
|
||||||
|
let should = chai.should();
|
||||||
|
|
||||||
|
chai.use(chaiHttp);
|
||||||
|
//Our parent block
|
||||||
|
describe('Wars', () => {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test the /GET awardings
|
||||||
|
*/
|
||||||
|
describe('/GET wars', () => {
|
||||||
|
it('it should GET all wars', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.get(urls.wars)
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.success);
|
||||||
|
res.body.should.be.a('array');
|
||||||
|
res.body.length.should.be.eql(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.wrongmethod);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('error').property('message')
|
||||||
|
.eql('this method is not allowed at ' + urls.wars);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should not DELETE an awarding without auth-token provided', (done) => {
|
||||||
|
chai.request(server)
|
||||||
|
.delete(urls.wars + '/someId')
|
||||||
|
.send({})
|
||||||
|
.end((err, res) => {
|
||||||
|
res.should.have.status(codes.forbidden);
|
||||||
|
res.body.should.be.a('object');
|
||||||
|
res.body.should.have.property('success').eql(false);
|
||||||
|
res.body.should.have.property('message').eql('No token provided.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,813 @@
|
||||||
|
info face="DejaVu Sans" size=19 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2
|
||||||
|
common lineHeight=23 base=18 scaleW=512 scaleH=512 pages=1 packed=0
|
||||||
|
page id=0 file="DEVAJU_SANS_19.png"
|
||||||
|
chars count=193
|
||||||
|
char id=0 x=298 y=0 width=13 height=20 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0
|
||||||
|
char id=10 x=0 y=0 width=22 height=22 xoffset=-1 yoffset=-1 xadvance=19 page=0 chnl=0
|
||||||
|
char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=17 xadvance=6 page=0 chnl=0
|
||||||
|
char id=33 x=500 y=42 width=4 height=16 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0
|
||||||
|
char id=34 x=67 y=75 width=7 height=7 xoffset=1 yoffset=3 xadvance=9 page=0 chnl=0
|
||||||
|
char id=35 x=40 y=59 width=15 height=16 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=36 x=287 y=0 width=11 height=20 xoffset=1 yoffset=2 xadvance=13 page=0 chnl=0
|
||||||
|
char id=37 x=22 y=59 width=18 height=16 xoffset=0 yoffset=3 xadvance=18 page=0 chnl=0
|
||||||
|
char id=38 x=55 y=59 width=15 height=16 xoffset=0 yoffset=3 xadvance=14 page=0 chnl=0
|
||||||
|
char id=39 x=507 y=59 width=4 height=7 xoffset=1 yoffset=3 xadvance=6 page=0 chnl=0
|
||||||
|
char id=40 x=240 y=0 width=7 height=20 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0
|
||||||
|
char id=41 x=247 y=0 width=7 height=20 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=0
|
||||||
|
char id=42 x=489 y=59 width=11 height=11 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0
|
||||||
|
char id=43 x=199 y=59 width=14 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
|
||||||
|
char id=44 x=74 y=75 width=5 height=7 xoffset=0 yoffset=14 xadvance=6 page=0 chnl=0
|
||||||
|
char id=45 x=119 y=75 width=7 height=4 xoffset=0 yoffset=10 xadvance=7 page=0 chnl=0
|
||||||
|
char id=46 x=115 y=75 width=4 height=5 xoffset=1 yoffset=14 xadvance=6 page=0 chnl=0
|
||||||
|
char id=47 x=51 y=22 width=9 height=18 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0
|
||||||
|
char id=48 x=0 y=59 width=12 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=49 x=396 y=42 width=11 height=16 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=50 x=407 y=42 width=11 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=51 x=418 y=42 width=11 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=52 x=429 y=42 width=13 height=16 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=53 x=442 y=42 width=11 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=54 x=453 y=42 width=12 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=55 x=465 y=42 width=11 height=16 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=56 x=476 y=42 width=12 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=57 x=488 y=42 width=12 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=58 x=430 y=59 width=4 height=12 xoffset=1 yoffset=7 xadvance=6 page=0 chnl=0
|
||||||
|
char id=59 x=152 y=59 width=5 height=15 xoffset=0 yoffset=6 xadvance=6 page=0 chnl=0
|
||||||
|
char id=60 x=171 y=59 width=14 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
|
||||||
|
char id=61 x=30 y=75 width=14 height=8 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=0
|
||||||
|
char id=62 x=185 y=59 width=14 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
|
||||||
|
char id=63 x=12 y=59 width=10 height=16 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=0
|
||||||
|
char id=64 x=268 y=0 width=19 height=20 xoffset=0 yoffset=2 xadvance=19 page=0 chnl=0
|
||||||
|
char id=65 x=78 y=42 width=15 height=16 xoffset=-1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=66 x=93 y=42 width=12 height=16 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=67 x=105 y=42 width=13 height=16 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=68 x=118 y=42 width=14 height=16 xoffset=1 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=69 x=132 y=42 width=11 height=16 xoffset=1 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=70 x=143 y=42 width=10 height=16 xoffset=1 yoffset=3 xadvance=11 page=0 chnl=0
|
||||||
|
char id=71 x=153 y=42 width=14 height=16 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=72 x=167 y=42 width=13 height=16 xoffset=1 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=73 x=504 y=22 width=4 height=16 xoffset=1 yoffset=3 xadvance=6 page=0 chnl=0
|
||||||
|
char id=74 x=233 y=0 width=7 height=20 xoffset=-2 yoffset=3 xadvance=6 page=0 chnl=0
|
||||||
|
char id=75 x=180 y=42 width=13 height=16 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=76 x=193 y=42 width=11 height=16 xoffset=1 yoffset=3 xadvance=11 page=0 chnl=0
|
||||||
|
char id=77 x=204 y=42 width=15 height=16 xoffset=1 yoffset=3 xadvance=17 page=0 chnl=0
|
||||||
|
char id=78 x=219 y=42 width=13 height=16 xoffset=1 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=79 x=232 y=42 width=15 height=16 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=80 x=247 y=42 width=11 height=16 xoffset=1 yoffset=3 xadvance=11 page=0 chnl=0
|
||||||
|
char id=81 x=11 y=22 width=15 height=19 xoffset=0 yoffset=3 xadvance=15 page=0 chnl=0
|
||||||
|
char id=82 x=258 y=42 width=13 height=16 xoffset=1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=83 x=271 y=42 width=12 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=84 x=283 y=42 width=14 height=16 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=85 x=297 y=42 width=13 height=16 xoffset=1 yoffset=3 xadvance=14 page=0 chnl=0
|
||||||
|
char id=86 x=310 y=42 width=15 height=16 xoffset=-1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=87 x=325 y=42 width=21 height=16 xoffset=-1 yoffset=3 xadvance=19 page=0 chnl=0
|
||||||
|
char id=88 x=346 y=42 width=15 height=16 xoffset=-1 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=89 x=361 y=42 width=14 height=16 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=90 x=375 y=42 width=13 height=16 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=91 x=254 y=0 width=7 height=20 xoffset=1 yoffset=2 xadvance=8 page=0 chnl=0
|
||||||
|
char id=92 x=60 y=22 width=9 height=18 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0
|
||||||
|
char id=93 x=261 y=0 width=7 height=20 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=0
|
||||||
|
char id=94 x=16 y=75 width=14 height=8 xoffset=1 yoffset=2 xadvance=16 page=0 chnl=0
|
||||||
|
char id=95 x=126 y=75 width=12 height=4 xoffset=-1 yoffset=20 xadvance=10 page=0 chnl=0
|
||||||
|
char id=96 x=100 y=75 width=8 height=6 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=0
|
||||||
|
char id=97 x=255 y=59 width=11 height=13 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=98 x=308 y=22 width=11 height=17 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=99 x=266 y=59 width=10 height=13 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=0
|
||||||
|
char id=100 x=319 y=22 width=11 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=101 x=276 y=59 width=12 height=13 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=102 x=330 y=22 width=9 height=17 xoffset=0 yoffset=2 xadvance=7 page=0 chnl=0
|
||||||
|
char id=103 x=339 y=22 width=11 height=17 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=104 x=350 y=22 width=11 height=17 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=105 x=361 y=22 width=4 height=17 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=0
|
||||||
|
char id=106 x=39 y=0 width=6 height=21 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0
|
||||||
|
char id=107 x=365 y=22 width=12 height=17 xoffset=1 yoffset=2 xadvance=11 page=0 chnl=0
|
||||||
|
char id=108 x=377 y=22 width=4 height=17 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=0
|
||||||
|
char id=109 x=288 y=59 width=18 height=13 xoffset=1 yoffset=6 xadvance=19 page=0 chnl=0
|
||||||
|
char id=110 x=306 y=59 width=11 height=13 xoffset=1 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=111 x=317 y=59 width=12 height=13 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=112 x=381 y=22 width=11 height=17 xoffset=1 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=113 x=392 y=22 width=11 height=17 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=114 x=329 y=59 width=8 height=13 xoffset=1 yoffset=6 xadvance=9 page=0 chnl=0
|
||||||
|
char id=115 x=337 y=59 width=10 height=13 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=0
|
||||||
|
char id=116 x=388 y=42 width=8 height=16 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0
|
||||||
|
char id=117 x=347 y=59 width=11 height=13 xoffset=1 yoffset=6 xadvance=13 page=0 chnl=0
|
||||||
|
char id=118 x=358 y=59 width=13 height=13 xoffset=-1 yoffset=6 xadvance=11 page=0 chnl=0
|
||||||
|
char id=119 x=371 y=59 width=17 height=13 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=0
|
||||||
|
char id=120 x=388 y=59 width=13 height=13 xoffset=-1 yoffset=6 xadvance=11 page=0 chnl=0
|
||||||
|
char id=121 x=403 y=22 width=13 height=17 xoffset=0 yoffset=6 xadvance=11 page=0 chnl=0
|
||||||
|
char id=122 x=401 y=59 width=10 height=13 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=0
|
||||||
|
char id=123 x=45 y=0 width=10 height=21 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=124 x=22 y=0 width=4 height=22 xoffset=1 yoffset=2 xadvance=6 page=0 chnl=0
|
||||||
|
char id=125 x=55 y=0 width=10 height=21 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=126 x=79 y=75 width=14 height=7 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=0
|
||||||
|
char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=17 xadvance=6 page=0 chnl=0
|
||||||
|
char id=161 x=504 y=42 width=4 height=16 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0
|
||||||
|
char id=162 x=501 y=0 width=10 height=19 xoffset=1 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=163 x=70 y=59 width=11 height=16 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=164 x=213 y=59 width=14 height=14 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=0
|
||||||
|
char id=165 x=81 y=59 width=14 height=16 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=166 x=26 y=22 width=4 height=19 xoffset=1 yoffset=3 xadvance=6 page=0 chnl=0
|
||||||
|
char id=167 x=30 y=22 width=10 height=19 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=0
|
||||||
|
char id=168 x=138 y=75 width=8 height=4 xoffset=1 yoffset=2 xadvance=10 page=0 chnl=0
|
||||||
|
char id=169 x=416 y=22 width=16 height=17 xoffset=2 yoffset=2 xadvance=20 page=0 chnl=0
|
||||||
|
char id=170 x=434 y=59 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0
|
||||||
|
char id=171 x=443 y=59 width=11 height=12 xoffset=0 yoffset=6 xadvance=11 page=0 chnl=0
|
||||||
|
char id=172 x=44 y=75 width=15 height=8 xoffset=1 yoffset=8 xadvance=17 page=0 chnl=0
|
||||||
|
char id=173 x=119 y=75 width=7 height=4 xoffset=0 yoffset=10 xadvance=7 page=0 chnl=0
|
||||||
|
char id=174 x=432 y=22 width=16 height=17 xoffset=2 yoffset=2 xadvance=20 page=0 chnl=0
|
||||||
|
char id=175 x=146 y=75 width=8 height=4 xoffset=1 yoffset=2 xadvance=10 page=0 chnl=0
|
||||||
|
char id=176 x=59 y=75 width=8 height=8 xoffset=1 yoffset=3 xadvance=10 page=0 chnl=0
|
||||||
|
char id=177 x=227 y=59 width=14 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
|
||||||
|
char id=178 x=500 y=59 width=7 height=10 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0
|
||||||
|
char id=179 x=0 y=75 width=8 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0
|
||||||
|
char id=180 x=108 y=75 width=7 height=6 xoffset=2 yoffset=1 xadvance=10 page=0 chnl=0
|
||||||
|
char id=181 x=448 y=22 width=12 height=17 xoffset=1 yoffset=6 xadvance=13 page=0 chnl=0
|
||||||
|
char id=182 x=40 y=22 width=11 height=19 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0
|
||||||
|
char id=183 x=115 y=75 width=4 height=5 xoffset=1 yoffset=8 xadvance=6 page=0 chnl=0
|
||||||
|
char id=184 x=93 y=75 width=7 height=7 xoffset=1 yoffset=17 xadvance=10 page=0 chnl=0
|
||||||
|
char id=185 x=8 y=75 width=8 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0
|
||||||
|
char id=186 x=454 y=59 width=10 height=12 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0
|
||||||
|
char id=187 x=464 y=59 width=11 height=12 xoffset=1 yoffset=6 xadvance=12 page=0 chnl=0
|
||||||
|
char id=188 x=69 y=22 width=20 height=18 xoffset=-1 yoffset=2 xadvance=18 page=0 chnl=0
|
||||||
|
char id=189 x=89 y=22 width=19 height=18 xoffset=-1 yoffset=2 xadvance=18 page=0 chnl=0
|
||||||
|
char id=190 x=108 y=22 width=21 height=18 xoffset=-1 yoffset=2 xadvance=19 page=0 chnl=0
|
||||||
|
char id=191 x=95 y=59 width=10 height=16 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=0
|
||||||
|
char id=192 x=311 y=0 width=15 height=20 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0
|
||||||
|
char id=193 x=326 y=0 width=15 height=20 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0
|
||||||
|
char id=194 x=341 y=0 width=15 height=20 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0
|
||||||
|
char id=195 x=65 y=0 width=16 height=21 xoffset=-2 yoffset=-2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=196 x=356 y=0 width=16 height=20 xoffset=-1 yoffset=-1 xadvance=14 page=0 chnl=0
|
||||||
|
char id=197 x=81 y=0 width=15 height=21 xoffset=-1 yoffset=-2 xadvance=13 page=0 chnl=0
|
||||||
|
char id=198 x=105 y=59 width=20 height=16 xoffset=-2 yoffset=3 xadvance=18 page=0 chnl=0
|
||||||
|
char id=199 x=372 y=0 width=13 height=20 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0
|
||||||
|
char id=200 x=385 y=0 width=11 height=20 xoffset=1 yoffset=-1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=201 x=396 y=0 width=11 height=20 xoffset=1 yoffset=-1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=202 x=407 y=0 width=11 height=20 xoffset=1 yoffset=-1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=203 x=418 y=0 width=11 height=20 xoffset=1 yoffset=-1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=204 x=429 y=0 width=7 height=20 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0
|
||||||
|
char id=205 x=436 y=0 width=7 height=20 xoffset=0 yoffset=-1 xadvance=6 page=0 chnl=0
|
||||||
|
char id=206 x=443 y=0 width=8 height=20 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0
|
||||||
|
char id=207 x=451 y=0 width=8 height=20 xoffset=0 yoffset=-1 xadvance=7 page=0 chnl=0
|
||||||
|
char id=208 x=125 y=59 width=16 height=16 xoffset=0 yoffset=3 xadvance=16 page=0 chnl=0
|
||||||
|
char id=209 x=96 y=0 width=13 height=21 xoffset=1 yoffset=-2 xadvance=15 page=0 chnl=0
|
||||||
|
char id=210 x=109 y=0 width=15 height=21 xoffset=0 yoffset=-2 xadvance=15 page=0 chnl=0
|
||||||
|
char id=211 x=124 y=0 width=15 height=21 xoffset=0 yoffset=-2 xadvance=15 page=0 chnl=0
|
||||||
|
char id=212 x=139 y=0 width=15 height=21 xoffset=0 yoffset=-2 xadvance=15 page=0 chnl=0
|
||||||
|
char id=213 x=154 y=0 width=15 height=21 xoffset=0 yoffset=-2 xadvance=15 page=0 chnl=0
|
||||||
|
char id=214 x=459 y=0 width=15 height=20 xoffset=0 yoffset=-1 xadvance=15 page=0 chnl=0
|
||||||
|
char id=215 x=241 y=59 width=14 height=14 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
|
||||||
|
char id=216 x=129 y=22 width=16 height=18 xoffset=-1 yoffset=2 xadvance=15 page=0 chnl=0
|
||||||
|
char id=217 x=169 y=0 width=13 height=21 xoffset=1 yoffset=-2 xadvance=14 page=0 chnl=0
|
||||||
|
char id=218 x=182 y=0 width=13 height=21 xoffset=1 yoffset=-2 xadvance=14 page=0 chnl=0
|
||||||
|
char id=219 x=195 y=0 width=13 height=21 xoffset=1 yoffset=-2 xadvance=14 page=0 chnl=0
|
||||||
|
char id=220 x=474 y=0 width=13 height=20 xoffset=1 yoffset=-1 xadvance=14 page=0 chnl=0
|
||||||
|
char id=221 x=487 y=0 width=14 height=20 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=222 x=141 y=59 width=11 height=16 xoffset=1 yoffset=3 xadvance=11 page=0 chnl=0
|
||||||
|
char id=223 x=460 y=22 width=12 height=17 xoffset=1 yoffset=2 xadvance=13 page=0 chnl=0
|
||||||
|
char id=224 x=145 y=22 width=11 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=225 x=156 y=22 width=11 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=226 x=167 y=22 width=11 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=227 x=472 y=22 width=11 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=228 x=483 y=22 width=11 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=229 x=0 y=22 width=11 height=20 xoffset=0 yoffset=-1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=230 x=411 y=59 width=19 height=13 xoffset=0 yoffset=6 xadvance=19 page=0 chnl=0
|
||||||
|
char id=231 x=494 y=22 width=10 height=17 xoffset=0 yoffset=6 xadvance=10 page=0 chnl=0
|
||||||
|
char id=232 x=178 y=22 width=12 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=233 x=190 y=22 width=12 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=234 x=202 y=22 width=12 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=235 x=0 y=42 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=236 x=214 y=22 width=8 height=18 xoffset=-2 yoffset=1 xadvance=6 page=0 chnl=0
|
||||||
|
char id=237 x=222 y=22 width=8 height=18 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=0
|
||||||
|
char id=238 x=230 y=22 width=9 height=18 xoffset=-2 yoffset=1 xadvance=6 page=0 chnl=0
|
||||||
|
char id=239 x=12 y=42 width=8 height=17 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0
|
||||||
|
char id=240 x=20 y=42 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=241 x=32 y=42 width=11 height=17 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=242 x=239 y=22 width=12 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=243 x=251 y=22 width=12 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=244 x=263 y=22 width=12 height=18 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=0
|
||||||
|
char id=245 x=43 y=42 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=246 x=55 y=42 width=12 height=17 xoffset=0 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=247 x=475 y=59 width=14 height=12 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=0
|
||||||
|
char id=248 x=157 y=59 width=14 height=15 xoffset=-1 yoffset=5 xadvance=12 page=0 chnl=0
|
||||||
|
char id=249 x=275 y=22 width=11 height=18 xoffset=1 yoffset=1 xadvance=13 page=0 chnl=0
|
||||||
|
char id=250 x=286 y=22 width=11 height=18 xoffset=1 yoffset=1 xadvance=13 page=0 chnl=0
|
||||||
|
char id=251 x=297 y=22 width=11 height=18 xoffset=1 yoffset=1 xadvance=13 page=0 chnl=0
|
||||||
|
char id=252 x=67 y=42 width=11 height=17 xoffset=1 yoffset=2 xadvance=13 page=0 chnl=0
|
||||||
|
char id=253 x=26 y=0 width=13 height=22 xoffset=0 yoffset=1 xadvance=11 page=0 chnl=0
|
||||||
|
char id=254 x=208 y=0 width=11 height=21 xoffset=1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
char id=255 x=219 y=0 width=14 height=21 xoffset=-1 yoffset=2 xadvance=12 page=0 chnl=0
|
||||||
|
kernings count=615
|
||||||
|
kerning first=65 second=171 amount=-1
|
||||||
|
kerning first=194 second=87 amount=-1
|
||||||
|
kerning first=86 second=58 amount=-2
|
||||||
|
kerning first=89 second=229 amount=-3
|
||||||
|
kerning first=196 second=65 amount=1
|
||||||
|
kerning first=45 second=66 amount=-1
|
||||||
|
kerning first=221 second=67 amount=-1
|
||||||
|
kerning first=45 second=71 amount=1
|
||||||
|
kerning first=187 second=88 amount=-1
|
||||||
|
kerning first=45 second=74 amount=1
|
||||||
|
kerning first=221 second=79 amount=-1
|
||||||
|
kerning first=45 second=81 amount=1
|
||||||
|
kerning first=65 second=84 amount=-1
|
||||||
|
kerning first=76 second=85 amount=-1
|
||||||
|
kerning first=45 second=86 amount=-1
|
||||||
|
kerning first=66 second=87 amount=-1
|
||||||
|
kerning first=45 second=88 amount=-1
|
||||||
|
kerning first=82 second=89 amount=-1
|
||||||
|
kerning first=65 second=192 amount=1
|
||||||
|
kerning first=84 second=97 amount=-3
|
||||||
|
kerning first=221 second=101 amount=-3
|
||||||
|
kerning first=65 second=102 amount=-1
|
||||||
|
kerning first=70 second=105 amount=-1
|
||||||
|
kerning first=89 second=250 amount=-2
|
||||||
|
kerning first=89 second=117 amount=-2
|
||||||
|
kerning first=192 second=119 amount=-1
|
||||||
|
kerning first=243 second=120 amount=-1
|
||||||
|
kerning first=82 second=253 amount=-1
|
||||||
|
kerning first=84 second=121 amount=-3
|
||||||
|
kerning first=76 second=217 amount=-1
|
||||||
|
kerning first=84 second=187 amount=-1
|
||||||
|
kerning first=192 second=193 amount=1
|
||||||
|
kerning first=65 second=194 amount=1
|
||||||
|
kerning first=221 second=196 amount=-1
|
||||||
|
kerning first=171 second=198 amount=1
|
||||||
|
kerning first=89 second=252 amount=-2
|
||||||
|
kerning first=75 second=210 amount=-1
|
||||||
|
kerning first=76 second=211 amount=-1
|
||||||
|
kerning first=75 second=212 amount=-1
|
||||||
|
kerning first=89 second=225 amount=-3
|
||||||
|
kerning first=84 second=228 amount=-2
|
||||||
|
kerning first=75 second=45 amount=-2
|
||||||
|
kerning first=84 second=231 amount=-3
|
||||||
|
kerning first=75 second=233 amount=-1
|
||||||
|
kerning first=87 second=234 amount=-1
|
||||||
|
kerning first=120 second=235 amount=-1
|
||||||
|
kerning first=80 second=244 amount=-1
|
||||||
|
kerning first=87 second=245 amount=-1
|
||||||
|
kerning first=120 second=246 amount=-1
|
||||||
|
kerning first=86 second=249 amount=-1
|
||||||
|
kerning first=192 second=253 amount=-1
|
||||||
|
kerning first=82 second=67 amount=-1
|
||||||
|
kerning first=221 second=213 amount=-1
|
||||||
|
kerning first=120 second=245 amount=-1
|
||||||
|
kerning first=87 second=111 amount=-1
|
||||||
|
kerning first=84 second=196 amount=-1
|
||||||
|
kerning first=195 second=65 amount=1
|
||||||
|
kerning first=89 second=210 amount=-1
|
||||||
|
kerning first=65 second=119 amount=-1
|
||||||
|
kerning first=192 second=121 amount=-1
|
||||||
|
kerning first=75 second=84 amount=-1
|
||||||
|
kerning first=79 second=46 amount=-1
|
||||||
|
kerning first=82 second=249 amount=-1
|
||||||
|
kerning first=80 second=101 amount=-1
|
||||||
|
kerning first=76 second=213 amount=-1
|
||||||
|
kerning first=221 second=243 amount=-3
|
||||||
|
kerning first=80 second=243 amount=-1
|
||||||
|
kerning first=70 second=225 amount=-2
|
||||||
|
kerning first=107 second=111 amount=-1
|
||||||
|
kerning first=75 second=235 amount=-1
|
||||||
|
kerning first=86 second=45 amount=-1
|
||||||
|
kerning first=87 second=242 amount=-1
|
||||||
|
kerning first=120 second=111 amount=-1
|
||||||
|
kerning first=107 second=249 amount=-1
|
||||||
|
kerning first=86 second=225 amount=-1
|
||||||
|
kerning first=193 second=84 amount=-1
|
||||||
|
kerning first=196 second=118 amount=-1
|
||||||
|
kerning first=75 second=250 amount=-1
|
||||||
|
kerning first=221 second=214 amount=-1
|
||||||
|
kerning first=195 second=119 amount=-1
|
||||||
|
kerning first=70 second=246 amount=-1
|
||||||
|
kerning first=87 second=194 amount=-1
|
||||||
|
kerning first=192 second=194 amount=1
|
||||||
|
kerning first=89 second=233 amount=-3
|
||||||
|
kerning first=120 second=244 amount=-1
|
||||||
|
kerning first=84 second=244 amount=-2
|
||||||
|
kerning first=76 second=121 amount=-2
|
||||||
|
kerning first=84 second=225 amount=-3
|
||||||
|
kerning first=76 second=219 amount=-1
|
||||||
|
kerning first=211 second=221 amount=-1
|
||||||
|
kerning first=195 second=192 amount=1
|
||||||
|
kerning first=107 second=253 amount=-1
|
||||||
|
kerning first=86 second=235 amount=-1
|
||||||
|
kerning first=86 second=250 amount=-1
|
||||||
|
kerning first=80 second=97 amount=-1
|
||||||
|
kerning first=221 second=97 amount=-3
|
||||||
|
kerning first=196 second=253 amount=-1
|
||||||
|
kerning first=82 second=234 amount=-1
|
||||||
|
kerning first=221 second=199 amount=-1
|
||||||
|
kerning first=196 second=171 amount=-1
|
||||||
|
kerning first=70 second=250 amount=-1
|
||||||
|
kerning first=86 second=227 amount=-1
|
||||||
|
kerning first=82 second=192 amount=-1
|
||||||
|
kerning first=187 second=192 amount=-1
|
||||||
|
kerning first=107 second=245 amount=-1
|
||||||
|
kerning first=193 second=65 amount=1
|
||||||
|
kerning first=84 second=117 amount=-3
|
||||||
|
kerning first=221 second=224 amount=-3
|
||||||
|
kerning first=80 second=224 amount=-1
|
||||||
|
kerning first=65 second=121 amount=-1
|
||||||
|
kerning first=89 second=235 amount=-3
|
||||||
|
kerning first=71 second=84 amount=-1
|
||||||
|
kerning first=45 second=87 amount=-1
|
||||||
|
kerning first=87 second=58 amount=-1
|
||||||
|
kerning first=89 second=212 amount=-1
|
||||||
|
kerning first=84 second=171 amount=-2
|
||||||
|
kerning first=187 second=195 amount=-1
|
||||||
|
kerning first=195 second=196 amount=1
|
||||||
|
kerning first=121 second=46 amount=-3
|
||||||
|
kerning first=89 second=199 amount=-1
|
||||||
|
kerning first=213 second=45 amount=1
|
||||||
|
kerning first=107 second=255 amount=-1
|
||||||
|
kerning first=45 second=89 amount=-2
|
||||||
|
kerning first=79 second=88 amount=-1
|
||||||
|
kerning first=187 second=84 amount=-2
|
||||||
|
kerning first=82 second=84 amount=-1
|
||||||
|
kerning first=187 second=193 amount=-1
|
||||||
|
kerning first=195 second=86 amount=-1
|
||||||
|
kerning first=196 second=193 amount=1
|
||||||
|
kerning first=65 second=221 amount=-1
|
||||||
|
kerning first=75 second=214 amount=-1
|
||||||
|
kerning first=84 second=246 amount=-2
|
||||||
|
kerning first=222 second=46 amount=-1
|
||||||
|
kerning first=195 second=121 amount=-1
|
||||||
|
kerning first=193 second=195 amount=1
|
||||||
|
kerning first=45 second=79 amount=1
|
||||||
|
kerning first=80 second=193 amount=-1
|
||||||
|
kerning first=253 second=58 amount=-1
|
||||||
|
kerning first=221 second=193 amount=-1
|
||||||
|
kerning first=171 second=89 amount=-1
|
||||||
|
kerning first=82 second=255 amount=-1
|
||||||
|
kerning first=86 second=229 amount=-1
|
||||||
|
kerning first=87 second=244 amount=-1
|
||||||
|
kerning first=194 second=192 amount=1
|
||||||
|
kerning first=193 second=193 amount=1
|
||||||
|
kerning first=89 second=79 amount=-1
|
||||||
|
kerning first=193 second=253 amount=-1
|
||||||
|
kerning first=210 second=45 amount=1
|
||||||
|
kerning first=192 second=171 amount=-1
|
||||||
|
kerning first=87 second=171 amount=-1
|
||||||
|
kerning first=45 second=210 amount=1
|
||||||
|
kerning first=195 second=194 amount=1
|
||||||
|
kerning first=88 second=67 amount=-1
|
||||||
|
kerning first=194 second=89 amount=-1
|
||||||
|
kerning first=87 second=246 amount=-1
|
||||||
|
kerning first=70 second=117 amount=-1
|
||||||
|
kerning first=82 second=232 amount=-1
|
||||||
|
kerning first=214 second=221 amount=-1
|
||||||
|
kerning first=82 second=86 amount=-1
|
||||||
|
kerning first=187 second=86 amount=-2
|
||||||
|
kerning first=221 second=105 amount=-1
|
||||||
|
kerning first=82 second=46 amount=-1
|
||||||
|
kerning first=75 second=252 amount=-1
|
||||||
|
kerning first=89 second=187 amount=-1
|
||||||
|
kerning first=211 second=88 amount=-1
|
||||||
|
kerning first=196 second=194 amount=1
|
||||||
|
kerning first=86 second=101 amount=-1
|
||||||
|
kerning first=70 second=233 amount=-1
|
||||||
|
kerning first=221 second=226 amount=-3
|
||||||
|
kerning first=80 second=65 amount=-1
|
||||||
|
kerning first=221 second=65 amount=-1
|
||||||
|
kerning first=80 second=226 amount=-1
|
||||||
|
kerning first=87 second=196 amount=-1
|
||||||
|
kerning first=192 second=196 amount=1
|
||||||
|
kerning first=102 second=46 amount=-1
|
||||||
|
kerning first=89 second=101 amount=-3
|
||||||
|
kerning first=70 second=234 amount=-1
|
||||||
|
kerning first=80 second=229 amount=-1
|
||||||
|
kerning first=214 second=88 amount=-1
|
||||||
|
kerning first=86 second=244 amount=-1
|
||||||
|
kerning first=221 second=251 amount=-2
|
||||||
|
kerning first=86 second=252 amount=-1
|
||||||
|
kerning first=214 second=45 amount=1
|
||||||
|
kerning first=76 second=84 amount=-3
|
||||||
|
kerning first=84 second=67 amount=-1
|
||||||
|
kerning first=75 second=101 amount=-1
|
||||||
|
kerning first=75 second=79 amount=-1
|
||||||
|
kerning first=84 second=111 amount=-3
|
||||||
|
kerning first=88 second=213 amount=-1
|
||||||
|
kerning first=84 second=58 amount=-2
|
||||||
|
kerning first=221 second=228 amount=-3
|
||||||
|
kerning first=80 second=228 amount=-1
|
||||||
|
kerning first=66 second=89 amount=-1
|
||||||
|
kerning first=75 second=121 amount=-1
|
||||||
|
kerning first=88 second=235 amount=-1
|
||||||
|
kerning first=82 second=242 amount=-1
|
||||||
|
kerning first=221 second=252 amount=-2
|
||||||
|
kerning first=194 second=121 amount=-1
|
||||||
|
kerning first=82 second=196 amount=-1
|
||||||
|
kerning first=187 second=196 amount=-1
|
||||||
|
kerning first=84 second=45 amount=-2
|
||||||
|
kerning first=89 second=192 amount=-1
|
||||||
|
kerning first=84 second=233 amount=-3
|
||||||
|
kerning first=89 second=195 amount=-1
|
||||||
|
kerning first=194 second=195 amount=1
|
||||||
|
kerning first=87 second=227 amount=-1
|
||||||
|
kerning first=107 second=242 amount=-1
|
||||||
|
kerning first=195 second=84 amount=-1
|
||||||
|
kerning first=84 second=253 amount=-3
|
||||||
|
kerning first=75 second=221 amount=-1
|
||||||
|
kerning first=88 second=232 amount=-1
|
||||||
|
kerning first=86 second=224 amount=-1
|
||||||
|
kerning first=196 second=89 amount=-1
|
||||||
|
kerning first=84 second=114 amount=-3
|
||||||
|
kerning first=87 second=117 amount=-1
|
||||||
|
kerning first=75 second=245 amount=-1
|
||||||
|
kerning first=120 second=234 amount=-1
|
||||||
|
kerning first=107 second=117 amount=-1
|
||||||
|
kerning first=193 second=89 amount=-1
|
||||||
|
kerning first=213 second=221 amount=-1
|
||||||
|
kerning first=76 second=87 amount=-2
|
||||||
|
kerning first=107 second=243 amount=-1
|
||||||
|
kerning first=82 second=243 amount=-1
|
||||||
|
kerning first=45 second=221 amount=-2
|
||||||
|
kerning first=221 second=249 amount=-2
|
||||||
|
kerning first=193 second=192 amount=1
|
||||||
|
kerning first=84 second=193 amount=-1
|
||||||
|
kerning first=84 second=250 amount=-3
|
||||||
|
kerning first=84 second=234 amount=-3
|
||||||
|
kerning first=45 second=211 amount=1
|
||||||
|
kerning first=192 second=221 amount=-1
|
||||||
|
kerning first=82 second=199 amount=-1
|
||||||
|
kerning first=89 second=214 amount=-1
|
||||||
|
kerning first=76 second=221 amount=-3
|
||||||
|
kerning first=75 second=244 amount=-1
|
||||||
|
kerning first=89 second=58 amount=-3
|
||||||
|
kerning first=75 second=220 amount=-1
|
||||||
|
kerning first=82 second=117 amount=-1
|
||||||
|
kerning first=192 second=87 amount=-1
|
||||||
|
kerning first=70 second=196 amount=-2
|
||||||
|
kerning first=211 second=45 amount=1
|
||||||
|
kerning first=87 second=229 amount=-1
|
||||||
|
kerning first=70 second=114 amount=-1
|
||||||
|
kerning first=107 second=251 amount=-1
|
||||||
|
kerning first=87 second=233 amount=-1
|
||||||
|
kerning first=89 second=194 amount=-1
|
||||||
|
kerning first=194 second=194 amount=1
|
||||||
|
kerning first=86 second=245 amount=-1
|
||||||
|
kerning first=193 second=119 amount=-1
|
||||||
|
kerning first=194 second=102 amount=-1
|
||||||
|
kerning first=82 second=111 amount=-1
|
||||||
|
kerning first=196 second=192 amount=1
|
||||||
|
kerning first=221 second=245 amount=-3
|
||||||
|
kerning first=193 second=196 amount=1
|
||||||
|
kerning first=89 second=224 amount=-3
|
||||||
|
kerning first=193 second=86 amount=-1
|
||||||
|
kerning first=208 second=221 amount=-1
|
||||||
|
kerning first=82 second=246 amount=-1
|
||||||
|
kerning first=221 second=235 amount=-3
|
||||||
|
kerning first=80 second=235 amount=-1
|
||||||
|
kerning first=195 second=87 amount=-1
|
||||||
|
kerning first=221 second=212 amount=-1
|
||||||
|
kerning first=255 second=58 amount=-1
|
||||||
|
kerning first=75 second=171 amount=-1
|
||||||
|
kerning first=86 second=195 amount=-1
|
||||||
|
kerning first=89 second=234 amount=-3
|
||||||
|
kerning first=81 second=45 amount=1
|
||||||
|
kerning first=192 second=65 amount=1
|
||||||
|
kerning first=221 second=45 amount=-2
|
||||||
|
kerning first=213 second=89 amount=-1
|
||||||
|
kerning first=70 second=227 amount=-2
|
||||||
|
kerning first=89 second=244 amount=-3
|
||||||
|
kerning first=86 second=255 amount=-1
|
||||||
|
kerning first=86 second=65 amount=-1
|
||||||
|
kerning first=221 second=225 amount=-3
|
||||||
|
kerning first=80 second=225 amount=-1
|
||||||
|
kerning first=75 second=85 amount=-1
|
||||||
|
kerning first=82 second=193 amount=-1
|
||||||
|
kerning first=76 second=253 amount=-2
|
||||||
|
kerning first=194 second=171 amount=-1
|
||||||
|
kerning first=89 second=171 amount=-2
|
||||||
|
kerning first=194 second=86 amount=-1
|
||||||
|
kerning first=86 second=251 amount=-1
|
||||||
|
kerning first=84 second=194 amount=-1
|
||||||
|
kerning first=210 second=46 amount=-1
|
||||||
|
kerning first=196 second=255 amount=-1
|
||||||
|
kerning first=70 second=111 amount=-1
|
||||||
|
kerning first=120 second=233 amount=-1
|
||||||
|
kerning first=84 second=115 amount=-3
|
||||||
|
kerning first=114 second=45 amount=-1
|
||||||
|
kerning first=194 second=221 amount=-1
|
||||||
|
kerning first=45 second=118 amount=-1
|
||||||
|
kerning first=89 second=196 amount=-1
|
||||||
|
kerning first=221 second=232 amount=-3
|
||||||
|
kerning first=114 second=171 amount=-1
|
||||||
|
kerning first=65 second=87 amount=-1
|
||||||
|
kerning first=88 second=199 amount=-1
|
||||||
|
kerning first=245 second=120 amount=-1
|
||||||
|
kerning first=75 second=251 amount=-1
|
||||||
|
kerning first=192 second=102 amount=-1
|
||||||
|
kerning first=70 second=101 amount=-1
|
||||||
|
kerning first=70 second=121 amount=-2
|
||||||
|
kerning first=196 second=119 amount=-1
|
||||||
|
kerning first=196 second=86 amount=-1
|
||||||
|
kerning first=89 second=105 amount=-1
|
||||||
|
kerning first=75 second=218 amount=-1
|
||||||
|
kerning first=80 second=46 amount=-3
|
||||||
|
kerning first=221 second=46 amount=-4
|
||||||
|
kerning first=70 second=58 amount=-1
|
||||||
|
kerning first=89 second=45 amount=-2
|
||||||
|
kerning first=212 second=46 amount=-1
|
||||||
|
kerning first=84 second=227 amount=-2
|
||||||
|
kerning first=70 second=194 amount=-2
|
||||||
|
kerning first=80 second=192 amount=-1
|
||||||
|
kerning first=221 second=192 amount=-1
|
||||||
|
kerning first=89 second=211 amount=-1
|
||||||
|
kerning first=45 second=214 amount=1
|
||||||
|
kerning first=107 second=246 amount=-1
|
||||||
|
kerning first=66 second=86 amount=-1
|
||||||
|
kerning first=87 second=250 amount=-1
|
||||||
|
kerning first=210 second=89 amount=-1
|
||||||
|
kerning first=76 second=220 amount=-1
|
||||||
|
kerning first=89 second=65 amount=-1
|
||||||
|
kerning first=194 second=65 amount=1
|
||||||
|
kerning first=222 second=58 amount=-1
|
||||||
|
kerning first=82 second=252 amount=-1
|
||||||
|
kerning first=193 second=121 amount=-1
|
||||||
|
kerning first=192 second=195 amount=1
|
||||||
|
kerning first=87 second=195 amount=-1
|
||||||
|
kerning first=84 second=199 amount=-1
|
||||||
|
kerning first=87 second=97 amount=-1
|
||||||
|
kerning first=187 second=66 amount=-1
|
||||||
|
kerning first=171 second=86 amount=-1
|
||||||
|
kerning first=82 second=45 amount=-1
|
||||||
|
kerning first=118 second=45 amount=-1
|
||||||
|
kerning first=89 second=251 amount=-2
|
||||||
|
kerning first=75 second=67 amount=-1
|
||||||
|
kerning first=86 second=232 amount=-1
|
||||||
|
kerning first=84 second=101 amount=-3
|
||||||
|
kerning first=120 second=101 amount=-1
|
||||||
|
kerning first=192 second=118 amount=-1
|
||||||
|
kerning first=107 second=250 amount=-1
|
||||||
|
kerning first=196 second=84 amount=-1
|
||||||
|
kerning first=65 second=193 amount=1
|
||||||
|
kerning first=75 second=111 amount=-1
|
||||||
|
kerning first=70 second=245 amount=-1
|
||||||
|
kerning first=70 second=224 amount=-2
|
||||||
|
kerning first=80 second=196 amount=-1
|
||||||
|
kerning first=89 second=228 amount=-3
|
||||||
|
kerning first=86 second=234 amount=-1
|
||||||
|
kerning first=75 second=211 amount=-1
|
||||||
|
kerning first=86 second=253 amount=-1
|
||||||
|
kerning first=84 second=99 amount=-3
|
||||||
|
kerning first=107 second=252 amount=-1
|
||||||
|
kerning first=195 second=193 amount=1
|
||||||
|
kerning first=196 second=196 amount=1
|
||||||
|
kerning first=86 second=46 amount=-2
|
||||||
|
kerning first=102 second=58 amount=-1
|
||||||
|
kerning first=82 second=87 amount=-1
|
||||||
|
kerning first=187 second=87 amount=-1
|
||||||
|
kerning first=75 second=253 amount=-1
|
||||||
|
kerning first=120 second=243 amount=-1
|
||||||
|
kerning first=187 second=89 amount=-2
|
||||||
|
kerning first=221 second=242 amount=-3
|
||||||
|
kerning first=80 second=242 amount=-1
|
||||||
|
kerning first=45 second=84 amount=-2
|
||||||
|
kerning first=76 second=214 amount=-1
|
||||||
|
kerning first=221 second=233 amount=-3
|
||||||
|
kerning first=221 second=195 amount=-1
|
||||||
|
kerning first=171 second=221 amount=-1
|
||||||
|
kerning first=66 second=221 amount=-1
|
||||||
|
kerning first=196 second=121 amount=-1
|
||||||
|
kerning first=82 second=250 amount=-1
|
||||||
|
kerning first=82 second=233 amount=-1
|
||||||
|
kerning first=196 second=102 amount=-1
|
||||||
|
kerning first=76 second=212 amount=-1
|
||||||
|
kerning first=221 second=117 amount=-2
|
||||||
|
kerning first=79 second=89 amount=-1
|
||||||
|
kerning first=70 second=226 amount=-2
|
||||||
|
kerning first=76 second=218 amount=-1
|
||||||
|
kerning first=195 second=253 amount=-1
|
||||||
|
kerning first=84 second=243 amount=-3
|
||||||
|
kerning first=88 second=79 amount=-1
|
||||||
|
kerning first=89 second=111 amount=-3
|
||||||
|
kerning first=84 second=224 amount=-2
|
||||||
|
kerning first=87 second=193 amount=-1
|
||||||
|
kerning first=75 second=255 amount=-1
|
||||||
|
kerning first=89 second=249 amount=-2
|
||||||
|
kerning first=89 second=67 amount=-1
|
||||||
|
kerning first=89 second=227 amount=-3
|
||||||
|
kerning first=193 second=255 amount=-1
|
||||||
|
kerning first=246 second=120 amount=-1
|
||||||
|
kerning first=75 second=234 amount=-1
|
||||||
|
kerning first=192 second=84 amount=-1
|
||||||
|
kerning first=87 second=101 amount=-1
|
||||||
|
kerning first=107 second=233 amount=-1
|
||||||
|
kerning first=84 second=195 amount=-1
|
||||||
|
kerning first=87 second=243 amount=-1
|
||||||
|
kerning first=213 second=46 amount=-1
|
||||||
|
kerning first=75 second=249 amount=-1
|
||||||
|
kerning first=221 second=58 amount=-3
|
||||||
|
kerning first=119 second=46 amount=-2
|
||||||
|
kerning first=79 second=45 amount=1
|
||||||
|
kerning first=194 second=253 amount=-1
|
||||||
|
kerning first=86 second=171 amount=-2
|
||||||
|
kerning first=68 second=89 amount=-1
|
||||||
|
kerning first=80 second=194 amount=-1
|
||||||
|
kerning first=221 second=194 amount=-1
|
||||||
|
kerning first=242 second=120 amount=-1
|
||||||
|
kerning first=195 second=255 amount=-1
|
||||||
|
kerning first=84 second=226 amount=-2
|
||||||
|
kerning first=210 second=88 amount=-1
|
||||||
|
kerning first=89 second=245 amount=-3
|
||||||
|
kerning first=70 second=65 amount=-2
|
||||||
|
kerning first=70 second=97 amount=-2
|
||||||
|
kerning first=70 second=228 amount=-2
|
||||||
|
kerning first=107 second=235 amount=-1
|
||||||
|
kerning first=221 second=229 amount=-3
|
||||||
|
kerning first=80 second=233 amount=-1
|
||||||
|
kerning first=66 second=171 amount=-1
|
||||||
|
kerning first=86 second=194 amount=-1
|
||||||
|
kerning first=87 second=114 amount=-1
|
||||||
|
kerning first=213 second=88 amount=-1
|
||||||
|
kerning first=221 second=234 amount=-3
|
||||||
|
kerning first=80 second=234 amount=-1
|
||||||
|
kerning first=84 second=105 amount=-1
|
||||||
|
kerning first=70 second=251 amount=-1
|
||||||
|
kerning first=194 second=255 amount=-1
|
||||||
|
kerning first=82 second=235 amount=-1
|
||||||
|
kerning first=194 second=118 amount=-1
|
||||||
|
kerning first=120 second=242 amount=-1
|
||||||
|
kerning first=87 second=224 amount=-1
|
||||||
|
kerning first=221 second=171 amount=-2
|
||||||
|
kerning first=70 second=195 amount=-2
|
||||||
|
kerning first=195 second=171 amount=-1
|
||||||
|
kerning first=114 second=46 amount=-2
|
||||||
|
kerning first=255 second=46 amount=-3
|
||||||
|
kerning first=76 second=210 amount=-1
|
||||||
|
kerning first=86 second=192 amount=-1
|
||||||
|
kerning first=84 second=65 amount=-1
|
||||||
|
kerning first=70 second=193 amount=-2
|
||||||
|
kerning first=70 second=253 amount=-2
|
||||||
|
kerning first=87 second=45 amount=-1
|
||||||
|
kerning first=194 second=84 amount=-1
|
||||||
|
kerning first=195 second=118 amount=-1
|
||||||
|
kerning first=75 second=89 amount=-1
|
||||||
|
kerning first=89 second=232 amount=-3
|
||||||
|
kerning first=71 second=89 amount=-1
|
||||||
|
kerning first=212 second=89 amount=-1
|
||||||
|
kerning first=65 second=118 amount=-1
|
||||||
|
kerning first=84 second=251 amount=-3
|
||||||
|
kerning first=87 second=226 amount=-1
|
||||||
|
kerning first=196 second=221 amount=-1
|
||||||
|
kerning first=119 second=58 amount=-1
|
||||||
|
kerning first=212 second=88 amount=-1
|
||||||
|
kerning first=89 second=46 amount=-4
|
||||||
|
kerning first=210 second=221 amount=-1
|
||||||
|
kerning first=86 second=242 amount=-1
|
||||||
|
kerning first=195 second=89 amount=-1
|
||||||
|
kerning first=193 second=102 amount=-1
|
||||||
|
kerning first=75 second=217 amount=-1
|
||||||
|
kerning first=221 second=211 amount=-1
|
||||||
|
kerning first=221 second=246 amount=-3
|
||||||
|
kerning first=65 second=86 amount=-1
|
||||||
|
kerning first=75 second=232 amount=-1
|
||||||
|
kerning first=194 second=119 amount=-1
|
||||||
|
kerning first=80 second=246 amount=-1
|
||||||
|
kerning first=102 second=171 amount=-1
|
||||||
|
kerning first=86 second=121 amount=-1
|
||||||
|
kerning first=75 second=242 amount=-1
|
||||||
|
kerning first=70 second=243 amount=-1
|
||||||
|
kerning first=193 second=87 amount=-1
|
||||||
|
kerning first=86 second=111 amount=-1
|
||||||
|
kerning first=82 second=121 amount=-1
|
||||||
|
kerning first=84 second=46 amount=-2
|
||||||
|
kerning first=88 second=233 amount=-1
|
||||||
|
kerning first=192 second=86 amount=-1
|
||||||
|
kerning first=88 second=234 amount=-1
|
||||||
|
kerning first=75 second=199 amount=-1
|
||||||
|
kerning first=45 second=213 amount=1
|
||||||
|
kerning first=68 second=221 amount=-1
|
||||||
|
kerning first=70 second=255 amount=-2
|
||||||
|
kerning first=221 second=250 amount=-2
|
||||||
|
kerning first=86 second=243 amount=-1
|
||||||
|
kerning first=65 second=196 amount=1
|
||||||
|
kerning first=87 second=65 amount=-1
|
||||||
|
kerning first=88 second=212 amount=-1
|
||||||
|
kerning first=194 second=196 amount=1
|
||||||
|
kerning first=87 second=252 amount=-1
|
||||||
|
kerning first=70 second=235 amount=-1
|
||||||
|
kerning first=107 second=121 amount=-1
|
||||||
|
kerning first=114 second=120 amount=-1
|
||||||
|
kerning first=75 second=219 amount=-1
|
||||||
|
kerning first=196 second=87 amount=-1
|
||||||
|
kerning first=102 second=45 amount=-1
|
||||||
|
kerning first=82 second=101 amount=-1
|
||||||
|
kerning first=221 second=227 amount=-3
|
||||||
|
kerning first=80 second=227 amount=-1
|
||||||
|
kerning first=75 second=243 amount=-1
|
||||||
|
kerning first=88 second=210 amount=-1
|
||||||
|
kerning first=87 second=249 amount=-1
|
||||||
|
kerning first=89 second=242 amount=-3
|
||||||
|
kerning first=70 second=232 amount=-1
|
||||||
|
kerning first=214 second=89 amount=-1
|
||||||
|
kerning first=221 second=210 amount=-1
|
||||||
|
kerning first=82 second=244 amount=-1
|
||||||
|
kerning first=211 second=89 amount=-1
|
||||||
|
kerning first=86 second=246 amount=-1
|
||||||
|
kerning first=82 second=58 amount=-1
|
||||||
|
kerning first=70 second=46 amount=-3
|
||||||
|
kerning first=211 second=46 amount=-1
|
||||||
|
kerning first=195 second=221 amount=-1
|
||||||
|
kerning first=80 second=245 amount=-1
|
||||||
|
kerning first=107 second=101 amount=-1
|
||||||
|
kerning first=193 second=221 amount=-1
|
||||||
|
kerning first=82 second=195 amount=-1
|
||||||
|
kerning first=65 second=65 amount=1
|
||||||
|
kerning first=89 second=243 amount=-3
|
||||||
|
kerning first=80 second=111 amount=-1
|
||||||
|
kerning first=86 second=117 amount=-1
|
||||||
|
kerning first=221 second=111 amount=-3
|
||||||
|
kerning first=84 second=235 amount=-3
|
||||||
|
kerning first=84 second=255 amount=-3
|
||||||
|
kerning first=84 second=229 amount=-2
|
||||||
|
kerning first=70 second=192 amount=-2
|
||||||
|
kerning first=88 second=171 amount=-1
|
||||||
|
kerning first=82 second=171 amount=-1
|
||||||
|
kerning first=193 second=171 amount=-1
|
||||||
|
kerning first=82 second=194 amount=-1
|
||||||
|
kerning first=187 second=194 amount=-1
|
||||||
|
kerning first=45 second=212 amount=1
|
||||||
|
kerning first=65 second=253 amount=-1
|
||||||
|
kerning first=82 second=245 amount=-1
|
||||||
|
kerning first=76 second=86 amount=-2
|
||||||
|
kerning first=86 second=228 amount=-1
|
||||||
|
kerning first=86 second=196 amount=-1
|
||||||
|
kerning first=86 second=233 amount=-1
|
||||||
|
kerning first=84 second=249 amount=-3
|
||||||
|
kerning first=88 second=45 amount=-1
|
||||||
|
kerning first=79 second=221 amount=-1
|
||||||
|
kerning first=88 second=211 amount=-1
|
||||||
|
kerning first=89 second=97 amount=-3
|
||||||
|
kerning first=87 second=228 amount=-1
|
||||||
|
kerning first=192 second=255 amount=-1
|
||||||
|
kerning first=171 second=84 amount=-1
|
||||||
|
kerning first=84 second=245 amount=-2
|
||||||
|
kerning first=89 second=213 amount=-1
|
||||||
|
kerning first=86 second=187 amount=-1
|
||||||
|
kerning first=75 second=117 amount=-1
|
||||||
|
kerning first=76 second=79 amount=-1
|
||||||
|
kerning first=65 second=89 amount=-1
|
||||||
|
kerning first=70 second=229 amount=-2
|
||||||
|
kerning first=253 second=46 amount=-3
|
||||||
|
kerning first=86 second=97 amount=-1
|
||||||
|
kerning first=80 second=232 amount=-1
|
||||||
|
kerning first=107 second=234 amount=-1
|
||||||
|
kerning first=70 second=244 amount=-1
|
||||||
|
kerning first=84 second=192 amount=-1
|
||||||
|
kerning first=107 second=244 amount=-1
|
||||||
|
kerning first=86 second=226 amount=-1
|
||||||
|
kerning first=70 second=249 amount=-1
|
||||||
|
kerning first=75 second=246 amount=-1
|
||||||
|
kerning first=70 second=252 amount=-1
|
||||||
|
kerning first=193 second=118 amount=-1
|
||||||
|
kerning first=87 second=232 amount=-1
|
||||||
|
kerning first=118 second=46 amount=-1
|
||||||
|
kerning first=244 second=120 amount=-1
|
||||||
|
kerning first=84 second=119 amount=-3
|
||||||
|
kerning first=89 second=193 amount=-1
|
||||||
|
kerning first=121 second=58 amount=-1
|
||||||
|
kerning first=194 second=193 amount=1
|
||||||
|
kerning first=74 second=45 amount=-1
|
||||||
|
kerning first=87 second=46 amount=-2
|
||||||
|
kerning first=70 second=242 amount=-1
|
||||||
|
kerning first=87 second=225 amount=-1
|
||||||
|
kerning first=71 second=221 amount=-1
|
||||||
|
kerning first=75 second=87 amount=-1
|
||||||
|
kerning first=212 second=221 amount=-1
|
||||||
|
kerning first=65 second=255 amount=-1
|
||||||
|
kerning first=111 second=120 amount=-1
|
||||||
|
kerning first=87 second=192 amount=-1
|
||||||
|
kerning first=192 second=192 amount=1
|
||||||
|
kerning first=75 second=213 amount=-1
|
||||||
|
kerning first=88 second=101 amount=-1
|
||||||
|
kerning first=88 second=214 amount=-1
|
||||||
|
kerning first=187 second=221 amount=-2
|
||||||
|
kerning first=82 second=221 amount=-1
|
||||||
|
kerning first=82 second=65 amount=-1
|
||||||
|
kerning first=187 second=65 amount=-1
|
||||||
|
kerning first=195 second=195 amount=1
|
||||||
|
kerning first=80 second=195 amount=-1
|
||||||
|
kerning first=208 second=89 amount=-1
|
||||||
|
kerning first=214 second=46 amount=-1
|
||||||
|
kerning first=212 second=45 amount=1
|
||||||
|
kerning first=87 second=251 amount=-1
|
||||||
|
kerning first=84 second=252 amount=-3
|
||||||
|
kerning first=76 second=255 amount=-2
|
||||||
|
kerning first=118 second=58 amount=-1
|
||||||
|
kerning first=193 second=194 amount=1
|
||||||
|
kerning first=76 second=89 amount=-3
|
||||||
|
kerning first=87 second=235 amount=-1
|
||||||
|
kerning first=82 second=251 amount=-1
|
||||||
|
kerning first=86 second=193 amount=-1
|
||||||
|
kerning first=221 second=187 amount=-1
|
||||||
|
kerning first=195 second=102 amount=-1
|
||||||
|
kerning first=120 second=232 amount=-1
|
||||||
|
kerning first=107 second=232 amount=-1
|
||||||
|
kerning first=84 second=232 amount=-3
|
||||||
|
kerning first=89 second=246 amount=-3
|
||||||
|
kerning first=221 second=244 amount=-3
|
||||||
|
kerning first=196 second=195 amount=1
|
||||||
|
kerning first=192 second=89 amount=-1
|
||||||
|
kerning first=84 second=242 amount=-2
|
||||||
|
kerning first=65 second=195 amount=1
|
||||||
|
kerning first=89 second=226 amount=-3
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,248 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const playerArrayContains = require('./util').playerArrayContains;
|
||||||
|
|
||||||
|
const WHITESPACE = ' ';
|
||||||
|
|
||||||
|
const parseWarLog = (lineArray, war) => {
|
||||||
|
const NAME_TOO_LONG_ERROR = 'Error: ENAMETOOLONG: name too long, open \'';
|
||||||
|
|
||||||
|
const stats = {
|
||||||
|
war: war,
|
||||||
|
clean: [],
|
||||||
|
budget: [],
|
||||||
|
points: [],
|
||||||
|
kills: [],
|
||||||
|
respawn: [],
|
||||||
|
revive: [],
|
||||||
|
flag: [],
|
||||||
|
transport: [],
|
||||||
|
players: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const addPlayerIfNotExists = (inputPlayer) => {
|
||||||
|
const player = getPlayerAndFractionFromString(inputPlayer);
|
||||||
|
if (player && player.name && player.fraction && !playerArrayContains(stats.players, player)) {
|
||||||
|
player['warId'] = war._id;
|
||||||
|
stats.players.push(player);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
lineArray.some(line => {
|
||||||
|
/**
|
||||||
|
* sanitize nameTooLongError coming up in first line
|
||||||
|
*/
|
||||||
|
if (line.includes(NAME_TOO_LONG_ERROR)) {
|
||||||
|
line = line.substring(line.indexOf(NAME_TOO_LONG_ERROR) + NAME_TOO_LONG_ERROR.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KILLS
|
||||||
|
*/
|
||||||
|
if (line.includes('(Abschuss)') && !line.includes('Fahrzeug')) {
|
||||||
|
stats.clean.push(line);
|
||||||
|
const shooterString = line.substring(line.lastIndexOf(' von: ') + 6, line.lastIndexOf('."'));
|
||||||
|
const shooter = getPlayerAndFractionFromString(shooterString);
|
||||||
|
const targetString = line.substring(line.lastIndexOf(' --- ') + 5, line.lastIndexOf(' von:'));
|
||||||
|
const target = getPlayerAndFractionFromString(targetString);
|
||||||
|
|
||||||
|
stats.kills.push({
|
||||||
|
war: war._id,
|
||||||
|
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
|
||||||
|
shooter: shooter ? shooter.name : null,
|
||||||
|
target: target ? target.name : null,
|
||||||
|
friendlyFire: shooter ? target.fraction === shooter.fraction : false,
|
||||||
|
fraction: shooter ? shooter.fraction : 'NONE'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BUDGET
|
||||||
|
*/
|
||||||
|
else if (line.includes('(Budget)')) {
|
||||||
|
stats.clean.push(line);
|
||||||
|
const budg = line.split(WHITESPACE);
|
||||||
|
if (line.includes('Startbudget')) {
|
||||||
|
stats.war['budgetBlufor'] = transformMoneyString(budg[9]);
|
||||||
|
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('/');
|
||||||
|
stats.war.date = new Date(dateString[0], dateString[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));
|
||||||
|
stats.war.endDate = getFullTimeDate(war.date, budg[5]);
|
||||||
|
} else {
|
||||||
|
stats.budget.push(getBudgetEntry(budg, war._id, war.date));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FLAG
|
||||||
|
*/
|
||||||
|
else if (line.includes('(Fahne)') && !line.includes('Dominator')) {
|
||||||
|
stats.clean.push(line);
|
||||||
|
const playerName = line.substring(line.lastIndexOf('rt von ') + 7).slice(0, -2);
|
||||||
|
const flagFraction = line.includes('NATO Flagge') ? 'BLUFOR' : 'OPFOR';
|
||||||
|
const capture = !!line.includes('Flagge erobert');
|
||||||
|
|
||||||
|
stats.flag.push({
|
||||||
|
war: war._id,
|
||||||
|
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
|
||||||
|
player: playerName,
|
||||||
|
flagFraction: flagFraction,
|
||||||
|
capture: capture
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POINTS
|
||||||
|
*/
|
||||||
|
else if (line.includes('(Punkte)')) {
|
||||||
|
stats.clean.push(line);
|
||||||
|
const pt = line.split(WHITESPACE);
|
||||||
|
|
||||||
|
if (line.includes('Endpunktestand')) {
|
||||||
|
stats.war['ptBlufor'] = parseInt(pt[9]);
|
||||||
|
stats.war['ptOpfor'] = parseInt(pt[12].slice(0, -1));
|
||||||
|
// EXIT LOOP
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
stats.points.push(getPointsEntry(pt, line, war._id, war.date))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RESPAWN
|
||||||
|
*/
|
||||||
|
else if (line.includes('(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)')) {
|
||||||
|
stats.clean.push(line);
|
||||||
|
const stabilized = !!line.includes('stabilisiert."');
|
||||||
|
const medicName = line.substring(line.lastIndexOf('wurde von ') + 10,
|
||||||
|
line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt'));
|
||||||
|
const medic = getPlayerAndFractionFromString(medicName);
|
||||||
|
const patientName = line.substring(line.lastIndexOf('--- ') + 4, line.lastIndexOf(' wurde von'));
|
||||||
|
const patient = getPlayerAndFractionFromString(patientName);
|
||||||
|
|
||||||
|
stats.revive.push({
|
||||||
|
war: war._id,
|
||||||
|
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
|
||||||
|
stabilized: stabilized,
|
||||||
|
medic: medic.name,
|
||||||
|
patient: patient.name,
|
||||||
|
fraction: medic.fraction
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRANSPORT
|
||||||
|
*/
|
||||||
|
else if (line.includes('(Transport)')) {
|
||||||
|
stats.clean.push(line);
|
||||||
|
const driverString = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(' eingeflogen'));
|
||||||
|
const driver = getPlayerAndFractionFromString(driverString);
|
||||||
|
const passengerString = line.substring(line.lastIndexOf('--- ') + 3, line.lastIndexOf(' wurde von'));
|
||||||
|
const passenger = getPlayerAndFractionFromString(passengerString);
|
||||||
|
const distance = parseInt(line.substring(line.lastIndexOf('eingeflogen (') + 13, line.lastIndexOf('m)') - 1));
|
||||||
|
|
||||||
|
stats.transport.push({
|
||||||
|
war: war._id,
|
||||||
|
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
|
||||||
|
driver: driver ? driver.name : null,
|
||||||
|
passenger: passenger ? passenger.name : null,
|
||||||
|
fraction: driver ? driver.fraction : 'NONE',
|
||||||
|
distance: distance
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PLAYERS
|
||||||
|
*/
|
||||||
|
else if (line.includes('(Fraktionsuebersicht)')) {
|
||||||
|
const playerString = line.substring(line.lastIndexOf('--- ') + 4, line.lastIndexOf(', PUID'));
|
||||||
|
addPlayerIfNotExists(playerString)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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]['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.war.playersBlufor = stats.players.filter(player => player.fraction === 'BLUFOR').length;
|
||||||
|
stats.war.playersOpfor = stats.players.filter(player => player.fraction === 'OPFOR').length;
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRespawnEntry = (respawn, playerName, warId, warDate) => {
|
||||||
|
return {
|
||||||
|
war: warId,
|
||||||
|
time: getFullTimeDate(warDate, respawn[5]),
|
||||||
|
player: playerName
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPointsEntry = (pt, line, warId, warDate) => {
|
||||||
|
return {
|
||||||
|
war: warId,
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBudgetEntry = (budg, warId, warDate) => {
|
||||||
|
return {
|
||||||
|
war: warId,
|
||||||
|
time: getFullTimeDate(warDate, budg[5]),
|
||||||
|
fraction: budg[7] === 'NATO' ? 'BLUFOR' : 'OPFOR',
|
||||||
|
oldBudget: transformMoneyString(budg[9]),
|
||||||
|
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 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') {
|
||||||
|
return {name: name, fraction: fraction};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformMoneyString = (budgetString) => {
|
||||||
|
if (!budgetString.includes('e+')) {
|
||||||
|
return parseInt(budgetString);
|
||||||
|
}
|
||||||
|
const budget = budgetString.split('e+');
|
||||||
|
return Math.round(parseFloat(budget[0]) * Math.pow(10, parseInt(budget[1])));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFullTimeDate = (date, timeString) => {
|
||||||
|
const returnDate = new Date(date);
|
||||||
|
const time = timeString.split(':');
|
||||||
|
returnDate.setHours(time[0]);
|
||||||
|
returnDate.setMinutes(time[1]);
|
||||||
|
return returnDate;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = parseWarLog;
|
|
@ -0,0 +1,267 @@
|
||||||
|
"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 async = require('async');
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const UserModel = require('../models/user');
|
||||||
|
const AwardingModel = require('../models/awarding');
|
||||||
|
const RankModel = require('../models/rank');
|
||||||
|
|
||||||
|
// http error code table
|
||||||
|
const codes = require('../routes/http-codes');
|
||||||
|
|
||||||
|
// standard input/output file extension
|
||||||
|
const fileExt = '.png';
|
||||||
|
const resourceDir = __dirname + '/../resource/';
|
||||||
|
|
||||||
|
|
||||||
|
let createSignature = (userId, res, next) => {
|
||||||
|
|
||||||
|
let loadedImage;
|
||||||
|
let user;
|
||||||
|
|
||||||
|
if (!String(userId).match(/^[0-9a-fA-F]{24}$/)) {
|
||||||
|
let error = new Error('no valid ID ' + userId);
|
||||||
|
error.status = codes.wrongdatatyperequest;
|
||||||
|
return next(error);
|
||||||
|
}
|
||||||
|
UserModel.findById(userId, ['username', 'rankLvl', 'squadId'])
|
||||||
|
.populate('squadId', ['name', 'fraction'])
|
||||||
|
.exec()
|
||||||
|
.then((resUser) => {
|
||||||
|
user = resUser;
|
||||||
|
let platePath;
|
||||||
|
if (resUser && resUser.squadId && resUser.squadId.fraction === 'BLUFOR') {
|
||||||
|
platePath = __dirname + '/backplate/blufor' + fileExt;
|
||||||
|
} else if (resUser && resUser.squadId && resUser.squadId.fraction === 'OPFOR') {
|
||||||
|
platePath = __dirname + '/backplate/opfor' + fileExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kill process on undefined platePath
|
||||||
|
if (!platePath) {
|
||||||
|
throw new Error('Fraction not defined for user with id ' + userId);
|
||||||
|
}
|
||||||
|
return jimp.read(platePath)
|
||||||
|
})
|
||||||
|
.then((image) => {
|
||||||
|
loadedImage = image;
|
||||||
|
}).then(() => {
|
||||||
|
return jimp.loadFont(__dirname + '/font/DEVAJU_SANS_19.fnt');
|
||||||
|
})
|
||||||
|
.then((font) => {
|
||||||
|
loadedImage.print(font, 128, 8, user.username)
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return jimp.loadFont(__dirname + '/font/DEJAVU_SANS_13.fnt');
|
||||||
|
})
|
||||||
|
.then((font) => {
|
||||||
|
loadedImage.print(font, 128, 35, user.squadId.name);
|
||||||
|
return font;
|
||||||
|
})
|
||||||
|
.then((font) => {
|
||||||
|
let rankH, rankW, rankX, rankY;
|
||||||
|
|
||||||
|
RankModel.findOne({'level': user.rankLvl, 'fraction': user.squadId.fraction}, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
if (user.squadId.fraction === 'BLUFOR') {
|
||||||
|
rankW = 25;
|
||||||
|
rankH = 60;
|
||||||
|
rankX = 36;
|
||||||
|
rankY = 34;
|
||||||
|
} else {
|
||||||
|
rankW = 37;
|
||||||
|
rankH = 58;
|
||||||
|
rankX = 30;
|
||||||
|
rankY = 34;
|
||||||
|
}
|
||||||
|
|
||||||
|
jimp.read(resourceDir + 'rank/' + result._id + fileExt)
|
||||||
|
.then((rankImage) => {
|
||||||
|
rankImage.resize(rankW, rankH);
|
||||||
|
loadedImage
|
||||||
|
.print(font, 128, 55, result.name)
|
||||||
|
.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);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* query decorations according to user id and
|
||||||
|
* add all graphics into given image
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
* @param loadedImage - background image
|
||||||
|
* @param res
|
||||||
|
* @param next
|
||||||
|
*/
|
||||||
|
let addDecorationsAndSave = (userId, loadedImage, res, next) => {
|
||||||
|
const medalW = 21;
|
||||||
|
const medalH = 40;
|
||||||
|
const ribbonW = 53;
|
||||||
|
const ribbonH = 15;
|
||||||
|
let medalPx = 630;
|
||||||
|
let medalPy = 5;
|
||||||
|
let ribbonPx = 598;
|
||||||
|
let ribbonPy = 95;
|
||||||
|
|
||||||
|
AwardingModel.find({
|
||||||
|
'userId': userId,
|
||||||
|
'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
|
||||||
|
awardings.sort((a1, a2) => {
|
||||||
|
if (!a1.decorationId.isMedal && !a2.decorationId.isMedal) {
|
||||||
|
if (a1.decorationId.fraction === a2.decorationId.fraction) {
|
||||||
|
if (a1.date !== a2.date) {
|
||||||
|
if (a1.date < a2.date) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a1.date > a2.date) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (a1.decorationId.fraction === 'GLOBAL' && a2.decorationId.fraction !== 'GLOBAL') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a2.decorationId.fraction === 'GLOBAL' && a1.decorationId.fraction !== 'GLOBAL') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a1.decorationId.isMedal !== a2.decorationId.isMedal) {
|
||||||
|
if (a1.decorationId.isMedal && !a2.decorationId.isMedal) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!a1.decorationId.isMedal && a2.decorationId.isMedal) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a1.decorationId.isMedal && a2.decorationId.isMedal) {
|
||||||
|
if (a1.date !== a2.date) {
|
||||||
|
if (a1.date < a2.date) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a1.date > a2.date) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
})
|
||||||
|
}, (err) => {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
compareImagesAndSave(loadedImage, userId, res, next);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
if (sig1 !== sig2) {
|
||||||
|
saveJimpImageAndCompress(generatedImage, userId, res, next)
|
||||||
|
} else {
|
||||||
|
res.locals.items = {status: 'nothing to do'};
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
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'})
|
||||||
|
]
|
||||||
|
}).then((files) => {
|
||||||
|
res.locals.items = {status: 'success'};
|
||||||
|
return next();
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = createSignature;
|
|
@ -1,9 +1,4 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const isSteamUUID = (input) => {
|
|
||||||
const steamUIDPattern = new RegExp('[0-9]{17}');
|
|
||||||
return steamUIDPattern.test(input);
|
|
||||||
};
|
|
||||||
|
|
||||||
const sortCollectionBy = (collection, key) => {
|
const sortCollectionBy = (collection, key) => {
|
||||||
collection.sort((a, b) => {
|
collection.sort((a, b) => {
|
||||||
|
@ -17,9 +12,7 @@ const sortCollectionBy = (collection, key) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const playerArrayContains = (arr, item) => {
|
const playerArrayContains = (arr, item) => {
|
||||||
let i = 0;
|
let i = 0, count = arr.length, matchFound = false;
|
||||||
let count = arr.length;
|
|
||||||
let matchFound = false;
|
|
||||||
|
|
||||||
for (; i < count; i++) {
|
for (; i < count; i++) {
|
||||||
if (arr[i].name === item.name && arr[i].fraction === item.fraction) {
|
if (arr[i].name === item.name && arr[i].fraction === item.fraction) {
|
||||||
|
@ -39,10 +32,11 @@ const timeStringToDecimal = (timeString) => {
|
||||||
return hour + (sek / 3600);
|
return hour + (sek / 3600);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const decimalToTimeString = (decimal) => {
|
const decimalToTimeString = (decimal) => {
|
||||||
const hours = parseInt(decimal.toString().split('.')[0]);
|
const hours = parseInt(decimal.toString().split(".")[0]);
|
||||||
const minutesFloat = ((decimal % 1) * 3600) / 60;
|
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);
|
const seconds = Math.round((minutesFloat - parseInt(minutes)) * 60);
|
||||||
|
|
||||||
return (hours < 10 ? '0' + hours : hours) + ':' +
|
return (hours < 10 ? '0' + hours : hours) + ':' +
|
||||||
|
@ -50,16 +44,7 @@ const decimalToTimeString = (decimal) => {
|
||||||
(seconds < 10 ? '0' + seconds : seconds);
|
(seconds < 10 ? '0' + seconds : seconds);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFileBuffer = (file) => {
|
|
||||||
if (file.encoding === 'base64') {
|
|
||||||
return Buffer.from(file.buffer.toString(), file.encoding);
|
|
||||||
}
|
|
||||||
return Buffer.from(file.buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.isSteamUUID = isSteamUUID;
|
|
||||||
exports.sortCollection = sortCollectionBy;
|
exports.sortCollection = sortCollectionBy;
|
||||||
exports.playerArrayContains = playerArrayContains;
|
exports.playerArrayContains = playerArrayContains;
|
||||||
exports.timeStringToDecimal = timeStringToDecimal;
|
exports.timeStringToDecimal = timeStringToDecimal;
|
||||||
exports.decimalToTimeString = decimalToTimeString;
|
exports.decimalToTimeString = decimalToTimeString;
|
||||||
exports.getFileBuffer = getFileBuffer;
|
|
|
@ -4,18 +4,18 @@
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
# array of available collection names
|
# array of available collection names
|
||||||
col=(app_user awarding campaign decoration logBudget logFlag logKill logPlayerCount logPoints logRespawn logRevive logServerFps logTransport logVehicle player promotion rank squad user war)
|
col=(app_user awarding campaign decoration logBudget logFlag logKill logPoints logRespawn logRevive logTransport player promotion rank squad user war )
|
||||||
|
|
||||||
if [ -z "$1" ]
|
if [ -z "$1" ]
|
||||||
then
|
then
|
||||||
DATE=$(date '+%Y-%m-%d')
|
DATE=$(date '+%Y-%m-%d')
|
||||||
mkdir -p ${DATE}/resource
|
mkdir -p ${DATE}/resource
|
||||||
cp -R ../server/resource/ ${DATE}/
|
cp -R ../api/resource/ ${DATE}/
|
||||||
else
|
else
|
||||||
DATE=${1}
|
DATE=${1}
|
||||||
tar -xzf ${DATE}.tar.gz
|
tar -xzf ${DATE}.tar.gz
|
||||||
rm -rf ../server/resource
|
rm -rf ../api/resource
|
||||||
cp -Rv ${DATE}/resource ../server/
|
cp -Rv ${DATE}/resource ../api/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for i in "${col[@]}"
|
for i in "${col[@]}"
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
|
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
echo "########################################################"
|
#####################################################
|
||||||
echo "###### INSTALLING ALL REQUIRED 3RD-PARTY SOFTWARE ######"
|
###### INSTALL ALL REQUIRED 3RD-PARTY SOFTWARE ######
|
||||||
echo "########################################################"
|
#####################################################
|
||||||
echo "# MONGO DB COMMUNITY"
|
# MONGO DB COMMUNITY
|
||||||
echo "# NPM"
|
# NPM
|
||||||
echo "# NODE"
|
# NODE
|
||||||
|
|
||||||
|
|
||||||
# mongodb key & repo
|
# mongodb key & repo
|
||||||
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
|
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
|
||||||
|
@ -25,26 +26,13 @@ sudo systemctl enable mongod.service
|
||||||
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
|
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
|
||||||
source ~/.nvm/nvm.sh
|
source ~/.nvm/nvm.sh
|
||||||
nvm install stable
|
nvm install stable
|
||||||
sudo ln -sf ~/.nvm/versions/node/$(node -v)/bin/node /usr/bin/node
|
sudo ln -s ~/.nvm/versions/node/$(node -v)/bin/node /usr/bin/node
|
||||||
|
|
||||||
# upgrade to latest npm version
|
# upgrade to latest npm version
|
||||||
sudo npm install -g npm@latest
|
sudo npm install -g npm@latest
|
||||||
|
|
||||||
if [ "${1}" == "prod" ]; then
|
if [ "${1}" == "prod" ]; then
|
||||||
echo "########################################################"
|
|
||||||
echo "################ SETTING UP APPLICATION ################"
|
|
||||||
echo "########################################################"
|
|
||||||
cd ./../..
|
|
||||||
npm install
|
|
||||||
npm run deploy-static:prod
|
|
||||||
echo "########################################################"
|
|
||||||
echo "####### INSTALLING PM2 AND INGRAIN AUTO STARTUP ########"
|
|
||||||
echo "########################################################"
|
|
||||||
sudo npm install -g pm2
|
sudo npm install -g pm2
|
||||||
pm2 start pm2-start.json
|
pm2 start ./../../pm2-start.json
|
||||||
pm2 save
|
|
||||||
pm2 startup systemd
|
pm2 startup systemd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo " ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑"
|
|
||||||
echo "IMPORTANT: Run the sudo command printed above to finish the pm2 setup"
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<code_scheme name="OPT-CC" version="173">
|
|
||||||
<option name="FORMATTER_TAGS_ENABLED" value="true" />
|
|
||||||
<JSCodeStyleSettings version="0">
|
|
||||||
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
|
|
||||||
</JSCodeStyleSettings>
|
|
||||||
<TypeScriptCodeStyleSettings version="0">
|
|
||||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
|
||||||
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
|
|
||||||
</TypeScriptCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="JavaScript">
|
|
||||||
<option name="RIGHT_MARGIN" value="120" />
|
|
||||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
|
||||||
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
|
||||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
|
||||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
|
||||||
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
|
||||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
|
||||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
|
||||||
<option name="WRAP_COMMENTS" value="true" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="TypeScript">
|
|
||||||
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
|
||||||
<option name="WRAP_COMMENTS" value="true" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
Binary file not shown.
|
@ -1,29 +1,32 @@
|
||||||
{
|
{
|
||||||
"name": "opt-cc",
|
"name": "opt-cc",
|
||||||
"version": "1.9.3",
|
"version": "1.6.7",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "5.5.2",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz",
|
||||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
"integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"co": "^4.6.0",
|
"co": "4.6.0",
|
||||||
"fast-deep-equal": "^1.0.0",
|
"fast-deep-equal": "1.0.0",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "2.0.0",
|
||||||
"json-schema-traverse": "^0.3.0"
|
"json-schema-traverse": "0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
|
||||||
|
"integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.1",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz",
|
||||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
"integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"requires": {
|
|
||||||
"color-convert": "^1.9.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"asn1": {
|
"asn1": {
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
|
@ -50,26 +53,29 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"aws4": {
|
"aws4": {
|
||||||
"version": "1.7.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||||
"integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
|
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"bcrypt-pbkdf": {
|
"bcrypt-pbkdf": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
|
||||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"tweetnacl": "^0.14.3"
|
"tweetnacl": "0.14.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"builtin-modules": {
|
"boom": {
|
||||||
"version": "1.1.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
|
||||||
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
|
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"hoek": "4.2.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"caseless": {
|
"caseless": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
|
@ -78,24 +84,23 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.4.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
|
||||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
"integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "^3.2.1",
|
"ansi-styles": "1.1.0",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "1.0.5",
|
||||||
"supports-color": "^5.3.0"
|
"has-ansi": "0.1.0",
|
||||||
|
"strip-ansi": "0.3.0",
|
||||||
|
"supports-color": "0.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "5.4.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz",
|
||||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
"integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"requires": {
|
|
||||||
"has-flag": "^3.0.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -105,28 +110,13 @@
|
||||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"color-convert": {
|
|
||||||
"version": "1.9.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
|
|
||||||
"integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"color-name": "1.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-name": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
|
|
||||||
"integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"combined-stream": {
|
"combined-stream": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
|
||||||
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
|
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
|
@ -136,26 +126,25 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"concurrently": {
|
"concurrently": {
|
||||||
"version": "3.6.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.5.0.tgz",
|
||||||
"integrity": "sha512-6XiIYtYzmGEccNZFkih5JOH92jLA4ulZArAYy5j1uDSdrPLB3KzdE8GW7t2fHPcg9ry2+5LP9IEYzXzxw9lFdA==",
|
"integrity": "sha1-jPG3cHppFqeKT/W3e7BN7FSzebI=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "^2.4.1",
|
"chalk": "0.5.1",
|
||||||
"commander": "2.6.0",
|
"commander": "2.6.0",
|
||||||
"date-fns": "^1.23.0",
|
"date-fns": "1.29.0",
|
||||||
"lodash": "^4.5.1",
|
"lodash": "4.17.4",
|
||||||
"read-pkg": "^3.0.0",
|
|
||||||
"rx": "2.3.24",
|
"rx": "2.3.24",
|
||||||
"spawn-command": "^0.0.2-1",
|
"spawn-command": "0.0.2-1",
|
||||||
"supports-color": "^3.2.3",
|
"supports-color": "3.2.3",
|
||||||
"tree-kill": "^1.1.0"
|
"tree-kill": "1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "2.5.7",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
|
||||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
|
"integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
|
@ -164,13 +153,33 @@
|
||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"cryptiles": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
|
||||||
|
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"boom": "5.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"boom": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"hoek": "4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dashdash": {
|
"dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0"
|
"assert-plus": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"date-fns": {
|
"date-fns": {
|
||||||
|
@ -192,16 +201,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"jsbn": "~0.1.0"
|
"jsbn": "0.1.1"
|
||||||
}
|
|
||||||
},
|
|
||||||
"error-ex": {
|
|
||||||
"version": "1.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
|
||||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"is-arrayish": "^0.2.1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"escape-string-regexp": {
|
"escape-string-regexp": {
|
||||||
|
@ -223,9 +223,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "1.1.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
|
||||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
|
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
|
@ -241,14 +241,14 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "2.3.2",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
|
||||||
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
|
"integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "0.4.0",
|
||||||
"combined-stream": "1.0.6",
|
"combined-stream": "1.0.5",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "2.1.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"getpass": {
|
"getpass": {
|
||||||
|
@ -257,15 +257,9 @@
|
||||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0"
|
"assert-plus": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graceful-fs": {
|
|
||||||
"version": "4.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
|
||||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"har-schema": {
|
"har-schema": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||||
|
@ -278,26 +272,41 @@
|
||||||
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
|
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^5.1.0",
|
"ajv": "5.3.0",
|
||||||
"har-schema": "^2.0.0"
|
"har-schema": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"has-ansi": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
|
||||||
|
"integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "3.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
|
||||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
"integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"hawk": {
|
||||||
|
"version": "6.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
|
||||||
|
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"boom": "4.3.1",
|
||||||
|
"cryptiles": "3.1.2",
|
||||||
|
"hoek": "4.2.0",
|
||||||
|
"sntp": "2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hoek": {
|
"hoek": {
|
||||||
"version": "4.2.1",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
|
||||||
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==",
|
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==",
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"hosted-git-info": {
|
|
||||||
"version": "2.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz",
|
|
||||||
"integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==",
|
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"http-signature": {
|
"http-signature": {
|
||||||
|
@ -306,24 +315,9 @@
|
||||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0",
|
"assert-plus": "1.0.0",
|
||||||
"jsprim": "^1.2.2",
|
"jsprim": "1.4.1",
|
||||||
"sshpk": "^1.7.0"
|
"sshpk": "1.13.1"
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-arrayish": {
|
|
||||||
"version": "0.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
|
||||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"is-builtin-module": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"builtin-modules": "^1.0.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-typedarray": {
|
"is-typedarray": {
|
||||||
|
@ -356,11 +350,11 @@
|
||||||
"integrity": "sha1-M4WseQGSEwy+Iw6ALsAskhW7/to=",
|
"integrity": "sha1-M4WseQGSEwy+Iw6ALsAskhW7/to=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"hoek": "4.x.x",
|
"hoek": "4.2.0",
|
||||||
"isemail": "2.x.x",
|
"isemail": "2.2.1",
|
||||||
"items": "2.x.x",
|
"items": "2.1.1",
|
||||||
"moment": "2.x.x",
|
"moment": "2.19.1",
|
||||||
"topo": "2.x.x"
|
"topo": "2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"jsbn": {
|
"jsbn": {
|
||||||
|
@ -370,12 +364,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"json-parse-better-errors": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"json-schema": {
|
"json-schema": {
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||||
|
@ -406,37 +394,25 @@
|
||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"load-json-file": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
|
||||||
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "^4.1.2",
|
|
||||||
"parse-json": "^4.0.0",
|
|
||||||
"pify": "^3.0.0",
|
|
||||||
"strip-bom": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.11",
|
"version": "4.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
|
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.33.0",
|
"version": "1.30.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
|
||||||
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
|
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mime-types": {
|
"mime-types": {
|
||||||
"version": "2.1.18",
|
"version": "2.1.17",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
|
||||||
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
|
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"mime-db": "~1.33.0"
|
"mime-db": "1.30.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
|
@ -446,60 +422,23 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.22.2",
|
"version": "2.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.19.1.tgz",
|
||||||
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=",
|
"integrity": "sha1-VtoaLRy/AdOLfhr8McELz6GSkWc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"normalize-package-data": {
|
|
||||||
"version": "2.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
|
||||||
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"hosted-git-info": "^2.1.4",
|
|
||||||
"is-builtin-module": "^1.0.0",
|
|
||||||
"semver": "2 || 3 || 4 || 5",
|
|
||||||
"validate-npm-package-license": "^3.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"oauth-sign": {
|
"oauth-sign": {
|
||||||
"version": "0.8.2",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
|
||||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
|
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"parse-json": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
|
||||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"error-ex": "^1.3.1",
|
|
||||||
"json-parse-better-errors": "^1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path-type": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"pify": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"performance-now": {
|
"performance-now": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pify": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||||
|
@ -507,48 +446,39 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"read-pkg": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"load-json-file": "^4.0.0",
|
|
||||||
"normalize-package-data": "^2.3.2",
|
|
||||||
"path-type": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"request": {
|
"request": {
|
||||||
"version": "2.87.0",
|
"version": "2.83.0",
|
||||||
"resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
|
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
|
||||||
"integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
|
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"aws-sign2": "~0.7.0",
|
"aws-sign2": "0.7.0",
|
||||||
"aws4": "^1.6.0",
|
"aws4": "1.6.0",
|
||||||
"caseless": "~0.12.0",
|
"caseless": "0.12.0",
|
||||||
"combined-stream": "~1.0.5",
|
"combined-stream": "1.0.5",
|
||||||
"extend": "~3.0.1",
|
"extend": "3.0.1",
|
||||||
"forever-agent": "~0.6.1",
|
"forever-agent": "0.6.1",
|
||||||
"form-data": "~2.3.1",
|
"form-data": "2.3.1",
|
||||||
"har-validator": "~5.0.3",
|
"har-validator": "5.0.3",
|
||||||
"http-signature": "~1.2.0",
|
"hawk": "6.0.2",
|
||||||
"is-typedarray": "~1.0.0",
|
"http-signature": "1.2.0",
|
||||||
"isstream": "~0.1.2",
|
"is-typedarray": "1.0.0",
|
||||||
"json-stringify-safe": "~5.0.1",
|
"isstream": "0.1.2",
|
||||||
"mime-types": "~2.1.17",
|
"json-stringify-safe": "5.0.1",
|
||||||
"oauth-sign": "~0.8.2",
|
"mime-types": "2.1.17",
|
||||||
"performance-now": "^2.1.0",
|
"oauth-sign": "0.8.2",
|
||||||
"qs": "~6.5.1",
|
"performance-now": "2.1.0",
|
||||||
"safe-buffer": "^5.1.1",
|
"qs": "6.5.1",
|
||||||
"tough-cookie": "~2.3.3",
|
"safe-buffer": "5.1.1",
|
||||||
"tunnel-agent": "^0.6.0",
|
"stringstream": "0.0.5",
|
||||||
"uuid": "^3.1.0"
|
"tough-cookie": "2.3.3",
|
||||||
|
"tunnel-agent": "0.6.0",
|
||||||
|
"uuid": "3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rx": {
|
"rx": {
|
||||||
|
@ -558,22 +488,19 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"sntp": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
},
|
"requires": {
|
||||||
"semver": {
|
"hoek": "4.2.0"
|
||||||
"version": "5.5.0",
|
}
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
|
|
||||||
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"spawn-command": {
|
"spawn-command": {
|
||||||
"version": "0.0.2-1",
|
"version": "0.0.2-1",
|
||||||
|
@ -581,76 +508,44 @@
|
||||||
"integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=",
|
"integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"spdx-correct": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"spdx-expression-parse": "^3.0.0",
|
|
||||||
"spdx-license-ids": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spdx-exceptions": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"spdx-expression-parse": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"spdx-exceptions": "^2.1.0",
|
|
||||||
"spdx-license-ids": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spdx-license-ids": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"sshpk": {
|
"sshpk": {
|
||||||
"version": "1.14.2",
|
"version": "1.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
|
||||||
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
|
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"asn1": "~0.2.3",
|
"asn1": "0.2.3",
|
||||||
"assert-plus": "^1.0.0",
|
"assert-plus": "1.0.0",
|
||||||
"bcrypt-pbkdf": "^1.0.0",
|
"bcrypt-pbkdf": "1.0.1",
|
||||||
"dashdash": "^1.12.0",
|
"dashdash": "1.14.1",
|
||||||
"ecc-jsbn": "~0.1.1",
|
"ecc-jsbn": "0.1.1",
|
||||||
"getpass": "^0.1.1",
|
"getpass": "0.1.7",
|
||||||
"jsbn": "~0.1.0",
|
"jsbn": "0.1.1",
|
||||||
"safer-buffer": "^2.0.2",
|
"tweetnacl": "0.14.5"
|
||||||
"tweetnacl": "~0.14.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"strip-bom": {
|
"stringstream": {
|
||||||
"version": "3.0.0",
|
"version": "0.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
|
||||||
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
|
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
|
||||||
|
"integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "0.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
|
||||||
"integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
|
"integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "^1.0.0"
|
"has-flag": "1.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"has-flag": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"topo": {
|
"topo": {
|
||||||
|
@ -659,16 +554,16 @@
|
||||||
"integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=",
|
"integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"hoek": "4.x.x"
|
"hoek": "4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
|
||||||
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
|
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"punycode": "^1.4.1"
|
"punycode": "1.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tree-kill": {
|
"tree-kill": {
|
||||||
|
@ -683,7 +578,7 @@
|
||||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tweetnacl": {
|
"tweetnacl": {
|
||||||
|
@ -694,43 +589,33 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.3.2",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
|
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"validate-npm-package-license": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"spdx-correct": "^3.0.0",
|
|
||||||
"spdx-expression-parse": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"verror": {
|
"verror": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0",
|
"assert-plus": "1.0.0",
|
||||||
"core-util-is": "1.0.2",
|
"core-util-is": "1.0.2",
|
||||||
"extsprintf": "^1.2.0"
|
"extsprintf": "1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wait-on": {
|
"wait-on": {
|
||||||
"version": "2.1.0",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.0.2.tgz",
|
||||||
"integrity": "sha512-hDwJ674+7dfiiK/cxtYCwPxlnjXDjto/pCz1PF02sXUhqCqCWsgvxZln0699PReWqXXgkxqkF6DDo5Rj9sjNvw==",
|
"integrity": "sha1-CoT9BwJMb8Joyw6r5YW+IXqvK6o=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js": "^2.4.1",
|
"core-js": "2.5.1",
|
||||||
"joi": "^9.2.0",
|
"joi": "9.2.0",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "1.2.0",
|
||||||
"request": "^2.78.0",
|
"request": "2.83.0",
|
||||||
"rx": "^4.1.0"
|
"rx": "4.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rx": {
|
"rx": {
|
||||||
|
|
27
package.json
27
package.json
|
@ -1,23 +1,20 @@
|
||||||
{
|
{
|
||||||
"name": "opt-cc",
|
"name": "opt-cc",
|
||||||
"version": "1.9.7",
|
"version": "1.7.0",
|
||||||
|
"license": "MIT",
|
||||||
"author": "Florian Hartwich <hardi@noarch.de>",
|
"author": "Florian Hartwich <hardi@noarch.de>",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run deploy-static-prod && npm start --prefix ./server",
|
"start": "npm run deploy-static-prod && npm start --prefix ./api",
|
||||||
"dev": "npm run deploy-static && npm run dev --prefix ./server",
|
"dev": "npm run deploy-static && npm run dev --prefix ./api",
|
||||||
"pre-deploy-clean": "rm -f ./public/resource",
|
"deploy-static": "cd ./static && $(npm bin)/ng build && ln -s ../api/resource/ ../public/resource",
|
||||||
"deploy-static": "npm run pre-deploy-clean && npm run build --prefix=static && npm run deploy-static:link-resource && npm run deploy-static:api-docs",
|
"deploy-static:prod": "cd ./static && $(npm bin)/ng build --prod --aot && ln -s ../api/resource/ ../public/resource",
|
||||||
"deploy-static:prod": "npm run pre-deploy-clean && npm run build:prod --prefix=static && npm run deploy-static:link-resource && npm run deploy-static:api-docs",
|
"postinstall": "npm install --prefix ./static && npm install --prefix ./api",
|
||||||
"deploy-static:link-resource": "ln -s ../server/resource/ public/resource",
|
"mongodb": "mkdir -p mongodb-data && mongod --dbpath ./mongodb-data",
|
||||||
"deploy-static:api-docs": "npm run api:docs --prefix=server",
|
"test": "npm test --prefix ./api",
|
||||||
"postinstall": "npm install --prefix ./static && npm install --prefix ./server",
|
"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",
|
||||||
"lint": "npm run lint --prefix=server && npm run lint --prefix=static",
|
"start-e2e": "npm run deploy-static && npm run e2e --prefix ./api",
|
||||||
"test": "npm test --prefix ./server",
|
"test-e2e": "npm run e2e --prefix ./static"
|
||||||
"e2e": "npm run deploy-static && concurrently \"npm run start-test --prefix ./server\" \"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 ./server",
|
|
||||||
"test-e2e": "npm run e2e --prefix ./static",
|
|
||||||
"test-api": "npm run api:test-docs --prefix ./server"
|
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"apps": [
|
"apps": [
|
||||||
{
|
{
|
||||||
"name": "opt-cc",
|
"name": "opt-cc",
|
||||||
"script": "./server/server.js",
|
"script": "./api/server.js",
|
||||||
"watch": false,
|
"watch": false,
|
||||||
"env": {
|
"env": {
|
||||||
"NODE_ENV": "production",
|
"NODE_ENV": "production",
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
'extends': 'google',
|
|
||||||
'parserOptions': {
|
|
||||||
'ecmaVersion': 6
|
|
||||||
},
|
|
||||||
'rules': {
|
|
||||||
'max-len': [2, 120, 4, {
|
|
||||||
'ignoreUrls': true
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,39 +0,0 @@
|
||||||
### 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
|
|
|
@ -1,19 +0,0 @@
|
||||||
### 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)
|
|
||||||
|
|
||||||
+ Attributes (object)
|
|
||||||
|
|
||||||
|
|
||||||
+ Response 200 (application/json; charset=utf-8)
|
|
||||||
|
|
||||||
+ Attributes
|
|
||||||
+ status: `success` (string, required) - action result message
|
|
|
@ -1,7 +0,0 @@
|
||||||
### 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])
|
|
|
@ -1,63 +0,0 @@
|
||||||
### Get Awardings [GET /awardings{?userId,inProgress,fractFilter,squadId}]
|
|
||||||
|
|
||||||
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`
|
|
||||||
|
|
||||||
+ squadId: `5aba54eaeadcce6332c6a774` (string, optional)
|
|
||||||
unique id of the squad
|
|
||||||
|
|
||||||
|
|
||||||
+ 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)
|
|
|
@ -1,129 +0,0 @@
|
||||||
### 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
|
|
||||||
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
|
|
||||||
B3RJTUUH4wIDDQIBeZj+RQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH
|
|
||||||
AAAAFklEQVQI12NgZ2f///8/w////xkZGQEq5gYTeotA1AAAAABJRU5ErkJggg==
|
|
||||||
-----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
|
|
||||||
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
|
|
||||||
B3RJTUUH4wIDDQIBeZj+RQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH
|
|
||||||
AAAAFklEQVQI12NgZ2f///8/w////xkZGQEq5gYTeotA1AAAAABJRU5ErkJggg==
|
|
||||||
-----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
|
|
|
@ -1,65 +0,0 @@
|
||||||
### 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)
|
|
|
@ -1,118 +0,0 @@
|
||||||
### 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
|
|
||||||
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
|
|
||||||
B3RJTUUH4wIDDQIBeZj+RQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH
|
|
||||||
AAAAFklEQVQI12NgZ2f///8/w////xkZGQEq5gYTeotA1AAAAABJRU5ErkJggg==
|
|
||||||
-----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
|
|
||||||
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
|
|
||||||
B3RJTUUH4wIDDQIBeZj+RQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH
|
|
||||||
AAAAFklEQVQI12NgZ2f///8/w////xkZGQEq5gYTeotA1AAAAABJRU5ErkJggg==
|
|
||||||
-----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
|
|
|
@ -1,112 +0,0 @@
|
||||||
### 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
|
|
||||||
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
|
|
||||||
B3RJTUUH4wIDDQIBeZj+RQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH
|
|
||||||
AAAAFklEQVQI12NgZ2f///8/w////xkZGQEq5gYTeotA1AAAAABJRU5ErkJggg==
|
|
||||||
-----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
|
|
||||||
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
|
|
||||||
B3RJTUUH4wIDDQIBeZj+RQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH
|
|
||||||
AAAAFklEQVQI12NgZ2f///8/w////xkZGQEq5gYTeotA1AAAAABJRU5ErkJggg==
|
|
||||||
-----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
|
|
|
@ -1,96 +0,0 @@
|
||||||
### List Users [GET /users{?q,fractFilter,squadId,decorationId,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`
|
|
||||||
|
|
||||||
+ squadId: `5aba54eaeadcce6332c6a774` (string, optional) - Field to filter by membership of certain squad
|
|
||||||
|
|
||||||
+ decorationId: `5abd3dff6e6a0334d95b8ba0` (string, optional) - Field to filter by ownership of certain decoration
|
|
||||||
|
|
||||||
+ 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
|
|
|
@ -1,11 +0,0 @@
|
||||||
### 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)
|
|
|
@ -1,13 +0,0 @@
|
||||||
### 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)
|
|
|
@ -1,54 +0,0 @@
|
||||||
## 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" <API_RESOURCE_PATH_GOES_HERE>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
|
||||||
:::
|
|
|
@ -1,10 +0,0 @@
|
||||||
## 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
|
|
|
@ -1,36 +0,0 @@
|
||||||
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`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
# 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
|
|
|
@ -1,26 +0,0 @@
|
||||||
# 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
|
|
|
@ -1,29 +0,0 @@
|
||||||
# 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
|
|
|
@ -1,23 +0,0 @@
|
||||||
# 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, proposer and army-user
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
+ proposer (Proposer, required) - app user who requested this awarding
|
|
||||||
+ decorationId (Decoration, required) - populated decoration object that is given with the awarding
|
|
||||||
+ userId (User, required) - populated user who gets this awarding
|
|
|
@ -1,19 +0,0 @@
|
||||||
# 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: WarWithPlayers (array[WarWithPlayers], required)
|
|
|
@ -1,19 +0,0 @@
|
||||||
# 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
|
|
|
@ -1,91 +0,0 @@
|
||||||
# Log (object)
|
|
||||||
## Properties
|
|
||||||
+ _id: `` (string, required) - log entry id
|
|
||||||
+ war: `` (string, required) - warId
|
|
||||||
+ time: `` (string, required) - logging timestamp
|
|
||||||
|
|
||||||
# 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`
|
|
||||||
+ shooterVehicle: `FV-720 Mora` (string, optional) - vehicle in whiock the shooting player sat
|
|
||||||
+ targetVehicle: `Ifrit-GMG` (string, optional) - vehicle in which the target player sat
|
|
||||||
+ magazine: `30 mm APFSDS` (string, optional) - magazine name used to execute the kill
|
|
||||||
|
|
||||||
#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
|
|
||||||
+ additionalShooter: `[GNC]Paolo`, `Dominik` (array[string], required) - additional crew members of shooter vehicle
|
|
||||||
+ target: `T-100` (string, required) - name of the vehicle
|
|
||||||
+ fraction: `BLUFOR` (enum, required) - fraction of the shooter
|
|
||||||
+ Members
|
|
||||||
+ `BLUFOR`
|
|
||||||
+ `OPFOR`
|
|
||||||
+ `NONE`
|
|
||||||
+ vehicleClass: `LIGHT` (enum[string], required) - class of shot vehicle
|
|
||||||
+ Members
|
|
||||||
+ `LIGHT`
|
|
||||||
+ `HEAVY`
|
|
||||||
+ `AIR`
|
|
||||||
+ `BOAT`
|
|
||||||
+ `UNKNOWN`
|
|
||||||
+ shooterVehicle: `FV-720 Mora` (string, optional) - vehicle in whiock the shooting player sat
|
|
||||||
+ magazine: `30 mm APFSDS` (string, optional) - magazine name used to execute the kill
|
|
|
@ -1,39 +0,0 @@
|
||||||
# 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
|
|
||||||
+ vehicleLight: 1 (number, required) - sum of light vehicle kills
|
|
||||||
+ vehicleHeavy: 1 (number, required) - sum of heavy vehicle kills
|
|
||||||
+ vehicleAir: 0 (number, required) - sum of air 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
|
|
||||||
+ travelDistance: 16535 (number, optional) - sum of transport meters as passenger
|
|
||||||
+ driverDistance: 1250 (number, optional) - sum of transport meters as pilot/driver
|
|
||||||
|
|
||||||
|
|
||||||
# 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 (number, optional) - unique ID for STEAM platform account
|
|
||||||
+ performance: `5abf65ae3fc5fa349ffd5cs2` (string, optional) - id of corresponding performance log entry
|
|
||||||
+ 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 returned for the highscore arrays
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
+ warId: War (War, required) - war in which this player took part
|
|
||||||
+ num: 1
|
|
|
@ -1,20 +0,0 @@
|
||||||
# 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
|
|
|
@ -1,16 +0,0 @@
|
||||||
# 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
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue