From cd77c4b7f238940b83bf412ddb7e4a433f02675d Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 21 Oct 2017 19:49:24 +0200 Subject: [PATCH] Add endpoints for log entries & add additional fraction fields for DOs --- api/config/api-url.js | 1 + api/models/logs/kill.js | 8 +- api/models/logs/points.js | 9 +- api/models/logs/revive.js | 5 + api/models/logs/transport.js | 5 + api/routes/logs.js | 175 +++++++++++++++++++++++++++++++++++ api/routes/wars.js | 9 +- api/server.js | 2 + api/tools/log-parse-tool.js | 18 ++-- 9 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 api/routes/logs.js diff --git a/api/config/api-url.js b/api/config/api-url.js index 87a179e..e8041c8 100644 --- a/api/config/api-url.js +++ b/api/config/api-url.js @@ -8,6 +8,7 @@ module.exports = { cmdCreateSig: rootRoute + '/cmd/createSignature', command: rootRoute + '/cmd', decorations: rootRoute + '/decorations', + logs: rootRoute + '/logs', overview: rootRoute + '/overview', players: rootRoute + '/players', ranks: rootRoute + '/ranks', diff --git a/api/models/logs/kill.js b/api/models/logs/kill.js index 3b06d86..b48761e 100644 --- a/api/models/logs/kill.js +++ b/api/models/logs/kill.js @@ -14,8 +14,7 @@ const LogKillSchema = new Schema({ required: true }, shooter: { - type: String, - required: true + type: String }, target: { type: String, @@ -24,6 +23,11 @@ const LogKillSchema = new Schema({ friendlyFire: { type: Boolean, required: true + }, + fraction: { + type: String, + enum: ['BLUFOR', 'OPFOR', 'NONE'], + required: true } }, { collection: 'logKill' diff --git a/api/models/logs/points.js b/api/models/logs/points.js index 4bedeb3..28aa39b 100644 --- a/api/models/logs/points.js +++ b/api/models/logs/points.js @@ -24,11 +24,16 @@ const LogKillSchema = new Schema({ get: v => Math.round(v), set: v => Math.round(v), required: true + }, + fraction: { + type: String, + enum: ['BLUFOR', 'OPFOR', 'NONE'], + required: true } }, { - collection: 'logKill' + collection: 'logPoints' }); // optional more indices LogKillSchema.index({war: 1, shooter: 1, target: 1}); -module.exports = mongoose.model('LogKill', LogKillSchema); +module.exports = mongoose.model('LogPoints', LogKillSchema); diff --git a/api/models/logs/revive.js b/api/models/logs/revive.js index 3b522f3..c5c9b10 100644 --- a/api/models/logs/revive.js +++ b/api/models/logs/revive.js @@ -24,6 +24,11 @@ const LogReviveSchema = new Schema({ stabilized: { type: Boolean, required: true + }, + fraction: { + type: String, + enum: ['BLUFOR', 'OPFOR'], + required: true } }, { collection: 'logRevive' diff --git a/api/models/logs/transport.js b/api/models/logs/transport.js index 5c3a9cf..09accf0 100644 --- a/api/models/logs/transport.js +++ b/api/models/logs/transport.js @@ -26,6 +26,11 @@ const LogTransportSchema = new Schema({ get: v => Math.round(v), set: v => Math.round(v), required: true + }, + fraction: { + type: String, + enum: ['BLUFOR', 'OPFOR'], + required: true } }, { collection: 'logTransport' diff --git a/api/routes/logs.js b/api/routes/logs.js new file mode 100644 index 0000000..0d0ffac --- /dev/null +++ b/api/routes/logs.js @@ -0,0 +1,175 @@ +"use strict"; + +// modules +const express = require('express'); +const logger = require('debug')('cc:wars'); + +// HTTP status codes by name +const codes = require('./http-codes'); + +const routerHandling = require('../middleware/router-handling'); + +// 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 notFoundError = new Error('No logs found'); + +const logsRouter = express.Router(); + +// routes ********************** +logsRouter.route('/:warId/budget') + .get((req, res, next) => { + const filter = {war: req.params.warId}; + if (req.query.fraction) filter['fraction'] = req.query.fraction; + LogBudgetModel.find(filter, {}, {sort: {time: 1}}, (err, logBudget) => { + if (err) return next(err); + if (!logBudget || logBudget.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logBudget; + 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; + LogRespawnModel.find(filter, {}, {sort: {time: 1}}, (err, logRespawn) => { + if (err) return next(err); + if (!logRespawn || logRespawn.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logRespawn; + 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; + LogReviveModel.find(filter, {}, {sort: {time: 1}}, (err, logRevive) => { + if (err) return next(err); + if (!logRevive || logRevive.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logRevive; + 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; + LogKillModel.find(filter, {}, {sort: {time: 1}}, (err, logKill) => { + if (err) return next(err); + if (!logKill || logKill.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logKill; + 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; + LogTransportModel.find(filter, {}, {sort: {time: 1}}, (err, logTransport) => { + if (err) return next(err); + if (!logTransport || logTransport.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logTransport; + 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; + LogFlagModel.find(filter, {}, {sort: {time: 1}}, (err, logFlag) => { + if (err) return next(err); + if (!logFlag || logFlag.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logFlag; + 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; + LogPointsModel.find(filter, {}, {sort: {time: 1}}, (err, logPoints) => { + if (err) return next(err); + if (!logPoints || logPoints.length === 0) { + const err = notFoundError; + err.status = codes.notfound; + return next(err) + } + res.locals.items = logPoints; + next(); + }) + }) + .all( + routerHandling.httpMethodNotAllowed + ); + +logsRouter.use(routerHandling.emptyResponse); + +module.exports = logsRouter; diff --git a/api/routes/wars.js b/api/routes/wars.js index 0940109..9424a1c 100644 --- a/api/routes/wars.js +++ b/api/routes/wars.js @@ -29,6 +29,7 @@ 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(); @@ -93,9 +94,11 @@ wars.route('/') LogFlagModel.create(statsResult.flag, function (err) { LogBudgetModel.create(statsResult.budget, function (err) { LogTransportModel.create(statsResult.transport, function (err) { - res.status(codes.created); - res.locals.items = war; - next(); + LogPointsModel.create(statsResult.points, function (err) { + res.status(codes.created); + res.locals.items = war; + next(); + }) }) }) }) diff --git a/api/server.js b/api/server.js index b961de2..9fda98e 100644 --- a/api/server.js +++ b/api/server.js @@ -35,6 +35,7 @@ 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 @@ -83,6 +84,7 @@ 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); diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 4f594f7..2b76d9b 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -40,8 +40,9 @@ const parseWarLog = (lineArray, war) => { war: war._id, time: getDateTime(line.split(' ')[5]), shooter: shooter ? shooter.name : null, - target: target ? target.name : null, - friendlyFire: target && shooter ? target.fraction === shooter.fraction : false + target: target.name, + friendlyFire: shooter ? target.fraction === shooter.fraction : false, + fraction: shooter ? shooter.fraction : 'NONE' }); addPlayersIfNotExists([shooter, target]); @@ -94,7 +95,7 @@ const parseWarLog = (lineArray, war) => { stats.war['ptBlufor'] = parseInt(pt[11]); stats.war['ptOpfor'] = parseInt(pt[14].slice(0, -1)); } else { - stats.points.push(getPointsEntry(pt, war._id)) + stats.points.push(getPointsEntry(pt, line, war._id)) } } @@ -125,7 +126,8 @@ const parseWarLog = (lineArray, war) => { time: getDateTime(line.split(' ')[5]), stabilized: stabilized, medic: medic.name, - patient: patientName + patient: patient.name, + fraction: medic.fraction }); addPlayersIfNotExists([medic, patient]); @@ -147,6 +149,7 @@ const parseWarLog = (lineArray, war) => { time: getDateTime(line.split(' ')[5]), driver: driver.name, passenger: passenger.name, + fraction: driver.fraction, distance: distance }); @@ -178,12 +181,13 @@ const getRespawnEntry = (respawn, playerName, warId) => { } }; -const getPointsEntry = (pt, warId) => { +const getPointsEntry = (pt, line, warId) => { return { war: warId, time: getDateTime(pt[5]), ptBlufor: parseInt(pt[12]), - ptOpfor: parseInt(pt[15].slice(0, -1)) + ptOpfor: parseInt(pt[15].slice(0, -1)), + fraction: line.includes('no Domination') ? 'NONE': line.includes('NATO +1') ? 'BLUFOR' : 'OPFOR' } }; @@ -201,7 +205,7 @@ const getPlayerAndFractionFromString = (nameAndFractionString) => { const nameArray = nameAndFractionString.split(' '); 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' + // do not return player for 'Selbstverschulden' or 'Error: No unit' if (name && name !== 'Error: No unit') { return {name: name, fraction: fraction}; }