428 lines
17 KiB
JavaScript
428 lines
17 KiB
JavaScript
const express = require('express')
|
|
const app = express();
|
|
const status = require('http-status');
|
|
const fetch = require('node-fetch');
|
|
const cors = require('cors');
|
|
const bodyParser = require('body-parser');
|
|
var mysql = require('mysql');
|
|
var passport = require('passport');
|
|
var LocalStrategy = require('passport-local').Strategy;
|
|
var session = require('express-session');
|
|
var MySQLStore = require('express-mysql-session')(session);
|
|
const bcrypt = require('bcrypt');
|
|
const path = require('path');
|
|
var connection = mysql.createPool({
|
|
connectionLimit: 25,
|
|
host: 'localhost',
|
|
user: 'simcompanies',
|
|
password: '',
|
|
database: 'simcompanies'
|
|
});
|
|
var sessionStore = new MySQLStore({
|
|
clearExpired: false,
|
|
schema: {
|
|
tableName: 'sessions',
|
|
columnNames: {
|
|
session_id: 'session_id',
|
|
expires: 'expires',
|
|
data: 'data'
|
|
}
|
|
}
|
|
}, connection);
|
|
|
|
const mockDataDay = require('./mockdata-test/day.json');
|
|
const mockDataWeek = require('./mockdata-test/week.json');
|
|
const mockDataMonth = require('./mockdata-test/month.json');
|
|
var resourceList;
|
|
const saltRounds = 13;
|
|
|
|
var serverStartupComplete = false;
|
|
|
|
const DEBUG = process.env.NODE_ENV === "debug" ? true : false;
|
|
|
|
function twoDigits(d) {
|
|
if (0 <= d && d < 10) return "0" + d.toString();
|
|
if (-10 < d && d < 0) return "-0" + (-1 * d).toString();
|
|
return d.toString();
|
|
}
|
|
Date.prototype.toMysqlFormat = function () {
|
|
return this.getFullYear() + "-" + twoDigits(1 + this.getMonth()) + "-" + twoDigits(this.getDate()) + " " + twoDigits(this.getHours()) + ":" + twoDigits(this.getMinutes()) + ":" + twoDigits(this.getSeconds());
|
|
};
|
|
|
|
|
|
async function loadData() {
|
|
var rL = await fetch("https://www.simcompanies.com/api/v3/en/encyclopedia/resources/");
|
|
resourceList = await rL.json();
|
|
serverStartupComplete = true;
|
|
console.log("SERVER STARTUP COMPLETED");
|
|
}
|
|
loadData();
|
|
|
|
app.use(cors({ credentials: true }));
|
|
app.use(bodyParser.urlencoded({ extended: true }));
|
|
app.use(bodyParser.json());
|
|
app.use(session({
|
|
secret: "simCoRoxUFocker",
|
|
saveUninitialized: true,
|
|
resave: true,
|
|
store: DEBUG ? undefined : sessionStore,
|
|
"cookie": {
|
|
"maxAge": 86400 * 1000
|
|
}
|
|
}));
|
|
app.use(passport.initialize());
|
|
app.use(passport.session());
|
|
|
|
app.get("*", function (req, res, next) {
|
|
if (!serverStartupComplete)
|
|
return res.send("Server is starting... Please try again soon.");
|
|
else return next();
|
|
});
|
|
|
|
app.use(express.static(path.join(__dirname, 'frontend')));
|
|
|
|
|
|
app.use(express.static(`${__dirname}/./frontend`));
|
|
app.all("/*", function (req, res, next) {
|
|
if (/^\/simcompanies\/API\/.*/.test(req.url))
|
|
req.url = req.url.substring(13);
|
|
if (!/^\/API\/.*/.test(req.url)) {
|
|
return res.sendFile(path.join(__dirname, 'frontend', 'index.html'));
|
|
} else return next();
|
|
});
|
|
|
|
const validatePassword = (email, password) => {
|
|
return new Promise(function (resolve, reject) {
|
|
connection.query(`SELECT * from user WHERE email = ${mysql.escape(email)} AND deactivated = 0`, function (err, rows) {
|
|
if (err) {
|
|
return reject("error querying the database - Please contact sys admin");
|
|
}
|
|
if (!rows.length) {
|
|
return resolve(false);
|
|
}
|
|
if (!bcrypt.compareSync(password, rows[0].password)) {
|
|
return resolve(false);
|
|
}
|
|
return resolve(rows[0]);
|
|
});
|
|
});
|
|
}
|
|
|
|
passport.use('local-login', new LocalStrategy({
|
|
usernameField: "email",
|
|
passwordField: "password",
|
|
passReqToCallback: true
|
|
}, async function (req, email, password, done) {
|
|
if (DEBUG) {
|
|
if (email === "test" && password === "test") {
|
|
return done(null, {
|
|
deactivated: false,
|
|
email: "test1",
|
|
id: 0,
|
|
created: new Date(),
|
|
password: "test"
|
|
});
|
|
} else return done(null, false);
|
|
}
|
|
try {
|
|
let user = await validatePassword(email, password);
|
|
if (user) {
|
|
return done(null, user);
|
|
}
|
|
else {
|
|
return done(null, false);
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
return done(null, false);
|
|
}
|
|
}
|
|
));
|
|
|
|
passport.serializeUser(function (user, done) {
|
|
done(null, user.id);
|
|
});
|
|
|
|
passport.deserializeUser(function (id, done) {
|
|
if (!DEBUG)
|
|
connection.query(`select * from user where id = ${id} AND deactivated = 0`, function (err, rows) {
|
|
done(err, rows[0]);
|
|
})
|
|
else {
|
|
if (id === 0) {
|
|
done(null, {
|
|
deactivated: false,
|
|
email: "test1",
|
|
id: 0,
|
|
created: new Date(),
|
|
password: "test"
|
|
});
|
|
} else return done(null, []);
|
|
}
|
|
});
|
|
|
|
app.post("/API/user/login", passport.authenticate('local-login'), function (req, res) {
|
|
return res.status(status.OK).send("login success");
|
|
});
|
|
|
|
app.put("/API/user/create", function (req, res) {
|
|
let { email, password } = req.body;
|
|
if (email && password) {
|
|
email = mysql.escape(email);
|
|
password = mysql.escape(bcrypt.hashSync(password, saltRounds));
|
|
if (DEBUG) return res.status(status.OK).send();
|
|
connection.query(`INSERT INTO user (deactivated, email, password) values (1, ${email}, ${password})`, function (err, rows) {
|
|
if (err)
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("the user seems to exist already - if you think this is an error contact the sys admin");
|
|
return res.status(status.OK).send("account successfully created");
|
|
});
|
|
} else {
|
|
return res.status(status.BAD_REQUEST).send("invalid data supplied");
|
|
}
|
|
});
|
|
|
|
app.all("*", function (req, res, next) {
|
|
if (req.isAuthenticated()) {
|
|
return next();
|
|
}
|
|
else {
|
|
return res.status(status.UNAUTHORIZED).send("please log in before using this site");
|
|
}
|
|
});
|
|
|
|
app.get("/API/testlogin", function (req, res) {
|
|
return res.status(status.OK).send(req.user["email"]);
|
|
});
|
|
|
|
app.delete("/API/user/logout", function (req, res) {
|
|
req.logout();
|
|
return res.status(status.OK).send("logout success");
|
|
});
|
|
|
|
app.get('/API/price/day', function (req, res) {
|
|
const kind = parseInt(req.query.kind);
|
|
if (Number.isInteger(kind)) {
|
|
//Mock Data:
|
|
if (kind === -1 || DEBUG) return res.send(mockDataDay);
|
|
|
|
if (kind >= 1 && kind <= 113) {
|
|
var dayend = new Date().toMysqlFormat();
|
|
var daybegin = new Date();
|
|
daybegin.setDate(daybegin.getDate() - 1);
|
|
daybegin = daybegin.toMysqlFormat();
|
|
const querystring = `SELECT time, price, quality FROM marketv2 WHERE kind = ${kind} AND time > "${daybegin}" AND time < "${dayend}" ORDER BY time, quality`;
|
|
connection.query(querystring, function (error, results, fields) {
|
|
if (error) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed");
|
|
}
|
|
return res.send(results);
|
|
});
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data range provided");
|
|
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data provided");
|
|
});
|
|
|
|
app.get('/API/amount/day', function (req, res) {
|
|
const kind = parseInt(req.query.kind);
|
|
if (Number.isInteger(kind)) {
|
|
//Mock Data:
|
|
if (kind === -1 || DEBUG) return res.send(mockDataDay);
|
|
|
|
if (kind >= 1 && kind <= 113) {
|
|
var dayend = new Date().toMysqlFormat();
|
|
var daybegin = new Date();
|
|
daybegin.setDate(daybegin.getDate() - 1);
|
|
daybegin = daybegin.toMysqlFormat();
|
|
const querystring = `SELECT time, quality, amount FROM marketcap WHERE kind = ${kind} AND time > "${daybegin}" AND time < "${dayend}" ORDER BY time, quality`;
|
|
connection.query(querystring, function (error, results, fields) {
|
|
if (error) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed");
|
|
}
|
|
return res.send(results);
|
|
});
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data range provided");
|
|
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data provided");
|
|
});
|
|
|
|
app.get('/API/price/week', function (req, res) {
|
|
const kind = parseInt(req.query.kind);
|
|
if (Number.isInteger(kind)) {
|
|
//Mock Data:
|
|
if (kind === -1 || DEBUG) return res.send(mockDataWeek);
|
|
|
|
if (kind >= 1 && kind <= 113) {
|
|
var day = new Date();
|
|
day.setDate(day.getDate() - 6)
|
|
var querying = "";
|
|
for (let i = 0; i < 7; i++) {
|
|
let currentday = day.toMysqlFormat().split(" ")[0];
|
|
querying += `SELECT "${currentday + " 3:00:00"}" as time,kind,quality,AVG(price) as price FROM marketv2 WHERE kind = ${kind} AND TIME > "${currentday} 00:00:00" AND TIME <= "${currentday} 05:59:59" GROUP BY kind,quality UNION `;
|
|
querying += `SELECT "${currentday + " 09:00:00"}" as time,kind,quality,AVG(price) as price FROM marketv2 WHERE kind = ${kind} AND TIME > "${currentday} 6:00:00" AND TIME <= "${currentday} 11:59:59" GROUP BY kind,quality UNION `;
|
|
querying += `SELECT "${currentday + " 15:00:00"}" as time,kind,quality,AVG(price) as price FROM marketv2 WHERE kind = ${kind} AND TIME > "${currentday} 12:00:00" AND TIME <= "${currentday} 17:59:59" GROUP BY kind,quality UNION `;
|
|
querying += `SELECT "${currentday + " 21:00:00"}" as time,kind,quality,AVG(price) as price FROM marketv2 WHERE kind = ${kind} AND TIME > "${currentday} 18:00:00" AND TIME <= "${currentday} 23:59:59" GROUP BY kind,quality ${i === 6 ? "" : "UNION"} `;
|
|
day.setDate(day.getDate() + 1);
|
|
}
|
|
connection.query(querying, function (error, results, fields) {
|
|
if (error) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed");
|
|
}
|
|
return res.send(results);
|
|
});
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data range provided");
|
|
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data provided");
|
|
});
|
|
|
|
app.get('/API/amount/week', function (req, res) {
|
|
const kind = parseInt(req.query.kind);
|
|
if (Number.isInteger(kind)) {
|
|
//Mock Data:
|
|
if (kind === -1 || DEBUG) return res.send(mockDataWeek);
|
|
|
|
if (kind >= 1 && kind <= 113) {
|
|
var day = new Date();
|
|
day.setDate(day.getDate() - 6)
|
|
var querying = "";
|
|
for (let i = 0; i < 7; i++) {
|
|
let currentday = day.toMysqlFormat().split(" ")[0];
|
|
querying += `SELECT "${currentday + " 3:00:00"}" as time,kind,quality,AVG(amount) as amount FROM marketcap WHERE kind = ${kind} AND TIME > "${currentday} 00:00:00" AND TIME <= "${currentday} 05:59:59" GROUP BY kind,quality UNION `;
|
|
querying += `SELECT "${currentday + " 09:00:00"}" as time,kind,quality,AVG(amount) as amount FROM marketcap WHERE kind = ${kind} AND TIME > "${currentday} 6:00:00" AND TIME <= "${currentday} 11:59:59" GROUP BY kind,quality UNION `;
|
|
querying += `SELECT "${currentday + " 15:00:00"}" as time,kind,quality,AVG(amount) as amount FROM marketcap WHERE kind = ${kind} AND TIME > "${currentday} 12:00:00" AND TIME <= "${currentday} 17:59:59" GROUP BY kind,quality UNION `;
|
|
querying += `SELECT "${currentday + " 21:00:00"}" as time,kind,quality,AVG(amount) as amount FROM marketcap WHERE kind = ${kind} AND TIME > "${currentday} 18:00:00" AND TIME <= "${currentday} 23:59:59" GROUP BY kind,quality ${i === 6 ? "" : "UNION"} `;
|
|
day.setDate(day.getDate() + 1);
|
|
}
|
|
connection.query(querying, function (error, results, fields) {
|
|
if (error) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed");
|
|
}
|
|
return res.send(results);
|
|
});
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data range provided");
|
|
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data provided");
|
|
});
|
|
|
|
app.get('/API/price/month', function (req, res) {
|
|
const kind = parseInt(req.query.kind);
|
|
if (Number.isInteger(kind)) {
|
|
//Mock Data:
|
|
if (kind === -1 || DEBUG) return res.send(mockDataMonth);
|
|
|
|
if (kind >= 1 && kind <= 113) {
|
|
var day = new Date();
|
|
day.setDate(day.getDate() - 29);
|
|
var querying = "";
|
|
for (let i = 0; i < 30; i++) {
|
|
let currentday = day.toMysqlFormat().split(" ")[0];
|
|
querying += `SELECT "${currentday}" as time,kind,quality,AVG(price) as price FROM marketv2 WHERE kind = ${kind} AND TIME >= "${currentday} 00:00:00" AND TIME <= "${currentday} 23:59:59" GROUP BY kind,quality ${i === 29 ? "" : "UNION"} `;
|
|
day.setDate(day.getDate() + 1);
|
|
}
|
|
connection.query(querying, function (error, results, fields) {
|
|
if (error) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed");
|
|
}
|
|
return res.send(results);
|
|
});
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data range provided");
|
|
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data provided");
|
|
});
|
|
|
|
app.get('/API/amount/month', function (req, res) {
|
|
const kind = parseInt(req.query.kind);
|
|
if (Number.isInteger(kind)) {
|
|
//Mock Data:
|
|
if (kind === -1 || DEBUG) return res.send(mockDataMonth);
|
|
|
|
if (kind >= 1 && kind <= 113) {
|
|
var day = new Date();
|
|
day.setDate(day.getDate() - 29);
|
|
var querying = "";
|
|
for (let i = 0; i < 30; i++) {
|
|
let currentday = day.toMysqlFormat().split(" ")[0];
|
|
querying += `SELECT "${currentday}" as time,kind,quality,AVG(amount) as amount FROM marketcap WHERE kind = ${kind} AND TIME >= "${currentday} 00:00:00" AND TIME <= "${currentday} 23:59:59" GROUP BY kind,quality ${i === 29 ? "" : "UNION"} `;
|
|
day.setDate(day.getDate() + 1);
|
|
}
|
|
connection.query(querying, function (error, results, fields) {
|
|
if (error) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed");
|
|
}
|
|
return res.send(results);
|
|
});
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data range provided");
|
|
|
|
}
|
|
else
|
|
return res.status(status.BAD_REQUEST).send("invalid data provided");
|
|
});
|
|
|
|
app.get('/API/resourcelist', function (req, res) {
|
|
return res.send(resourceList);
|
|
});
|
|
|
|
app.post("/API/user/setname", async function (req, res) {
|
|
let { email, password } = req.body;
|
|
if (email && password) {
|
|
if (DEBUG) return res.status(status.OK).send("username changed");
|
|
try {
|
|
if (!await validatePassword(req.user.email, password))
|
|
return res.status(status.UNAUTHORIZED).send("wrong password supplied");
|
|
} catch (e) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send(e);
|
|
}
|
|
connection.query(`UPDATE user SET email = ${mysql.escape(email)} WHERE email = ${mysql.escape(req.user.email)}`, function (err, rows) {
|
|
if (err)
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("the username seems invalid or already taken - if you think this is an error contact the sys admin");
|
|
req.user.email = email;
|
|
return res.status(status.OK).send("username changed");
|
|
});
|
|
} else {
|
|
return res.status(status.BAD_REQUEST).send("invalid data supplied");
|
|
}
|
|
});
|
|
|
|
app.post("/API/user/setpassword", async function (req, res) {
|
|
let { oldpassword, newpassword } = req.body;
|
|
if (oldpassword && newpassword) {
|
|
if (DEBUG) return res.status(status.OK).send("password changed");
|
|
try {
|
|
if (!await validatePassword(req.user.email, oldpassword))
|
|
return res.status(status.UNAUTHORIZED).send("wrong password supplied");
|
|
} catch (e) {
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send(e);
|
|
}
|
|
connection.query(`UPDATE user SET password = ${mysql.escape(bcrypt.hashSync(newpassword, saltRounds))} WHERE email = ${mysql.escape(req.user.email)}`, function (err, rows) {
|
|
if (err)
|
|
return res.status(status.INTERNAL_SERVER_ERROR).send("the password could not be set - if you think this is an error contact the sys admin");
|
|
return res.status(status.OK).send("password changed");
|
|
});
|
|
} else {
|
|
return res.status(status.BAD_REQUEST).send("invalid data supplied");
|
|
}
|
|
});
|
|
|
|
app.listen(3001);
|