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'); 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(); }); passport.use('local-login', new LocalStrategy({ usernameField: "email", passwordField: "password", passReqToCallback: true }, 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); } email = mysql.escape(email); connection.query(`SELECT * from user WHERE email = ${email} AND deactivated = 0`, function (err, rows) { if (err) { return res.status(static.INTERNAL_SERVER_ERROR).send("error querying the database - Please contact sys admin"); } if (!rows.length) { return done(null, false); } if (!bcrypt.compareSync(password, rows[0].password)) { return done(null, false); } return done(null, rows[0]); }) } )); 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.get('/API/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/week', 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 day = new Date(); var querying = ""; for (let i = 0; i < 7; i++) { let currentday = day.toMysqlFormat().split(" ")[0]; querying += `SELECT "${currentday + " 21:00:00"}" as id,kind,quality,AVG(price) FROM marketv2 WHERE kind = 1 AND TIME > "${currentday} 18:00:00" AND TIME <= "${currentday} 23:59:59" GROUP BY kind,quality UNION `; querying += `SELECT "${currentday + " 15:00:00"}" as id,kind,quality,AVG(price) FROM marketv2 WHERE kind = 1 AND TIME > "${currentday} 12:00:00" AND TIME <= "${currentday} 17:59:59" GROUP BY kind,quality UNION `; querying += `SELECT "${currentday + " 09:00:00"}" as id,kind,quality,AVG(price) FROM marketv2 WHERE kind = 1 AND TIME > "${currentday} 6:00:00" AND TIME <= "${currentday} 11:59:59" GROUP BY kind,quality UNION `; querying += `SELECT "${currentday + " 3:00:00"}" as id,kind,quality,AVG(price) FROM marketv2 WHERE kind = 1 AND TIME > "${currentday} 00:00:00" AND TIME <= "${currentday} 05: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/resourcelist', function (req, res) { return res.send(resourceList); }); app.listen(3001);