diff --git a/backend/index.js b/backend/index.js index 8b1707d..59c02b1 100644 --- a/backend/index.js +++ b/backend/index.js @@ -2,30 +2,78 @@ 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.createConnection({ +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..."); + return res.send("Server is starting... Please try again soon."); else return next(); }); @@ -39,29 +87,116 @@ app.all("/*", function (req, res, next) { 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) { + 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.send(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 { + res.status(status.BAD_REQUEST).send("invalid data supplied"); + } +}); + +app.all("*", function (req, res, next) { + if (req.isAuthenticated()) { + return next(); + } + else { + res.status(status.UNAUTHORIZED).send("please log in before using this site"); + } +}); + +app.get("/API/testlogin", function (req, res) { + res.status(status.OK).send(req.user["email"]); +}); app.get('/API/day', function (req, res) { - var date = new Date(req.query.date); const kind = parseInt(req.query.kind); - if (date instanceof Date && Number.isInteger(kind)) { + if (Number.isInteger(kind)) { //Mock Data: - if (kind === -1) return res.send(mockDataDay); + if (kind === -1 || DEBUG) return res.send(mockDataDay); - if (!isNaN(date.getTime()) && kind >= 1 && kind <= 113) { - const daybegin = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`; - date.setDate(date.getDate() + 1); - const dayend = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`; - const querystring = `SELECT time, price FROM market WHERE kind = ${kind} AND time > "${daybegin}" AND time < "${dayend}"` + if (kind >= 1 && kind <= 113) { + var dayend = new Date().toMysqlFormat(); + var daybegin = new Date(); + daybegin.setDate(daybegin.getDate() - 1); + daybegin = daybegin.toISOString().slice(0, 19).replace('T', ' '); + 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) { - throw error; + res.status(status.INTERNAL_SERVER_ERROR).send("database connection failed"); } res.send(results); }); } else - res.status(status.BAD_REQUEST).send("invalid data provided"); + res.status(status.BAD_REQUEST).send("invalid data range provided"); } else @@ -72,4 +207,4 @@ app.get('/API/resourcelist', function (req, res) { res.send(resourceList); }); -app.listen(3001); \ No newline at end of file +app.listen(3001); diff --git a/backend/mockdata-test/day.json b/backend/mockdata-test/day.json index 086eb08..6a830c4 100644 --- a/backend/mockdata-test/day.json +++ b/backend/mockdata-test/day.json @@ -1,946 +1,1532 @@ [ { - "time": "2020-04-16T22:00:09.000Z", - "price": 0.268 + "time": "2020-04-29T17:00:04.000Z", + "price": 0.24, + "quality": 0 }, { - "time": "2020-04-16T22:05:05.000Z", - "price": 0.268 + "time": "2020-04-29T17:00:04.000Z", + "price": 0.244, + "quality": 1 }, { - "time": "2020-04-16T22:10:04.000Z", - "price": 0.268 + "time": "2020-04-29T17:00:04.000Z", + "price": 0.244, + "quality": 2 }, { - "time": "2020-04-16T22:15:09.000Z", - "price": 0.27 + "time": "2020-04-29T17:00:04.000Z", + "price": 0.243, + "quality": 3 }, { - "time": "2020-04-16T22:20:12.000Z", - "price": 0.264 + "time": "2020-04-29T17:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-16T22:25:11.000Z", - "price": 0.268 + "time": "2020-04-29T17:00:04.000Z", + "price": 0.245, + "quality": 5 }, { - "time": "2020-04-16T22:30:12.000Z", - "price": 0.27 + "time": "2020-04-29T17:30:03.000Z", + "price": 0.244, + "quality": 0 }, { - "time": "2020-04-16T22:35:07.000Z", - "price": 0.271 + "time": "2020-04-29T17:30:03.000Z", + "price": 0.245, + "quality": 1 }, { - "time": "2020-04-16T22:40:08.000Z", - "price": 0.263 + "time": "2020-04-29T17:30:03.000Z", + "price": 0.246, + "quality": 2 }, { - "time": "2020-04-16T22:45:12.000Z", - "price": 0.26 + "time": "2020-04-29T17:30:03.000Z", + "price": 0.248, + "quality": 3 }, { - "time": "2020-04-16T22:50:14.000Z", - "price": 0.268 + "time": "2020-04-29T17:30:03.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-16T22:55:24.000Z", - "price": 0.267 + "time": "2020-04-29T17:30:03.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-16T23:00:21.000Z", - "price": 0.269 + "time": "2020-04-29T18:00:03.000Z", + "price": 0.244, + "quality": 0 }, { - "time": "2020-04-16T23:05:05.000Z", - "price": 0.259 + "time": "2020-04-29T18:00:03.000Z", + "price": 0.246, + "quality": 1 }, { - "time": "2020-04-16T23:10:23.000Z", - "price": 0.272 + "time": "2020-04-29T18:00:03.000Z", + "price": 0.247, + "quality": 2 }, { - "time": "2020-04-16T23:15:11.000Z", - "price": 0.272 + "time": "2020-04-29T18:00:03.000Z", + "price": 0.249, + "quality": 3 }, { - "time": "2020-04-16T23:20:27.000Z", - "price": 0.273 + "time": "2020-04-29T18:00:03.000Z", + "price": 0.244, + "quality": 4 }, { - "time": "2020-04-16T23:25:20.000Z", - "price": 0.272 + "time": "2020-04-29T18:00:03.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-16T23:30:16.000Z", - "price": 0.271 + "time": "2020-04-29T18:30:03.000Z", + "price": 0.24, + "quality": 0 }, { - "time": "2020-04-16T23:35:04.000Z", - "price": 0.274 + "time": "2020-04-29T18:30:03.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-16T23:40:05.000Z", - "price": 0.271 + "time": "2020-04-29T18:30:03.000Z", + "price": 0.247, + "quality": 2 }, { - "time": "2020-04-16T23:45:09.000Z", - "price": 0.265 + "time": "2020-04-29T18:30:03.000Z", + "price": 0.249, + "quality": 3 }, { - "time": "2020-04-16T23:50:12.000Z", - "price": 0.274 + "time": "2020-04-29T18:30:03.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-16T23:55:13.000Z", - "price": 0.27 + "time": "2020-04-29T18:30:03.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T00:00:06.000Z", - "price": 0.25 + "time": "2020-04-29T19:00:04.000Z", + "price": 0.247, + "quality": 0 }, { - "time": "2020-04-17T00:05:13.000Z", - "price": 0.272 + "time": "2020-04-29T19:00:04.000Z", + "price": 0.246, + "quality": 1 }, { - "time": "2020-04-17T00:10:27.000Z", - "price": 0.272 + "time": "2020-04-29T19:00:04.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T00:15:25.000Z", - "price": 0.27 + "time": "2020-04-29T19:00:04.000Z", + "price": 0.249, + "quality": 3 }, { - "time": "2020-04-17T00:20:23.000Z", - "price": 0.27 + "time": "2020-04-29T19:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T00:25:07.000Z", - "price": 0.27 + "time": "2020-04-29T19:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T00:30:17.000Z", - "price": 0.259 + "time": "2020-04-29T19:30:04.000Z", + "price": 0.244, + "quality": 0 }, { - "time": "2020-04-17T00:35:07.000Z", - "price": 0.27 + "time": "2020-04-29T19:30:04.000Z", + "price": 0.245, + "quality": 1 }, { - "time": "2020-04-17T00:40:04.000Z", - "price": 0.263 + "time": "2020-04-29T19:30:04.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T00:45:05.000Z", - "price": 0.269 + "time": "2020-04-29T19:30:04.000Z", + "price": 0.248, + "quality": 3 }, { - "time": "2020-04-17T00:50:06.000Z", - "price": 0.269 + "time": "2020-04-29T19:30:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T00:55:13.000Z", - "price": 0.268 + "time": "2020-04-29T19:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T01:00:10.000Z", - "price": 0.268 + "time": "2020-04-29T20:00:04.000Z", + "price": 0.243, + "quality": 0 }, { - "time": "2020-04-17T01:05:10.000Z", - "price": 0.269 + "time": "2020-04-29T20:00:04.000Z", + "price": 0.247, + "quality": 1 }, { - "time": "2020-04-17T01:10:28.000Z", - "price": 0.268 + "time": "2020-04-29T20:00:04.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T01:15:24.000Z", - "price": 0.268 + "time": "2020-04-29T20:00:04.000Z", + "price": 0.249, + "quality": 3 }, { - "time": "2020-04-17T01:20:22.000Z", - "price": 0.268 + "time": "2020-04-29T20:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T01:25:32.000Z", - "price": 0.264 + "time": "2020-04-29T20:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T01:30:44.000Z", - "price": 0.26 + "time": "2020-04-29T20:30:03.000Z", + "price": 0.245, + "quality": 0 }, { - "time": "2020-04-17T01:35:04.000Z", - "price": 0.262 + "time": "2020-04-29T20:30:03.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-17T01:40:14.000Z", - "price": 0.265 + "time": "2020-04-29T20:30:03.000Z", + "price": 0.249, + "quality": 2 }, { - "time": "2020-04-17T01:45:07.000Z", - "price": 0.266 + "time": "2020-04-29T20:30:03.000Z", + "price": 0.248, + "quality": 3 }, { - "time": "2020-04-17T01:50:03.000Z", - "price": 0.267 + "time": "2020-04-29T20:30:03.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T01:55:04.000Z", - "price": 0.259 + "time": "2020-04-29T20:30:03.000Z", + "price": 0.255, + "quality": 5 }, { - "time": "2020-04-17T02:00:04.000Z", - "price": 0.269 + "time": "2020-04-29T21:00:04.000Z", + "price": 0.239, + "quality": 0 }, { - "time": "2020-04-17T02:05:46.000Z", - "price": 0.269 + "time": "2020-04-29T21:00:04.000Z", + "price": 0.247, + "quality": 1 }, { - "time": "2020-04-17T02:10:16.000Z", - "price": 0.269 + "time": "2020-04-29T21:00:04.000Z", + "price": 0.244, + "quality": 2 }, { - "time": "2020-04-17T02:17:46.000Z", - "price": 0.27 + "time": "2020-04-29T21:00:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T02:20:23.000Z", - "price": 0.271 + "time": "2020-04-29T21:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T02:25:14.000Z", - "price": 0.271 + "time": "2020-04-29T21:00:04.000Z", + "price": 0.245, + "quality": 5 }, { - "time": "2020-04-17T02:30:07.000Z", - "price": 0.267 + "time": "2020-04-29T21:30:03.000Z", + "price": 0.245, + "quality": 0 }, { - "time": "2020-04-17T02:35:05.000Z", - "price": 0.269 + "time": "2020-04-29T21:30:03.000Z", + "price": 0.23, + "quality": 1 }, { - "time": "2020-04-17T02:40:07.000Z", - "price": 0.27 + "time": "2020-04-29T21:30:03.000Z", + "price": 0.246, + "quality": 2 }, { - "time": "2020-04-17T02:45:10.000Z", - "price": 0.272 + "time": "2020-04-29T21:30:03.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T02:50:08.000Z", - "price": 0.267 + "time": "2020-04-29T21:30:03.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T02:55:04.000Z", - "price": 0.267 + "time": "2020-04-29T21:30:03.000Z", + "price": 0.255, + "quality": 5 }, { - "time": "2020-04-17T03:00:06.000Z", - "price": 0.27 + "time": "2020-04-29T22:00:06.000Z", + "price": 0.246, + "quality": 0 }, { - "time": "2020-04-17T03:05:07.000Z", - "price": 0.26 + "time": "2020-04-29T22:00:06.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-17T03:10:04.000Z", - "price": 0.271 + "time": "2020-04-29T22:00:06.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T03:15:06.000Z", - "price": 0.271 + "time": "2020-04-29T22:00:06.000Z", + "price": 0.249, + "quality": 3 }, { - "time": "2020-04-17T03:20:08.000Z", - "price": 0.271 + "time": "2020-04-29T22:00:06.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T03:25:05.000Z", - "price": 0.267 + "time": "2020-04-29T22:00:06.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T03:30:13.000Z", - "price": 0.27 + "time": "2020-04-29T22:30:04.000Z", + "price": 0.247, + "quality": 0 }, { - "time": "2020-04-17T03:35:08.000Z", - "price": 0.271 + "time": "2020-04-29T22:30:04.000Z", + "price": 0.246, + "quality": 1 }, { - "time": "2020-04-17T03:40:04.000Z", - "price": 0.271 + "time": "2020-04-29T22:30:04.000Z", + "price": 0.249, + "quality": 2 }, { - "time": "2020-04-17T03:45:10.000Z", - "price": 0.27 + "time": "2020-04-29T22:30:04.000Z", + "price": 0.251, + "quality": 3 }, { - "time": "2020-04-17T03:50:07.000Z", - "price": 0.26 + "time": "2020-04-29T22:30:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T03:55:08.000Z", - "price": 0.27 + "time": "2020-04-29T22:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T04:00:04.000Z", - "price": 0.265 + "time": "2020-04-29T23:00:05.000Z", + "price": 0.247, + "quality": 0 }, { - "time": "2020-04-17T04:05:05.000Z", - "price": 0.267 + "time": "2020-04-29T23:00:05.000Z", + "price": 0.247, + "quality": 1 }, { - "time": "2020-04-17T04:10:08.000Z", - "price": 0.266 + "time": "2020-04-29T23:00:05.000Z", + "price": 0.249, + "quality": 2 }, { - "time": "2020-04-17T04:15:14.000Z", - "price": 0.267 + "time": "2020-04-29T23:00:05.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T04:20:07.000Z", - "price": 0.24 + "time": "2020-04-29T23:00:05.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T04:25:19.000Z", - "price": 0.27 + "time": "2020-04-29T23:00:05.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T04:30:07.000Z", - "price": 0.271 + "time": "2020-04-29T23:30:04.000Z", + "price": 0.247, + "quality": 0 }, { - "time": "2020-04-17T04:35:04.000Z", - "price": 0.269 + "time": "2020-04-29T23:30:04.000Z", + "price": 0.247, + "quality": 1 }, { - "time": "2020-04-17T04:40:07.000Z", - "price": 0.269 + "time": "2020-04-29T23:30:04.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T04:45:06.000Z", - "price": 0.268 + "time": "2020-04-29T23:30:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T04:50:08.000Z", - "price": 0.269 + "time": "2020-04-29T23:30:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T04:55:08.000Z", - "price": 0.269 + "time": "2020-04-29T23:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T05:00:05.000Z", - "price": 0.265 + "time": "2020-04-30T00:00:04.000Z", + "price": 0.246, + "quality": 0 }, { - "time": "2020-04-17T05:05:06.000Z", - "price": 0.267 + "time": "2020-04-30T00:00:04.000Z", + "price": 0.247, + "quality": 1 }, { - "time": "2020-04-17T05:10:05.000Z", - "price": 0.264 + "time": "2020-04-30T00:00:04.000Z", + "price": 0.247, + "quality": 2 }, { - "time": "2020-04-17T05:15:07.000Z", - "price": 0.266 + "time": "2020-04-30T00:00:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T05:20:06.000Z", - "price": 0.269 + "time": "2020-04-30T00:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T05:25:08.000Z", - "price": 0.272 + "time": "2020-04-30T00:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T05:30:07.000Z", - "price": 0.273 + "time": "2020-04-30T00:30:04.000Z", + "price": 0.246, + "quality": 0 }, { - "time": "2020-04-17T05:35:06.000Z", - "price": 0.274 + "time": "2020-04-30T00:30:04.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-17T05:40:06.000Z", - "price": 0.274 + "time": "2020-04-30T00:30:04.000Z", + "price": 0.25, + "quality": 2 }, { - "time": "2020-04-17T05:45:06.000Z", - "price": 0.272 + "time": "2020-04-30T00:30:04.000Z", + "price": 0.251, + "quality": 3 }, { - "time": "2020-04-17T05:50:08.000Z", - "price": 0.277 + "time": "2020-04-30T00:30:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T05:55:09.000Z", - "price": 0.275 + "time": "2020-04-30T00:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T06:00:11.000Z", - "price": 0.275 + "time": "2020-04-30T01:00:04.000Z", + "price": 0.242, + "quality": 0 }, { - "time": "2020-04-17T06:05:13.000Z", - "price": 0.274 + "time": "2020-04-30T01:00:04.000Z", + "price": 0.245, + "quality": 1 }, { - "time": "2020-04-17T06:10:17.000Z", - "price": 0.272 + "time": "2020-04-30T01:00:04.000Z", + "price": 0.243, + "quality": 2 }, { - "time": "2020-04-17T06:15:09.000Z", - "price": 0.272 + "time": "2020-04-30T01:00:04.000Z", + "price": 0.251, + "quality": 3 }, { - "time": "2020-04-17T06:20:07.000Z", - "price": 0.26 + "time": "2020-04-30T01:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T06:25:07.000Z", - "price": 0.269 + "time": "2020-04-30T01:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T06:30:07.000Z", - "price": 0.268 + "time": "2020-04-30T01:30:04.000Z", + "price": 0.246, + "quality": 0 }, { - "time": "2020-04-17T06:35:07.000Z", - "price": 0.272 + "time": "2020-04-30T01:30:04.000Z", + "price": 0.246, + "quality": 1 }, { - "time": "2020-04-17T06:40:05.000Z", - "price": 0.273 + "time": "2020-04-30T01:30:04.000Z", + "price": 0.247, + "quality": 2 }, { - "time": "2020-04-17T06:45:05.000Z", - "price": 0.272 + "time": "2020-04-30T01:30:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T06:50:07.000Z", - "price": 0.272 + "time": "2020-04-30T01:30:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T06:55:08.000Z", - "price": 0.27 + "time": "2020-04-30T01:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T07:00:05.000Z", - "price": 0.271 + "time": "2020-04-30T02:00:06.000Z", + "price": 0.247, + "quality": 0 }, { - "time": "2020-04-17T07:05:05.000Z", - "price": 0.273 + "time": "2020-04-30T02:00:06.000Z", + "price": 0.247, + "quality": 1 }, { - "time": "2020-04-17T07:10:06.000Z", - "price": 0.27 + "time": "2020-04-30T02:00:06.000Z", + "price": 0.25, + "quality": 2 }, { - "time": "2020-04-17T07:15:07.000Z", - "price": 0.268 + "time": "2020-04-30T02:00:06.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T07:20:06.000Z", - "price": 0.271 + "time": "2020-04-30T02:00:06.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T07:25:06.000Z", - "price": 0.27 + "time": "2020-04-30T02:00:06.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T07:30:07.000Z", - "price": 0.27 + "time": "2020-04-30T02:30:04.000Z", + "price": 0.243, + "quality": 0 }, { - "time": "2020-04-17T07:35:10.000Z", - "price": 0.268 + "time": "2020-04-30T02:30:04.000Z", + "price": 0.244, + "quality": 1 }, { - "time": "2020-04-17T07:40:09.000Z", - "price": 0.268 + "time": "2020-04-30T02:30:04.000Z", + "price": 0.25, + "quality": 2 }, { - "time": "2020-04-17T07:45:06.000Z", - "price": 0.273 + "time": "2020-04-30T02:30:04.000Z", + "price": 0.252, + "quality": 3 }, { - "time": "2020-04-17T07:50:07.000Z", - "price": 0.269 + "time": "2020-04-30T02:30:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T07:55:07.000Z", - "price": 0.274 + "time": "2020-04-30T02:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T08:00:09.000Z", - "price": 0.272 + "time": "2020-04-30T03:00:04.000Z", + "price": 0.245, + "quality": 0 }, { - "time": "2020-04-17T08:05:08.000Z", - "price": 0.27 + "time": "2020-04-30T03:00:04.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-17T08:10:07.000Z", - "price": 0.268 + "time": "2020-04-30T03:00:04.000Z", + "price": 0.249, + "quality": 2 }, { - "time": "2020-04-17T08:15:07.000Z", - "price": 0.269 + "time": "2020-04-30T03:00:04.000Z", + "price": 0.247, + "quality": 3 }, { - "time": "2020-04-17T08:20:06.000Z", - "price": 0.265 + "time": "2020-04-30T03:00:04.000Z", + "price": 0.254, + "quality": 4 }, { - "time": "2020-04-17T08:25:05.000Z", - "price": 0.265 + "time": "2020-04-30T03:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T08:30:07.000Z", - "price": 0.26 + "time": "2020-04-30T03:30:03.000Z", + "price": 0.243, + "quality": 0 }, { - "time": "2020-04-17T08:35:07.000Z", - "price": 0.26 + "time": "2020-04-30T03:30:03.000Z", + "price": 0.249, + "quality": 1 }, { - "time": "2020-04-17T08:40:09.000Z", - "price": 0.261 + "time": "2020-04-30T03:30:03.000Z", + "price": 0.249, + "quality": 2 }, { - "time": "2020-04-17T08:45:10.000Z", - "price": 0.26 + "time": "2020-04-30T03:30:03.000Z", + "price": 0.252, + "quality": 3 }, { - "time": "2020-04-17T08:50:10.000Z", - "price": 0.264 + "time": "2020-04-30T03:30:03.000Z", + "price": 0.252, + "quality": 4 }, { - "time": "2020-04-17T08:55:11.000Z", - "price": 0.265 + "time": "2020-04-30T03:30:03.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T09:00:08.000Z", - "price": 0.265 + "time": "2020-04-30T04:00:04.000Z", + "price": 0.242, + "quality": 0 }, { - "time": "2020-04-17T09:05:09.000Z", - "price": 0.265 + "time": "2020-04-30T04:00:04.000Z", + "price": 0.244, + "quality": 1 }, { - "time": "2020-04-17T09:10:07.000Z", - "price": 0.265 + "time": "2020-04-30T04:00:04.000Z", + "price": 0.25, + "quality": 2 }, { - "time": "2020-04-17T09:15:09.000Z", - "price": 0.272 + "time": "2020-04-30T04:00:04.000Z", + "price": 0.251, + "quality": 3 }, { - "time": "2020-04-17T09:20:06.000Z", - "price": 0.265 + "time": "2020-04-30T04:00:04.000Z", + "price": 0.252, + "quality": 4 }, { - "time": "2020-04-17T09:25:09.000Z", - "price": 0.265 + "time": "2020-04-30T04:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T09:30:06.000Z", - "price": 0.265 + "time": "2020-04-30T04:30:04.000Z", + "price": 0.241, + "quality": 0 }, { - "time": "2020-04-17T09:35:15.000Z", - "price": 0.265 + "time": "2020-04-30T04:30:04.000Z", + "price": 0.243, + "quality": 1 }, { - "time": "2020-04-17T09:40:08.000Z", - "price": 0.265 + "time": "2020-04-30T04:30:04.000Z", + "price": 0.242, + "quality": 2 }, { - "time": "2020-04-17T09:45:07.000Z", - "price": 0.269 + "time": "2020-04-30T04:30:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T09:50:07.000Z", - "price": 0.265 + "time": "2020-04-30T04:30:04.000Z", + "price": 0.252, + "quality": 4 }, { - "time": "2020-04-17T09:55:05.000Z", - "price": 0.264 + "time": "2020-04-30T04:30:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T10:00:09.000Z", - "price": 0.262 + "time": "2020-04-30T05:00:04.000Z", + "price": 0.239, + "quality": 0 }, { - "time": "2020-04-17T10:05:11.000Z", - "price": 0.262 + "time": "2020-04-30T05:00:04.000Z", + "price": 0.242, + "quality": 1 }, { - "time": "2020-04-17T10:10:08.000Z", - "price": 0.262 + "time": "2020-04-30T05:00:04.000Z", + "price": 0.25, + "quality": 2 }, { - "time": "2020-04-17T10:15:06.000Z", - "price": 0.264 + "time": "2020-04-30T05:00:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T10:20:05.000Z", - "price": 0.267 + "time": "2020-04-30T05:00:04.000Z", + "price": 0.252, + "quality": 4 }, { - "time": "2020-04-17T10:25:07.000Z", - "price": 0.271 + "time": "2020-04-30T05:00:04.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T10:30:06.000Z", - "price": 0.264 + "time": "2020-04-30T05:30:03.000Z", + "price": 0.24, + "quality": 0 }, { - "time": "2020-04-17T10:35:06.000Z", - "price": 0.265 + "time": "2020-04-30T05:30:03.000Z", + "price": 0.249, + "quality": 1 }, { - "time": "2020-04-17T10:40:05.000Z", - "price": 0.26 + "time": "2020-04-30T05:30:03.000Z", + "price": 0.244, + "quality": 2 }, { - "time": "2020-04-17T10:45:07.000Z", - "price": 0.271 + "time": "2020-04-30T05:30:03.000Z", + "price": 0.245, + "quality": 3 }, { - "time": "2020-04-17T10:50:08.000Z", - "price": 0.268 + "time": "2020-04-30T05:30:03.000Z", + "price": 0.25, + "quality": 4 }, { - "time": "2020-04-17T10:55:07.000Z", - "price": 0.266 + "time": "2020-04-30T05:30:03.000Z", + "price": 0.258, + "quality": 5 }, { - "time": "2020-04-17T11:00:06.000Z", - "price": 0.266 + "time": "2020-04-30T06:00:04.000Z", + "price": 0.245, + "quality": 0 }, { - "time": "2020-04-17T11:05:11.000Z", - "price": 0.268 + "time": "2020-04-30T06:00:04.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-17T11:10:06.000Z", - "price": 0.27 + "time": "2020-04-30T06:00:04.000Z", + "price": 0.247, + "quality": 2 }, { - "time": "2020-04-17T11:15:06.000Z", - "price": 0.268 + "time": "2020-04-30T06:00:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T11:20:08.000Z", - "price": 0.26 + "time": "2020-04-30T06:00:04.000Z", + "price": 0.26, + "quality": 4 }, { - "time": "2020-04-17T11:25:08.000Z", - "price": 0.26 + "time": "2020-04-30T06:00:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T11:30:08.000Z", - "price": 0.265 + "time": "2020-04-30T06:30:04.000Z", + "price": 0.245, + "quality": 0 }, { - "time": "2020-04-17T11:35:34.000Z", - "price": 0.27 + "time": "2020-04-30T06:30:04.000Z", + "price": 0.248, + "quality": 1 }, { - "time": "2020-04-17T11:40:07.000Z", - "price": 0.269 + "time": "2020-04-30T06:30:04.000Z", + "price": 0.249, + "quality": 2 }, { - "time": "2020-04-17T11:45:08.000Z", - "price": 0.269 + "time": "2020-04-30T06:30:04.000Z", + "price": 0.247, + "quality": 3 }, { - "time": "2020-04-17T11:50:06.000Z", - "price": 0.25 + "time": "2020-04-30T06:30:04.000Z", + "price": 0.26, + "quality": 4 }, { - "time": "2020-04-17T11:55:06.000Z", - "price": 0.26 + "time": "2020-04-30T06:30:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T12:00:06.000Z", - "price": 0.268 + "time": "2020-04-30T07:00:05.000Z", + "price": 0.244, + "quality": 0 }, { - "time": "2020-04-17T12:05:08.000Z", - "price": 0.268 + "time": "2020-04-30T07:00:05.000Z", + "price": 0.245, + "quality": 1 }, { - "time": "2020-04-17T12:10:09.000Z", - "price": 0.267 + "time": "2020-04-30T07:00:05.000Z", + "price": 0.246, + "quality": 2 }, { - "time": "2020-04-17T12:15:08.000Z", - "price": 0.26 + "time": "2020-04-30T07:00:05.000Z", + "price": 0.247, + "quality": 3 }, { - "time": "2020-04-17T12:20:07.000Z", - "price": 0.27 + "time": "2020-04-30T07:00:05.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T12:25:11.000Z", - "price": 0.269 + "time": "2020-04-30T07:00:05.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T12:30:08.000Z", - "price": 0.266 + "time": "2020-04-30T07:30:04.000Z", + "price": 0.242, + "quality": 0 }, { - "time": "2020-04-17T12:35:08.000Z", - "price": 0.264 + "time": "2020-04-30T07:30:04.000Z", + "price": 0.243, + "quality": 1 }, { - "time": "2020-04-17T12:40:09.000Z", - "price": 0.263 + "time": "2020-04-30T07:30:04.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T12:45:10.000Z", - "price": 0.26 + "time": "2020-04-30T07:30:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T12:50:09.000Z", - "price": 0.259 + "time": "2020-04-30T07:30:04.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T12:55:07.000Z", - "price": 0.26 + "time": "2020-04-30T07:30:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T13:00:04.000Z", - "price": 0.259 + "time": "2020-04-30T08:00:03.000Z", + "price": 0.242, + "quality": 0 }, { - "time": "2020-04-17T13:05:06.000Z", - "price": 0.263 + "time": "2020-04-30T08:00:03.000Z", + "price": 0.242, + "quality": 1 }, { - "time": "2020-04-17T13:10:06.000Z", - "price": 0.265 + "time": "2020-04-30T08:00:03.000Z", + "price": 0.244, + "quality": 2 }, { - "time": "2020-04-17T13:15:10.000Z", - "price": 0.266 + "time": "2020-04-30T08:00:03.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T13:20:05.000Z", - "price": 0.266 + "time": "2020-04-30T08:00:03.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T13:25:06.000Z", - "price": 0.262 + "time": "2020-04-30T08:00:03.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T13:30:09.000Z", - "price": 0.268 + "time": "2020-04-30T08:30:04.000Z", + "price": 0.24, + "quality": 0 }, { - "time": "2020-04-17T13:35:06.000Z", - "price": 0.268 + "time": "2020-04-30T08:30:04.000Z", + "price": 0.242, + "quality": 1 }, { - "time": "2020-04-17T13:40:08.000Z", - "price": 0.269 + "time": "2020-04-30T08:30:04.000Z", + "price": 0.244, + "quality": 2 }, { - "time": "2020-04-17T13:45:09.000Z", - "price": 0.268 + "time": "2020-04-30T08:30:04.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T13:50:06.000Z", - "price": 0.26 + "time": "2020-04-30T08:30:04.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T13:55:05.000Z", - "price": 0.26 + "time": "2020-04-30T08:30:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T14:00:07.000Z", - "price": 0.264 + "time": "2020-04-30T09:00:03.000Z", + "price": 0.235, + "quality": 0 }, { - "time": "2020-04-17T14:05:08.000Z", - "price": 0.264 + "time": "2020-04-30T09:00:03.000Z", + "price": 0.245, + "quality": 1 }, { - "time": "2020-04-17T14:10:08.000Z", - "price": 0.264 + "time": "2020-04-30T09:00:03.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T14:15:07.000Z", - "price": 0.263 + "time": "2020-04-30T09:00:03.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T14:20:06.000Z", - "price": 0.25 + "time": "2020-04-30T09:00:03.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T14:25:07.000Z", - "price": 0.264 + "time": "2020-04-30T09:00:03.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T14:30:07.000Z", - "price": 0.271 + "time": "2020-04-30T09:30:03.000Z", + "price": 0.239, + "quality": 0 }, { - "time": "2020-04-17T14:35:08.000Z", - "price": 0.269 + "time": "2020-04-30T09:30:03.000Z", + "price": 0.242, + "quality": 1 }, { - "time": "2020-04-17T14:40:07.000Z", - "price": 0.272 + "time": "2020-04-30T09:30:03.000Z", + "price": 0.245, + "quality": 2 }, { - "time": "2020-04-17T14:45:10.000Z", - "price": 0.271 + "time": "2020-04-30T09:30:03.000Z", + "price": 0.25, + "quality": 3 }, { - "time": "2020-04-17T14:50:06.000Z", - "price": 0.27 + "time": "2020-04-30T09:30:03.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T14:55:07.000Z", - "price": 0.267 + "time": "2020-04-30T09:30:03.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T15:00:07.000Z", - "price": 0.268 + "time": "2020-04-30T10:00:04.000Z", + "price": 0.241, + "quality": 0 }, { - "time": "2020-04-17T15:05:07.000Z", - "price": 0.268 + "time": "2020-04-30T10:00:04.000Z", + "price": 0.244, + "quality": 1 }, { - "time": "2020-04-17T15:10:09.000Z", - "price": 0.268 + "time": "2020-04-30T10:00:04.000Z", + "price": 0.245, + "quality": 2 }, { - "time": "2020-04-17T15:15:06.000Z", - "price": 0.269 + "time": "2020-04-30T10:00:04.000Z", + "price": 0.251, + "quality": 3 }, { - "time": "2020-04-17T15:20:05.000Z", - "price": 0.269 + "time": "2020-04-30T10:00:04.000Z", + "price": 0.259, + "quality": 4 }, { - "time": "2020-04-17T15:25:10.000Z", - "price": 0.263 + "time": "2020-04-30T10:00:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T15:30:07.000Z", - "price": 0.27 + "time": "2020-04-30T10:30:04.000Z", + "price": 0.24, + "quality": 0 }, { - "time": "2020-04-17T15:35:06.000Z", - "price": 0.273 + "time": "2020-04-30T10:30:04.000Z", + "price": 0.244, + "quality": 1 }, { - "time": "2020-04-17T15:40:06.000Z", - "price": 0.27 + "time": "2020-04-30T10:30:04.000Z", + "price": 0.248, + "quality": 2 }, { - "time": "2020-04-17T15:45:06.000Z", - "price": 0.27 + "time": "2020-04-30T10:30:04.000Z", + "price": 0.252, + "quality": 3 }, { - "time": "2020-04-17T15:50:08.000Z", - "price": 0.265 + "time": "2020-04-30T10:30:04.000Z", + "price": 0.26, + "quality": 4 }, { - "time": "2020-04-17T15:55:05.000Z", - "price": 0.27 + "time": "2020-04-30T10:30:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T16:00:06.000Z", - "price": 0.27 + "time": "2020-04-30T11:00:04.000Z", + "price": 0.243, + "quality": 0 }, { - "time": "2020-04-17T16:05:07.000Z", - "price": 0.272 + "time": "2020-04-30T11:00:04.000Z", + "price": 0.242, + "quality": 1 }, { - "time": "2020-04-17T16:10:05.000Z", - "price": 0.268 + "time": "2020-04-30T11:00:04.000Z", + "price": 0.245, + "quality": 2 }, { - "time": "2020-04-17T16:15:04.000Z", - "price": 0.269 + "time": "2020-04-30T11:00:04.000Z", + "price": 0.252, + "quality": 3 }, { - "time": "2020-04-17T16:20:08.000Z", - "price": 0.26 + "time": "2020-04-30T11:00:04.000Z", + "price": 0.26, + "quality": 4 }, { - "time": "2020-04-17T16:25:05.000Z", - "price": 0.269 + "time": "2020-04-30T11:00:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T16:30:06.000Z", - "price": 0.269 + "time": "2020-04-30T11:30:04.000Z", + "price": 0.246, + "quality": 0 }, { - "time": "2020-04-17T16:35:05.000Z", - "price": 0.267 + "time": "2020-04-30T11:30:04.000Z", + "price": 0.246, + "quality": 1 }, { - "time": "2020-04-17T16:40:09.000Z", - "price": 0.25 + "time": "2020-04-30T11:30:04.000Z", + "price": 0.246, + "quality": 2 }, { - "time": "2020-04-17T16:45:07.000Z", - "price": 0.265 + "time": "2020-04-30T11:30:04.000Z", + "price": 0.252, + "quality": 3 }, { - "time": "2020-04-17T16:50:08.000Z", - "price": 0.265 + "time": "2020-04-30T11:30:04.000Z", + "price": 0.26, + "quality": 4 }, { - "time": "2020-04-17T16:55:07.000Z", - "price": 0.261 + "time": "2020-04-30T11:30:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T17:00:05.000Z", - "price": 0.264 + "time": "2020-04-30T12:00:04.000Z", + "price": 0.243, + "quality": 0 }, { - "time": "2020-04-17T17:05:03.000Z", - "price": 0.266 + "time": "2020-04-30T12:00:04.000Z", + "price": 0.245, + "quality": 1 }, { - "time": "2020-04-17T17:10:03.000Z", - "price": 0.26 + "time": "2020-04-30T12:00:04.000Z", + "price": 0.245, + "quality": 2 }, { - "time": "2020-04-17T17:15:04.000Z", - "price": 0.261 + "time": "2020-04-30T12:00:04.000Z", + "price": 0.252, + "quality": 3 }, { - "time": "2020-04-17T17:20:04.000Z", - "price": 0.261 + "time": "2020-04-30T12:00:04.000Z", + "price": 0.26, + "quality": 4 }, { - "time": "2020-04-17T17:25:04.000Z", - "price": 0.258 + "time": "2020-04-30T12:00:04.000Z", + "price": 0.26, + "quality": 5 }, { - "time": "2020-04-17T17:30:03.000Z", - "price": 0.255 + "time": "2020-04-30T12:30:04.000Z", + "price": 0.242, + "quality": 0 }, { - "time": "2020-04-17T17:35:06.000Z", - "price": 0.26 + "time": "2020-04-30T12:30:04.000Z", + "price": 0.241, + "quality": 1 + }, + { + "time": "2020-04-30T12:30:04.000Z", + "price": 0.248, + "quality": 2 + }, + { + "time": "2020-04-30T12:30:04.000Z", + "price": 0.242, + "quality": 3 + }, + { + "time": "2020-04-30T12:30:04.000Z", + "price": 0.26, + "quality": 4 + }, + { + "time": "2020-04-30T12:30:04.000Z", + "price": 0.26, + "quality": 5 + }, + { + "time": "2020-04-30T13:00:03.000Z", + "price": 0.24, + "quality": 0 + }, + { + "time": "2020-04-30T13:00:03.000Z", + "price": 0.242, + "quality": 1 + }, + { + "time": "2020-04-30T13:00:03.000Z", + "price": 0.248, + "quality": 2 + }, + { + "time": "2020-04-30T13:00:03.000Z", + "price": 0.246, + "quality": 3 + }, + { + "time": "2020-04-30T13:00:03.000Z", + "price": 0.249, + "quality": 4 + }, + { + "time": "2020-04-30T13:00:03.000Z", + "price": 0.26, + "quality": 5 + }, + { + "time": "2020-04-30T13:30:04.000Z", + "price": 0.239, + "quality": 0 + }, + { + "time": "2020-04-30T13:30:04.000Z", + "price": 0.243, + "quality": 1 + }, + { + "time": "2020-04-30T13:30:04.000Z", + "price": 0.247, + "quality": 2 + }, + { + "time": "2020-04-30T13:30:04.000Z", + "price": 0.251, + "quality": 3 + }, + { + "time": "2020-04-30T13:30:04.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T13:30:04.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T14:00:03.000Z", + "price": 0.242, + "quality": 0 + }, + { + "time": "2020-04-30T14:00:03.000Z", + "price": 0.243, + "quality": 1 + }, + { + "time": "2020-04-30T14:00:03.000Z", + "price": 0.248, + "quality": 2 + }, + { + "time": "2020-04-30T14:00:03.000Z", + "price": 0.251, + "quality": 3 + }, + { + "time": "2020-04-30T14:00:03.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T14:00:03.000Z", + "price": 0.249, + "quality": 5 + }, + { + "time": "2020-04-30T14:30:04.000Z", + "price": 0.244, + "quality": 0 + }, + { + "time": "2020-04-30T14:30:04.000Z", + "price": 0.248, + "quality": 1 + }, + { + "time": "2020-04-30T14:30:04.000Z", + "price": 0.249, + "quality": 2 + }, + { + "time": "2020-04-30T14:30:04.000Z", + "price": 0.249, + "quality": 3 + }, + { + "time": "2020-04-30T14:30:04.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T14:30:04.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T15:00:04.000Z", + "price": 0.245, + "quality": 0 + }, + { + "time": "2020-04-30T15:00:04.000Z", + "price": 0.245, + "quality": 1 + }, + { + "time": "2020-04-30T15:00:04.000Z", + "price": 0.249, + "quality": 2 + }, + { + "time": "2020-04-30T15:00:04.000Z", + "price": 0.249, + "quality": 3 + }, + { + "time": "2020-04-30T15:00:04.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T15:00:04.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T15:30:10.000Z", + "price": 0.243, + "quality": 0 + }, + { + "time": "2020-04-30T15:30:10.000Z", + "price": 0.245, + "quality": 1 + }, + { + "time": "2020-04-30T15:30:10.000Z", + "price": 0.244, + "quality": 2 + }, + { + "time": "2020-04-30T15:30:10.000Z", + "price": 0.25, + "quality": 3 + }, + { + "time": "2020-04-30T15:30:10.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T15:30:10.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T16:00:04.000Z", + "price": 0.243, + "quality": 0 + }, + { + "time": "2020-04-30T16:00:04.000Z", + "price": 0.24, + "quality": 1 + }, + { + "time": "2020-04-30T16:00:04.000Z", + "price": 0.25, + "quality": 2 + }, + { + "time": "2020-04-30T16:00:04.000Z", + "price": 0.25, + "quality": 3 + }, + { + "time": "2020-04-30T16:00:04.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T16:00:04.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T16:30:04.000Z", + "price": 0.242, + "quality": 0 + }, + { + "time": "2020-04-30T16:30:04.000Z", + "price": 0.248, + "quality": 1 + }, + { + "time": "2020-04-30T16:30:04.000Z", + "price": 0.242, + "quality": 2 + }, + { + "time": "2020-04-30T16:30:04.000Z", + "price": 0.251, + "quality": 3 + }, + { + "time": "2020-04-30T16:30:04.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T16:30:04.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T17:30:04.000Z", + "price": 0.24, + "quality": 0 + }, + { + "time": "2020-04-30T17:30:04.000Z", + "price": 0.242, + "quality": 1 + }, + { + "time": "2020-04-30T17:30:04.000Z", + "price": 0.248, + "quality": 2 + }, + { + "time": "2020-04-30T17:30:04.000Z", + "price": 0.251, + "quality": 3 + }, + { + "time": "2020-04-30T17:30:04.000Z", + "price": 0.248, + "quality": 4 + }, + { + "time": "2020-04-30T17:30:04.000Z", + "price": 0.259, + "quality": 5 + }, + { + "time": "2020-04-30T18:00:04.000Z", + "price": 0.245, + "quality": 0 + }, + { + "time": "2020-04-30T18:00:04.000Z", + "price": 0.248, + "quality": 1 + }, + { + "time": "2020-04-30T18:00:04.000Z", + "price": 0.246, + "quality": 2 + }, + { + "time": "2020-04-30T18:00:04.000Z", + "price": 0.251, + "quality": 3 + }, + { + "time": "2020-04-30T18:00:04.000Z", + "price": 0.258, + "quality": 4 + }, + { + "time": "2020-04-30T18:00:04.000Z", + "price": 0.247, + "quality": 5 + }, + { + "time": "2020-04-30T18:30:04.000Z", + "price": 0.243, + "quality": 0 + }, + { + "time": "2020-04-30T18:30:04.000Z", + "price": 0.243, + "quality": 1 + }, + { + "time": "2020-04-30T18:30:04.000Z", + "price": 0.243, + "quality": 2 + }, + { + "time": "2020-04-30T18:30:04.000Z", + "price": 0.251, + "quality": 3 + }, + { + "time": "2020-04-30T18:30:04.000Z", + "price": 0.244, + "quality": 4 + }, + { + "time": "2020-04-30T18:30:04.000Z", + "price": 0.247, + "quality": 5 } ] \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index eebf721..37d7d2c 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -48,6 +48,20 @@ "picomatch": "^2.0.4" } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -58,6 +72,15 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bcrypt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-4.0.1.tgz", + "integrity": "sha512-hSIZHkUxIDS5zA2o00Kf2O5RfVbQ888n54xQoF/eIaquU4uaLxK8vhhBdktd0B3n2MjkcAWzv4mnhogykBKOUQ==", + "requires": { + "node-addon-api": "^2.0.0", + "node-pre-gyp": "0.14.0" + } + }, "bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -156,6 +179,11 @@ "readdirp": "~3.3.0" } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "ci-info": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", @@ -166,6 +194,11 @@ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -197,6 +230,11 @@ "xdg-basedir": "^3.0.0" } }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -225,6 +263,15 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, "create-error-class": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", @@ -233,6 +280,58 @@ "capture-stack-trace": "^1.0.0" } }, + "cross-env": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", + "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -261,6 +360,11 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -271,6 +375,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -360,6 +469,99 @@ "vary": "~1.1.2" } }, + "express-mysql-session": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/express-mysql-session/-/express-mysql-session-2.1.4.tgz", + "integrity": "sha512-Fcq168xVI8jtIJLhVHLJvBCvJlHnFWCcPmtt93UrWH38T2YsB919KrMCCh57/YkECkfff/L5zTQ95K1DxfOixg==", + "requires": { + "debug": "4.1.1", + "express-session": "1.17.0", + "mysql": "2.18.1", + "underscore": "1.9.2" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "express-session": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", + "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + } + } + }, + "express-session": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz", + "integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -392,17 +594,91 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "requires": { + "minipass": "^2.6.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, "fsevents": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", "optional": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "glob-parent": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", @@ -447,6 +723,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -477,6 +758,14 @@ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "requires": { + "minimatch": "^3.0.4" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -487,6 +776,15 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -669,6 +967,45 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -685,16 +1022,74 @@ "sqlstring": "2.3.1" } }, + "needle": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.1.tgz", + "integrity": "sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "node-addon-api": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz", + "integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==" + }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, + "node-pre-gyp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", + "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "dependencies": { + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } + }, "nodemon": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz", @@ -740,6 +1135,29 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -748,6 +1166,27 @@ "path-key": "^2.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -756,6 +1195,38 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -777,6 +1248,33 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", @@ -792,6 +1290,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "picomatch": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", @@ -836,6 +1339,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -902,6 +1410,14 @@ "rc": "^1.0.1" } }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -912,6 +1428,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -963,6 +1484,11 @@ "send": "0.17.1" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -1039,6 +1565,27 @@ "has-flag": "^3.0.0" } }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -1082,6 +1629,14 @@ "mime-types": "~2.1.24" } }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -1090,6 +1645,11 @@ "debug": "^2.2.0" } }, + "underscore": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz", + "integrity": "sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==" + }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", @@ -1156,6 +1716,14 @@ "isexe": "^2.0.0" } }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", @@ -1164,6 +1732,11 @@ "string-width": "^2.1.1" } }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/backend/package.json b/backend/package.json index 91ef49c..6fd2b7a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,16 +5,26 @@ "main": "index.js", "scripts": { "start": "node index.js", - "debug": "nodemon index.js", + "debug": "cross-env NODE_ENV=debug nodemon index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Oliver Boehlk", "license": "GPL-3.0", "dependencies": { + "bcrypt": "^4.0.1", + "body-parser": "^1.19.0", + "cors": "^2.8.5", "express": "^4.17.1", + "express-mysql-session": "^2.1.4", + "express-session": "^1.17.1", "http-status": "^1.4.2", "mysql": "^2.18.1", "node-fetch": "^2.6.0", - "nodemon": "^2.0.2" + "nodemon": "^2.0.2", + "passport": "^0.4.1", + "passport-local": "^1.0.0" + }, + "devDependencies": { + "cross-env": "^7.0.2" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 482ba0f..0c7b100 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1292,6 +1292,18 @@ "@babel/runtime": "^7.4.4" } }, + "@material-ui/lab": { + "version": "4.0.0-alpha.51", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.51.tgz", + "integrity": "sha512-X/qv/sZQGhXhKDn83L94gNahGDQj2Rd6r7/9tPpQbSn2A1LAt1+jlTiWD1HUgDXZEPqTsJMajOjWSEmTL7/q7w==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@material-ui/styles": { "version": "4.9.10", "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.10.tgz", diff --git a/frontend/package.json b/frontend/package.json index e197578..870a97b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,41 +1,42 @@ { - "name": "simcompanies-dashboard", - "version": "0.1.0", - "homepage": "https://projects.oliver.boehlk.io/simcompanies/", - "private": true, - "dependencies": { - "@material-ui/core": "^4.9.8", - "@material-ui/icons": "^4.9.1", - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/react": "^9.4.0", - "@testing-library/user-event": "^7.2.1", - "react": "^16.12.0", - "react-dom": "^16.12.0", - "react-router-dom": "^5.1.2", - "react-scripts": "3.4.0", - "typeface-roboto": "0.0.75", - "recharts": "^1.8.5" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": "react-app" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "proxy": "http://127.0.0.1:3001" -} \ No newline at end of file + "name": "simcompanies-dashboard", + "version": "0.1.0", + "homepage": "https://projects.oliver.boehlk.io/simcompanies/", + "private": true, + "dependencies": { + "@material-ui/core": "^4.9.8", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.51", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.4.0", + "@testing-library/user-event": "^7.2.1", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-router-dom": "^5.1.2", + "react-scripts": "3.4.0", + "recharts": "^1.8.5", + "typeface-roboto": "0.0.75" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "proxy": "http://127.0.0.1:3001" +} diff --git a/frontend/src/App.css b/frontend/src/App.css index 61592b6..af7bf6f 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -9,3 +9,12 @@ margin-left: 10px; height: 64px; } + +.loginBackground { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + margin: auto; + min-height: 100vh; + background-image: url(./img/loginBackground.png); +} \ No newline at end of file diff --git a/frontend/src/App.js b/frontend/src/App.js index 4348a7e..a60257f 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -4,12 +4,53 @@ import { } from "react-router-dom"; import Navbar from "./components/navigation"; import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import { + Route, Switch +} from "react-router-dom"; +import Login from './components/login/login'; +import CreateAccount from './components/login/createAccount'; import "./App.css"; +import { Redirect } from "react-router-dom"; +class ProtectedRoute extends Component { + constructor(props) { + super(props); + this.state = { auth: null }; + } + async componentWillMount() { + const url = "/simcompanies/API/testlogin"; + const response = await fetch(url); + if (response.status == "200") { + this.setState({ + auth: true + }); + } else { + this.setState({ + auth: false + }); + } + } + render() { + const { component: Component, ...props } = this.props; + return ( + this.state.auth === null ? + "Loading..." : + ( + this.state.auth ? + : + + )} + /> + ) + } +} class App extends Component { + render() { const theme = createMuiTheme({ palette: { @@ -24,11 +65,16 @@ class App extends Component { } }) + //change basename in browserrouter if uri changes return ( - + + + + + diff --git a/frontend/src/components/content.js b/frontend/src/components/content.js index 2369ca6..8b84c4a 100644 --- a/frontend/src/components/content.js +++ b/frontend/src/components/content.js @@ -7,6 +7,7 @@ import { import SelectResource from './selectResource'; import ResourceChart from './resourcechart/resourcechart'; + const useStyles = makeStyles(theme => ({ root: { flexGrow: 1, @@ -23,7 +24,7 @@ export default function Content() {
- } /> + } />
); diff --git a/frontend/src/components/login/createAccount.js b/frontend/src/components/login/createAccount.js new file mode 100644 index 0000000..3f3ed5f --- /dev/null +++ b/frontend/src/components/login/createAccount.js @@ -0,0 +1,187 @@ +import React from 'react'; +import { Link } from "react-router-dom"; +import { makeStyles, withStyles } from '@material-ui/core/styles'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import Logo from "../../img/logo.png"; +import TextField from '@material-ui/core/TextField'; +import Grid from '@material-ui/core/Grid'; +import { Redirect } from "react-router-dom"; +import LoginFeedback from './loginfeedback'; + +const url = "/simcompanies/API/user/create" + +const useStyles = makeStyles(theme => ({ + card: { + backgroundColor: "#0B1929", + display: "flex" + }, + logo: { + maxWidth: "50%", + height: "auto" + }, + input: { + color: "#9daac1" + }, + grid: { + display: "flex" + } +})); + +const CssTextField = withStyles({ + root: { + '& label.Mui-focused': { + color: '#FFC800', + }, + '&:hover label': { + color: '#FFC800', + }, + '& label': { + color: 'white', + }, + '& .MuiOutlinedInput-root': { + '& input': { + color: "white" + }, + '& fieldset': { + borderColor: 'white', + color: "white" + }, + '&:hover fieldset': { + borderColor: "#FFC800", + }, + '&.Mui-focused fieldset': { + borderColor: '#FFC800', + }, + }, + }, +})(TextField); + +export default function CreateAccount() { + const classes = useStyles(); + const [username, setUsername] = React.useState(""); + const [password, setPassword] = React.useState(""); + const [login, setLogin] = React.useState(true); + const [status, setStatus] = React.useState(null); + const [statusText, setStatusText] = React.useState(null); + const [disabled, setDisabled] = React.useState(false); + + const putCreateAccount = async (url, data) => { + const response = await fetch(url, { + method: 'PUT', + mode: 'cors', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json' + }, + redirect: 'follow', + referrerPolicy: 'no-referrer', + body: JSON.stringify(data) + }); + const text = await response.text() + await setStatusText(text) + setStatus(response.status) + if (response.status == "200") { + setTimeout(() => { setLogin(false) }, 2000) + } + setDisabled(false) + setTimeout(() => { setStatus(null) }, 2000) + } + const handleClick = (e) => { + if (username !== "" && password !== "") { + setDisabled(true) + putCreateAccount(url, { email: username, password: password }) + + setUsername("") + setPassword("") + } + } + + const handleKeyDown = (e) => { + if (e.key === "Enter") { + if (username !== "" && password !== "") { + setDisabled(true) + putCreateAccount(url, { email: username, password: password }) + + setUsername("") + setPassword("") + } + } + } + const handleChangeUSR = (e) => { + setUsername(e.target.value) + } + const handleChangePW = (e) => { + setPassword(e.target.value) + } + + return ( + login === true ? + + + + + SC Dashboard Logo + +
+ + + + + + Create new Account + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
: + ) + +} diff --git a/frontend/src/components/login/login.js b/frontend/src/components/login/login.js new file mode 100644 index 0000000..6afb83e --- /dev/null +++ b/frontend/src/components/login/login.js @@ -0,0 +1,206 @@ +import React from 'react'; +import { Link } from "react-router-dom"; +import { makeStyles, withStyles } from '@material-ui/core/styles'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import Logo from "../../img/logo.png"; +import TextField from '@material-ui/core/TextField'; +import Grid from '@material-ui/core/Grid'; +import Link1 from '@material-ui/core/Link'; +import { Redirect } from "react-router-dom"; +import LoginFeedback from './loginfeedback'; + + +const useStyles = makeStyles(theme => ({ + card: { + backgroundColor: "#0B1929", + display: "flex" + }, + logo: { + maxWidth: "50%", + height: "auto" + }, + input: { + color: "#9daac1" + }, + grid: { + display: "flex" + } +})); + +const CssTextField = withStyles({ + root: { + '& label.Mui-focused': { + color: "#FFC800", + }, + '&:hover label': { + color: '#FFC800', + }, + '& label': { + color: 'white', + }, + '& .MuiOutlinedInput-root': { + '& input': { + color: "white" + }, + '& fieldset': { + borderColor: 'white', + color: "white" + }, + '&:hover fieldset': { + borderColor: "#FFC800", + }, + '&.Mui-focused fieldset': { + borderColor: "#FFC800", + }, + }, + }, +})(TextField); + + +export default function Login() { + const classes = useStyles(); + const url = "/simcompanies/API/user/login" + const [username, setUsername] = React.useState(""); + const [password, setPassword] = React.useState(""); + const [login, setLogin] = React.useState(true); + const [status, setStatus] = React.useState(null); + const [disabled, setDisabled] = React.useState(false); + const [statusText, setStatusText] = React.useState(null); + + const postLogin = async (url, data) => { + + const response = await fetch(url, { + method: 'POST', + mode: 'cors', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/json' + }, + redirect: 'follow', + referrerPolicy: 'no-referrer', + body: JSON.stringify(data) + }); + + const text = await response.text() + await setStatusText(text) + setStatus(response.status) + if (response.status == "200") { + setTimeout(() => { setLogin(false) }, 2000) + + } + setDisabled(false) + setTimeout(() => { setStatus(null) }, 2000) + } + + const handleClick = (e) => { + + if (username !== "" && password !== "") { + setDisabled(true) + postLogin(url, { email: username, password: password }) + + setUsername("") + setPassword("") + } + } + + const handleKeyDown = (e) => { + if (e.key === "Enter") { + if (username !== "" && password !== "") { + setDisabled(true) + postLogin(url, { email: username, password: password }) + + setUsername("") + setPassword("") + } + } + } + + const handleChangeUSR = (e) => { + setUsername(e.target.value) + } + const handleChangePW = (e) => { + setPassword(e.target.value) + } + + + return ( + + login === true ? + < Box className="loginBackground" display="flex" justifyContent="center" alignItems="center" m={1} p={1} > + + + + SC Dashboard Logo + +
+ + + + + + Login + + + + + + + + + + + + + + + + + + Create new Account + + + + + + + + + + + +
+
+
+ + : + ) + +} diff --git a/frontend/src/components/login/loginfeedback.js b/frontend/src/components/login/loginfeedback.js new file mode 100644 index 0000000..cecdfa5 --- /dev/null +++ b/frontend/src/components/login/loginfeedback.js @@ -0,0 +1,66 @@ +import React, { useEffect } from 'react'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; + +function Alert(props) { + return ; +} + +export default function LoginFeedback(props) { + const [login, setLogin] = React.useState(null); + const [open, setOpen] = React.useState(true); + const [open1, setOpen1] = React.useState(true); + const [output, setOutput] = React.useState(null); + const [change, setChange] = React.useState(false); + + useEffect(() => { + if (login != props.login) { + setChange(true) + setOpen(true) + setOpen1(true) + setLogin(props.login) + } + }, [login, setLogin, props.login]); + + const handleClose = (event, reason) => { + + setOpen(false); + }; + const handleClose1 = (event, reason) => { + setOpen1(false); + }; + + const snack = (login) => { + if (login == "200") { + setOutput( + + + {props.text} + + ) + } else if (login != null) { + setOutput( + + + {props.text} + + + ) + } else { + setOutput(null) + } + setChange(false) + } + + if (change == true) { + snack(login) + } + + return ( + + {output} + + + ) + +} diff --git a/frontend/src/components/resourcechart/resourcechart.js b/frontend/src/components/resourcechart/resourcechart.js index 010e659..b943e16 100644 --- a/frontend/src/components/resourcechart/resourcechart.js +++ b/frontend/src/components/resourcechart/resourcechart.js @@ -11,11 +11,15 @@ import CardContent from '@material-ui/core/CardContent'; import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import Grid from '@material-ui/core/Grid'; +import Button from '@material-ui/core/Button'; const useStyles = makeStyles((theme) => ({ root: { display: 'flex', }, + card: { + padding: 20 + } })); const output = (data) => { @@ -38,7 +42,14 @@ const output = (data) => { - + + + + + + + + ) } @@ -49,20 +60,60 @@ export default function ResourceChart(props) { const [data, setData] = React.useState(null); let { id } = useParams(); const loadData = async () => { - let nextData = await fetch(`/simcompanies/API/day?date=${props["day"]}&kind=${id}`); - nextData = await nextData.json(); - for (let i = 0; i < nextData.length; i++) { - nextData[i]["time"] = new Date(nextData[i]["time"]); - nextData[i]["time"] = nextData[i]["time"].toLocaleTimeString(); + let dayData = await fetch(`/simcompanies/API/day?kind=${id}`); + let dataWithDate = await dayData.json(); + let qualitySortedData = []; + for (let i = 0; i < dataWithDate.length; i++) { + if (i === 0) qualitySortedData.push(dataWithDate[i]); + else { + if (dataWithDate[i]["time"] === qualitySortedData[qualitySortedData.length - 1]["time"]) { + switch (dataWithDate[i].quality) { + case 0: break; + case 1: + qualitySortedData[qualitySortedData.length - 1]["q1"] = dataWithDate[i]["price"]; + break; + case 2: + qualitySortedData[qualitySortedData.length - 1]["q2"] = dataWithDate[i]["price"]; + break; + case 3: + qualitySortedData[qualitySortedData.length - 1]["q3"] = dataWithDate[i]["price"]; + break; + case 4: + qualitySortedData[qualitySortedData.length - 1]["q4"] = dataWithDate[i]["price"]; + break; + case 5: + qualitySortedData[qualitySortedData.length - 1]["q5"] = dataWithDate[i]["price"]; + break; + case 6: + qualitySortedData[qualitySortedData.length - 1]["q6"] = dataWithDate[i]["price"]; + break; + case 7: + qualitySortedData[qualitySortedData.length - 1]["q7"] = dataWithDate[i]["price"]; + break; + default: + break; + } + } else { + qualitySortedData.push(dataWithDate[i]); + qualitySortedData[qualitySortedData.length - 1]["q0"] = qualitySortedData[qualitySortedData.length - 1]["price"]; + } + } } - setData(nextData) + for (let i = 0; i < qualitySortedData.length; i++) { + qualitySortedData[i]["time"] = new Date(qualitySortedData[i]["time"]); + qualitySortedData[i]["time"] = qualitySortedData[i]["time"].toLocaleTimeString(); + } + console.log(qualitySortedData); + setData(qualitySortedData) } if (data === null) { loadData(); } - + const handleClick = (e) => { + loadData() + } return (
@@ -73,16 +124,17 @@ export default function ResourceChart(props) { - + {output(data)} +
- - ); } diff --git a/frontend/src/components/selectResource/index.js b/frontend/src/components/selectResource/index.js index 9027869..716e85e 100644 --- a/frontend/src/components/selectResource/index.js +++ b/frontend/src/components/selectResource/index.js @@ -2,37 +2,207 @@ import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Grid from '@material-ui/core/Grid'; import ResourceCard from './resourceCard'; +import Typography from '@material-ui/core/Typography'; const useStyles = makeStyles(theme => ({ - card: { - + grid: { + display: "flex" } })); +const agri = [66, 3, 4, 5, 6, 7, 8, 9, 40, 72, 106] +const construct = [101, 102, 103, 104, 105, 107, 108, 109, 110, 111] +const fashion = [41, 46, 60, 61, 62, 63, 64, 65, 70, 71] +const energy = [10, 11, 12, 1, 73, 74, 83] +const electronics = [20, 21, 22, 23, 24, 25, 26, 27, 28, 79, 98] +const auto = [47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 112] +const aero = [77, 78, 80, 81, 82, 84, 85, 86, 87, 88, 89] +const resource = [2, 13, 14, 15, 16, 17, 18, 19, 42, 43, 44, 45, 68, 69, 75, 76] +const research = [29, 30, 31, 32, 33, 34, 35, 58, 59, 100, 113] export default function SelectResource() { const classes = useStyles(); - const [resources, setResources] = React.useState(null); + const [resources, setResources] = React.useState([]); const loadResources = async () => { var resourceJSON = await fetch("/simcompanies/API/resourcelist"); resourceJSON = await resourceJSON.json(); - let rArr = []; + let rArr = [[], [], [], [], [], [], [], [], [], []]; for (let i = 0; i < resourceJSON.length; i++) { - rArr.push(); + if (agri.includes(resourceJSON[i]["db_letter"])) { + rArr[0].push(); + } else if (construct.includes(resourceJSON[i]["db_letter"])) { + rArr[1].push(); + } else if (fashion.includes(resourceJSON[i]["db_letter"])) { + rArr[2].push(); + } else if (energy.includes(resourceJSON[i]["db_letter"])) { + rArr[3].push(); + } else if (electronics.includes(resourceJSON[i]["db_letter"])) { + rArr[4].push(); + } else if (auto.includes(resourceJSON[i]["db_letter"])) { + rArr[5].push(); + } else if (aero.includes(resourceJSON[i]["db_letter"])) { + rArr[6].push(); + } else if (resource.includes(resourceJSON[i]["db_letter"])) { + rArr[7].push(); + } else if (research.includes(resourceJSON[i]["db_letter"])) { + rArr[8].push(); + } else { + rArr[9].push(); + } + } setResources(rArr); } - if (resources === null) + if (resources.length === 0) loadResources(); return ( - - {resources} + + + + + + Agriculture & Food + + + + + {resources[0]} + + + + + + + + + Construction + + + + + {resources[1]} + + + + + + + + + Fashion + + + + + {resources[2]} + + + + + + + + + Energy + + + + + {resources[3]} + + + + + + + + + Electronics + + + + + {resources[4]} + + + + + + + + + Automotive + + + + + {resources[5]} + + + + + + + + + Aerospace + + + + + {resources[6]} + + + + + + + + + Resources + + + + + {resources[7]} + + + + + + + + + Research + + + + + {resources[8]} + + + + + + + + + Others + + + + + {resources[9]} + + + + ); diff --git a/frontend/src/components/selectResource/resourceCard.js b/frontend/src/components/selectResource/resourceCard.js index 683f04c..f5be27b 100644 --- a/frontend/src/components/selectResource/resourceCard.js +++ b/frontend/src/components/selectResource/resourceCard.js @@ -8,7 +8,7 @@ import { Link } from 'react-router-dom'; import Link1 from '@material-ui/core/Link'; import ListItem from '@material-ui/core/ListItem'; import ListItemText from '@material-ui/core/ListItemText'; -import CardMedia from '@material-ui/core/CardMedia'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; const useStyles = makeStyles(theme => ({ @@ -46,7 +46,10 @@ export default function ResourceCard(props) { - {props.resource["name"]} + + {props.resource["name"]} + + diff --git a/frontend/src/img/loginBackground.png b/frontend/src/img/loginBackground.png new file mode 100644 index 0000000..6c8a852 Binary files /dev/null and b/frontend/src/img/loginBackground.png differ