Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion data/migrations/20200611095430_initial.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,18 @@ exports.up = async (knex) => {
tbl.integer('cost').notNullable().defaultTo(0);
tbl.integer('budget_increase').notNullable().defaultTo(0);
tbl.decimal('poll_increase').notNullable().defaultTo(0);
tbl.specificType('authorized_roles', 'text ARRAY');
tbl.specificType('required_systems', 'text ARRAY');
});

// MANY actions to MANY roles
await knex.schema.createTable('action_role', (tbl) => {
tbl.increments('id');
tbl.string('action_id').notNullable();
tbl.string('role_id').notNullable();
tbl.foreign('action_id').references('id').inTable('action');
tbl.foreign('role_id').references('id').inTable('role');
});

await knex.schema.createTable('game', (tbl) => {
tbl.string('id').primary().notNullable();
tbl
Expand Down
14 changes: 0 additions & 14 deletions data/seeds/static_7_action.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ exports.seed = (knex) =>
cost: 1000,
budget_increase: 0,
poll_increase: 5,
authorized_roles: ['R1'],
required_systems: ['S4', 'S5', 'S9', 'S6', 'S10', 'S1', 'S2'],
},
{
Expand All @@ -20,7 +19,6 @@ exports.seed = (knex) =>
cost: 800,
budget_increase: 0,
poll_increase: 4,
authorized_roles: ['R7'],
required_systems: ['S8', 'S9', 'S7', 'S10'],
},
{
Expand All @@ -30,7 +28,6 @@ exports.seed = (knex) =>
cost: 600,
budget_increase: 0,
poll_increase: 3,
authorized_roles: ['R5'],
required_systems: ['S4', 'S5', 'S6'],
},
{
Expand All @@ -40,7 +37,6 @@ exports.seed = (knex) =>
cost: 600,
budget_increase: 0,
poll_increase: 3,
authorized_roles: ['R9'],
required_systems: ['S8', 'S9', 'S10'],
},
{
Expand All @@ -50,7 +46,6 @@ exports.seed = (knex) =>
cost: 500,
budget_increase: 0,
poll_increase: 2,
authorized_roles: ['R2', 'R4'],
required_systems: ['S5'],
},
{
Expand All @@ -60,7 +55,6 @@ exports.seed = (knex) =>
cost: 500,
budget_increase: 0,
poll_increase: 2,
authorized_roles: ['R8'],
required_systems: ['S9'],
},
{
Expand All @@ -70,7 +64,6 @@ exports.seed = (knex) =>
cost: 500,
budget_increase: 0,
poll_increase: 2,
authorized_roles: ['R3'],
required_systems: ['S1', 'S5'],
},
{
Expand All @@ -80,7 +73,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R1'],
required_systems: ['S4', 'S5'],
},
{
Expand All @@ -90,7 +82,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R5'],
required_systems: ['S4', 'S6'],
},
{
Expand All @@ -100,7 +91,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R9'],
required_systems: ['S8', 'S10'],
},
{
Expand All @@ -110,7 +100,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R2', 'R4'],
required_systems: ['S2', 'S5'],
},
{
Expand All @@ -120,7 +109,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R2', 'R4'],
required_systems: ['S2', 'S6'],
},
{
Expand All @@ -130,7 +118,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R7', 'R8'],
required_systems: ['S7', 'S9'],
},
{
Expand All @@ -140,7 +127,6 @@ exports.seed = (knex) =>
cost: 0,
budget_increase: 200,
poll_increase: 0,
authorized_roles: ['R7', 'R8'],
required_systems: ['S7', 'S10'],
},
]),
Expand Down
26 changes: 26 additions & 0 deletions data/seeds/static_8_action_role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
exports.seed = (knex) =>
knex('action_role')
.del()
.then(() =>
knex('action_role').insert([
{ action_id: 'A1', role_id: 'R1' },
{ action_id: 'A2', role_id: 'R7' },
{ action_id: 'A3', role_id: 'R5' },
{ action_id: 'A4', role_id: 'R9' },
{ action_id: 'A5', role_id: 'R2' },
{ action_id: 'A5', role_id: 'R4' },
{ action_id: 'A6', role_id: 'R8' },
{ action_id: 'A7', role_id: 'R3' },
{ action_id: 'A8', role_id: 'R1' },
{ action_id: 'A9', role_id: 'R5' },
{ action_id: 'A10', role_id: 'R9' },
{ action_id: 'A11', role_id: 'R2' },
{ action_id: 'A11', role_id: 'R4' },
{ action_id: 'A12', role_id: 'R2' },
{ action_id: 'A12', role_id: 'R4' },
{ action_id: 'A13', role_id: 'R7' },
{ action_id: 'A13', role_id: 'R8' },
{ action_id: 'A14', role_id: 'R7' },
{ action_id: 'A14', role_id: 'R8' },
]),
);
5 changes: 3 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const logger = require('./logger');
const db = require('./models/db');
const { getResponses } = require('./models/response');
const { getInjections } = require('./models/injection');
const { getActions } = require('./models/action');

const app = express();

Expand All @@ -32,7 +33,7 @@ app.get('/', async (req, res) => {
});
});

// STATIC DB data are expose via REST api
// STATIC DB data is exposed via REST api

app.get('/mitigations', async (req, res) => {
const records = await db('mitigation');
Expand All @@ -55,7 +56,7 @@ app.get('/responses', async (req, res) => {
});

app.get('/actions', async (req, res) => {
const records = await db('action');
const records = await getActions();
res.json(records);
});

Expand Down
1 change: 1 addition & 0 deletions src/constants/SocketEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
JOINGAME: 'joinGame',
GAMEUPDATED: 'gameUpdated',
CHANGEMITIGATION: 'changeMitigation',
PERFORMACTION: 'performAction',
STARTSIMULATION: 'startSimulation',
PAUSESIMULATION: 'pauseSimulation',
FINISHSIMULATION: 'finishSimulation',
Expand Down
18 changes: 18 additions & 0 deletions src/models/action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const db = require('./db');

const getActions = async () => {
const records = await db('action').select('action.*', 'r.roles').joinRaw(`
LEFT JOIN (
SELECT ar.action_id, array_agg(role.name) AS roles
FROM action_role ar
LEFT JOIN role
ON role.id = ar.role_id
GROUP BY ar.action_id
) r ON r.action_id = action.id
`);
return records;
};

module.exports = {
getActions,
};
50 changes: 50 additions & 0 deletions src/models/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,60 @@ const makeNonCorrectInjectionResponse = async ({ gameId, injectionId }) => {
return getGame(gameId);
};

const performAction = async ({ gameId, actionId }) => {
try {
const { budget, poll } = await db('game')
.select('game.budget', 'game.poll')
.where({ 'game.id': gameId })
.first();

const {
cost,
budget_increase: budgetIncrease,
poll_increase: pollIncrease,
required_systems: requiredSystems,
} = await db('action').where({ id: actionId }).first();

if (budget < cost) {
throw new Error('Not enough budget');
}

const unavailableSystems = await db('game_system')
.select()
.where({ game_id: gameId, state: false })
.whereIn('system_id', requiredSystems);

if (unavailableSystems.length > 0) {
throw new Error(
'The required systems for this action are not available.',
);
}

await db('game')
.where({ id: gameId })
.update({
budget: budget - cost + budgetIncrease,
poll: Math.min(poll + pollIncrease, 100),
});
} catch (error) {
logger.error('performAction ERROR: %s', error);
switch (error.message) {
case 'Not enough budget':
throw error;
case 'The required systems for this action are not available':
throw error;
default:
throw new Error('Server error on performing action');
}
}
return getGame(gameId);
};

module.exports = {
createGame,
getGame,
changeMitigation,
performAction,
startSimulation,
pauseSimulation,
makeResponses,
Expand Down
15 changes: 15 additions & 0 deletions src/socketio.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
createGame,
getGame,
changeMitigation,
performAction,
startSimulation,
pauseSimulation,
makeResponses,
Expand Down Expand Up @@ -210,6 +211,20 @@ module.exports = (http) => {
}
},
);

socket.on(SocketEvents.PERFORMACTION, async ({ actionId }, callback) => {
logger.info('PERFORMACTION: %s', JSON.stringify({ gameId, actionId }));
try {
const game = await performAction({
gameId,
actionId,
});
io.in(gameId).emit(SocketEvents.GAMEUPDATED, game);
callback({ game });
} catch (error) {
callback({ error: error.message });
}
});
});

return io;
Expand Down