Massive refactor complete
This commit is contained in:
+71
-52
@@ -4,7 +4,7 @@ require('dotenv').config();
|
||||
//libraries
|
||||
let bcrypt = require('bcrypt');
|
||||
let formidable = require('formidable');
|
||||
let sendmail = require('sendmail')();
|
||||
let sendmail = require('sendmail')({silent: true});
|
||||
|
||||
//utilities
|
||||
let { log, validateEmail } = require('../common/utilities.js');
|
||||
@@ -20,7 +20,7 @@ const signupRequest = (connection) => (req, res) => {
|
||||
|
||||
//prevent too many clicks
|
||||
if (isThrottled(fields.email)) {
|
||||
res.status(400).write(log('signup throttled', fields.email));
|
||||
res.status(400).write(log('Signup throttled', fields.email));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
@@ -65,11 +65,15 @@ const signupRequest = (connection) => (req, res) => {
|
||||
connection.query(query, [fields.email, fields.username, salt, hash, rand], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//TODO: make the verification email prettier
|
||||
//build the verification email
|
||||
let addr = `http://${process.env.WEB_ADDRESS}/verifyrequest?email=${fields.email}&verify=${rand}`;
|
||||
let msg = 'Hello! Please visit the following address to verify your account: ';
|
||||
let msgHtml = `<html><body><p>${msg}<a href='${addr}'>${addr}</a></p></body></html>`;
|
||||
|
||||
//BUGFIX: is gmail being cruel?
|
||||
let sentinel = false;
|
||||
|
||||
//send the verification email
|
||||
sendmail({
|
||||
from: `signup@${process.env.WEB_ADDRESS}`,
|
||||
@@ -78,32 +82,39 @@ const signupRequest = (connection) => (req, res) => {
|
||||
text: msg + addr,
|
||||
html: msgHtml
|
||||
}, (err, reply) => {
|
||||
//final check
|
||||
if (err) {
|
||||
res.status(400).write(log('Something went wrong (did you use a valid email?)', err));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
if (err) { //final check
|
||||
let msg = log('Something went wrong (did you use a valid email?)', err);
|
||||
|
||||
res.status(200).write(log('Verification email sent!', fields.email));
|
||||
res.end();
|
||||
if (!sentinel) {
|
||||
res.status(400).write(msg);
|
||||
res.end();
|
||||
}
|
||||
} else {
|
||||
let msg = log('Verification email sent!', fields.email);
|
||||
|
||||
if (!sentinel) {
|
||||
res.status(200).json({ msg: msg });
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
sentinel = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const verifyRequest = (connection) => (req, res) => {
|
||||
//get the saved data
|
||||
let query = 'SELECT email, username, salt, hash, verify FROM signups WHERE email = ?;';
|
||||
|
||||
let query = 'SELECT * FROM signups WHERE email = ?;';
|
||||
connection.query(query, [req.query.email], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//correct number of results
|
||||
if (results.length != 1) {
|
||||
if (results.length !== 1) {
|
||||
console.log(req.query.email);
|
||||
res.status(400).write(log('That account does not exist or this link has already been used.', req.query.email, req.query.verify));
|
||||
res.end();
|
||||
return;
|
||||
@@ -126,12 +137,13 @@ const verifyRequest = (connection) => (req, res) => {
|
||||
connection.query(query, [results[0].email], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//TODO: prettier verification page
|
||||
res.status(200).write(log('Verification succeeded!', req.query.email));
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const loginRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
@@ -155,7 +167,7 @@ const loginRequest = (connection) => (req, res) => {
|
||||
|
||||
//found this email?
|
||||
if (results.length === 0) {
|
||||
res.status(400).write(log('Incorrect email or password', fields.email, 'Did not find this email'));
|
||||
res.status(400).write(log('Incorrect email or password', fields.email, 'Did not find this email')); //NOTE: deliberately obscure incorrect email or password
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
@@ -183,25 +195,25 @@ const loginRequest = (connection) => (req, res) => {
|
||||
id: results[0].id,
|
||||
email: fields.email,
|
||||
username: results[0].username,
|
||||
token: rand
|
||||
token: rand,
|
||||
msg: log('Logged in', fields.email, rand)
|
||||
});
|
||||
res.end();
|
||||
log('Logged in', fields.email, rand);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const logoutRequest = (connection) => (req, res) => {
|
||||
let query = 'DELETE FROM sessions WHERE sessions.accountId IN (SELECT accounts.id FROM accounts WHERE email = ?) AND token = ?;';
|
||||
connection.query(query, [req.body.email, req.body.token], (err) => {
|
||||
let query = 'DELETE FROM sessions WHERE sessions.accountId = ? AND token = ?;'; //NOTE: The user now loses this access token
|
||||
connection.query(query, [req.body.id, req.body.token], (err) => {
|
||||
if (err) throw err;
|
||||
log('Logged out', req.body.email, req.body.token);
|
||||
log('Logged out', req.body.id, req.body.token);
|
||||
});
|
||||
|
||||
res.end();
|
||||
}
|
||||
res.end(); //NOTE: don't send a response
|
||||
};
|
||||
|
||||
const passwordChangeRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
@@ -212,23 +224,19 @@ const passwordChangeRequest = (connection) => (req, res) => {
|
||||
if (err) throw err;
|
||||
|
||||
//validate password, retype
|
||||
if (!validateEmail(fields.email) || fields.password.length < 8 || fields.password !== fields.retype) {
|
||||
res.status(400).write(log('Invalid password change data', fields.email));
|
||||
if (fields.password.length < 8 || fields.password !== fields.retype) {
|
||||
res.status(400).write(log('Invalid password change data', fields.id));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//validate token
|
||||
query = 'SELECT sessions.token FROM sessions WHERE sessions.accountId IN (SELECT id FROM accounts WHERE email = ?);';
|
||||
connection.query(query, [fields.email], (err, results) => {
|
||||
query = 'SELECT COUNT(*) AS total FROM sessions WHERE sessions.accountId = ? AND sessions.token = ?;';
|
||||
connection.query(query, [fields.id, fields.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
let found = false;
|
||||
|
||||
results.map((result) => { if (result.token == fields.token) found = true; });
|
||||
|
||||
if (!found) {
|
||||
res.status(400).write(log('Invalid password change authentication', fields.email, fields.token));
|
||||
if (results[0].total !== 1) {
|
||||
res.status(400).write(log('Invalid password change credentials', fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
@@ -239,26 +247,26 @@ const passwordChangeRequest = (connection) => (req, res) => {
|
||||
bcrypt.hash(fields.password, salt, (err, hash) => {
|
||||
if (err) throw err;
|
||||
|
||||
let query = 'UPDATE accounts SET salt = ?, hash = ? WHERE email = ?;';
|
||||
connection.query(query, [salt, hash, fields.email], (err) => {
|
||||
let query = 'UPDATE accounts SET salt = ?, hash = ? WHERE id = ?;';
|
||||
connection.query(query, [salt, hash, fields.id], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//clear all session data for this user (a 'feature')
|
||||
let query = 'DELETE FROM sessions WHERE sessions.accountId IN (SELECT accounts.id FROM accounts WHERE email = ?);';
|
||||
connection.query(query, [fields.email], (err) => {
|
||||
let query = 'DELETE FROM sessions WHERE sessions.accountId = ?;';
|
||||
connection.query(query, [fields.id], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//create the new session
|
||||
let rand = Math.floor(Math.random() * 100000);
|
||||
|
||||
let query = 'INSERT INTO sessions (accountId, token) VALUES ((SELECT accounts.id FROM accounts WHERE email = ?), ?);';
|
||||
connection.query(query, [fields.email, rand], (err) => {
|
||||
let query = 'INSERT INTO sessions (accountId, token) VALUES (?, ?);';
|
||||
connection.query(query, [fields.id, rand], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//send json containing the account info
|
||||
res.status(200).json({
|
||||
token: rand,
|
||||
msg: log('Password changed!', fields.email)
|
||||
msg: log('Password changed!', fields.id)
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
@@ -268,7 +276,7 @@ const passwordChangeRequest = (connection) => (req, res) => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const passwordRecoverRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
@@ -280,14 +288,14 @@ const passwordRecoverRequest = (connection) => (req, res) => {
|
||||
|
||||
//prevent too many clicks
|
||||
if (isThrottled(fields.email)) {
|
||||
res.status(400).write(log('recover throttled', fields.email));
|
||||
res.status(400).write(log('Recover throttled', fields.email));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
throttle(fields.email);
|
||||
|
||||
//validate email, username and password
|
||||
//validate email
|
||||
if (!validateEmail(fields.email)) {
|
||||
res.status(400).write(log('Invalid recover data', fields.email));
|
||||
res.end();
|
||||
@@ -312,11 +320,15 @@ const passwordRecoverRequest = (connection) => (req, res) => {
|
||||
connection.query(query, [results[0].id, rand], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//TODO: prettier recovery email
|
||||
//build the recovery email
|
||||
let addr = `http://${process.env.WEB_ADDRESS}/passwordreset?email=${fields.email}&token=${rand}`;
|
||||
let msg = 'Hello! Please visit the following address to set a new password (if you didn\'t request a password recovery, ignore this email): ';
|
||||
let msgHtml = `<html><body><p>${msg}<a href='${addr}'>${addr}</a></p></body></html>`;
|
||||
|
||||
//BUGFIX: is gmail being cruel?
|
||||
let sentinel = false;
|
||||
|
||||
//send the verification email
|
||||
sendmail({
|
||||
from: `passwordrecover@${process.env.WEB_ADDRESS}`,
|
||||
@@ -327,18 +339,25 @@ const passwordRecoverRequest = (connection) => (req, res) => {
|
||||
}, (err, reply) => {
|
||||
//final check
|
||||
if (err) {
|
||||
res.status(400).write(log('Something went wrong (did you use a valid email?)', err));
|
||||
if (!sentinel) {
|
||||
let msg = log('Something went wrong (did you use a valid email?)', err);
|
||||
|
||||
res.status(400).write(msg);
|
||||
res.end();
|
||||
}
|
||||
} else {
|
||||
let msg = log('Recovery email sent!', fields.email);
|
||||
|
||||
res.status(200).json({ msg: msg });
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).write(log('Recovery email sent!', fields.email));
|
||||
res.end();
|
||||
sentinel = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const passwordResetRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
@@ -348,7 +367,7 @@ const passwordResetRequest = (connection) => (req, res) => {
|
||||
form.parse(req, (err, fields) => {
|
||||
if (err) throw err;
|
||||
|
||||
//validate email, username and password
|
||||
//validate email and password
|
||||
if (!validateEmail(fields.email) || fields.password.length < 8 || fields.password !== fields.retype) {
|
||||
res.status(400).write(log('Invalid reset data (invalid email/password)', fields.email));
|
||||
res.end();
|
||||
@@ -383,7 +402,7 @@ const passwordResetRequest = (connection) => (req, res) => {
|
||||
connection.query(query, [fields.email], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
res.status(200).write(log('Password updated!', fields.email));
|
||||
res.status(200).json({ msg: log('Password updated!', fields.email) });
|
||||
res.end();
|
||||
return;
|
||||
});
|
||||
@@ -392,7 +411,7 @@ const passwordResetRequest = (connection) => (req, res) => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
signupRequest: signupRequest,
|
||||
|
||||
+36
-39
@@ -8,35 +8,33 @@ let CronJob = require('cron').CronJob;
|
||||
let { log } = require('../common/utilities.js');
|
||||
|
||||
const attackRequest = (connection) => (req, res) => {
|
||||
//verify the attacker's credentials
|
||||
let query = 'SELECT accountId FROM sessions WHERE accountId IN (SELECT id FROM accounts WHERE username = ?) AND token = ?;';
|
||||
connection.query(query, [req.body.attacker, req.body.token], (err, results) => {
|
||||
//verify the attacker's credentials (only the attacker can launch an attack)
|
||||
let query = 'SELECT COUNT(*) AS total FROM sessions WHERE accountId = ? AND accountId IN (SELECT id FROM accounts WHERE username = ?) AND token = ?;';
|
||||
connection.query(query, [req.body.id, req.body.attacker, req.body.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid attack credentials', req.body.attacker, req.body.defender, req.body.token));
|
||||
if (results[0].total !== 1) {
|
||||
res.status(400).write(log('Invalid attack credentials', req.body.id, req.body.attacker, req.body.defender, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
let attackerId = results[0].accountId;
|
||||
|
||||
//verify that the defender exists
|
||||
let query = 'SELECT id FROM accounts WHERE username = ?;';
|
||||
//verify that the defender's profile exists
|
||||
let query = 'SELECT accountId FROM profiles WHERE accountId IN (SELECT id FROM accounts WHERE username = ?);';
|
||||
connection.query(query, [req.body.defender], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid defender credentials', req.body.attacker, req.body.defender));
|
||||
res.status(400).write(log('Invalid defender credentials', req.body.id, req.body.attacker, req.body.defender, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
let defenderId = results[0].id;
|
||||
let defenderId = results[0].accountId;
|
||||
|
||||
//verify that the attacker has enough soldiers
|
||||
let query = 'SELECT soldiers FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [attackerId], (err, results) => {
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results[0].soldiers <= 0) {
|
||||
@@ -52,54 +50,57 @@ const attackRequest = (connection) => (req, res) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (attacking) {
|
||||
res.status(400).write(log('You are already attacking someone', req.body.attacker, req.body.defender));
|
||||
res.status(400).write(log('You are already attacking someone', req.body.id, req.body.attacker, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//create the pending attack value
|
||||
//create the pending attack record
|
||||
let query = 'INSERT INTO pendingCombat (eventTime, attackerId, defenderId, attackingUnits) VALUES (DATE_ADD(CURRENT_TIMESTAMP(), INTERVAL 60 * ? SECOND), ?, ?, ?);';
|
||||
connection.query(query, [attackingUnits, attackerId, defenderId, attackingUnits], (err) => {
|
||||
connection.query(query, [attackingUnits, req.body.id, defenderId, attackingUnits], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
res.status(200).json({
|
||||
status: 'attacking',
|
||||
defender: req.body.defender
|
||||
attacker: req.body.attacker,
|
||||
defender: req.body.defender,
|
||||
msg: log('Attacking', req.body.attacker, req.body.defender)
|
||||
});
|
||||
res.end();
|
||||
|
||||
log(`attacking ${req.body.defender}`, req.body.attacker, req.body.defender)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const attackStatusRequest = (connection) => (req, res) => {
|
||||
isAttacking(connection, req.body.username, (err, attacking, defender) => {
|
||||
const attackStatusRequest = (connection) => (req, res) => { //TODO: proper credentials
|
||||
isAttacking(connection, req.body.attacker, (err, attacking, defender) => {
|
||||
if (err) throw err;
|
||||
|
||||
res.status(200).json({
|
||||
status: log(attacking ? 'attacking' : 'idle', req.body.username, defender),
|
||||
defender: defender
|
||||
status: attacking ? 'attacking' : 'idle',
|
||||
attacker: req.body.attacker,
|
||||
defender: defender,
|
||||
msg: null
|
||||
});
|
||||
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const combatLogRequest = (connection) => (req, res) => {
|
||||
let query = 'SELECT pastCombat.*, atk.username AS attackerUsername, def.username AS defenderUsername FROM pastCombat JOIN accounts AS atk ON pastCombat.attackerId = atk.id JOIN accounts AS def ON pastCombat.defenderId = def.id WHERE atk.username = ? OR def.username = ? ORDER BY eventTime DESC LIMIT ?, ?;';
|
||||
let query = 'SELECT pastCombat.*, atk.username AS attacker, def.username AS defender FROM pastCombat JOIN accounts AS atk ON pastCombat.attackerId = atk.id JOIN accounts AS def ON pastCombat.defenderId = def.id WHERE atk.username = ? OR def.username = ? ORDER BY eventTime DESC LIMIT ?, ?;';
|
||||
connection.query(query, [req.body.username, req.body.username, req.body.start, req.body.length], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
res.status(200).json(results);
|
||||
log('Combat log sent', req.body.username, req.body.start, req.body.length, JSON.stringify(results));
|
||||
log('Combat log sent', req.body.username, req.body.start, req.body.length);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const runCombatTick = (connection) => {
|
||||
//once per second
|
||||
let combatTick = new CronJob('* * * * * *', () => {
|
||||
//find each pending combat
|
||||
let query = 'SELECT * FROM pendingCombat WHERE eventTime < CURRENT_TIMESTAMP();';
|
||||
@@ -140,6 +141,7 @@ const runCombatTick = (connection) => {
|
||||
}
|
||||
|
||||
//determine the victor
|
||||
//TODO: add equipment effectiveness
|
||||
let rand = Math.random() * (pendingCombat.attackingUnits + defendingUnits * (undefended ? 0.25 : 1));
|
||||
let victor = rand <= pendingCombat.attackingUnits ? 'attacker' : 'defender';
|
||||
|
||||
@@ -147,23 +149,18 @@ const runCombatTick = (connection) => {
|
||||
let spoilsGold = Math.floor(results[0].gold * (victor === 'attacker' ? 0.1 : 0.02));
|
||||
let casualtiesVictor = Math.floor((pendingCombat.attackingUnits >= 10 ? pendingCombat.attackingUnits - 10 : 0) * (victor === 'attacker' ? 0.05 : 0.1));
|
||||
|
||||
//NOTE: there is a negative gold bug somewhere
|
||||
if (spoilsGold <= 0) {
|
||||
log('WARNING: spoilsGold <= 0', pendingCombat.attackerId, pendingCombat.defenderId, spoilsGold);
|
||||
}
|
||||
|
||||
//save the combat
|
||||
let query = 'INSERT INTO pastCombat (eventTime, attackerId, defenderId, attackingUnits, defendingUnits, undefended, victor, spoilsGold, casualtiesVictor) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);';
|
||||
connection.query(query, [pendingCombat.eventTime, pendingCombat.attackerId, pendingCombat.defenderId, pendingCombat.attackingUnits, defendingUnits, undefended, victor, spoilsGold, casualtiesVictor], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//update the attacker profile
|
||||
let query = 'UPDATE profiles SET gold = gold + ?, soldiers = soldiers - ? WHERE id = ?;';
|
||||
let query = 'UPDATE profiles SET gold = gold + ?, soldiers = soldiers - ? WHERE accountId = ?;';
|
||||
connection.query(query, [spoilsGold, casualtiesVictor, pendingCombat.attackerId], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//update the defender profile
|
||||
let query = 'UPDATE profiles SET gold = gold - ? WHERE id = ?;';
|
||||
let query = 'UPDATE profiles SET gold = gold - ? WHERE accountId = ?;';
|
||||
connection.query(query, [spoilsGold, pendingCombat.defenderId], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
@@ -185,12 +182,12 @@ const runCombatTick = (connection) => {
|
||||
});
|
||||
|
||||
combatTick.start();
|
||||
}
|
||||
};
|
||||
|
||||
const isNormalInteger = (str) => {
|
||||
let n = Math.floor(Number(str));
|
||||
return n !== Infinity && String(n) == str && n >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
const isAttacking = (connection, user, cb) => {
|
||||
let query;
|
||||
@@ -200,7 +197,7 @@ const isAttacking = (connection, user, cb) => {
|
||||
} else if (typeof(user) === 'string') {
|
||||
query = 'SELECT * FROM pendingCombat WHERE attackerId IN (SELECT id FROM accounts WHERE username = ?);';
|
||||
} else {
|
||||
return cb('Unknown argument type for user');
|
||||
return cb(`Unknown argument type for user: ${typeof(user)}`);
|
||||
}
|
||||
|
||||
connection.query(query, [user], (err, results) => {
|
||||
@@ -217,7 +214,7 @@ const isAttacking = (connection, user, cb) => {
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
attackRequest: attackRequest,
|
||||
@@ -225,4 +222,4 @@ module.exports = {
|
||||
combatLogRequest: combatLogRequest,
|
||||
runCombatTick: runCombatTick,
|
||||
isAttacking: isAttacking
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -42,8 +42,8 @@ function handleDisconnect() {
|
||||
|
||||
//finally
|
||||
return connection;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
connectToDatabase: handleDisconnect
|
||||
}
|
||||
};
|
||||
+4
-2
@@ -10,7 +10,9 @@ let equipmentStatistics = require('./equipment_statistics.json');
|
||||
const statisticsRequest = () => (req, res) => {
|
||||
res.status(200).json(equipmentStatistics);
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
|
||||
//TODO: incomplete
|
||||
|
||||
const listRequest = (connection) => (req, res) => {
|
||||
//verify identity
|
||||
@@ -37,7 +39,7 @@ const listRequest = (connection) => (req, res) => {
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
statisticsRequest: statisticsRequest,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"Weapons": {
|
||||
"Stick": { "cost": 50, "combatBoost": 0.02, "scientists": 1 },
|
||||
"Dagger": { "cost": 75, "combatBoost": 0.03, "scientists": 2 },
|
||||
"Sword": { "cost": 100, "combatBoost": 0.04, "scientists": 3 },
|
||||
"Longsword": { "cost": 150, "combatBoost": 0.05, "scientists": 4 },
|
||||
"Frying Pan": { "cost": 200, "combatBoost": 0.06, "scientists": 5 }
|
||||
"Stick": { "cost": 50, "combatBoost": 0.02, "scientistsRequired": 1 },
|
||||
"Dagger": { "cost": 75, "combatBoost": 0.03, "scientistsRequired": 2 },
|
||||
"Sword": { "cost": 100, "combatBoost": 0.04, "scientistsRequired": 3 },
|
||||
"Longsword": { "cost": 150, "combatBoost": 0.05, "scientistsRequired": 4 },
|
||||
"Frying Pan": { "cost": 200, "combatBoost": 0.06, "scientistsRequired": 5 }
|
||||
},
|
||||
"Armour": {
|
||||
"Leather": { "cost": 75, "combatBoost": 0.02, "scientists": 2 },
|
||||
"Gambeson": { "cost": 100, "combatBoost": 0.03, "scientists": 3 },
|
||||
"Chainmail": { "cost": 150, "combatBoost": 0.04, "scientists": 4 },
|
||||
"Platemail": { "cost": 200, "combatBoost": 0.05, "scientists": 5 }
|
||||
"Leather": { "cost": 75, "combatBoost": 0.02, "scientistsRequired": 2 },
|
||||
"Gambeson": { "cost": 100, "combatBoost": 0.03, "scientistsRequired": 3 },
|
||||
"Chainmail": { "cost": 150, "combatBoost": 0.04, "scientistsRequired": 4 },
|
||||
"Platemail": { "cost": 200, "combatBoost": 0.05, "scientistsRequired": 5 }
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -15,6 +15,7 @@ app.use(bodyParser.json());
|
||||
|
||||
//handle the news request
|
||||
let news = require('./news.js');
|
||||
app.get('/newsrequest', news.newsRequest());
|
||||
app.post('/newsrequest', news.newsRequest());
|
||||
|
||||
//database
|
||||
@@ -46,9 +47,9 @@ app.post('/attackstatusrequest', combat.attackStatusRequest(connection));
|
||||
app.post('/combatlogrequest', combat.combatLogRequest(connection));
|
||||
combat.runCombatTick(connection);
|
||||
|
||||
let equipment = require('./equipment.js');
|
||||
app.post('/equipmentstatisticsrequest', equipment.statisticsRequest());
|
||||
app.post('/equipmentlistrequest', equipment.listRequest(connection));
|
||||
//let equipment = require('./equipment.js');
|
||||
//app.post('/equipmentstatisticsrequest', equipment.statisticsRequest());
|
||||
//app.post('/equipmentlistrequest', equipment.listRequest(connection));
|
||||
|
||||
//static directories
|
||||
app.use('/styles', express.static(path.resolve(__dirname + '/../public/styles')) );
|
||||
|
||||
+9
-5
@@ -5,18 +5,20 @@ require('dotenv').config();
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
|
||||
let { log } = require('../common/utilities.js');
|
||||
|
||||
const newsRequest = () => (req, res) => {
|
||||
let fpath = path.join(__dirname, '..', 'public', 'news');
|
||||
let fileNames = fs.readdirSync(fpath);
|
||||
|
||||
//set the maximum
|
||||
let max = parseInt(req.body.max);
|
||||
if (max > fileNames.length) {
|
||||
let max = parseInt(req.body.length) || 99;
|
||||
if (isNaN(max) || max > fileNames.length) {
|
||||
max = fileNames.length;
|
||||
}
|
||||
|
||||
//build the object to send
|
||||
let json = {} //TODO: caching
|
||||
let json = {}; //TODO: caching
|
||||
|
||||
//send each file as json
|
||||
for (let i = 0; i < max; i++) {
|
||||
@@ -26,8 +28,10 @@ const newsRequest = () => (req, res) => {
|
||||
//actually send the data
|
||||
res.json(json);
|
||||
res.end();
|
||||
}
|
||||
|
||||
log('News sent', max, fileNames, JSON.stringify(json));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
newsRequest: newsRequest
|
||||
}
|
||||
};
|
||||
+230
-267
@@ -2,7 +2,6 @@
|
||||
require('dotenv').config();
|
||||
|
||||
//libraries
|
||||
let formidable = require('formidable');
|
||||
let CronJob = require('cron').CronJob;
|
||||
|
||||
let { isAttacking } = require('./combat.js');
|
||||
@@ -12,87 +11,73 @@ let { log } = require('../common/utilities.js');
|
||||
|
||||
//profile creation & requesting
|
||||
const profileCreateRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
let form = formidable.IncomingForm();
|
||||
//separate this section so it can be used elsewhere too
|
||||
return profileCreateRequestInner(connection, req, res, req.body);
|
||||
};
|
||||
|
||||
//parse form TODO: form? That was a bad idea
|
||||
form.parse(req, (err, fields) => {
|
||||
if (err) throw err;
|
||||
|
||||
//separate this section so it can be used elsewhere too
|
||||
return profileCreateRequestInner(connection, req, res, fields);
|
||||
});
|
||||
}
|
||||
|
||||
function profileCreateRequestInner(connection, req, res, fields) {
|
||||
function profileCreateRequestInner(connection, req, res, body) {
|
||||
let query = 'SELECT accountId FROM profiles WHERE accountId IN (SELECT accounts.id FROM accounts WHERE username = ?);';
|
||||
connection.query(query, [fields.username], (err, results) => {
|
||||
connection.query(query, [body.username], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length === 1) {
|
||||
res.status(400).write(log('That profile already exists', fields.username));
|
||||
res.status(400).write(log('That profile already exists', body.username));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//check ID, username and token match
|
||||
//check ID, username and token match (only the profile's owner can create it)
|
||||
let query = 'SELECT accountId FROM sessions WHERE accountId IN (SELECT id FROM accounts WHERE username = ?) AND token = ?;';
|
||||
connection.query(query, [fields.username, fields.token], (err, results) => {
|
||||
connection.query(query, [body.username, body.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1 || results[0].accountId != fields.id) {
|
||||
res.status(400).write(log('Invalid profile creation credentials', fields.username, fields.id, fields.token));
|
||||
if (results.length !== 1 || results[0].accountId != body.id) {
|
||||
res.status(400).write(log('Invalid profile creation credentials', body.username, body.id, body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//create the profile
|
||||
let query = 'INSERT INTO profiles (accountId) SELECT accounts.id FROM accounts WHERE username = ?;';
|
||||
connection.query(query, [fields.username], (err) => {
|
||||
connection.query(query, [body.username], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
log('Profile created', fields.username, fields.id, fields.token);
|
||||
log('Profile created', body.username, body.id, body.token);
|
||||
|
||||
return profileRequestInner(connection, req, res, fields);
|
||||
return profileRequestInner(connection, req, res, body);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const profileRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
let form = formidable.IncomingForm();
|
||||
|
||||
//parse form
|
||||
form.parse(req, (err, fields) => {
|
||||
if (err) throw err;
|
||||
|
||||
//separate this section so it can be used elsewhere too
|
||||
return profileRequestInner(connection, req, res, fields);
|
||||
});
|
||||
};
|
||||
|
||||
function profileRequestInner(connection, req, res, fields) {
|
||||
const profileRequest = (connection) => (req, res) => {
|
||||
//separate this section so it can be used elsewhere too
|
||||
return profileRequestInner(connection, req, res, req.body);
|
||||
};
|
||||
|
||||
function profileRequestInner(connection, req, res, body) {
|
||||
//find the profile
|
||||
let query = 'SELECT * FROM profiles WHERE accountId IN (SELECT accounts.id FROM accounts WHERE username = ?);';
|
||||
connection.query(query, [fields.username], (err, results) => {
|
||||
connection.query(query, [body.username], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
//pass it off to the profile creation process, IF the user is requesting their own profile
|
||||
let query = 'SELECT id FROM accounts WHERE id = ? AND id IN (SELECT accountId FROM sessions WHERE token = ?);';
|
||||
connection.query(query, [fields.id, fields.token], (err, results) => {
|
||||
connection.query(query, [body.id, body.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length === 1) {
|
||||
return profileCreateRequestInner(connection, req, res, fields);
|
||||
return profileCreateRequestInner(connection, req, res, body);
|
||||
} else {
|
||||
res.status(400).write(log('Profile not found', fields.username, fields.id, fields.token));
|
||||
res.status(400).write(log('Profile not found', body.username, body.id, body.token));
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//results.length === 1
|
||||
res.status(200).json({
|
||||
username: fields.username,
|
||||
username: body.username,
|
||||
gold: results[0].gold,
|
||||
recruits: results[0].recruits,
|
||||
soldiers: results[0].soldiers,
|
||||
@@ -100,71 +85,161 @@ function profileRequestInner(connection, req, res, fields) {
|
||||
scientists: results[0].scientists
|
||||
});
|
||||
res.end();
|
||||
log('Profile sent', fields.username, fields.id, fields.token);
|
||||
log('Profile sent', body.username, body.id, body.token);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//actual actions to be taken
|
||||
const recruitRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
let form = formidable.IncomingForm();
|
||||
|
||||
//parse form
|
||||
form.parse(req, (err, fields) => {
|
||||
//verify the credentials
|
||||
let query = 'SELECT COUNT(*) AS total FROM sessions WHERE accountId = ? AND token = ?;';
|
||||
connection.query(query, [req.body.id, req.body.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//verify the credentials
|
||||
let query = 'SELECT accountId FROM sessions WHERE accountId = ? AND token = ?;';
|
||||
connection.query(query, [fields.id, fields.token], (err, results) => {
|
||||
if (results[0].total !== 1) {
|
||||
res.status(400).write(log('Invalid recruit credentials - 1', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify enough time has passed since the last successful recruit action
|
||||
let query = 'SELECT TIMESTAMPDIFF(HOUR, (SELECT lastRecruitTime FROM profiles WHERE accountId = ?), CURRENT_TIMESTAMP());';
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid recruit credentials', fields.username, fields.id, fields.token));
|
||||
res.status(400).write(log('Invalid database state', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify enough time has passed since the last successful recruit action
|
||||
let query = 'SELECT TIMESTAMPDIFF(HOUR, (SELECT lastRecruitTime FROM profiles WHERE accountId = ?), CURRENT_TIMESTAMP());';
|
||||
connection.query(query, [fields.id], (err, results) => {
|
||||
let timespans = results[0][Object.keys(results[0])];
|
||||
|
||||
//not enough time has passed
|
||||
if (timespans < 20) {
|
||||
res.status(400).write(log('Not enough time has passed', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//update the profile with the new data (gaining 1 recruit)
|
||||
let query = 'UPDATE profiles SET recruits = recruits + 1, lastRecruitTime = CURRENT_TIMESTAMP() WHERE accountId = ?;';
|
||||
connection.query(query, [req.body.id], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid database state', fields.username, fields.id, fields.token));
|
||||
//send the new profile data as JSON
|
||||
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//check just in case
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//results.length === 1
|
||||
res.status(200).json({
|
||||
username: results[0].username,
|
||||
gold: results[0].gold,
|
||||
recruits: results[0].recruits,
|
||||
soldiers: results[0].soldiers,
|
||||
spies: results[0].spies,
|
||||
scientists: results[0].scientists
|
||||
});
|
||||
res.end();
|
||||
|
||||
log('Recruit successful', results[0].username, req.body.id, req.body.token);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const trainRequest = (connection) => (req, res) => {
|
||||
//verify the credentials (NOTE: duplication)
|
||||
let query = 'SELECT COUNT(*) AS total FROM sessions WHERE accountId = ? AND token = ?;';
|
||||
connection.query(query, [req.body.id, req.body.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results[0].total !== 1) {
|
||||
res.status(400).write(log('Invalid train credentials - 1', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify the role argument
|
||||
if (req.body.role !== 'soldier' && req.body.role !== 'spy' && req.body.role !== 'scientist') {
|
||||
res.status(400).write(log('Invalid train parameters', req.body.role, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//can't train while attacking
|
||||
isAttacking(connection, req.body.id, (err, attacking) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (attacking) {
|
||||
res.status(400).write(log('Can\'t train while attacking', req.body.id));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//determine the cost of the training TODO: make these global for the client too
|
||||
let cost = 0;
|
||||
switch(req.body.role) {
|
||||
case 'soldier':
|
||||
cost = 100;
|
||||
break;
|
||||
|
||||
case 'spy':
|
||||
cost = 200;
|
||||
break;
|
||||
|
||||
case 'scientist':
|
||||
cost = 120;
|
||||
break;
|
||||
}
|
||||
|
||||
//verify that the user has a high enough gold and recruit balance
|
||||
let query = 'SELECT recruits, gold FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results[0].recruits <= 0) {
|
||||
res.status(400).write(log('Not enough recruits', results[0].recruits, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
let timespans = results[0][Object.keys(results[0])];
|
||||
|
||||
//not enough time has passed
|
||||
if (timespans < 22) {
|
||||
res.status(400).write(log('Not enough time has passed', fields.username, fields.id, fields.token));
|
||||
if (results[0].gold < cost) {
|
||||
res.status(400).write(log('Not enough gold', results[0].gold, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//update the profile with the new data (gaining 1 recruit)
|
||||
let query = 'UPDATE profiles SET recruits = recruits + 1, lastRecruitTime = CURRENT_TIMESTAMP() WHERE accountId = ?;';
|
||||
connection.query(query, [fields.id], (err) => {
|
||||
//update the profile with new values (NOTE: extra protection for network latency)
|
||||
let query = 'UPDATE profiles SET gold = gold - ?, recruits = recruits - 1, soldiers = soldiers + ?, spies = spies + ?, scientists = scientists + ? WHERE accountId = ? AND gold >= ? AND recruits > 0;';
|
||||
connection.query(query, [cost, req.body.role === 'soldier' ? 1 : 0, req.body.role === 'spy' ? 1 : 0, req.body.role === 'scientist' ? 1 : 0, req.body.id, cost], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//send the new profile data as JSON (NOTE: possible duplication)
|
||||
let query = 'SELECT * FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [fields.id], (err, results) => {
|
||||
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//check just in case
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid recruit credentials', fields.username, fields.id, fields.token));
|
||||
res.status(400).write(log('Invalid recruit credentials - 2', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//results.length === 1
|
||||
res.status(200).json({
|
||||
username: fields.username, //TODO: join here
|
||||
username: results[0].username,
|
||||
gold: results[0].gold,
|
||||
recruits: results[0].recruits,
|
||||
soldiers: results[0].soldiers,
|
||||
@@ -172,227 +247,115 @@ const recruitRequest = (connection) => (req, res) => {
|
||||
scientists: results[0].scientists
|
||||
});
|
||||
res.end();
|
||||
log('Recruit successful', fields.username, fields.id, fields.token);
|
||||
log('Train executed', results[0].username, req.body.role, req.body.id, req.body.token);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const trainRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
let form = formidable.IncomingForm();
|
||||
|
||||
//parse form
|
||||
form.parse(req, (err, fields) => {
|
||||
if (err) throw err;
|
||||
|
||||
//verify the credentials (NOTE: duplication)
|
||||
let query = 'SELECT accountId FROM sessions WHERE accountId = ? AND token = ?;';
|
||||
connection.query(query, [fields.id, fields.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid train credentials', fields.username, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify the role argument
|
||||
if (fields.role !== 'soldier' && fields.role !== 'spy' && fields.role !== 'scientist') {
|
||||
res.status(400).write(log('Invalid train parameters', fields.username, fields.role, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//can't train while attacking
|
||||
isAttacking(connection, fields.id, (err, attacking) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (attacking) {
|
||||
res.status(400).write(log('Can\'t train while attacking', fields.id));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//determine the cost of the training TODO: make these global for the client too
|
||||
let cost = 0;
|
||||
switch(fields.role) {
|
||||
case 'soldier':
|
||||
cost = 100;
|
||||
break;
|
||||
|
||||
case 'spy':
|
||||
cost = 200;
|
||||
break;
|
||||
|
||||
case 'scientist':
|
||||
cost = 120;
|
||||
break;
|
||||
}
|
||||
|
||||
//verify that the user has a high enough gold and recruit balance
|
||||
let query = 'SELECT recruits, gold FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [fields.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results[0].recruits <= 0) {
|
||||
res.status(400).write(log('Not enough recruits', fields.username, results[0].recruits, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (results[0].gold < cost) {
|
||||
res.status(400).write(log('Not enough gold', fields.username, results[0].gold, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//update the profile with new values
|
||||
let query = 'UPDATE profiles SET gold = gold - ?, recruits = recruits - 1, soldiers = soldiers + ?, spies = spies + ?, scientists = scientists + ? WHERE accountId = ? AND gold >= ? AND recruits > 0;';
|
||||
connection.query(query, [cost, fields.role === 'soldier' ? 1 : 0, fields.role === 'spy' ? 1 : 0, fields.role === 'scientist' ? 1 : 0, fields.id, cost], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
//send the new profile data as JSON (NOTE: possible duplication)
|
||||
let query = 'SELECT * FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [fields.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//check just in case
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid recruit credentials', fields.username, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//results.length === 1
|
||||
res.status(200).json({
|
||||
username: fields.username, //TODO: join here
|
||||
gold: results[0].gold,
|
||||
recruits: results[0].recruits,
|
||||
soldiers: results[0].soldiers,
|
||||
spies: results[0].spies,
|
||||
scientists: results[0].scientists
|
||||
});
|
||||
res.end();
|
||||
log('Train executed', fields.username, fields.role, fields.id, fields.token);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const untrainRequest = (connection) => (req, res) => {
|
||||
//formidable handles forms
|
||||
let form = formidable.IncomingForm();
|
||||
|
||||
//parse form
|
||||
form.parse(req, (err, fields) => {
|
||||
//verify the credentials (NOTE: duplication)
|
||||
let query = 'SELECT accountId FROM sessions WHERE accountId = ? AND token = ?;';
|
||||
connection.query(query, [req.body.id, req.body.token], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//verify the credentials (NOTE: duplication)
|
||||
let query = 'SELECT accountId FROM sessions WHERE accountId = ? AND token = ?;';
|
||||
connection.query(query, [fields.id, fields.token], (err, results) => {
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid untrain credentials - 1', req.body.role, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify the role argument
|
||||
if (req.body.role !== 'soldier' && req.body.role !== 'spy' && req.body.role !== 'scientist') {
|
||||
res.status(400).write(log('Invalid untrain parameters', req.body.role, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//can't untrain while attacking
|
||||
isAttacking(connection, req.body.id, (err, attacking) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid untrain credentials', fields.username, fields.role, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify the role argument
|
||||
if (fields.role !== 'soldier' && fields.role !== 'spy' && fields.role !== 'scientist') {
|
||||
res.status(400).write(log('Invalid untrain parameters', fields.username, fields.role, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//can't untrain while attacking
|
||||
isAttacking(connection, fields.id, (err, attacking) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (attacking) {
|
||||
res.status(400).write(log('Can\'t untrain while attacking', fields.id));
|
||||
if (attacking) {
|
||||
res.status(400).write(log('Can\'t untrain while attacking', req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify that the user has a high enough balance
|
||||
let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (req.body.role === 'soldier' && results[0].soldiers <= 0) {
|
||||
res.status(400).write(log('Not enough soldiers', results[0].soldiers, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//verify that the user has a high enough balance
|
||||
let query = 'SELECT soldiers, spies, scientists FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [fields.id], (err, results) => {
|
||||
if (req.body.role === 'spy' && results[0].spies <= 0) {
|
||||
res.status(400).write(log('Not enough spies', results[0].spies, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.body.role === 'scientist' && results[0].scientists <= 0) {
|
||||
res.status(400).write(log('Not enough scientists', results[0].scientists, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//hacky
|
||||
let roleName = null;
|
||||
|
||||
if (req.body.role === 'soldier') {
|
||||
roleName = 'soldiers';
|
||||
} else if (req.body.role === 'spy') {
|
||||
roleName = 'spies';
|
||||
} else if (req.body.role === 'scientist') {
|
||||
roleName = 'scientists';
|
||||
} else {
|
||||
res.status(400).write(log('Unknown role received', req.body.role, req.body.id, req.body.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//update the profile with new values (NOTE: extra protection for network latency)
|
||||
let query = `UPDATE profiles SET recruits = recruits + 1, soldiers = soldiers - ?, spies = spies - ?, scientists = scientists - ? WHERE accountId = ? AND ${roleName} > 0;`;
|
||||
connection.query(query, [roleName === 'soldiers' ? 1 : 0, roleName === 'spies' ? 1 : 0, roleName === 'scientists' ? 1 : 0, req.body.id], (err) => {
|
||||
if (err) throw err;
|
||||
|
||||
if (fields.role === 'soldier' && results[0].soldiers <= 0) {
|
||||
res.status(400).write(log('Not enough soldiers', fields.username, results[0].soldiers, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fields.role === 'spy' && results[0].spies <= 0) {
|
||||
res.status(400).write(log('Not enough spies', fields.username, results[0].spies, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fields.role === 'scientist' && results[0].scientists <= 0) {
|
||||
res.status(400).write(log('Not enough scientists', fields.username, results[0].scientists, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//hacky
|
||||
let role = null;
|
||||
if (fields.role === 'soldier') {
|
||||
role = 'soldiers';
|
||||
} else if (fields.role === 'spy') {
|
||||
role = 'spies';
|
||||
} else if (fields.role === 'scientist') {
|
||||
role = 'scientists';
|
||||
} else {
|
||||
res.status(400).write(log('Unknown role found', fields.role));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//update the profile with new values
|
||||
let query = `UPDATE profiles SET recruits = recruits + 1, soldiers = soldiers - ?, spies = spies - ?, scientists = scientists - ? WHERE accountId = ? AND ${role} > 0;`;
|
||||
connection.query(query, [fields.role === 'soldier' ? 1 : 0, fields.role === 'spy' ? 1 : 0, fields.role === 'scientist' ? 1 : 0, fields.id], (err) => {
|
||||
//send the new profile data as JSON (NOTE: possible duplication)
|
||||
let query = 'SELECT username, profiles.* FROM profiles JOIN accounts ON accounts.id = profiles.accountId WHERE accounts.id = ?;';
|
||||
connection.query(query, [req.body.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//send the new profile data as JSON (NOTE: possible duplication)
|
||||
let query = 'SELECT * FROM profiles WHERE accountId = ?;';
|
||||
connection.query(query, [fields.id], (err, results) => {
|
||||
if (err) throw err;
|
||||
|
||||
//check just in case
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid untrain credentials', fields.username, fields.role, fields.id, fields.token));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
//results.length === 1
|
||||
res.status(200).json({
|
||||
username: fields.username, //TODO: join here
|
||||
gold: results[0].gold,
|
||||
recruits: results[0].recruits,
|
||||
soldiers: results[0].soldiers,
|
||||
spies: results[0].spies,
|
||||
scientists: results[0].scientists
|
||||
});
|
||||
//check just in case
|
||||
if (results.length !== 1) {
|
||||
res.status(400).write(log('Invalid untrain credentials - 2', req.body.role, req.body.id, req.body.token));
|
||||
res.end();
|
||||
log('Untrain executed', fields.username, fields.role, fields.id, fields.token);
|
||||
return;
|
||||
}
|
||||
|
||||
//results.length === 1
|
||||
res.status(200).json({
|
||||
username: results[0].username,
|
||||
gold: results[0].gold,
|
||||
recruits: results[0].recruits,
|
||||
soldiers: results[0].soldiers,
|
||||
spies: results[0].spies,
|
||||
scientists: results[0].scientists
|
||||
});
|
||||
res.end();
|
||||
log('Untrain executed', results[0].username, roleName, req.body.id, req.body.token);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const ladderRequest = (connection) => (req, res) => {
|
||||
let query = 'SELECT username, soldiers, recruits, gold FROM accounts JOIN profiles ON accounts.id = profiles.accountId ORDER BY soldiers DESC, recruits DESC, gold DESC LIMIT ?, ?;';
|
||||
@@ -402,7 +365,7 @@ const ladderRequest = (connection) => (req, res) => {
|
||||
res.status(200).json(results);
|
||||
log('Ladder sent', req.body.start, req.body.length, results);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const runGoldTick = (connection) => {
|
||||
let goldTickJob = new CronJob('0 */30 * * * *', () => {
|
||||
@@ -415,7 +378,7 @@ const runGoldTick = (connection) => {
|
||||
});
|
||||
|
||||
goldTickJob.start();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
// profileCreate: profileCreate, //NOTE: Not actually used
|
||||
@@ -425,4 +388,4 @@ module.exports = {
|
||||
untrainRequest: untrainRequest,
|
||||
ladderRequest: ladderRequest,
|
||||
runGoldTick: runGoldTick
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user