From 9c56fb4e9794b7bbffb17e69e954a4289ccfc0c2 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 15 Mar 2022 14:46:24 +0100 Subject: [PATCH 01/55] Continued MVP server framework --- src/server/index.js | 20 + src/server/match.js | 29 ++ src/server/package-lock.json | 865 ++++++++++++++++++++++++++++++++++- src/server/package.json | 6 +- src/server/public/index.html | 9 + 5 files changed, 927 insertions(+), 2 deletions(-) create mode 100644 src/server/index.js create mode 100644 src/server/match.js create mode 100644 src/server/public/index.html diff --git a/src/server/index.js b/src/server/index.js new file mode 100644 index 0000000..f1b3b08 --- /dev/null +++ b/src/server/index.js @@ -0,0 +1,20 @@ +const path = require("path"); +const express = require("express"); +const app = express(); +const port = 3000; + +const Match = require("./match.js"); + +app.listen(port, () => { + console.log(`Listening on port ${port}`) +}) + +app.get("/", (req, res) => { + res.sendFile(path.join(__dirname, "public", "index.html")); +}); + + +app.get("/match", (req, res) => { + let match = new Match(1, [1, 2]); + res.send(JSON.stringify(match)); +}); diff --git a/src/server/match.js b/src/server/match.js new file mode 100644 index 0000000..03ede07 --- /dev/null +++ b/src/server/match.js @@ -0,0 +1,29 @@ +class Match { + tournamentId = null; + teamIds = []; + scores = {}; + winner = null; + + constructor(tournamentId, teamIds) { + this.tournamentId = tournamentId; + this.teamIds = teamIds; + //this.scores = Array(teamIds.length).fill(0); + for (let teamId of teamIds) { + this.scores[teamId] = 0; + } + } + + setScore = function(teamId, score) { + scores[teamId] = score; + }; + + getScore = function(teamId) { + return scores[teamId]; + }; + + setWinner = function(teamId) { + this.winner = teamId; + }; +} + +module.exports = Match; diff --git a/src/server/package-lock.json b/src/server/package-lock.json index 983a3af..afc6d85 100644 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -7,7 +7,870 @@ "": { "name": "tournament-server", "version": "1.0.0", - "license": "ISC" + "license": "ISC", + "dependencies": { + "express": "^4.17.3" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "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" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.2", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "requires": { + "bytes": "3.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" } } } diff --git a/src/server/package.json b/src/server/package.json index b6813f6..95c47ba 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -4,8 +4,12 @@ "description": "DCST1008 Project - Server - Asura Tournament Management System", "main": "index.js", "scripts": { + "start": "nodemon index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "felixalb, kristoju, jonajha, krisleri", - "license": "ISC" + "license": "ISC", + "dependencies": { + "express": "^4.17.3" + } } diff --git a/src/server/public/index.html b/src/server/public/index.html new file mode 100644 index 0000000..d7ac3ff --- /dev/null +++ b/src/server/public/index.html @@ -0,0 +1,9 @@ + + + test + + +

Replace with files from client build

+ + + From 50f4ea890bd7592cdc3802fdf5c6e20e5c75ef33 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 15 Mar 2022 22:37:15 +0100 Subject: [PATCH 02/55] Updated requirements --- src/server/.gitignore | 3 + src/server/package-lock.json | 2243 ++++++++++++++++++++++++++++++++++ src/server/package.json | 3 + 3 files changed, 2249 insertions(+) diff --git a/src/server/.gitignore b/src/server/.gitignore index c6bba59..978055e 100644 --- a/src/server/.gitignore +++ b/src/server/.gitignore @@ -1,3 +1,6 @@ +# Database credentials +sql_creds.txt + # Logs logs *.log diff --git a/src/server/package-lock.json b/src/server/package-lock.json index afc6d85..f243d18 100644 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -10,8 +10,38 @@ "license": "ISC", "dependencies": { "express": "^4.17.3" + }, + "devDependencies": { + "nodemon": "^2.0.15" } }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -24,11 +54,72 @@ "node": ">= 0.6" } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", @@ -49,6 +140,50 @@ "node": ">= 0.8" } }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -57,6 +192,192 @@ "node": ">= 0.8" } }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -89,6 +410,15 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -97,6 +427,33 @@ "ms": "2.0.0" } }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, "node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -110,11 +467,35 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -123,6 +504,24 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -176,6 +575,18 @@ "node": ">= 0.10.0" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -209,6 +620,111 @@ "node": ">= 0.6" } }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "node_modules/http-errors": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", @@ -235,11 +751,44 @@ "node": ">=0.10.0" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -248,6 +797,199 @@ "node": ">= 0.10" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -299,6 +1041,33 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -312,6 +1081,83 @@ "node": ">= 0.6" } }, + "node_modules/nodemon": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", + "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -323,6 +1169,48 @@ "node": ">= 0.8" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -336,6 +1224,27 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -348,6 +1257,34 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", @@ -381,6 +1318,72 @@ "node": ">= 0.8" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -405,6 +1408,36 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/send": { "version": "0.17.2", "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", @@ -452,6 +1485,12 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -460,6 +1499,74 @@ "node": ">= 0.6" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -468,6 +1575,30 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -480,6 +1611,33 @@ "node": ">= 0.6" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -488,6 +1646,61 @@ "node": ">= 0.8" } }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -503,9 +1716,92 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } }, "dependencies": { + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -515,11 +1811,57 @@ "negotiator": "0.6.3" } }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", @@ -537,11 +1879,183 @@ "type-is": "~1.6.18" } }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -565,6 +2079,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -573,6 +2093,27 @@ "ms": "2.0.0" } }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -583,16 +2124,52 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -640,6 +2217,15 @@ "vary": "~1.1.2" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -664,6 +2250,83 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "requires": { + "ini": "2.0.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "http-errors": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", @@ -684,16 +2347,181 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -727,6 +2555,27 @@ "mime-db": "1.52.0" } }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -737,6 +2586,62 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "nodemon": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", + "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -745,6 +2650,41 @@ "ee-first": "1.1.1" } }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -755,6 +2695,18 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -764,6 +2716,31 @@ "ipaddr.js": "1.9.1" } }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, "qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", @@ -785,6 +2762,62 @@ "unpipe": "1.0.0" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + } + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -795,6 +2828,29 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "send": { "version": "0.17.2", "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", @@ -838,16 +2894,87 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -857,11 +2984,77 @@ "mime-types": "~2.1.24" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -871,6 +3064,56 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/src/server/package.json b/src/server/package.json index 95c47ba..ab27930 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -11,5 +11,8 @@ "license": "ISC", "dependencies": { "express": "^4.17.3" + }, + "devDependencies": { + "nodemon": "^2.0.15" } } From c92ecba883bb59fc0590f41649108b8d98fbfa1b Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 16 Mar 2022 14:33:07 +0100 Subject: [PATCH 03/55] Make database connection --- src/server/.gitignore | 1 + src/server/index.js | 56 +- src/server/package-lock.json | 714 +++++++++++++++++- src/server/package.json | 6 +- .../public/{index.html => landing.html} | 0 src/server/public/tournament.html | 17 + 6 files changed, 763 insertions(+), 31 deletions(-) rename src/server/public/{index.html => landing.html} (100%) create mode 100644 src/server/public/tournament.html diff --git a/src/server/.gitignore b/src/server/.gitignore index 978055e..1cd3789 100644 --- a/src/server/.gitignore +++ b/src/server/.gitignore @@ -1,5 +1,6 @@ # Database credentials sql_creds.txt +config/config.json # Logs logs diff --git a/src/server/index.js b/src/server/index.js index f1b3b08..9aa7b45 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -1,20 +1,64 @@ const path = require("path"); const express = require("express"); -const app = express(); -const port = 3000; +const mysql = require("mysql"); +require("dotenv").config(); +let connection = mysql.createConnection({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_DATABASE +}); const Match = require("./match.js"); +const app = express(); +const port = 3000; +app.engine('html', require('ejs').renderFile); app.listen(port, () => { console.log(`Listening on port ${port}`) }) + app.get("/", (req, res) => { - res.sendFile(path.join(__dirname, "public", "index.html")); + res.sendFile(path.join(__dirname, "public", "landing.html")); +}); + +app.get("/getMatches", (req, res) => { + connection.query("SELECT * FROM matches", (err, matches) => { + if (err) { + console.log(err); + } else { + res.send(matches); + } + }); }); -app.get("/match", (req, res) => { - let match = new Match(1, [1, 2]); - res.send(JSON.stringify(match)); +let tournaments = { + "1": { + "name": "Tournament 1", + "description": "This is the first tournament", + "matches":[ + {"id": "2", + "player1": "Player 1", + "player2": "Player 2", + "winner": "Player 1", + } + ] + }, + "2": { + "name": "Tournament 2", + "description": "This is the second tournament", + "matches":[ + {"id": "2", + "player1": "Player 1", + "player2": "Player 2", + "winner": "Player 1", + }] + } +}; +app.get("/tournament/:tournamentId", (req, res) => { + res.render(path.join(__dirname, "public", "tournament.html"), {"tournament":tournaments[req.params.tournamentId]}); }); + + diff --git a/src/server/package-lock.json b/src/server/package-lock.json index f243d18..1081da5 100644 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -9,7 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "express": "^4.17.3" + "dotenv": "^16.0.0", + "ejs": "^3.1.6", + "express": "^4.17.3", + "mysql": "^2.18.1", + "sequelize": "^6.17.0" }, "devDependencies": { "nodemon": "^2.0.15" @@ -36,6 +40,29 @@ "node": ">=6" } }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "node_modules/@types/node": { + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + }, + "node_modules/@types/validator": { + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz", + "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -105,11 +132,23 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -166,7 +205,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -358,8 +396,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "node_modules/configstore": { "version": "5.0.1", @@ -410,6 +447,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -479,6 +521,19 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "engines": { + "node": ">=12" + } + }, + "node_modules/dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, "node_modules/duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -490,6 +545,20 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "node_modules/ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "dependencies": { + "jake": "^10.6.1" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -527,6 +596,14 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -575,6 +652,14 @@ "node": ">= 0.10.0" } }, + "node_modules/filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "dependencies": { + "minimatch": "^3.0.4" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -705,7 +790,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, "engines": { "node": ">=4" } @@ -775,6 +859,14 @@ "node": ">=0.8.19" } }, + "node_modules/inflection": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.2.tgz", + "integrity": "sha512-cmZlljCRTBFouT8UzMzrGcVEvkv6D/wBdcdKG7J1QH5cXjtU75Dm+P27v9EKu/Y43UYyCJd1WC4zLebRrC8NBw==", + "engines": [ + "node >= 0.4.0" + ] + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -918,6 +1010,65 @@ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "dependencies": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, "node_modules/json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -945,6 +1096,11 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -958,7 +1114,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -1054,7 +1209,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1068,11 +1222,49 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz", + "integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -1224,6 +1416,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -1245,6 +1442,11 @@ "node": ">=4" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1339,6 +1541,25 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1384,6 +1605,11 @@ "lowercase-keys": "^1.0.0" } }, + "node_modules/retry-as-promised": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-5.0.0.tgz", + "integrity": "sha512-6S+5LvtTl2ggBumk04hBo/4Uf6fRJUwIgunGZ7CYEBCeufGFW1Pu6ucUf/UskHeWOIsUcLOGLFXPig5tR5V1nA==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1466,6 +1692,107 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/sequelize": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.17.0.tgz", + "integrity": "sha512-AZus+0YZDq91Zg0hzDaO5atTzHgJruI23V8nBlAhkLuI81Z53nSRdAe/4R1A6vGOZ/RfCLP9idF4tfQnoAsM5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], + "dependencies": { + "@types/debug": "^4.1.7", + "@types/validator": "^13.7.1", + "debug": "^4.3.3", + "dottie": "^2.0.2", + "inflection": "^1.13.2", + "lodash": "^4.17.21", + "moment": "^2.29.1", + "moment-timezone": "^0.5.34", + "pg-connection-string": "^2.5.0", + "retry-as-promised": "^5.0.0", + "semver": "^7.3.5", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.7.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/sequelize/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sequelize/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/sequelize/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/serve-static": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", @@ -1491,6 +1818,14 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1499,6 +1834,19 @@ "node": ">= 0.6" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -1538,7 +1886,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -1575,6 +1922,11 @@ "node": ">=0.6" } }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, "node_modules/touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -1701,6 +2053,11 @@ "node": ">=4" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1709,6 +2066,22 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1729,6 +2102,14 @@ "node": ">=8" } }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1776,8 +2157,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } }, "dependencies": { @@ -1796,6 +2176,29 @@ "defer-to-connect": "^1.0.1" } }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, + "@types/node": { + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + }, + "@types/validator": { + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz", + "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1850,11 +2253,20 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" }, "binary-extensions": { "version": "2.2.0", @@ -1899,7 +2311,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2039,8 +2450,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "configstore": { "version": "5.0.1", @@ -2079,6 +2489,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -2133,6 +2548,16 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + }, + "dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -2144,6 +2569,14 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "requires": { + "jake": "^10.6.1" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2175,6 +2608,11 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -2217,6 +2655,14 @@ "vary": "~1.1.2" } }, + "filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "requires": { + "minimatch": "^3.0.4" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2312,8 +2758,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-yarn": { "version": "2.1.0", @@ -2365,6 +2810,11 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "inflection": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.2.tgz", + "integrity": "sha512-cmZlljCRTBFouT8UzMzrGcVEvkv6D/wBdcdKG7J1QH5cXjtU75Dm+P27v9EKu/Y43UYyCJd1WC4zLebRrC8NBw==" + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2466,6 +2916,55 @@ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "requires": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } + } + }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -2490,6 +2989,11 @@ "package-json": "^6.3.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -2500,7 +3004,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -2565,7 +3068,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2576,11 +3078,42 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-timezone": { + "version": "0.5.34", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz", + "integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==", + "requires": { + "moment": ">= 2.9.0" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -2695,6 +3228,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -2707,6 +3245,11 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2782,6 +3325,27 @@ } } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -2818,6 +3382,11 @@ "lowercase-keys": "^1.0.0" } }, + "retry-as-promised": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-5.0.0.tgz", + "integrity": "sha512-6S+5LvtTl2ggBumk04hBo/4Uf6fRJUwIgunGZ7CYEBCeufGFW1Pu6ucUf/UskHeWOIsUcLOGLFXPig5tR5V1nA==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2878,6 +3447,57 @@ } } }, + "sequelize": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.17.0.tgz", + "integrity": "sha512-AZus+0YZDq91Zg0hzDaO5atTzHgJruI23V8nBlAhkLuI81Z53nSRdAe/4R1A6vGOZ/RfCLP9idF4tfQnoAsM5A==", + "requires": { + "@types/debug": "^4.1.7", + "@types/validator": "^13.7.1", + "debug": "^4.3.3", + "dottie": "^2.0.2", + "inflection": "^1.13.2", + "lodash": "^4.17.21", + "moment": "^2.29.1", + "moment-timezone": "^0.5.34", + "pg-connection-string": "^2.5.0", + "retry-as-promised": "^5.0.0", + "semver": "^7.3.5", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.7.0", + "wkx": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==" + }, "serve-static": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", @@ -2900,11 +3520,31 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2935,7 +3575,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -2960,6 +3599,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -3055,11 +3699,26 @@ "prepend-http": "^2.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3074,6 +3733,14 @@ "string-width": "^4.0.0" } }, + "wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "requires": { + "@types/node": "*" + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3112,8 +3779,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/src/server/package.json b/src/server/package.json index ab27930..4e810b8 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -10,7 +10,11 @@ "author": "felixalb, kristoju, jonajha, krisleri", "license": "ISC", "dependencies": { - "express": "^4.17.3" + "dotenv": "^16.0.0", + "ejs": "^3.1.6", + "express": "^4.17.3", + "mysql": "^2.18.1", + "sequelize": "^6.17.0" }, "devDependencies": { "nodemon": "^2.0.15" diff --git a/src/server/public/index.html b/src/server/public/landing.html similarity index 100% rename from src/server/public/index.html rename to src/server/public/landing.html diff --git a/src/server/public/tournament.html b/src/server/public/tournament.html new file mode 100644 index 0000000..670b775 --- /dev/null +++ b/src/server/public/tournament.html @@ -0,0 +1,17 @@ + + + + + + + Document + + +

Tournament

+
+ + + \ No newline at end of file From 7eb631fd2152aad9c517cb7d6c3a9cfe1049c3f0 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 16 Mar 2022 15:40:33 +0100 Subject: [PATCH 04/55] Improved database interface --- src/server/.gitignore | 4 -- src/server/README.md | 14 +++++++ src/server/index.js | 94 ++++++++++++++++++++++++++----------------- 3 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 src/server/README.md diff --git a/src/server/.gitignore b/src/server/.gitignore index 1cd3789..c6bba59 100644 --- a/src/server/.gitignore +++ b/src/server/.gitignore @@ -1,7 +1,3 @@ -# Database credentials -sql_creds.txt -config/config.json - # Logs logs *.log diff --git a/src/server/README.md b/src/server/README.md new file mode 100644 index 0000000..0f340d5 --- /dev/null +++ b/src/server/README.md @@ -0,0 +1,14 @@ +## Server installation +* Clone the repository +** Checkout the "server" branch if not merged +* Enter the server directory: `cd src/server` +* Install the node dependencies: `npm install` +* Create the file `.env` containing your database login: +``` +DB_HOST=mysql.stud.ntnu.no +DB_USER=dbusername +DB_PASSWORD=dbpassword +DB_DATABASE=dbnamei +``` +* Build the client (separate instructions) +* Start the server `npm start` diff --git a/src/server/index.js b/src/server/index.js index 9aa7b45..582a29b 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -23,42 +23,60 @@ app.get("/", (req, res) => { res.sendFile(path.join(__dirname, "public", "landing.html")); }); -app.get("/getMatches", (req, res) => { - connection.query("SELECT * FROM matches", (err, matches) => { - if (err) { - console.log(err); - } else { - res.send(matches); - } +app.get("/tournament/:tournamentId/getMatches", (req, res) => { + let tournamentId = req.params.tournamentId; + getMatchesByTournamentId(tournamentId) + .then((result) => res.send({"status": "OK", "data": result})) + .catch((err) => res.send({"status": "ERROR", "data": err})); +}); + +// app.get("/getMatches", (req, res) => { +// connection.query("SELECT * FROM matches", (err, matches) => { +// if (err) { +// console.log(err); +// } else { +// res.send(matches); +// } +// }); +// }); + + +// let tournaments = { +// "1": { +// "name": "Tournament 1", +// "description": "This is the first tournament", +// "matches":[ +// {"id": "2", +// "player1": "Player 1", +// "player2": "Player 2", +// "winner": "Player 1", +// } +// ] +// }, +// "2": { +// "name": "Tournament 2", +// "description": "This is the second tournament", +// "matches":[ +// {"id": "2", +// "player1": "Player 1", +// "player2": "Player 2", +// "winner": "Player 1", +// }] +// } +// }; +// app.get("/tournament/:tournamentId", (req, res) => { +// res.render(path.join(__dirname, "public", "tournament.html"), {"tournament":tournaments[req.params.tournamentId]}); +// }); + +function getMatchesByTournamentId(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM matches WHERE tournament_id = ?", [mysql.escape(tournamentId)], (err, matches) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(matches); + } + }); }); -}); - - -let tournaments = { - "1": { - "name": "Tournament 1", - "description": "This is the first tournament", - "matches":[ - {"id": "2", - "player1": "Player 1", - "player2": "Player 2", - "winner": "Player 1", - } - ] - }, - "2": { - "name": "Tournament 2", - "description": "This is the second tournament", - "matches":[ - {"id": "2", - "player1": "Player 1", - "player2": "Player 2", - "winner": "Player 1", - }] - } -}; -app.get("/tournament/:tournamentId", (req, res) => { - res.render(path.join(__dirname, "public", "tournament.html"), {"tournament":tournaments[req.params.tournamentId]}); -}); - - +} From bcd1bd276e3534797150162f573ec4cae301e3ff Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 16 Mar 2022 15:46:04 +0100 Subject: [PATCH 05/55] Start input validation on database interface --- src/server/index.js | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 582a29b..af48368 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -25,9 +25,14 @@ app.get("/", (req, res) => { app.get("/tournament/:tournamentId/getMatches", (req, res) => { let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return + } + tournamentId = parseInt(tournamentId); getMatchesByTournamentId(tournamentId) - .then((result) => res.send({"status": "OK", "data": result})) - .catch((err) => res.send({"status": "ERROR", "data": err})); + .then(matches => res.send({"status": "OK", "data": matches})) + .catch(err => res.send({"status": "error", "data": err})); }); // app.get("/getMatches", (req, res) => { @@ -40,30 +45,6 @@ app.get("/tournament/:tournamentId/getMatches", (req, res) => { // }); // }); - -// let tournaments = { -// "1": { -// "name": "Tournament 1", -// "description": "This is the first tournament", -// "matches":[ -// {"id": "2", -// "player1": "Player 1", -// "player2": "Player 2", -// "winner": "Player 1", -// } -// ] -// }, -// "2": { -// "name": "Tournament 2", -// "description": "This is the second tournament", -// "matches":[ -// {"id": "2", -// "player1": "Player 1", -// "player2": "Player 2", -// "winner": "Player 1", -// }] -// } -// }; // app.get("/tournament/:tournamentId", (req, res) => { // res.render(path.join(__dirname, "public", "tournament.html"), {"tournament":tournaments[req.params.tournamentId]}); // }); From 19a7cb538dad17e4a8c06f56841327adc1294dc7 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 20 Mar 2022 15:34:13 +0100 Subject: [PATCH 06/55] Created DB module, cleaned working dir --- src/server/index.js | 55 ++++++----------- src/server/management/initDB.sql | 89 ++++++++++++++++++++++++++++ src/server/management/startServer.sh | 3 + src/server/match.js | 29 --------- src/server/package.json | 3 +- src/server/tmdb.js | 58 ++++++++++++++++++ 6 files changed, 169 insertions(+), 68 deletions(-) create mode 100644 src/server/management/initDB.sql create mode 100755 src/server/management/startServer.sh delete mode 100644 src/server/match.js create mode 100644 src/server/tmdb.js diff --git a/src/server/index.js b/src/server/index.js index af48368..674760e 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -1,27 +1,32 @@ const path = require("path"); const express = require("express"); -const mysql = require("mysql"); require("dotenv").config(); -let connection = mysql.createConnection({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_DATABASE -}); -const Match = require("./match.js"); +// Our self-written module for handling database operations +let tmdb = require("./tmdb.js"); +// #region Express setup const app = express(); const port = 3000; -app.engine('html', require('ejs').renderFile); +//app.engine('html', require('ejs').renderFile); app.listen(port, () => { console.log(`Listening on port ${port}`) }) +// #endregion - +// #region frontend +// Serve static files from the React app app.get("/", (req, res) => { res.sendFile(path.join(__dirname, "public", "landing.html")); }); +// #endregion + +// #region API +app.get("/tournament/getTournaments", (req, res) => { + tmdb.getTournaments() + .then(tournaments => {res.json({"status": "OK", "data": tournaments}); }) + .catch(err => {res.json({"status": "error", "data": err}); }); +}); app.get("/tournament/:tournamentId/getMatches", (req, res) => { let tournamentId = req.params.tournamentId; @@ -30,34 +35,8 @@ app.get("/tournament/:tournamentId/getMatches", (req, res) => { return } tournamentId = parseInt(tournamentId); - getMatchesByTournamentId(tournamentId) + tmdb.getMatchesByTournamentId(tournamentId) .then(matches => res.send({"status": "OK", "data": matches})) .catch(err => res.send({"status": "error", "data": err})); }); - -// app.get("/getMatches", (req, res) => { -// connection.query("SELECT * FROM matches", (err, matches) => { -// if (err) { -// console.log(err); -// } else { -// res.send(matches); -// } -// }); -// }); - -// app.get("/tournament/:tournamentId", (req, res) => { -// res.render(path.join(__dirname, "public", "tournament.html"), {"tournament":tournaments[req.params.tournamentId]}); -// }); - -function getMatchesByTournamentId(tournamentId) { - return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM matches WHERE tournament_id = ?", [mysql.escape(tournamentId)], (err, matches) => { - if (err) { - console.log(err); - reject(err); - } else { - resolve(matches); - } - }); - }); -} +// #endregion \ No newline at end of file diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql new file mode 100644 index 0000000..f779af1 --- /dev/null +++ b/src/server/management/initDB.sql @@ -0,0 +1,89 @@ +-- WARNING: Will delete EVERYTHING in the database! + +DROP TABLE IF EXISTS players; +DROP TABLE IF EXISTS matches; +DROP TABLE IF EXISTS teams; +DROP TABLE IF EXISTS tournaments; + +-- Create the tables +CREATE TABLE tournaments ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + name TEXT NOT NULL, + startTime DATETIME NOT NULL, + endTime DATETIME NOT NULL +); + +CREATE TABLE teams ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + tournamentId INTEGER NOT NULL, + name TEXT NOT NULL, + + FOREIGN KEY (tournamentId) REFERENCES tournaments (id) +); + +CREATE TABLE matches ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + tournamentId INTEGER NOT NULL, + parentMatchId INTEGER, + team1Id INTEGER, + team2Id INTEGER, + winnerId INTEGER, + + FOREIGN KEY (tournamentId) REFERENCES tournaments (id), + FOREIGN KEY (team1Id) REFERENCES teams (id), + FOREIGN KEY (team2Id) REFERENCES teams (id) +); + +CREATE TABLE players ( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + name TEXT NOT NULL, + teamId INTEGER NOT NULL, + + FOREIGN KEY (teamId) REFERENCES teams (id) +); + +-- Example data (Two tournaments, 4 teams, single elimination) +INSERT INTO tournaments (name, startTime, endTime) VALUES ('Tournament 1', '2022-04-01 16:00:00', '2022-04-01 20:00:00'); +INSERT INTO tournaments (name, startTime, endTime) VALUES ('Tournament 2', '2022-04-03 17:30:00', '2022-04-02 21:30:00'); + +INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 +INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 +INSERT INTO teams (tournamentId, name) VALUES (1, 'Team Liquid'); -- 3 +INSERT INTO teams (tournamentId, name) VALUES (1, 'LDLC'); -- 4 + +INSERT INTO teams (tournamentId, name) VALUES (2, 'Astralis'); -- 5 +INSERT INTO teams (tournamentId, name) VALUES (2, 'Entropiq'); -- 6 +INSERT INTO teams (tournamentId, name) VALUES (2, 'Team Vitality'); -- 7 +INSERT INTO teams (tournamentId, name) VALUES (2, 'Godsent'); -- 8 + +-- tournament 1 -- +-- Final match +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (1, NULL, NULL, NULL); -- 1 +-- Semi-finals +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (1, 1, 1, 2); -- 2 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (1, 1, 3, 4); -- 3 + +-- tournament 2 -- +-- Final match +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (2, NULL, NULL, NULL); -- 4 +-- Semi-finals +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (2, 4, 5, 7); -- 5 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (2, 4, 6, 8); -- 6 + +-- Players +INSERT INTO players (name, teamId) VALUES ('Player 1', 1); +INSERT INTO players (name, teamId) VALUES ('Player 2', 1); +INSERT INTO players (name, teamId) VALUES ('Player 3', 2); +INSERT INTO players (name, teamId) VALUES ('Player 4', 2); +INSERT INTO players (name, teamId) VALUES ('Player 5', 3); +INSERT INTO players (name, teamId) VALUES ('Player 6', 3); +INSERT INTO players (name, teamId) VALUES ('Player 7', 4); +INSERT INTO players (name, teamId) VALUES ('Player 8', 4); +INSERT INTO players (name, teamId) VALUES ('Player 9', 5); +INSERT INTO players (name, teamId) VALUES ('Player 10', 5); +INSERT INTO players (name, teamId) VALUES ('Player 11', 6); +INSERT INTO players (name, teamId) VALUES ('Player 12', 6); +INSERT INTO players (name, teamId) VALUES ('Player 13', 7); +INSERT INTO players (name, teamId) VALUES ('Player 14', 7); +INSERT INTO players (name, teamId) VALUES ('Player 15', 8); +INSERT INTO players (name, teamId) VALUES ('Player 16', 8); \ No newline at end of file diff --git a/src/server/management/startServer.sh b/src/server/management/startServer.sh new file mode 100755 index 0000000..9e08642 --- /dev/null +++ b/src/server/management/startServer.sh @@ -0,0 +1,3 @@ + autossh -L 3306:mysql.stud.ntnu.no:3306 isvegg -N & + + npm start diff --git a/src/server/match.js b/src/server/match.js deleted file mode 100644 index 03ede07..0000000 --- a/src/server/match.js +++ /dev/null @@ -1,29 +0,0 @@ -class Match { - tournamentId = null; - teamIds = []; - scores = {}; - winner = null; - - constructor(tournamentId, teamIds) { - this.tournamentId = tournamentId; - this.teamIds = teamIds; - //this.scores = Array(teamIds.length).fill(0); - for (let teamId of teamIds) { - this.scores[teamId] = 0; - } - } - - setScore = function(teamId, score) { - scores[teamId] = score; - }; - - getScore = function(teamId) { - return scores[teamId]; - }; - - setWinner = function(teamId) { - this.winner = teamId; - }; -} - -module.exports = Match; diff --git a/src/server/package.json b/src/server/package.json index 4e810b8..2888015 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "start": "nodemon index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "initdb": "mysql -h mysql.stud.ntnu.no -u felixalb_sysut -p felixalb_asura < ./management/initDB.sql" }, "author": "felixalb, kristoju, jonajha, krisleri", "license": "ISC", diff --git a/src/server/tmdb.js b/src/server/tmdb.js new file mode 100644 index 0000000..1ae6824 --- /dev/null +++ b/src/server/tmdb.js @@ -0,0 +1,58 @@ +// TMDB - Tournament Manager DataBase +// Handles all the database operations for the Tournament Manager +// Exports the following functions: +module.exports = { + getMatchesByTournamentId: getMatchesByTournamentId, + getTournaments: getTournaments, + executeStatement: executeStatement +} + +const mysql = require("mysql"); + +let connection = mysql.createConnection({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_DATABASE +}); + +function getMatchesByTournamentId(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM matches WHERE tournament_id = ?", [mysql.escape(tournamentId)], (err, matches) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(matches); + } + }); + }); +} + +function getTournaments() { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM tournaments", (err, tournaments) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(tournaments); + } + }); + }); +} + +// Dangerous function, use with caution. +// Used to initialize and manage the database by management tools, not by the main application. +function executeStatement(statement) { + return new Promise(function(resolve, reject) { + connection.query(statement, (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(sets); + } + }); + }); +} \ No newline at end of file From 906a7ada4033b65bbf6c9cbb9f7e1c2425ee4a60 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 20 Mar 2022 21:06:35 +0100 Subject: [PATCH 07/55] Implemented getMatch methods --- src/server/index.js | 34 ++++++++++++ src/server/management/initDB.sql | 5 +- src/server/tmdb.js | 89 +++++++++++++++++++++++++++++++- 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 674760e..4ec2cfc 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -12,6 +12,8 @@ const port = 3000; app.listen(port, () => { console.log(`Listening on port ${port}`) }) +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); // #endregion // #region frontend @@ -39,4 +41,36 @@ app.get("/tournament/:tournamentId/getMatches", (req, res) => { .then(matches => res.send({"status": "OK", "data": matches})) .catch(err => res.send({"status": "error", "data": err})); }); + +app.get("/match/:matchId/getMatch", (req, res) => { + let matchId = req.params.matchId; + if (isNaN(matchId)) { + res.json({"status": "error", "data": "matchId must be a number"}); + return + } + matchId = parseInt(matchId); + tmdb.getMatch(matchId) + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); + +// JSON body: {"winner": "teamId"} +app.post("/match/:matchId/setWinner", (req, res) => { + let matchId = req.params.matchId; + let winnerId = req.body.winnerId; + if (isNaN(matchId)) { + res.json({"status": "error", "data": "matchId must be a number"}); + return + } + if (winnerId == undefined || isNaN(winnerId)) { + res.json({"status": "error", "data": "winnerId must be a number"}); + return + } + + matchId = parseInt(matchId); + winnerId = parseInt(winnerId); + tmdb.setMatchWinner(matchId, winnerId) + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); // #endregion \ No newline at end of file diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index f779af1..53fd002 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -9,6 +9,7 @@ DROP TABLE IF EXISTS tournaments; CREATE TABLE tournaments ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name TEXT NOT NULL, + description TEXT, startTime DATETIME NOT NULL, endTime DATETIME NOT NULL ); @@ -43,8 +44,8 @@ CREATE TABLE players ( ); -- Example data (Two tournaments, 4 teams, single elimination) -INSERT INTO tournaments (name, startTime, endTime) VALUES ('Tournament 1', '2022-04-01 16:00:00', '2022-04-01 20:00:00'); -INSERT INTO tournaments (name, startTime, endTime) VALUES ('Tournament 2', '2022-04-03 17:30:00', '2022-04-02 21:30:00'); +INSERT INTO tournaments (name, description, startTime, endTime) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-04-01 16:00:00', '2022-04-01 20:00:00'); +INSERT INTO tournaments (name, description, startTime, endTime) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-04-03 17:30:00', '2022-04-02 21:30:00'); INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 1ae6824..a19c977 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -4,9 +4,11 @@ module.exports = { getMatchesByTournamentId: getMatchesByTournamentId, getTournaments: getTournaments, - executeStatement: executeStatement + getMatch: getMatch, + setMatchWinner: setMatchWinner, } +const { query } = require("express"); const mysql = require("mysql"); let connection = mysql.createConnection({ @@ -18,7 +20,7 @@ let connection = mysql.createConnection({ function getMatchesByTournamentId(tournamentId) { return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM matches WHERE tournament_id = ?", [mysql.escape(tournamentId)], (err, matches) => { + connection.query("SELECT * FROM matches WHERE tournamentId = ?", [mysql.escape(tournamentId)], (err, matches) => { if (err) { console.log(err); reject(err); @@ -42,6 +44,89 @@ function getTournaments() { }); } +// Returns the match of the exact given id. +function getMatch(matchId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM matches WHERE id = ?", [mysql.escape(matchId)], (err, matches) => { + if (err) { + reject(err); + } else { + if (matches.length == 0) { + reject("No such match exists"); + } + resolve(matches[0]); + } + }); + }); +} + +// Removes a given team from a given match. This is done by setting the teamId-property containing the given team to null. +function unsetContestant(matchId, teamId) { + let match = getMatch(matchId); + if (match.team1Id == teamId) { + connection.query("UPDATE matches SET team1Id = NULL WHERE id = ?", [mysql.escape(matchId)], (err, result) => { + if (err) { console.log(err); } + }); + } else if (match.team2Id == teamId) { + connection.query("UPDATE matches SET team2Id = NULL WHERE id = ?", [mysql.escape(matchId)], (err, result) => { + if (err) { console.log(err); } + }); + } else { + console.log("Error: Team not found in match"); + } +} + +// Sets the winnerId-property of a given match. +// Also appoints the winner as a contestant to the next(parent) match. +function setMatchWinner(matchId, winnerId) { + return new Promise(function(resolve, reject) { + getMatch(matchId) + .catch(err => reject(err)) + .then(match => { + if (winnerId != match.team1Id && winnerId != match.team2Id) { + reject("Winner must be one of the teams in the match"); + } + + // Final match doesn't have a parent + if (match.parentMatchId != null) { + // Enter the winner of the match into the parent match + getMatch(match.parentMatchId) + .catch(err =>reject(err)) + .then(parentMatch => { + if (parentMatch.team1Id == null) { + connection.query("UPDATE matches SET team1Id = ? WHERE id = ?", + [mysql.escape(winnerId), mysql.escape(parentMatch.id)], (err, sets) => { + if (err) { reject(err); } + }); + } else if (parentMatch.team2Id == null) { + connection.query("UPDATE matches SET team2Id = ? WHERE id = ?", + [mysql.escape(winnerId), mysql.escape(parentMatch.id)], (err, sets) => { + if (err) { reject(err); } + }); + } else { + reject("Parent match already has two teams"); + } + }); + } + + // Lastly, if all checks passed, actually set the winnerId property + connection.query("UPDATE matches SET winnerId = ? WHERE id = ?", + [mysql.escape(winnerId), mysql.escape(matchId)], (err, sets) => { + if (err) { + // If this update fails, we need to undo the parent match update + unsetContestant(parentMatchId, winnerId); + reject(err); + } + getMatch(matchId) + .catch(err => reject(err)) + .then(match => resolve(match)); + }); + + }); + }); +} + + // Dangerous function, use with caution. // Used to initialize and manage the database by management tools, not by the main application. function executeStatement(statement) { From 53f166bb3d15b2470f22b08943711ad27568fb41 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 21 Mar 2022 09:28:26 +0100 Subject: [PATCH 08/55] Added api prefix --- src/server/index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 4ec2cfc..63df944 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -14,23 +14,25 @@ app.listen(port, () => { }) app.use(express.json()); app.use(express.urlencoded({ extended: true })); +let api = express.Router(); +app.use("/api", api); // #endregion // #region frontend // Serve static files from the React app -app.get("/", (req, res) => { +api.get("/", (req, res) => { res.sendFile(path.join(__dirname, "public", "landing.html")); }); // #endregion // #region API -app.get("/tournament/getTournaments", (req, res) => { +api.get("/tournament/getTournaments", (req, res) => { tmdb.getTournaments() .then(tournaments => {res.json({"status": "OK", "data": tournaments}); }) .catch(err => {res.json({"status": "error", "data": err}); }); }); -app.get("/tournament/:tournamentId/getMatches", (req, res) => { +api.get("/tournament/:tournamentId/getMatches", (req, res) => { let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { res.json({"status": "error", "data": "tournamentId must be a number"}); @@ -42,7 +44,7 @@ app.get("/tournament/:tournamentId/getMatches", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -app.get("/match/:matchId/getMatch", (req, res) => { +api.get("/match/:matchId/getMatch", (req, res) => { let matchId = req.params.matchId; if (isNaN(matchId)) { res.json({"status": "error", "data": "matchId must be a number"}); @@ -55,7 +57,7 @@ app.get("/match/:matchId/getMatch", (req, res) => { }); // JSON body: {"winner": "teamId"} -app.post("/match/:matchId/setWinner", (req, res) => { +api.post("/match/:matchId/setWinner", (req, res) => { let matchId = req.params.matchId; let winnerId = req.body.winnerId; if (isNaN(matchId)) { From 665ad0dd38ae8453442d4eb40c581806d3302dfa Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Thu, 24 Mar 2022 18:47:35 +0100 Subject: [PATCH 09/55] Major dev session --- src/server/index.js | 96 ++++++++++++++++++++++++++++---- src/server/management/initDB.sql | 5 +- src/server/package-lock.json | 12 ++-- src/server/tmdb.js | 42 +++++++++++++- 4 files changed, 134 insertions(+), 21 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 63df944..5c3c8a8 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -8,7 +8,6 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); const port = 3000; -//app.engine('html', require('ejs').renderFile); app.listen(port, () => { console.log(`Listening on port ${port}`) }) @@ -16,6 +15,13 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); let api = express.Router(); app.use("/api", api); + +api.use(function(req, res, next) { + res.header("Access-Control-Allow-Origin", "*"); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + next(); +}); + // #endregion // #region frontend @@ -28,8 +34,21 @@ api.get("/", (req, res) => { // #region API api.get("/tournament/getTournaments", (req, res) => { tmdb.getTournaments() - .then(tournaments => {res.json({"status": "OK", "data": tournaments}); }) - .catch(err => {res.json({"status": "error", "data": err}); }); + .then(tournaments => res.json({"status": "OK", "data": tournaments})) + .catch(err => res.json({"status": "error", "data": err})); +}); + +api.get("/tournament/:tournamentId", (req, res) => { + let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "Invalid tournament id"}); + return; + } + tmdb.getTournament(parseInt(tournamentId)) + .catch(err => res.json({"status": "error", "data": err})) + .then(tournament => res.json({"status": "OK", "data": tournament})); + // .then(tournament => res.json({"status": "OK", "data": tournament})); + // .then(console.log("lol")) }); api.get("/tournament/:tournamentId/getMatches", (req, res) => { @@ -40,8 +59,8 @@ api.get("/tournament/:tournamentId/getMatches", (req, res) => { } tournamentId = parseInt(tournamentId); tmdb.getMatchesByTournamentId(tournamentId) - .then(matches => res.send({"status": "OK", "data": matches})) - .catch(err => res.send({"status": "error", "data": err})); + .then(matches => res.send({"status": "OK", "data": matches})) + .catch(err => res.send({"status": "error", "data": err})); }); api.get("/match/:matchId/getMatch", (req, res) => { @@ -52,11 +71,11 @@ api.get("/match/:matchId/getMatch", (req, res) => { } matchId = parseInt(matchId); tmdb.getMatch(matchId) - .then(match => res.send({"status": "OK", "data": match})) - .catch(err => res.send({"status": "error", "data": err})); + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); }); -// JSON body: {"winner": "teamId"} +// JSON body: {"winner": teamId} api.post("/match/:matchId/setWinner", (req, res) => { let matchId = req.params.matchId; let winnerId = req.body.winnerId; @@ -68,11 +87,66 @@ api.post("/match/:matchId/setWinner", (req, res) => { res.json({"status": "error", "data": "winnerId must be a number"}); return } - + matchId = parseInt(matchId); winnerId = parseInt(winnerId); tmdb.setMatchWinner(matchId, winnerId) - .then(match => res.send({"status": "OK", "data": match})) - .catch(err => res.send({"status": "error", "data": err})); + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); + +//Takes JSON body +api.post("/tournament/create", (req, res) => { + //Check that req body is valid + if (req.body.name == undefined || req.body.name == "") { + res.json({"status": "error", "data": "No data supplied"}); + return + } + //Check that req is json + // if (req.get("Content-Type") != "application/json") { + console.log(req.get("Content-Type")); + let name = req.body.name; + let description = req.body.description; + let teamLimit = req.body.teamLimit; + let startDate = req.body.startDate; + let endDate = req.body.endDate; + if (name == undefined || name == "" || description == undefined || description == "") { + res.json({"status": "error", "data": "name and description must be provided"}); + return + } + if (teamLimit == undefined ) { + res.json({"status": "error", "data": "teamLimit must be provided"}); + return + } + try { + teamLimit = parseInt(teamLimit); + } catch (err) { + res.json({"status": "error", "data": "teamLimit must be a number"}); + return + } + if (startDate == undefined || endDate == undefined) { + res.json({"status": "error", "data": "startDate and endDate must be defined"}); + return + } + try { + startDate = new Date(startDate); + endDate = new Date(endDate); + } catch (err) { + res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); + return + } + let today = new Date(); + if (startDate < today) { + res.json({"status": "error", "data": "startDate cannot be in the past"}); + return + } + if (startDate > endDate) { + res.json({"status": "error", "data": "startDate cannot be after endDate"}); + return + } + + tmdb.createTournament(name, description, startDate, endDate, teamLimit) + .catch(err => res.json({"status": "error", "data": err})) + .then(msg => res.json({"status": "OK", "data": msg})); }); // #endregion \ No newline at end of file diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 53fd002..392dc4d 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -10,6 +10,7 @@ CREATE TABLE tournaments ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name TEXT NOT NULL, description TEXT, + teamLimit INTEGER NOT NULL, startTime DATETIME NOT NULL, endTime DATETIME NOT NULL ); @@ -44,8 +45,8 @@ CREATE TABLE players ( ); -- Example data (Two tournaments, 4 teams, single elimination) -INSERT INTO tournaments (name, description, startTime, endTime) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-04-01 16:00:00', '2022-04-01 20:00:00'); -INSERT INTO tournaments (name, description, startTime, endTime) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-04-03 17:30:00', '2022-04-02 21:30:00'); +INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-04-01 16:00:00', '2022-04-01 20:00:00', 4); +INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-04-03 17:30:00', '2022-04-04 21:30:00', 4); INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 diff --git a/src/server/package-lock.json b/src/server/package-lock.json index 1081da5..30e2427 100644 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -1217,9 +1217,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/moment": { @@ -3073,9 +3073,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "moment": { diff --git a/src/server/tmdb.js b/src/server/tmdb.js index a19c977..ad42b56 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -4,11 +4,12 @@ module.exports = { getMatchesByTournamentId: getMatchesByTournamentId, getTournaments: getTournaments, + getTournament, getTournament, getMatch: getMatch, setMatchWinner: setMatchWinner, + createTournament: createTournament, } -const { query } = require("express"); const mysql = require("mysql"); let connection = mysql.createConnection({ @@ -44,6 +45,25 @@ function getTournaments() { }); } +function getTournament(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM tournaments WHERE id = ?", [mysql.escape(tournamentId)], (err, tournaments) => { + if (err) { + console.log(err); + reject(err); + } else { + if (tournaments.length == 0) { + reject("No such tournament exists"); + } + //TODO number of competing teams + + let tournament = tournaments[0]; + resolve(tournament); + } + }); + }); +} + // Returns the match of the exact given id. function getMatch(matchId) { return new Promise(function(resolve, reject) { @@ -54,7 +74,9 @@ function getMatch(matchId) { if (matches.length == 0) { reject("No such match exists"); } - resolve(matches[0]); + + let match = matches[0]; + resolve(match); } }); }); @@ -126,6 +148,22 @@ function setMatchWinner(matchId, winnerId) { }); } +function createTournament(name, description, startDate, endDate, teamLimit) { + startDate = startDate.toISOString().slice(0, 19).replace('T', ' '); + endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); + return new Promise(function(resolve, reject) { + connection.query("INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES (?, ?, ?, ?, ?)", + [mysql.escape(name), mysql.escape(description), startDate, endDate, teamLimit], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve("Tournament created"); + } + }); + }); +} + // Dangerous function, use with caution. // Used to initialize and manage the database by management tools, not by the main application. From db3e7ed9327868c43fb0e21f1ef53033fc317d51 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Thu, 24 Mar 2022 21:45:47 +0100 Subject: [PATCH 10/55] Long development session --- src/server/index.js | 13 ++++++++++++ src/server/management/initDB.sql | 34 ++++++++++++++++++++++++-------- src/server/tmdb.js | 14 +++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 5c3c8a8..cb2b020 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -51,6 +51,7 @@ api.get("/tournament/:tournamentId", (req, res) => { // .then(console.log("lol")) }); + api.get("/tournament/:tournamentId/getMatches", (req, res) => { let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { @@ -63,6 +64,18 @@ api.get("/tournament/:tournamentId/getMatches", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); +api.get("/tournament/:tournamentId/getTeams", (req, res) => { + let tournamentId = req.params.tournamentId; + if (!tournamentId || isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return + } + tournamentId = parseInt(tournamentId); + tmdb.getTeamsByTournamentId(tournamentId) + .then(teams => res.send({"status": "OK", "data": teams})) + .catch(err => res.send({"status": "error", "data": err})); +}); + api.get("/match/:matchId/getMatch", (req, res) => { let matchId = req.params.matchId; if (isNaN(matchId)) { diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 392dc4d..73ae385 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -30,6 +30,7 @@ CREATE TABLE matches ( team1Id INTEGER, team2Id INTEGER, winnerId INTEGER, + tier INTEGER, FOREIGN KEY (tournamentId) REFERENCES tournaments (id), FOREIGN KEY (team1Id) REFERENCES teams (id), @@ -46,7 +47,7 @@ CREATE TABLE players ( -- Example data (Two tournaments, 4 teams, single elimination) INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-04-01 16:00:00', '2022-04-01 20:00:00', 4); -INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-04-03 17:30:00', '2022-04-04 21:30:00', 4); +INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-04-03 17:30:00', '2022-04-04 21:30:00', 8); INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 @@ -57,20 +58,29 @@ INSERT INTO teams (tournamentId, name) VALUES (2, 'Astralis'); -- 5 INSERT INTO teams (tournamentId, name) VALUES (2, 'Entropiq'); -- 6 INSERT INTO teams (tournamentId, name) VALUES (2, 'Team Vitality'); -- 7 INSERT INTO teams (tournamentId, name) VALUES (2, 'Godsent'); -- 8 +INSERT INTO teams (tournamentId, name) VALUES (2, 'Team Secret'); -- 9 +INSERT INTO teams (tournamentId, name) VALUES (2, 'Virtus.pro'); -- 10 +INSERT INTO teams (tournamentId, name) VALUES (2, 'Natus Vincere'); -- 11 +INSERT INTO teams (tournamentId, name) VALUES (2, 'FaZe'); -- 12 -- tournament 1 -- -- Final match -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (1, NULL, NULL, NULL); -- 1 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (1, NULL, NULL, NULL, 0); -- 1 -- Semi-finals -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (1, 1, 1, 2); -- 2 -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (1, 1, 3, 4); -- 3 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (1, 1, 1, 2, 1); -- 2 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (1, 1, 3, 4, 1); -- 3 -- tournament 2 -- -- Final match -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (2, NULL, NULL, NULL); -- 4 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, NULL, NULL, NULL, 0); -- 4 -- Semi-finals -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (2, 4, 5, 7); -- 5 -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id) VALUES (2, 4, 6, 8); -- 6 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 4, NULL, NULL, 1); -- 5 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 4, NULL, NULL, 1); -- 6 +-- Quarter-finals +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 5, 5, 6, 2); -- 7 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 5, 7, 8, 2); -- 8 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 9, 10, 2); -- 9 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 11, 12, 2); -- 10 -- Players INSERT INTO players (name, teamId) VALUES ('Player 1', 1); @@ -88,4 +98,12 @@ INSERT INTO players (name, teamId) VALUES ('Player 12', 6); INSERT INTO players (name, teamId) VALUES ('Player 13', 7); INSERT INTO players (name, teamId) VALUES ('Player 14', 7); INSERT INTO players (name, teamId) VALUES ('Player 15', 8); -INSERT INTO players (name, teamId) VALUES ('Player 16', 8); \ No newline at end of file +INSERT INTO players (name, teamId) VALUES ('Player 16', 8); +INSERT INTO players (name, teamId) VALUES ('Player 17', 9); +INSERT INTO players (name, teamId) VALUES ('Player 18', 9); +INSERT INTO players (name, teamId) VALUES ('Player 19', 10); +INSERT INTO players (name, teamId) VALUES ('Player 20', 10); +INSERT INTO players (name, teamId) VALUES ('Player 21', 11); +INSERT INTO players (name, teamId) VALUES ('Player 22', 11); +INSERT INTO players (name, teamId) VALUES ('Player 23', 12); +INSERT INTO players (name, teamId) VALUES ('Player 24', 12); diff --git a/src/server/tmdb.js b/src/server/tmdb.js index ad42b56..8aed35b 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -8,6 +8,7 @@ module.exports = { getMatch: getMatch, setMatchWinner: setMatchWinner, createTournament: createTournament, + getTeamsByTournamentId: getTeamsByTournamentId, } const mysql = require("mysql"); @@ -164,6 +165,19 @@ function createTournament(name, description, startDate, endDate, teamLimit) { }); } +function getTeamsByTournamentId(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM teams WHERE tournamentId = ?", [mysql.escape(tournamentId)], (err, teams) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(teams); + } + }); + }); +} + // Dangerous function, use with caution. // Used to initialize and manage the database by management tools, not by the main application. From ecc66a630b73c311e08f6e83adca6c41a1cc5edf Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Fri, 25 Mar 2022 02:43:57 +0100 Subject: [PATCH 11/55] Fixed winner / team endpoints --- src/server/README.md | 2 +- src/server/index.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/server/README.md b/src/server/README.md index 0f340d5..0442f92 100644 --- a/src/server/README.md +++ b/src/server/README.md @@ -8,7 +8,7 @@ DB_HOST=mysql.stud.ntnu.no DB_USER=dbusername DB_PASSWORD=dbpassword -DB_DATABASE=dbnamei +DB_DATABASE=dbname ``` * Build the client (separate instructions) * Start the server `npm start` diff --git a/src/server/index.js b/src/server/index.js index cb2b020..8504eda 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -7,7 +7,7 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3000; +const port = 3001; app.listen(port, () => { console.log(`Listening on port ${port}`) }) @@ -88,7 +88,6 @@ api.get("/match/:matchId/getMatch", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -// JSON body: {"winner": teamId} api.post("/match/:matchId/setWinner", (req, res) => { let matchId = req.params.matchId; let winnerId = req.body.winnerId; From 4e3e4f58e41d1e524a5ba4fd2bfa9e57ec815c78 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Fri, 25 Mar 2022 15:01:36 +0100 Subject: [PATCH 12/55] Logging. Tournament editor. --- src/server/index.js | 43 +++++++++++++++++++++++++++++++++ src/server/package-lock.json | 35 +++++++++++++++------------ src/server/package.json | 1 + src/server/tmdb.js | 46 +++++++++++++++++++++++++++++++++--- 4 files changed, 107 insertions(+), 18 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 8504eda..b788772 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -21,6 +21,7 @@ api.use(function(req, res, next) { res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); +api.use(require('express-log-url')); // #endregion @@ -161,4 +162,46 @@ api.post("/tournament/create", (req, res) => { .catch(err => res.json({"status": "error", "data": err})) .then(msg => res.json({"status": "OK", "data": msg})); }); + +api.post("/tournament/:tournamentId/edit", (req, res) => { + let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return + } + tournamentId = parseInt(tournamentId); + let name = req.body.name; + let description = req.body.description; + let startDate = req.body.startDate; + let endDate = req.body.endDate; + console.log(startDate); + if (name == undefined || name == "" || description == undefined || description == "") { + res.json({"status": "error", "data": "name and description must be provided"}); + return + } + if (startDate == undefined || endDate == undefined) { + res.json({"status": "error", "data": "startDate and endDate must be defined"}); + return + } + try { + startDate = new Date(startDate); + endDate = new Date(endDate); + } catch (err) { + res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); + return + } + // let today = new Date(); + // if (startDate < today) { + // res.json({"status": "error", "data": "startDate cannot be in the past"}); + // return + // } + if (startDate > endDate) { + res.json({"status": "error", "data": "startDate cannot be after endDate"}); + return + } + + tmdb.editTournament(tournamentId, name, description, startDate, endDate) + .catch(err => res.json({"status": "error", "data": err})) + .then(msg => res.json({"status": "OK", "data": msg})); +}); // #endregion \ No newline at end of file diff --git a/src/server/package-lock.json b/src/server/package-lock.json index 30e2427..07ff362 100644 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -12,6 +12,7 @@ "dotenv": "^16.0.0", "ejs": "^3.1.6", "express": "^4.17.3", + "express-log-url": "^1.5.1", "mysql": "^2.18.1", "sequelize": "^6.17.0" }, @@ -103,7 +104,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -288,7 +288,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -304,7 +303,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -313,7 +311,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -379,7 +376,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -390,8 +386,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -652,6 +647,14 @@ "node": ">= 0.10.0" } }, + "node_modules/express-log-url": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/express-log-url/-/express-log-url-1.5.1.tgz", + "integrity": "sha512-72eLutsZY7PgP9/c3L962yLl4tmhmfgupoOFudWa11WzLgvfIHkC9lxYoMAF/PQ6aB/E0phY1+TW9YCnjFEtdQ==", + "dependencies": { + "chalk": "^4.1.0" + } + }, "node_modules/filelist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", @@ -2233,7 +2236,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -2372,7 +2374,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2381,14 +2382,12 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -2436,7 +2435,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -2444,8 +2442,7 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "concat-map": { "version": "0.0.1", @@ -2655,6 +2652,14 @@ "vary": "~1.1.2" } }, + "express-log-url": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/express-log-url/-/express-log-url-1.5.1.tgz", + "integrity": "sha512-72eLutsZY7PgP9/c3L962yLl4tmhmfgupoOFudWa11WzLgvfIHkC9lxYoMAF/PQ6aB/E0phY1+TW9YCnjFEtdQ==", + "requires": { + "chalk": "^4.1.0" + } + }, "filelist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", diff --git a/src/server/package.json b/src/server/package.json index 2888015..4d39607 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -14,6 +14,7 @@ "dotenv": "^16.0.0", "ejs": "^3.1.6", "express": "^4.17.3", + "express-log-url": "^1.5.1", "mysql": "^2.18.1", "sequelize": "^6.17.0" }, diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 8aed35b..49100ad 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -8,6 +8,7 @@ module.exports = { getMatch: getMatch, setMatchWinner: setMatchWinner, createTournament: createTournament, + editTournament: editTournament, getTeamsByTournamentId: getTeamsByTournamentId, } @@ -84,8 +85,8 @@ function getMatch(matchId) { } // Removes a given team from a given match. This is done by setting the teamId-property containing the given team to null. -function unsetContestant(matchId, teamId) { - let match = getMatch(matchId); +async function unsetContestant(matchId, teamId) { + let match = await getMatch(matchId); if (match.team1Id == teamId) { connection.query("UPDATE matches SET team1Id = NULL WHERE id = ?", [mysql.escape(matchId)], (err, result) => { if (err) { console.log(err); } @@ -110,8 +111,11 @@ function setMatchWinner(matchId, winnerId) { reject("Winner must be one of the teams in the match"); } - // Final match doesn't have a parent + // Final match doesn't have a parent, skip this step if (match.parentMatchId != null) { + if (match.winnerId != null) { + unsetContestant(match.parentMatchId, match.winnerId); + } // Enter the winner of the match into the parent match getMatch(match.parentMatchId) .catch(err =>reject(err)) @@ -159,12 +163,48 @@ function createTournament(name, description, startDate, endDate, teamLimit) { console.log(err); reject(err); } else { + + // Create the matches for the tournament + let tournamentId = sets.insertId; + let tiers = Math.log2(teamLimit); + for (let tier = 0; tier < tiers; tier++) { + let matchCount = Math.pow(2, tier); + for (let matchId = 0; matchId < matchCount; matchId++) { + let parentMatchId = null; + if (tier > 0) { + parentMatchId = Math.pow(2, tier - 1) + Math.floor((matchId - (matchId % 2)) / 2); + } + connection.query("INSERT INTO matches (tournamentId, parentMatchId, tier) VALUES (?, ?, ?)", + [tournamentId, parentMatchId, tier], (err, sets) => { + if (err) { + console.error("Could not create match:"); + console.log(err); + } + }); + } + } resolve("Tournament created"); } }); }); } +function editTournament(tournamentId, name, description, startDate, endDate) { + startDate = startDate.toISOString().slice(0, 19).replace('T', ' '); + endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); + return new Promise(function(resolve, reject) { + connection.query("UPDATE tournaments SET name = ?, description = ?, startTime = ?, endTime = ? WHERE id = ?", + [mysql.escape(name), mysql.escape(description), startDate, endDate, mysql.escape(tournamentId)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve("Tournament updated"); + } + }); + }); +} + function getTeamsByTournamentId(tournamentId) { return new Promise(function(resolve, reject) { connection.query("SELECT * FROM teams WHERE tournamentId = ?", [mysql.escape(tournamentId)], (err, teams) => { From d844103b2c0c992b29dab1633241ea860f42ec90 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 27 Mar 2022 22:21:05 +0200 Subject: [PATCH 13/55] Added team methods --- src/server/index.js | 44 +++++++++++-- src/server/tmdb.js | 148 ++++++++++++++++++++++++++++---------------- 2 files changed, 136 insertions(+), 56 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index b788772..cece8a2 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -39,6 +39,7 @@ api.get("/tournament/getTournaments", (req, res) => { .catch(err => res.json({"status": "error", "data": err})); }); +// #region tournament/:tournamentId api.get("/tournament/:tournamentId", (req, res) => { let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { @@ -48,11 +49,8 @@ api.get("/tournament/:tournamentId", (req, res) => { tmdb.getTournament(parseInt(tournamentId)) .catch(err => res.json({"status": "error", "data": err})) .then(tournament => res.json({"status": "OK", "data": tournament})); - // .then(tournament => res.json({"status": "OK", "data": tournament})); - // .then(console.log("lol")) }); - api.get("/tournament/:tournamentId/getMatches", (req, res) => { let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { @@ -76,8 +74,12 @@ api.get("/tournament/:tournamentId/getTeams", (req, res) => { .then(teams => res.send({"status": "OK", "data": teams})) .catch(err => res.send({"status": "error", "data": err})); }); +// #endregion -api.get("/match/:matchId/getMatch", (req, res) => { +// #region match/:matchId + + +api.get("/match/:matchId", (req, res) => { let matchId = req.params.matchId; if (isNaN(matchId)) { res.json({"status": "error", "data": "matchId must be a number"}); @@ -107,6 +109,40 @@ api.post("/match/:matchId/setWinner", (req, res) => { .then(match => res.send({"status": "OK", "data": match})) .catch(err => res.send({"status": "error", "data": err})); }); +// #endregion + +// #region team/:teamId +api.get("/team/:teamId", (req, res) => { + let teamId = req.params.teamId; + if (isNaN(teamId)) { + res.json({"status": "error", "data": "teamId must be a number"}); + return + } + teamId = parseInt(teamId); + tmdb.getTeam(teamId) + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); + +api.post("/team/:teamId/edit", (req, res) => { + let teamId = req.params.teamId; + let teamName = req.body.teamName; + if (isNaN(teamId)) { + res.json({"status": "error", "data": "teamId must be a number"}); + return + } + if (teamName == undefined) { + res.json({"status": "error", "data": "teamName must be a string"}); + return + } + teamId = parseInt(teamId); + tmdb.editTeam(teamId, teamName) + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); + + +// #endregion //Takes JSON body api.post("/tournament/create", (req, res) => { diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 49100ad..c8ce2a1 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -5,6 +5,8 @@ module.exports = { getMatchesByTournamentId: getMatchesByTournamentId, getTournaments: getTournaments, getTournament, getTournament, + getTeam: getTeam, + editTeam: editTeam, getMatch: getMatch, setMatchWinner: setMatchWinner, createTournament: createTournament, @@ -21,55 +23,16 @@ let connection = mysql.createConnection({ database: process.env.DB_DATABASE }); -function getMatchesByTournamentId(tournamentId) { - return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM matches WHERE tournamentId = ?", [mysql.escape(tournamentId)], (err, matches) => { - if (err) { - console.log(err); - reject(err); - } else { - resolve(matches); - } - }); - }); -} - -function getTournaments() { - return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM tournaments", (err, tournaments) => { - if (err) { - console.log(err); - reject(err); - } else { - resolve(tournaments); - } - }); - }); -} - -function getTournament(tournamentId) { - return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM tournaments WHERE id = ?", [mysql.escape(tournamentId)], (err, tournaments) => { - if (err) { - console.log(err); - reject(err); - } else { - if (tournaments.length == 0) { - reject("No such tournament exists"); - } - //TODO number of competing teams - - let tournament = tournaments[0]; - resolve(tournament); - } - }); - }); +function escapeString(str) { + // return mysql.escape(str); + return str; } +// #region match // Returns the match of the exact given id. function getMatch(matchId) { return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM matches WHERE id = ?", [mysql.escape(matchId)], (err, matches) => { + connection.query("SELECT * FROM matches WHERE id = ?", [escapeString(matchId)], (err, matches) => { if (err) { reject(err); } else { @@ -88,11 +51,11 @@ function getMatch(matchId) { async function unsetContestant(matchId, teamId) { let match = await getMatch(matchId); if (match.team1Id == teamId) { - connection.query("UPDATE matches SET team1Id = NULL WHERE id = ?", [mysql.escape(matchId)], (err, result) => { + connection.query("UPDATE matches SET team1Id = NULL WHERE id = ?", [escapeString(matchId)], (err, result) => { if (err) { console.log(err); } }); } else if (match.team2Id == teamId) { - connection.query("UPDATE matches SET team2Id = NULL WHERE id = ?", [mysql.escape(matchId)], (err, result) => { + connection.query("UPDATE matches SET team2Id = NULL WHERE id = ?", [escapeString(matchId)], (err, result) => { if (err) { console.log(err); } }); } else { @@ -122,12 +85,12 @@ function setMatchWinner(matchId, winnerId) { .then(parentMatch => { if (parentMatch.team1Id == null) { connection.query("UPDATE matches SET team1Id = ? WHERE id = ?", - [mysql.escape(winnerId), mysql.escape(parentMatch.id)], (err, sets) => { + [escapeString(winnerId), escapeString(parentMatch.id)], (err, sets) => { if (err) { reject(err); } }); } else if (parentMatch.team2Id == null) { connection.query("UPDATE matches SET team2Id = ? WHERE id = ?", - [mysql.escape(winnerId), mysql.escape(parentMatch.id)], (err, sets) => { + [escapeString(winnerId), escapeString(parentMatch.id)], (err, sets) => { if (err) { reject(err); } }); } else { @@ -138,7 +101,7 @@ function setMatchWinner(matchId, winnerId) { // Lastly, if all checks passed, actually set the winnerId property connection.query("UPDATE matches SET winnerId = ? WHERE id = ?", - [mysql.escape(winnerId), mysql.escape(matchId)], (err, sets) => { + [escapeString(winnerId), escapeString(matchId)], (err, sets) => { if (err) { // If this update fails, we need to undo the parent match update unsetContestant(parentMatchId, winnerId); @@ -152,13 +115,61 @@ function setMatchWinner(matchId, winnerId) { }); }); } +// #endregion + +// #region tournament + +function getTournaments() { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM tournaments", (err, tournaments) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(tournaments); + } + }); + }); +} + +function getTournament(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM tournaments WHERE id = ?", [escapeString(tournamentId)], (err, tournaments) => { + if (err) { + console.log(err); + reject(err); + } else { + if (tournaments.length == 0) { + reject("No such tournament exists"); + } + //TODO number of competing teams + + let tournament = tournaments[0]; + resolve(tournament); + } + }); + }); +} + +function getMatchesByTournamentId(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM matches WHERE tournamentId = ?", [escapeString(tournamentId)], (err, matches) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(matches); + } + }); + }); +} function createTournament(name, description, startDate, endDate, teamLimit) { startDate = startDate.toISOString().slice(0, 19).replace('T', ' '); endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); return new Promise(function(resolve, reject) { connection.query("INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES (?, ?, ?, ?, ?)", - [mysql.escape(name), mysql.escape(description), startDate, endDate, teamLimit], (err, sets) => { + [escapeString(name), escapeString(description), startDate, endDate, teamLimit], (err, sets) => { if (err) { console.log(err); reject(err); @@ -194,7 +205,7 @@ function editTournament(tournamentId, name, description, startDate, endDate) { endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); return new Promise(function(resolve, reject) { connection.query("UPDATE tournaments SET name = ?, description = ?, startTime = ?, endTime = ? WHERE id = ?", - [mysql.escape(name), mysql.escape(description), startDate, endDate, mysql.escape(tournamentId)], (err, sets) => { + [escapeString(name), escapeString(description), startDate, endDate, escapeString(tournamentId)], (err, sets) => { if (err) { console.log(err); reject(err); @@ -207,7 +218,7 @@ function editTournament(tournamentId, name, description, startDate, endDate) { function getTeamsByTournamentId(tournamentId) { return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM teams WHERE tournamentId = ?", [mysql.escape(tournamentId)], (err, teams) => { + connection.query("SELECT * FROM teams WHERE tournamentId = ?", [escapeString(tournamentId)], (err, teams) => { if (err) { console.log(err); reject(err); @@ -217,7 +228,40 @@ function getTeamsByTournamentId(tournamentId) { }); }); } +// #endregion +// #region team + +function getTeam(teamId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM teams WHERE id = ?", [escapeString(teamId)], (err, teams) => { + if (err) { + console.log(err); + reject(err); + } else { + if (teams.length == 0) { + reject("No such team exists"); + } + resolve(teams[0]); + } + }); + }); +} + +function editTeam(teamId, name) { + return new Promise(function(resolve, reject) { + connection.query("UPDATE teams SET name = ? WHERE id = ?", [escapeString(name), escapeString(teamId)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve("Team updated"); + } + }); + }); +} + +// #endregion // Dangerous function, use with caution. // Used to initialize and manage the database by management tools, not by the main application. From e3dfba5a1407f368452340783805f33c9c5cf9bd Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 28 Mar 2022 15:19:55 +0200 Subject: [PATCH 14/55] Coding session - Team manager --- src/server/index.js | 39 ++++++++++++++++++++++------ src/server/tmdb.js | 63 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index cece8a2..f6d465a 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -126,13 +126,14 @@ api.get("/team/:teamId", (req, res) => { api.post("/team/:teamId/edit", (req, res) => { let teamId = req.params.teamId; - let teamName = req.body.teamName; + let teamName = req.body.name; + console.log(req.body); if (isNaN(teamId)) { res.json({"status": "error", "data": "teamId must be a number"}); return } - if (teamName == undefined) { - res.json({"status": "error", "data": "teamName must be a string"}); + if (teamName == undefined || teamName == "") { + res.json({"status": "error", "data": "teamName must be a non-empty string"}); return } teamId = parseInt(teamId); @@ -157,7 +158,7 @@ api.post("/tournament/create", (req, res) => { let name = req.body.name; let description = req.body.description; let teamLimit = req.body.teamLimit; - let startDate = req.body.startDate; + let startDate = req.body.startDate; //TODO: timezones, 2 hr skips let endDate = req.body.endDate; if (name == undefined || name == "" || description == undefined || description == "") { res.json({"status": "error", "data": "name and description must be provided"}); @@ -195,8 +196,9 @@ api.post("/tournament/create", (req, res) => { } tmdb.createTournament(name, description, startDate, endDate, teamLimit) - .catch(err => res.json({"status": "error", "data": err})) - .then(msg => res.json({"status": "OK", "data": msg})); + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); + }); api.post("/tournament/:tournamentId/edit", (req, res) => { @@ -237,7 +239,28 @@ api.post("/tournament/:tournamentId/edit", (req, res) => { } tmdb.editTournament(tournamentId, name, description, startDate, endDate) - .catch(err => res.json({"status": "error", "data": err})) - .then(msg => res.json({"status": "OK", "data": msg})); + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); + }); + +api.post("/tournament/:tournamentId/createTeam", (req, res) => { + let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return; + } + tournamentId = parseInt(tournamentId); + let teamName = req.body.name; + if (teamName == undefined || teamName == "") { + res.json({"status": "error", "data": "teamName must be a non-empty string"}); + return; + } + + tmdb.createTeam(tournamentId, teamName) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); +}); + + // #endregion \ No newline at end of file diff --git a/src/server/tmdb.js b/src/server/tmdb.js index c8ce2a1..131f46f 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -6,6 +6,7 @@ module.exports = { getTournaments: getTournaments, getTournament, getTournament, getTeam: getTeam, + createTeam: createTeam, editTeam: editTeam, getMatch: getMatch, setMatchWinner: setMatchWinner, @@ -121,18 +122,30 @@ function setMatchWinner(matchId, winnerId) { function getTournaments() { return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM tournaments", (err, tournaments) => { + // 1. Get the list of tournament IDs + // 2. getTournament() for each ID + // 3. Return list of tournaments + let tournamentList = []; + connection.query("SELECT id FROM tournaments", async (err, tournamentIds) => { if (err) { console.log(err); reject(err); } else { + let tournaments = await Promise.all(tournamentIds.map(async function(tournament){ + return await getTournament(tournament.id); + })); resolve(tournaments); } }); + }); } function getTournament(tournamentId) { + // 1. Get the tournament + // 2. Get all teams associated with the tournament + // 3. Associate the teams with the tournament + // 4. Return the tournament return new Promise(function(resolve, reject) { connection.query("SELECT * FROM tournaments WHERE id = ?", [escapeString(tournamentId)], (err, tournaments) => { if (err) { @@ -142,10 +155,14 @@ function getTournament(tournamentId) { if (tournaments.length == 0) { reject("No such tournament exists"); } - //TODO number of competing teams - - let tournament = tournaments[0]; - resolve(tournament); + + getTeamsByTournamentId(tournamentId) + .catch(err => reject(err)) + .then(teams => { + let tournament = tournaments[0]; + tournament.teamCount = teams.length; + resolve(tournament); + }); } }); }); @@ -194,7 +211,7 @@ function createTournament(name, description, startDate, endDate, teamLimit) { }); } } - resolve("Tournament created"); + resolve({message: "Tournament created", tournamentId: sets.insertId}); } }); }); @@ -248,7 +265,14 @@ function getTeam(teamId) { }); } -function editTeam(teamId, name) { +async function editTeam(teamId, name) { + let team = await getTeam(teamId); + if (!team) { + return Promise.reject("No such team exists"); + } + if (team.name == name) { + return {message: "Team name unchanged"}; + } return new Promise(function(resolve, reject) { connection.query("UPDATE teams SET name = ? WHERE id = ?", [escapeString(name), escapeString(teamId)], (err, sets) => { if (err) { @@ -261,6 +285,31 @@ function editTeam(teamId, name) { }); } +async function createTeam(tournamentId, name) { + //Check that the tournament exists + let tournament = await getTournament(tournamentId); + + return new Promise(function(resolve, reject) { + if (!tournament) { + reject("No such tournament exists"); + return; + } + if (tournament.teamLimit <= tournament.teamCount) { + reject("Tournament is full"); + return; + } + + connection.query("INSERT INTO teams (tournamentId, name) VALUES (?, ?)", [escapeString(tournamentId), escapeString(name)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve({message: "Team created", teamId: sets.insertId}); + } + }); + }); +} + // #endregion // Dangerous function, use with caution. From 01b7566ffc84ed7fe4b0ba2e0e6318b80ac1740c Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 28 Mar 2022 19:32:11 +0200 Subject: [PATCH 15/55] Moved static root --- src/server/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index f6d465a..913a957 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -27,9 +27,8 @@ api.use(require('express-log-url')); // #region frontend // Serve static files from the React app -api.get("/", (req, res) => { - res.sendFile(path.join(__dirname, "public", "landing.html")); -}); +app.use('/static', express.static(path.join(__dirname, 'clientbuild'))); + // #endregion // #region API From f2e30593948c2a50308d063d85468fffa6ed10ad Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 28 Mar 2022 19:46:39 +0200 Subject: [PATCH 16/55] header fix --- src/server/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/index.js b/src/server/index.js index 913a957..0d6d0c7 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -18,7 +18,7 @@ app.use("/api", api); api.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); api.use(require('express-log-url')); From d97e943ff1c619d81e096b35a81afe77a3bafc9c Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 28 Mar 2022 21:21:55 +0200 Subject: [PATCH 17/55] Change static listening path --- src/server/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 0d6d0c7..e04a38d 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -7,7 +7,7 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3001; +const port = 3000; app.listen(port, () => { console.log(`Listening on port ${port}`) }) @@ -27,7 +27,8 @@ api.use(require('express-log-url')); // #region frontend // Serve static files from the React app -app.use('/static', express.static(path.join(__dirname, 'clientbuild'))); +app.use('/', express.static(path.join(__dirname, 'clientbuild'))); +app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild'))); // #endregion @@ -262,4 +263,4 @@ api.post("/tournament/:tournamentId/createTeam", (req, res) => { }); -// #endregion \ No newline at end of file +// #endregion From 5c494d7018b615112a8792231f70b4604ac04461 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 28 Mar 2022 22:28:34 +0200 Subject: [PATCH 18/55] Changed hosting path --- src/server/index.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index e04a38d..b1136cf 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -7,14 +7,15 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3000; +const port = 5000; app.listen(port, () => { console.log(`Listening on port ${port}`) }) app.use(express.json()); app.use(express.urlencoded({ extended: true })); let api = express.Router(); -app.use("/api", api); +// app.use("/api", api); +app.use("/", api); api.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); @@ -26,9 +27,19 @@ api.use(require('express-log-url')); // #endregion // #region frontend + +api.get("/", (req, res) => { + res.redirect("https://asura.feal.no/"); +}); // Serve static files from the React app -app.use('/', express.static(path.join(__dirname, 'clientbuild'))); -app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild'))); +// app.use('/', express.static(path.join(__dirname, 'clientbuild'))); +// app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +// app.use('/tournament/*', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +// app.use('/static', express.static(path.join(__dirname, 'clientbuild/static'))); +// app.get('/*', function (req, res) { +// res.sendFile(path.join(__dirname, 'clientbuild', 'index.html')); +// }); +// app.use('/*', express.static(path.join(__dirname, 'clientbuild'))); // #endregion From f3f5dbd864c53bb78f292a999dd24bde2123c7df Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 10:45:50 +0200 Subject: [PATCH 19/55] Revert hosting --- src/server/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index b1136cf..9ed1cf0 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -15,7 +15,7 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); let api = express.Router(); // app.use("/api", api); -app.use("/", api); +app.use("/api", api); api.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); @@ -28,17 +28,18 @@ api.use(require('express-log-url')); // #region frontend -api.get("/", (req, res) => { - res.redirect("https://asura.feal.no/"); -}); +// api.get("/", (req, res) => { +// res.redirect("https://asura.feal.no/"); +// }); // Serve static files from the React app // app.use('/', express.static(path.join(__dirname, 'clientbuild'))); // app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); // app.use('/tournament/*', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); -// app.use('/static', express.static(path.join(__dirname, 'clientbuild/static'))); -// app.get('/*', function (req, res) { -// res.sendFile(path.join(__dirname, 'clientbuild', 'index.html')); -// }); +app.use('/static', express.static(path.join(__dirname, 'clientbuild/static'))); +app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))); +app.get('/*', function (req, res) { + res.sendFile(path.join(__dirname, 'clientbuild', 'index.html')); +}); // app.use('/*', express.static(path.join(__dirname, 'clientbuild'))); // #endregion From 08e328b8e4cb7333138f8aa4f32f8e7bbda5a6f0 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 10:55:49 +0200 Subject: [PATCH 20/55] Serve clientbuild format on a single server program --- src/server/clientbuild | 1 + src/server/index.js | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) create mode 120000 src/server/clientbuild diff --git a/src/server/clientbuild b/src/server/clientbuild new file mode 120000 index 0000000..4c7af6a --- /dev/null +++ b/src/server/clientbuild @@ -0,0 +1 @@ +../../../sysut_client/src/client/build \ No newline at end of file diff --git a/src/server/index.js b/src/server/index.js index 9ed1cf0..bc96a80 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -7,7 +7,7 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 5000; +const port = 3000; app.listen(port, () => { console.log(`Listening on port ${port}`) }) @@ -32,14 +32,14 @@ api.use(require('express-log-url')); // res.redirect("https://asura.feal.no/"); // }); // Serve static files from the React app -// app.use('/', express.static(path.join(__dirname, 'clientbuild'))); +app.use('/', express.static(path.join(__dirname, 'clientbuild'))); // app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); -// app.use('/tournament/*', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +app.use('/tournament/*', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); app.use('/static', express.static(path.join(__dirname, 'clientbuild/static'))); app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))); -app.get('/*', function (req, res) { - res.sendFile(path.join(__dirname, 'clientbuild', 'index.html')); -}); +// app.get('/*', function (req, res) { + // res.sendFile(path.join(__dirname, 'clientbuild', 'index.html')); +// }); // app.use('/*', express.static(path.join(__dirname, 'clientbuild'))); // #endregion From bfd5df5e67f8734c5138e25ce3eee0ce4ba1e6d7 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 14:13:29 +0200 Subject: [PATCH 21/55] DB link, place teams in brackets --- src/server/index.js | 5 +-- src/server/management/initDB.sql | 3 +- src/server/tmdb.js | 53 ++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index bc96a80..f10e519 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -59,8 +59,9 @@ api.get("/tournament/:tournamentId", (req, res) => { return; } tmdb.getTournament(parseInt(tournamentId)) - .catch(err => res.json({"status": "error", "data": err})) - .then(tournament => res.json({"status": "OK", "data": tournament})); + .then(tournament => res.json({"status": "OK", "data": tournament})) + .catch(err => res.json({"status": "error", "data": err})); + }); api.get("/tournament/:tournamentId/getMatches", (req, res) => { diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 73ae385..c33966f 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -34,7 +34,8 @@ CREATE TABLE matches ( FOREIGN KEY (tournamentId) REFERENCES tournaments (id), FOREIGN KEY (team1Id) REFERENCES teams (id), - FOREIGN KEY (team2Id) REFERENCES teams (id) + FOREIGN KEY (team2Id) REFERENCES teams (id), + FOREIGN KEY (winnerId) REFERENCES teams (id) ); CREATE TABLE players ( diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 131f46f..fd271f1 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -299,30 +299,57 @@ async function createTeam(tournamentId, name) { return; } - connection.query("INSERT INTO teams (tournamentId, name) VALUES (?, ?)", [escapeString(tournamentId), escapeString(name)], (err, sets) => { + connection.query("INSERT INTO teams (tournamentId, name) VALUES (?, ?)", [escapeString(tournamentId), escapeString(name)], async (err, sets) => { if (err) { console.log(err); reject(err); } else { + await assignFirstMatch(sets.insertId, tournamentId); resolve({message: "Team created", teamId: sets.insertId}); } }); }); } -// #endregion -// Dangerous function, use with caution. -// Used to initialize and manage the database by management tools, not by the main application. -function executeStatement(statement) { +//Private function, assigns a starting match to the given team +async function assignFirstMatch(teamId, tournamentId) { + let tournament = await getTournament(tournamentId); + let matches = await getMatchesByTournamentId(tournamentId); + + let highTier = Math.log2(tournament.teamLimit)-1; + console.log(highTier); + let highTierMatches = matches.filter(match => match.tier == highTier); + console.log(matches); + return new Promise(function(resolve, reject) { - connection.query(statement, (err, sets) => { - if (err) { - console.log(err); - reject(err); - } else { - resolve(sets); + for (let match of highTierMatches) { + if (match.team1Id == null) { + console.log("Assigning team " + teamId + " to match " + match.id + " as team 1"); + connection.query("UPDATE matches SET team1Id = ? WHERE id = ?", [escapeString(teamId), escapeString(match.id)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve("Team assigned to match " + match.id); + } + }); + return + } else if (match.team2Id == null) { + console.log("Assigning team " + teamId + " to match " + match.id + " as team 2"); + connection.query("UPDATE matches SET team2Id = ? WHERE id = ?", [escapeString(teamId), escapeString(match.id)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve("Team assigned to match " + match.id); + } + }); + return } - }); + } + reject("Could not assign team to any matches"); }); -} \ No newline at end of file +} + +// #endregion From 075d2f448902282d8c36ff409de04a596c1bcedb Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 15:34:31 +0200 Subject: [PATCH 22/55] Fix parent match id generation --- src/server/tmdb.js | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index fd271f1..7b0c5ca 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -160,6 +160,14 @@ function getTournament(tournamentId) { .catch(err => reject(err)) .then(teams => { let tournament = tournaments[0]; + //TODO: CHeckh this +// /home/felixalb/Documents/NTNU/semester2/sysut_server/src/server/tmdb.js:163 +// tournament.teamCount = teams.length; +// ^ + +// TypeError: Cannot set properties of undefined (setting 'teamCount') +// at /home/felixalb/Documents/NTNU/semester2/sysut_server/src/server/tmdb.js:163:34 + tournament.teamCount = teams.length; resolve(tournament); }); @@ -181,34 +189,46 @@ function getMatchesByTournamentId(tournamentId) { }); } +function createMatch(tournamentId, parentMatchId, tier) { + //Returns Promise witht the inserted ID. + return new Promise(function(resolve, reject) { + connection.query("INSERT INTO matches (tournamentId, parentMatchId, tier) VALUES (?, ?, ?)", + [escapeString(tournamentId), escapeString(parentMatchId), escapeString(tier)], (err, result) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(result.insertId); + } + }); + }); +} + function createTournament(name, description, startDate, endDate, teamLimit) { startDate = startDate.toISOString().slice(0, 19).replace('T', ' '); endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); return new Promise(function(resolve, reject) { connection.query("INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES (?, ?, ?, ?, ?)", - [escapeString(name), escapeString(description), startDate, endDate, teamLimit], (err, sets) => { + [escapeString(name), escapeString(description), startDate, endDate, teamLimit], async (err, sets) => { if (err) { console.log(err); reject(err); } else { - // Create the matches for the tournament + let matchIds = []; let tournamentId = sets.insertId; let tiers = Math.log2(teamLimit); + for (let tier = 0; tier < tiers; tier++) { let matchCount = Math.pow(2, tier); - for (let matchId = 0; matchId < matchCount; matchId++) { + for (let i = 0; i < matchCount; i++) { let parentMatchId = null; if (tier > 0) { - parentMatchId = Math.pow(2, tier - 1) + Math.floor((matchId - (matchId % 2)) / 2); + let parentMatchIndex = Math.pow(2, tier - 1) + Math.floor((i - (i % 2)) / 2) - 1; + parentMatchId = matchIds[parentMatchIndex]; } - connection.query("INSERT INTO matches (tournamentId, parentMatchId, tier) VALUES (?, ?, ?)", - [tournamentId, parentMatchId, tier], (err, sets) => { - if (err) { - console.error("Could not create match:"); - console.log(err); - } - }); + let newMatchId = await createMatch(tournamentId, parentMatchId, tier); + matchIds.push(newMatchId); } } resolve({message: "Tournament created", tournamentId: sets.insertId}); @@ -311,6 +331,19 @@ async function createTeam(tournamentId, name) { }); } +function deleteTeam(teamId) { + return new Promise(async function(resolve, reject) { + connection.query("DELETE FROM teams WHERE id = ?", [escapeString(teamId)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + + resolve("Team deleted"); + } + }); + }); +} //Private function, assigns a starting match to the given team async function assignFirstMatch(teamId, tournamentId) { From 0ae9c547552d0055f0c5f27bf0f14c91a51b3fad Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 16:00:41 +0200 Subject: [PATCH 23/55] Delete teams --- src/server/index.js | 17 +++++++++++++++++ src/server/management/initDB.sql | 6 +++--- src/server/tmdb.js | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index f10e519..c8ffd27 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -137,6 +137,23 @@ api.get("/team/:teamId", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); +api.post("/team/:teamId/delete", (req, res) => { + let teamId = req.params.teamId; + if (isNaN(teamId)) { + res.json({"status": "error", "data": "teamId must be a number"}); + return + } + try { + teamId = parseInt(teamId); + } catch (err) { + res.json({"status": "error", "data": "teamId must be a number"}); + return + } + tmdb.deleteTeam(teamId) + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); + api.post("/team/:teamId/edit", (req, res) => { let teamId = req.params.teamId; let teamName = req.body.name; diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index c33966f..a858525 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -33,9 +33,9 @@ CREATE TABLE matches ( tier INTEGER, FOREIGN KEY (tournamentId) REFERENCES tournaments (id), - FOREIGN KEY (team1Id) REFERENCES teams (id), - FOREIGN KEY (team2Id) REFERENCES teams (id), - FOREIGN KEY (winnerId) REFERENCES teams (id) + FOREIGN KEY (team1Id) REFERENCES teams (id) ON DELETE SET NULL, + FOREIGN KEY (team2Id) REFERENCES teams (id) ON DELETE SET NULL, + FOREIGN KEY (winnerId) REFERENCES teams (id) ON DELETE SET NULL ); CREATE TABLE players ( diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 7b0c5ca..39c00ff 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -8,6 +8,7 @@ module.exports = { getTeam: getTeam, createTeam: createTeam, editTeam: editTeam, + deleteTeam: deleteTeam, getMatch: getMatch, setMatchWinner: setMatchWinner, createTournament: createTournament, @@ -338,7 +339,6 @@ function deleteTeam(teamId) { console.log(err); reject(err); } else { - resolve("Team deleted"); } }); From b1d55783f4251f86bb377ef0f41e0cc45feb48d4 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 16:10:00 +0200 Subject: [PATCH 24/55] Change from HTTP POST to HTTP DELETE --- src/server/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/index.js b/src/server/index.js index c8ffd27..5bdc0c0 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -137,7 +137,7 @@ api.get("/team/:teamId", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -api.post("/team/:teamId/delete", (req, res) => { +api.delete("/team/:teamId", (req, res) => { let teamId = req.params.teamId; if (isNaN(teamId)) { res.json({"status": "error", "data": "teamId must be a number"}); From 12199d5f12a2ae06cdf2bb679b95a43de85e03ce Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 29 Mar 2022 20:08:31 +0200 Subject: [PATCH 25/55] Team linking --- src/server/management/initDB.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index a858525..216c308 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -43,7 +43,7 @@ CREATE TABLE players ( name TEXT NOT NULL, teamId INTEGER NOT NULL, - FOREIGN KEY (teamId) REFERENCES teams (id) + FOREIGN KEY (teamId) REFERENCES teams (id) ON DELETE CASCADE ); -- Example data (Two tournaments, 4 teams, single elimination) From a95a2f6ea8b79b042a6147fc7bb7fc7c215b2a39 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 30 Mar 2022 00:10:10 +0200 Subject: [PATCH 26/55] Delete tournaments, clean up --- src/server/index.js | 142 +++++++++++++++++-------------- src/server/management/initDB.sql | 4 +- src/server/tmdb.js | 40 +++++---- 3 files changed, 101 insertions(+), 85 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 5bdc0c0..ff60022 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -19,6 +19,7 @@ app.use("/api", api); api.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); + res.header("Access-Control-Allow-Methods", "GET, POST, DELETE"); // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); @@ -28,9 +29,6 @@ api.use(require('express-log-url')); // #region frontend -// api.get("/", (req, res) => { -// res.redirect("https://asura.feal.no/"); -// }); // Serve static files from the React app app.use('/', express.static(path.join(__dirname, 'clientbuild'))); // app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); @@ -87,6 +85,80 @@ api.get("/tournament/:tournamentId/getTeams", (req, res) => { .then(teams => res.send({"status": "OK", "data": teams})) .catch(err => res.send({"status": "error", "data": err})); }); + +api.post("/tournament/:tournamentId/edit", (req, res) => { + let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return + } + tournamentId = parseInt(tournamentId); + let name = req.body.name; + let description = req.body.description; + let startDate = req.body.startDate; + let endDate = req.body.endDate; + console.log(startDate); + if (name == undefined || name == "" || description == undefined || description == "") { + res.json({"status": "error", "data": "name and description must be provided"}); + return + } + if (startDate == undefined || endDate == undefined) { + res.json({"status": "error", "data": "startDate and endDate must be defined"}); + return + } + try { + startDate = new Date(startDate); + endDate = new Date(endDate); + } catch (err) { + res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); + return + } + // let today = new Date(); + // if (startDate < today) { + // res.json({"status": "error", "data": "startDate cannot be in the past"}); + // return + // } + if (startDate > endDate) { + res.json({"status": "error", "data": "startDate cannot be after endDate"}); + return + } + + tmdb.editTournament(tournamentId, name, description, startDate, endDate) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); + +}); + +api.post("/tournament/:tournamentId/createTeam", (req, res) => { + let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return; + } + tournamentId = parseInt(tournamentId); + let teamName = req.body.name; + if (teamName == undefined || teamName == "") { + res.json({"status": "error", "data": "teamName must be a non-empty string"}); + return; + } + + tmdb.createTeam(tournamentId, teamName) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); +}); + +api.delete("/tournament/:tournamentId", (req, res) => { + let tournamentId = req.params.tournamentId; + if (isNaN(tournamentId)) { + res.json({"status": "error", "data": "tournamentId must be a number"}); + return; + } + tournamentId = parseInt(tournamentId); + tmdb.deleteTournament(tournamentId) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); +}); + // #endregion // #region match/:matchId @@ -229,68 +301,6 @@ api.post("/tournament/create", (req, res) => { .then(msg => res.json({"status": "OK", "data": msg})) .catch(err => res.json({"status": "error", "data": err})); -}); - -api.post("/tournament/:tournamentId/edit", (req, res) => { - let tournamentId = req.params.tournamentId; - if (isNaN(tournamentId)) { - res.json({"status": "error", "data": "tournamentId must be a number"}); - return - } - tournamentId = parseInt(tournamentId); - let name = req.body.name; - let description = req.body.description; - let startDate = req.body.startDate; - let endDate = req.body.endDate; - console.log(startDate); - if (name == undefined || name == "" || description == undefined || description == "") { - res.json({"status": "error", "data": "name and description must be provided"}); - return - } - if (startDate == undefined || endDate == undefined) { - res.json({"status": "error", "data": "startDate and endDate must be defined"}); - return - } - try { - startDate = new Date(startDate); - endDate = new Date(endDate); - } catch (err) { - res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); - return - } - // let today = new Date(); - // if (startDate < today) { - // res.json({"status": "error", "data": "startDate cannot be in the past"}); - // return - // } - if (startDate > endDate) { - res.json({"status": "error", "data": "startDate cannot be after endDate"}); - return - } - - tmdb.editTournament(tournamentId, name, description, startDate, endDate) - .then(msg => res.json({"status": "OK", "data": msg})) - .catch(err => res.json({"status": "error", "data": err})); - -}); - -api.post("/tournament/:tournamentId/createTeam", (req, res) => { - let tournamentId = req.params.tournamentId; - if (isNaN(tournamentId)) { - res.json({"status": "error", "data": "tournamentId must be a number"}); - return; - } - tournamentId = parseInt(tournamentId); - let teamName = req.body.name; - if (teamName == undefined || teamName == "") { - res.json({"status": "error", "data": "teamName must be a non-empty string"}); - return; - } - - tmdb.createTeam(tournamentId, teamName) - .then(msg => res.json({"status": "OK", "data": msg})) - .catch(err => res.json({"status": "error", "data": err})); -}); - +}); // #endregion diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 216c308..3bbe8ef 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -20,7 +20,7 @@ CREATE TABLE teams ( tournamentId INTEGER NOT NULL, name TEXT NOT NULL, - FOREIGN KEY (tournamentId) REFERENCES tournaments (id) + FOREIGN KEY (tournamentId) REFERENCES tournaments (id) ON DELETE CASCADE ); CREATE TABLE matches ( @@ -32,7 +32,7 @@ CREATE TABLE matches ( winnerId INTEGER, tier INTEGER, - FOREIGN KEY (tournamentId) REFERENCES tournaments (id), + FOREIGN KEY (tournamentId) REFERENCES tournaments (id) ON DELETE CASCADE, FOREIGN KEY (team1Id) REFERENCES teams (id) ON DELETE SET NULL, FOREIGN KEY (team2Id) REFERENCES teams (id) ON DELETE SET NULL, FOREIGN KEY (winnerId) REFERENCES teams (id) ON DELETE SET NULL diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 39c00ff..95d03e6 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -12,6 +12,7 @@ module.exports = { getMatch: getMatch, setMatchWinner: setMatchWinner, createTournament: createTournament, + deleteTournament: deleteTournament, editTournament: editTournament, getTeamsByTournamentId: getTeamsByTournamentId, } @@ -153,25 +154,30 @@ function getTournament(tournamentId) { console.log(err); reject(err); } else { - if (tournaments.length == 0) { - reject("No such tournament exists"); - } + if (tournaments.length == 0) { + reject("No such tournament exists"); + return + } - getTeamsByTournamentId(tournamentId) - .catch(err => reject(err)) - .then(teams => { - let tournament = tournaments[0]; - //TODO: CHeckh this -// /home/felixalb/Documents/NTNU/semester2/sysut_server/src/server/tmdb.js:163 -// tournament.teamCount = teams.length; -// ^ + getTeamsByTournamentId(tournamentId) + .catch(err => reject(err)) + .then(teams => { + let tournament = tournaments[0]; + tournament.teamCount = teams.length; + resolve(tournament); + }); + } + }); + }); +} -// TypeError: Cannot set properties of undefined (setting 'teamCount') -// at /home/felixalb/Documents/NTNU/semester2/sysut_server/src/server/tmdb.js:163:34 - - tournament.teamCount = teams.length; - resolve(tournament); - }); +function deleteTournament(tournamentId) { + return new Promise(function(resolve, reject) { + connection.query("DELETE FROM tournaments WHERE id = ?", [escapeString(tournamentId)], (err, result) => { + if (err) { + reject(err); + } else { + resolve(); } }); }); From a56ef5a0f1d136066c746ed9a8abd26c48bcddfd Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Tue, 5 Apr 2022 10:58:40 +0200 Subject: [PATCH 27/55] Auto restart database connection --- src/server/tmdb.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 95d03e6..9b0056c 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -19,12 +19,35 @@ module.exports = { const mysql = require("mysql"); -let connection = mysql.createConnection({ +let db_config = { host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE -}); +}; +let connection +// https://stackoverflow.com/a/20211143 +function handleDisconnect() { + connection = mysql.createConnection(db_config); // Recreate the connection + + connection.connect(function(err) { + if(err) { + console.log('error when connecting to db:', err); + setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect, + } // to avoid a hot loop, and to allow our node script to + }); // process asynchronous requests in the meantime. + // If you're also serving http, display a 503 error. + connection.on('error', function(err) { + console.log('db error', err); + if(err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually + handleDisconnect(); // lost due to either server restart, or a + } else { // connnection idle timeout (the wait_timeout + throw err; // server variable configures this) + } + }); +} + +handleDisconnect(); //Start the auto-restarting connection function escapeString(str) { // return mysql.escape(str); From f1bb45ee8171f7a28491d86dfa8dadc30f681372 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 6 Apr 2022 10:17:29 +0200 Subject: [PATCH 28/55] Change timezone on mysql connection --- src/server/tmdb.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 9b0056c..d7223f0 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -45,8 +45,16 @@ function handleDisconnect() { throw err; // server variable configures this) } }); + connection.on('connection', conn => { + conn.query("SET time_zone='+02:00';", error => { + if(error){ + throw error + } + }) + }); } + handleDisconnect(); //Start the auto-restarting connection function escapeString(str) { From 3a4cd2c922c50fdfc203724222158df3388c2faf Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 6 Apr 2022 10:19:24 +0200 Subject: [PATCH 29/55] Change demo data --- src/server/management/initDB.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 3bbe8ef..4bf4bfb 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -47,8 +47,8 @@ CREATE TABLE players ( ); -- Example data (Two tournaments, 4 teams, single elimination) -INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-04-01 16:00:00', '2022-04-01 20:00:00', 4); -INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-04-03 17:30:00', '2022-04-04 21:30:00', 8); +INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-06-01 16:00:00', '2022-06-01 20:00:00', 4); +INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-03-03 17:30:00', '2022-03-04 21:30:00', 8); INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 From 184ed8413b9f7dd3189dd306b076bdfd1e0cbce2 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 6 Apr 2022 10:31:56 +0200 Subject: [PATCH 30/55] Undo timezone change --- src/server/tmdb.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index d7223f0..a21742f 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -45,13 +45,6 @@ function handleDisconnect() { throw err; // server variable configures this) } }); - connection.on('connection', conn => { - conn.query("SET time_zone='+02:00';", error => { - if(error){ - throw error - } - }) - }); } From 5cfed3a3bf955bd58f7ac8ce3cb83da55d92d436 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 20 Apr 2022 14:34:57 +0200 Subject: [PATCH 31/55] Timezone compensation --- src/server/index.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index ff60022..a437ba9 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -107,8 +107,8 @@ api.post("/tournament/:tournamentId/edit", (req, res) => { return } try { - startDate = new Date(startDate); - endDate = new Date(endDate); + startDate = new Date(parseInt(startDate)); + endDate = new Date(parseInt(endDate)); } catch (err) { res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); return @@ -262,6 +262,7 @@ api.post("/tournament/create", (req, res) => { let teamLimit = req.body.teamLimit; let startDate = req.body.startDate; //TODO: timezones, 2 hr skips let endDate = req.body.endDate; + console.log(startDate, endDate); if (name == undefined || name == "" || description == undefined || description == "") { res.json({"status": "error", "data": "name and description must be provided"}); return @@ -281,8 +282,8 @@ api.post("/tournament/create", (req, res) => { return } try { - startDate = new Date(startDate); - endDate = new Date(endDate); + startDate = new Date(parseInt(startDate)); + endDate = new Date(parseInt(endDate)); } catch (err) { res.json({"status": "error", "data": "startDate and endDate must be valid dates"}); return @@ -293,14 +294,14 @@ api.post("/tournament/create", (req, res) => { return } if (startDate > endDate) { - res.json({"status": "error", "data": "startDate cannot be after endDate"}); + res.json({"status": "error", "data": "endDate must be later than startDate"}); return } + console.log(startDate); tmdb.createTournament(name, description, startDate, endDate, teamLimit) .then(msg => res.json({"status": "OK", "data": msg})) .catch(err => res.json({"status": "error", "data": err})); - }); // #endregion From dd83b1f8f816c742094676e67528ee950e31686b Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Thu, 21 Apr 2022 15:05:19 +0200 Subject: [PATCH 32/55] Rebuild setWinner() and install passport for google login --- src/server/index.js | 53 +++++- src/server/package-lock.json | 304 +++++++++++++++++++++++++++++++++++ src/server/package.json | 3 + src/server/tmdb.js | 132 ++++++++------- 4 files changed, 429 insertions(+), 63 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index a437ba9..9bb5748 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -1,5 +1,6 @@ const path = require("path"); const express = require("express"); +const session = require('express-session'); require("dotenv").config(); // Our self-written module for handling database operations @@ -7,14 +8,18 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3000; +const port = 3001; app.listen(port, () => { console.log(`Listening on port ${port}`) }) app.use(express.json()); app.use(express.urlencoded({ extended: true })); +app.use(session({ + resave: true, + saveUninitialized: true, + secret: 'ASURASECRET' +})); let api = express.Router(); -// app.use("/api", api); app.use("/api", api); api.use(function(req, res, next) { @@ -42,6 +47,50 @@ app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))) // #endregion +// #region PASSPORT / OAUTH + +const passport = require('passport'); +var userProfile; + +app.use(passport.initialize()); +app.use(passport.session()); + +app.get('/success', (req, res) => res.send(userProfile)); +// app.get('/error', (req, res) => res.send("error logging in")); + +passport.serializeUser(function(user, cb) { + cb(null, user); +}); + +passport.deserializeUser(function(obj, cb) { + cb(null, obj); +}); + +const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy; +passport.use(new GoogleStrategy({ + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + callbackURL: process.env.GOOGLE_CALLBACK_URL + }, + function(accessToken, refreshToken, profile, done) { + userProfile=profile; + return done(null, userProfile); + } +)); + +app.get('/auth/google', + passport.authenticate('google', { scope : ['profile', 'email'] })); + +app.get('/auth/google/callback', + passport.authenticate('google', { failureRedirect: '/error' }), + function(req, res) { + // Successful authentication, redirect success. + res.redirect('/success'); + }); + +// #endregion + + // #region API api.get("/tournament/getTournaments", (req, res) => { tmdb.getTournaments() diff --git a/src/server/package-lock.json b/src/server/package-lock.json index 07ff362..2be5617 100644 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -13,7 +13,10 @@ "ejs": "^3.1.6", "express": "^4.17.3", "express-log-url": "^1.5.1", + "express-session": "^1.17.2", "mysql": "^2.18.1", + "passport": "^0.5.2", + "passport-google-oauth": "^2.0.0", "sequelize": "^6.17.0" }, "devDependencies": { @@ -142,6 +145,14 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -655,6 +666,40 @@ "chalk": "^4.1.0" } }, + "node_modules/express-session": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", + "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "dependencies": { + "cookie": "0.4.1", + "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.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/filelist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", @@ -1353,6 +1398,11 @@ "node": ">=8" } }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1364,6 +1414,14 @@ "node": ">= 0.8" } }, + "node_modules/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==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1414,11 +1472,107 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz", + "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-google-oauth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz", + "integrity": "sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA==", + "dependencies": { + "passport-google-oauth1": "1.x.x", + "passport-google-oauth20": "2.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-google-oauth1": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz", + "integrity": "sha1-r3SoA99R7GRvZqRNgigr5vEI4Mw=", + "dependencies": { + "passport-oauth1": "1.x.x" + } + }, + "node_modules/passport-google-oauth20": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", + "integrity": "sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==", + "dependencies": { + "passport-oauth2": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-oauth1": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.2.0.tgz", + "integrity": "sha512-Sv2YWodC6jN12M/OXwmR4BIXeeIHjjbwYTQw4kS6tHK4zYzSEpxBgSJJnknBjICA5cj0ju3FSnG1XmHgIhYnLg==", + "dependencies": { + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "utils-merge": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-oauth2": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.6.1.tgz", + "integrity": "sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ==", + "dependencies": { + "base64url": "3.x.x", + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "node_modules/pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", @@ -1501,6 +1655,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1975,6 +2137,22 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uid2": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", + "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==" + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -2265,6 +2443,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + }, "bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -2660,6 +2843,33 @@ "chalk": "^4.1.0" } }, + "express-session": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", + "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "requires": { + "cookie": "0.4.1", + "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.1", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, "filelist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", @@ -3180,6 +3390,11 @@ "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true }, + "oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -3188,6 +3403,11 @@ "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", @@ -3228,11 +3448,77 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz", + "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-google-oauth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz", + "integrity": "sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA==", + "requires": { + "passport-google-oauth1": "1.x.x", + "passport-google-oauth20": "2.x.x" + } + }, + "passport-google-oauth1": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz", + "integrity": "sha1-r3SoA99R7GRvZqRNgigr5vEI4Mw=", + "requires": { + "passport-oauth1": "1.x.x" + } + }, + "passport-google-oauth20": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", + "integrity": "sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==", + "requires": { + "passport-oauth2": "1.x.x" + } + }, + "passport-oauth1": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.2.0.tgz", + "integrity": "sha512-Sv2YWodC6jN12M/OXwmR4BIXeeIHjjbwYTQw4kS6tHK4zYzSEpxBgSJJnknBjICA5cj0ju3FSnG1XmHgIhYnLg==", + "requires": { + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "utils-merge": "1.x.x" + } + }, + "passport-oauth2": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.6.1.tgz", + "integrity": "sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ==", + "requires": { + "base64url": "3.x.x", + "oauth": "0.9.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "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-to-regexp": { "version": "0.1.7", "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=" + }, "pg-connection-string": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", @@ -3294,6 +3580,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" }, + "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", @@ -3642,6 +3933,19 @@ "is-typedarray": "^1.0.0" } }, + "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" + } + }, + "uid2": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", + "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==" + }, "undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", diff --git a/src/server/package.json b/src/server/package.json index 4d39607..f91af11 100644 --- a/src/server/package.json +++ b/src/server/package.json @@ -15,7 +15,10 @@ "ejs": "^3.1.6", "express": "^4.17.3", "express-log-url": "^1.5.1", + "express-session": "^1.17.2", "mysql": "^2.18.1", + "passport": "^0.5.2", + "passport-google-oauth": "^2.0.0", "sequelize": "^6.17.0" }, "devDependencies": { diff --git a/src/server/tmdb.js b/src/server/tmdb.js index a21742f..d83cb34 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -77,71 +77,81 @@ function getMatch(matchId) { // Removes a given team from a given match. This is done by setting the teamId-property containing the given team to null. async function unsetContestant(matchId, teamId) { let match = await getMatch(matchId); - if (match.team1Id == teamId) { - connection.query("UPDATE matches SET team1Id = NULL WHERE id = ?", [escapeString(matchId)], (err, result) => { - if (err) { console.log(err); } - }); - } else if (match.team2Id == teamId) { - connection.query("UPDATE matches SET team2Id = NULL WHERE id = ?", [escapeString(matchId)], (err, result) => { - if (err) { console.log(err); } - }); - } else { - console.log("Error: Team not found in match"); - } -} - -// Sets the winnerId-property of a given match. -// Also appoints the winner as a contestant to the next(parent) match. -function setMatchWinner(matchId, winnerId) { return new Promise(function(resolve, reject) { - getMatch(matchId) - .catch(err => reject(err)) - .then(match => { - if (winnerId != match.team1Id && winnerId != match.team2Id) { - reject("Winner must be one of the teams in the match"); - } - - // Final match doesn't have a parent, skip this step - if (match.parentMatchId != null) { - if (match.winnerId != null) { - unsetContestant(match.parentMatchId, match.winnerId); - } - // Enter the winner of the match into the parent match - getMatch(match.parentMatchId) - .catch(err =>reject(err)) - .then(parentMatch => { - if (parentMatch.team1Id == null) { - connection.query("UPDATE matches SET team1Id = ? WHERE id = ?", - [escapeString(winnerId), escapeString(parentMatch.id)], (err, sets) => { - if (err) { reject(err); } - }); - } else if (parentMatch.team2Id == null) { - connection.query("UPDATE matches SET team2Id = ? WHERE id = ?", - [escapeString(winnerId), escapeString(parentMatch.id)], (err, sets) => { - if (err) { reject(err); } - }); - } else { - reject("Parent match already has two teams"); - } - }); - } - - // Lastly, if all checks passed, actually set the winnerId property - connection.query("UPDATE matches SET winnerId = ? WHERE id = ?", - [escapeString(winnerId), escapeString(matchId)], (err, sets) => { - if (err) { - // If this update fails, we need to undo the parent match update - unsetContestant(parentMatchId, winnerId); - reject(err); - } - getMatch(matchId) - .catch(err => reject(err)) - .then(match => resolve(match)); - }); - + + if (match.team1Id == teamId) { + connection.query("UPDATE matches SET team1Id = NULL WHERE id = ?", [escapeString(matchId)], (err, result) => { + if (err) { console.log(err); reject(err); } + resolve(); }); + } else if (match.team2Id == teamId) { + connection.query("UPDATE matches SET team2Id = NULL WHERE id = ?", [escapeString(matchId)], (err, result) => { + if (err) { console.log(err); reject(err); } + resolve(); + }); + } else { + console.log("Error: Team not found in match"); + reject("Error: Team not found in match"); + } }); } + + +async function insertContestant(matchId, teamId, prevMatchId) { + let match = await getMatch(matchId); + connection.query("SELECT * FROM matches WHERE parentMatchId = ?", [escapeString(matchId)], (err, childMatches) => { + if (err) { console.log(err); } + let isFirst = prevMatchId == childMatches[0].id; + if (isFirst) { + if (match.team1Id != null) { return; } + connection.query("UPDATE matches SET team1Id = ? WHERE id = ?", + [escapeString(teamId), escapeString(matchId)], (err, sets) => { + if (err) { console.log(err); } + }); + } else { + if (match.team2Id != null) { return; } + connection.query("UPDATE matches SET team2Id = ? WHERE id = ?", + [escapeString(teamId), escapeString(matchId)], (err, sets) => { + if (err) { console.log(err); } + }); + } + }); +} + +async function setMatchWinner(matchId, winnerId) { + return new Promise(async function(resolve, reject) { + let match = await getMatch(matchId); + if (winnerId != match.team1Id && winnerId != match.team2Id && winnerId != null) { + reject("Winner id must be one of the teams in the match, or null"); + return; + } + let oldWinnerId = match.winnerId; + connection.query("UPDATE matches SET winnerId = ? WHERE id = ?",[escapeString(winnerId), escapeString(matchId)], async (err, sets) => { + if (err) { + reject(err); + return; + } + + // Remove the old winner from the next match + if (oldWinnerId != null && match.parentMatchId != null) { + let parentMatch = await getMatch(match.parentMatchId); + // Do not undo the match if the parent match is played and finished + if (parentMatch.winnerId != null) { + connection.query("UPDATE matches SET winnerId = ? WHERE id = ?", [escapeString(oldWinnerId), escapeString(match.parentMatchId)], (err, sets) => {}); + reject("The next match is already played"); + return; + } + await unsetContestant(match.parentMatchId, oldWinnerId); + } + if (match.parentMatchId != null && winnerId != null) { + insertContestant(match.parentMatchId, winnerId, matchId); + } + + resolve(getMatch(matchId)); + }); + }); +} + // #endregion // #region tournament From 864150041432f71bebbe867acda47ff2dfe23fed Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Thu, 21 Apr 2022 16:39:35 +0200 Subject: [PATCH 33/55] Fix login-url --- src/server/index.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 9bb5748..d7770cb 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -8,7 +8,7 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3001; +const port = 3000; app.listen(port, () => { console.log(`Listening on port ${port}`) }) @@ -36,15 +36,10 @@ api.use(require('express-log-url')); // Serve static files from the React app app.use('/', express.static(path.join(__dirname, 'clientbuild'))); -// app.use('/tournament/', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +app.use('/login', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); app.use('/tournament/*', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); app.use('/static', express.static(path.join(__dirname, 'clientbuild/static'))); app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))); -// app.get('/*', function (req, res) { - // res.sendFile(path.join(__dirname, 'clientbuild', 'index.html')); -// }); -// app.use('/*', express.static(path.join(__dirname, 'clientbuild'))); - // #endregion // #region PASSPORT / OAUTH From 0ff1db6fb46772405a07be9b218e24e0dac2c805 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Fri, 22 Apr 2022 11:16:41 +0200 Subject: [PATCH 34/55] Started login system --- src/server/index.js | 69 ++++++++++++++++++--- src/server/management/initDB.sql | 40 +++--------- src/server/tmdb.js | 103 +++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 40 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index d7770cb..a379581 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -1,6 +1,7 @@ const path = require("path"); const express = require("express"); const session = require('express-session'); +const https = require("https"); require("dotenv").config(); // Our self-written module for handling database operations @@ -8,7 +9,7 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3000; +const port = 3001; app.listen(port, () => { console.log(`Listening on port ${port}`) }) @@ -29,6 +30,7 @@ api.use(function(req, res, next) { next(); }); api.use(require('express-log-url')); +app.use(require('express-log-url')); // #endregion @@ -78,10 +80,17 @@ app.get('/auth/google', app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/error' }), - function(req, res) { - // Successful authentication, redirect success. - res.redirect('/success'); - }); + async function(req, res) { + // Get user profile from passport + let user = { + id: req.user.id, + name: req.user.displayName, + email: req.user.emails[0].value + } + req.session.user = user; + res.json(user); + } +); // #endregion @@ -89,8 +98,8 @@ app.get('/auth/google/callback', // #region API api.get("/tournament/getTournaments", (req, res) => { tmdb.getTournaments() - .then(tournaments => res.json({"status": "OK", "data": tournaments})) - .catch(err => res.json({"status": "error", "data": err})); + .then(tournaments => res.json({"status": "OK", "data": tournaments})) + .catch(err => res.json({"status": "error", "data": err})); }); // #region tournament/:tournamentId @@ -349,3 +358,49 @@ api.post("/tournament/create", (req, res) => { }); // #endregion + +// #region users + +api.get("/users/getSessionUser", (req, res) => { + if (req.session.user) { + res.json({"status": "OK", "data": req.session.user}); + } else { + res.json({"status": "error", "data": "No user logged in"}); + } +}); + +api.get("/users/getUsers", (req, res) => { + tmdb.getUsers() + .then(users => res.json({"status": "OK", "data": users})) + .catch(err => res.json({"status": "error", "data": err})); +}); + +api.post("/users/createBlank", (req, res) => { + let email = req.body.newUserEmail; + // Check if the user already exists + tmdb.getUserByEmail(email) + .then(user => { + res.json({"status": "error", "data": "User already exists", user: user}); + }) + .catch(err => { + console.log(err); + if (err == "No such user exists") { + // Create a new user + tmdb.createUserBlank(email) + .then(user => { + res.json({"status": "OK", "data": user}); + }) + .catch(err => { + res.json({"status": "error", "data": err}); + }); + } else { + res.json({"status": "error", "data": err}); + } + }); +}); + +api.post("/users/edit", (req, res) => { + +}); + +// #endregion \ No newline at end of file diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 4bf4bfb..deeaf60 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -1,9 +1,9 @@ -- WARNING: Will delete EVERYTHING in the database! -DROP TABLE IF EXISTS players; DROP TABLE IF EXISTS matches; DROP TABLE IF EXISTS teams; DROP TABLE IF EXISTS tournaments; +DROP TABLE IF EXISTS users; -- Create the tables CREATE TABLE tournaments ( @@ -38,12 +38,12 @@ CREATE TABLE matches ( FOREIGN KEY (winnerId) REFERENCES teams (id) ON DELETE SET NULL ); -CREATE TABLE players ( +CREATE TABLE users ( id INTEGER PRIMARY KEY AUTO_INCREMENT, - name TEXT NOT NULL, - teamId INTEGER NOT NULL, - - FOREIGN KEY (teamId) REFERENCES teams (id) ON DELETE CASCADE + googleId INTEGER, + name TEXT, + email TEXT NOT NULL, + isManager BOOLEAN NOT NULL ); -- Example data (Two tournaments, 4 teams, single elimination) @@ -81,30 +81,4 @@ INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 5, 5, 6, 2); -- 7 INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 5, 7, 8, 2); -- 8 INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 9, 10, 2); -- 9 -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 11, 12, 2); -- 10 - --- Players -INSERT INTO players (name, teamId) VALUES ('Player 1', 1); -INSERT INTO players (name, teamId) VALUES ('Player 2', 1); -INSERT INTO players (name, teamId) VALUES ('Player 3', 2); -INSERT INTO players (name, teamId) VALUES ('Player 4', 2); -INSERT INTO players (name, teamId) VALUES ('Player 5', 3); -INSERT INTO players (name, teamId) VALUES ('Player 6', 3); -INSERT INTO players (name, teamId) VALUES ('Player 7', 4); -INSERT INTO players (name, teamId) VALUES ('Player 8', 4); -INSERT INTO players (name, teamId) VALUES ('Player 9', 5); -INSERT INTO players (name, teamId) VALUES ('Player 10', 5); -INSERT INTO players (name, teamId) VALUES ('Player 11', 6); -INSERT INTO players (name, teamId) VALUES ('Player 12', 6); -INSERT INTO players (name, teamId) VALUES ('Player 13', 7); -INSERT INTO players (name, teamId) VALUES ('Player 14', 7); -INSERT INTO players (name, teamId) VALUES ('Player 15', 8); -INSERT INTO players (name, teamId) VALUES ('Player 16', 8); -INSERT INTO players (name, teamId) VALUES ('Player 17', 9); -INSERT INTO players (name, teamId) VALUES ('Player 18', 9); -INSERT INTO players (name, teamId) VALUES ('Player 19', 10); -INSERT INTO players (name, teamId) VALUES ('Player 20', 10); -INSERT INTO players (name, teamId) VALUES ('Player 21', 11); -INSERT INTO players (name, teamId) VALUES ('Player 22', 11); -INSERT INTO players (name, teamId) VALUES ('Player 23', 12); -INSERT INTO players (name, teamId) VALUES ('Player 24', 12); +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 11, 12, 2); -- 10 \ No newline at end of file diff --git a/src/server/tmdb.js b/src/server/tmdb.js index d83cb34..9578bc0 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -15,10 +15,16 @@ module.exports = { deleteTournament: deleteTournament, editTournament: editTournament, getTeamsByTournamentId: getTeamsByTournamentId, + getUsers: getUsers, + getUserByEmail: getUserByEmail, + createUserBlank: createUserBlank, + editUser: editUser, } const mysql = require("mysql"); +// #region Database setup + let db_config = { host: process.env.DB_HOST, user: process.env.DB_USER, @@ -55,6 +61,8 @@ function escapeString(str) { return str; } +// #endregion + // #region match // Returns the match of the exact given id. function getMatch(matchId) { @@ -426,3 +434,98 @@ async function assignFirstMatch(teamId, tournamentId) { } // #endregion + + +// #region users + +function getUsers () { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM users", (err, users) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve(users); + } + }); + }); +} + +function getUserByGoogleId(googleId) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM users WHERE googleId = ?", [escapeString(googleId)], (err, users) => { + if (err) { + console.log(err); + reject(err); + } else { + if (users.length == 0) { + reject("No such user exists"); + } + resolve(users[0]); + } + }); + }); +} + +function getUserByEmail(email) { + return new Promise(function(resolve, reject) { + connection.query("SELECT * FROM users WHERE email = ?", [escapeString(email)], (err, users) => { + if (err) { + console.log(err); + reject(err); + } else { + if (users.length == 0) { + reject("No such user exists"); + return; + } + resolve(users[0]); + } + }); + }); +} + +function createUserBlank(email) { + return new Promise(function(resolve, reject) { + //Check that the user doesn't already exist + getUserByEmail(email).then(user => { + reject("No such user exists"); + }).catch(err => { + if (err != "No such user exists") { + console.log(err); + reject(err); + return; + } + // Create a user, with only an email address + connection.query("INSERT INTO users (email, isManager) VALUES (?), FALSE", [escapeString(email)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + resolve({message: "User Created", userId: sets.insertId}); + } + }); + }); + }); +} + +function editUser(email, user) { + return new Promise(function(resolve, reject) { + connection.query("UPDATE users SET googleId = ?, name = ?, isManager = ? WHERE email = ?", [escapeString(user.googleId), escapeString(user.name), escapeString(user.isManager), escapeString(email)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + } else { + console.log(sets); + resolve("User updated"); + } + }); + }); +} + +function userIsManager(userId) { + getUser(userId) + .then(user => { return user.isManager; }) + .catch(err => { console.log(err); return false; }); +} + +// #endregion \ No newline at end of file From 63618245e24fcd2dfe395150bca277d228353293 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Fri, 22 Apr 2022 19:32:25 +0200 Subject: [PATCH 35/55] User system expanded --- src/server/index.js | 61 ++++++++++++++++++++++++++++---- src/server/management/initDB.sql | 2 +- src/server/tmdb.js | 3 +- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index a379581..2dd8fa5 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -17,8 +17,13 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(session({ resave: true, - saveUninitialized: true, - secret: 'ASURASECRET' + saveUninitialized: false, + secret: process.env.COOKIE_SECRET, + rolling: true, + cookie: { + secure: process.env.COOKIE_SECURE, + maxAge: 60 * 60 * 1000 // 1 hour (in milliseconds) + } })); let api = express.Router(); app.use("/api", api); @@ -76,19 +81,43 @@ passport.use(new GoogleStrategy({ )); app.get('/auth/google', - passport.authenticate('google', { scope : ['profile', 'email'] })); + passport.authenticate('google', { scope : ['profile', 'email'] +})); app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/error' }), async function(req, res) { // Get user profile from passport let user = { - id: req.user.id, + googleId: req.user.id, + asuraId: null, name: req.user.displayName, - email: req.user.emails[0].value + email: req.user.emails[0].value, + imgurl: req.user.photos[0].value } - req.session.user = user; - res.json(user); + + // Check if user exists in database + tmdb.getUserByEmail(user.email) + .then(dbUser => { + user.asuraId = dbUser.id; + if (!dbUser.googleId) { + // User is "preregistered" with email only, so complete the registration + user.isManager = false; + tmdb.editUser(user.email, user) + .then(() => { user.asuraId = dbUser.id}) + .catch(err => console.log(err)); + } else { + user = dbUser; + } + + req.session.user = user; + res.json({"status": "OK", "data": user}); + }) + .catch(err => { + // User is neither registered nor preregistered + res.json({"status": "error", message: "Email is not in administrator list."}); + return + }); } ); @@ -369,6 +398,17 @@ api.get("/users/getSessionUser", (req, res) => { } }); +api.get("/users/getSavedUser", (req, res) => { + if (!req.session.user) { + res.json({"status": "error", "data": "No user logged in"}); + return + } + let googleId = req.session.user.googleId; + tmdb.getUserByGoogleId(googleId) + .then(user => res.json({"status": "OK", "data": user})) + .catch(err => res.json({"status": "error", "data": err})); +}); + api.get("/users/getUsers", (req, res) => { tmdb.getUsers() .then(users => res.json({"status": "OK", "data": users})) @@ -403,4 +443,11 @@ api.post("/users/edit", (req, res) => { }); + +api.get("/dumpsession", (req, res) => { + let out = {}; + out.session = req.session; + out.header = req.headers; + res.json(out); +}); // #endregion \ No newline at end of file diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index deeaf60..a3b5beb 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -40,7 +40,7 @@ CREATE TABLE matches ( CREATE TABLE users ( id INTEGER PRIMARY KEY AUTO_INCREMENT, - googleId INTEGER, + googleId TEXT, name TEXT, email TEXT NOT NULL, isManager BOOLEAN NOT NULL diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 9578bc0..9dc0bc7 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -17,6 +17,7 @@ module.exports = { getTeamsByTournamentId: getTeamsByTournamentId, getUsers: getUsers, getUserByEmail: getUserByEmail, + getUserByGoogleId: getUserByGoogleId, createUserBlank: createUserBlank, editUser: editUser, } @@ -496,7 +497,7 @@ function createUserBlank(email) { return; } // Create a user, with only an email address - connection.query("INSERT INTO users (email, isManager) VALUES (?), FALSE", [escapeString(email)], (err, sets) => { + connection.query("INSERT INTO users (email, isManager) VALUES (?, FALSE)", [escapeString(email)], (err, sets) => { if (err) { console.log(err); reject(err); From 2793e591e6bc21d7d2a51d4d123c63946e40bdc2 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Fri, 22 Apr 2022 22:26:07 +0200 Subject: [PATCH 36/55] Finish session / cookie setup --- src/server/index.js | 99 ++++++++++++++++++++++++++++++++++++--------- src/server/tmdb.js | 5 +++ 2 files changed, 85 insertions(+), 19 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 2dd8fa5..96e35e1 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -21,7 +21,8 @@ app.use(session({ secret: process.env.COOKIE_SECRET, rolling: true, cookie: { - secure: process.env.COOKIE_SECURE, + secure: (process.env.COOKIE_SECRET == "true"), // All env vars are strings, so cast bool manually + sameSite: 'strict', // Browsers will reject a "secure" cookie without this maxAge: 60 * 60 * 1000 // 1 hour (in milliseconds) } })); @@ -52,6 +53,7 @@ app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))) // #region PASSPORT / OAUTH const passport = require('passport'); +const { getUserByEmail } = require("./tmdb.js"); var userProfile; app.use(passport.initialize()); @@ -88,35 +90,39 @@ app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/error' }), async function(req, res) { // Get user profile from passport + // This is retrieved from the callback url data ?code=... let user = { googleId: req.user.id, - asuraId: null, name: req.user.displayName, email: req.user.emails[0].value, - imgurl: req.user.photos[0].value + imgurl: req.user.photos[0].value, + asuraId: null, } // Check if user exists in database tmdb.getUserByEmail(user.email) .then(dbUser => { - user.asuraId = dbUser.id; - if (!dbUser.googleId) { - // User is "preregistered" with email only, so complete the registration - user.isManager = false; - tmdb.editUser(user.email, user) - .then(() => { user.asuraId = dbUser.id}) - .catch(err => console.log(err)); + user.asuraId = dbUser.id; // asuraId is the database id / primary key + if (dbUser.googleId) { + // User is already registered with google, simply log them in + req.session.user = dbUser; } else { - user = dbUser; + // User is "preregistered" with email only, so complete the registration + // This step will register the name, img and googleId + user.isManager = false; + tmdb.editUser(user.email, user).catch(err => console.log(err)); + + req.session.user = user; } - req.session.user = user; res.json({"status": "OK", "data": user}); + return; }) .catch(err => { - // User is neither registered nor preregistered + // User is not in the database at all, do not give them a session. + res.session.user = null; res.json({"status": "error", message: "Email is not in administrator list."}); - return + return; }); } ); @@ -330,7 +336,11 @@ api.post("/team/:teamId/edit", (req, res) => { // #endregion //Takes JSON body -api.post("/tournament/create", (req, res) => { +api.post("/tournament/create", async (req, res) => { + if (!(await isManager(req.session))) { + res.json({"status": "error", "data": "Not authorized"}); + return + } //Check that req body is valid if (req.body.name == undefined || req.body.name == "") { res.json({"status": "error", "data": "No data supplied"}); @@ -390,6 +400,33 @@ api.post("/tournament/create", (req, res) => { // #region users +function isLoggedIn(session) { + return new Promise((resolve, reject) => { + if (session.user == undefined || session.user.googleId == undefined) { + return resolve(false); + } + let googleId = session.user.googleId; + + tmdb.getUserByGoogleId(googleId) + .then(user => {return resolve(user != undefined) }) + .catch(err => {resolve(false) }); + }); +} + + +function isManager(session) { + return new Promise((resolve, reject) => { + if (session.user == undefined || session.user.googleId == undefined) { + return resolve(false); + } + let googleId = session.user.googleId; + tmdb.getUserByGoogleId(googleId) + .then(user => {return resolve(user.isManager) }) + .catch(err => {resolve(false) }); + }); +} + + api.get("/users/getSessionUser", (req, res) => { if (req.session.user) { res.json({"status": "OK", "data": req.session.user}); @@ -415,8 +452,12 @@ api.get("/users/getUsers", (req, res) => { .catch(err => res.json({"status": "error", "data": err})); }); -api.post("/users/createBlank", (req, res) => { - let email = req.body.newUserEmail; +api.post("/users/createBlank", async (req, res) => { + if (!(await isManager(req.session))) { + res.json({"status": "error", "data": "Not authorized"}); + return + } + let email = req.body.email; // Check if the user already exists tmdb.getUserByEmail(email) .then(user => { @@ -439,15 +480,35 @@ api.post("/users/createBlank", (req, res) => { }); }); -api.post("/users/edit", (req, res) => { +api.post("/users/changeManagerStatus", async (req, res) => { + if (!await isManager(req.session)) { + res.json({"status": "error", "data": "Not authorized"}); + return + } + let emailAddress = req.body.emailAddress; + let isManager = req.body.isManager; + + tmdb.getUserByEmail(emailAddress) + .then(user => { + tmdb.changeManagerStatus(user.id, isManager) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); + }) + .catch(err => { + console.log(err); + res.json({"status": "error", "data": "Could not update the specified user"}); + }); }); -api.get("/dumpsession", (req, res) => { +api.get("/dumpsession", async (req, res) => { let out = {}; out.session = req.session; out.header = req.headers; + out.isLoggedIn = await isLoggedIn(req.session); + out.isManager = await isManager(req.session); + console.log(out); res.json(out); }); // #endregion \ No newline at end of file diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 9dc0bc7..59ca863 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -446,6 +446,9 @@ function getUsers () { console.log(err); reject(err); } else { + users.forEach((user, index) => { + this[index].isManager = (this[index].isManager == 1); + }); resolve(users); } }); @@ -462,6 +465,7 @@ function getUserByGoogleId(googleId) { if (users.length == 0) { reject("No such user exists"); } + users[0].isManager = users[0].isManager == 1; resolve(users[0]); } }); @@ -479,6 +483,7 @@ function getUserByEmail(email) { reject("No such user exists"); return; } + users[0].isManager = users[0].isManager == 1; resolve(users[0]); } }); From 61e4193455f10bee8924515591118311dfd5ef2e Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 08:36:21 +0200 Subject: [PATCH 37/55] Fix bug in getUsers --- src/server/tmdb.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 59ca863..885ee94 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -441,13 +441,16 @@ async function assignFirstMatch(teamId, tournamentId) { function getUsers () { return new Promise(function(resolve, reject) { - connection.query("SELECT * FROM users", (err, users) => { + connection.query("SELECT * FROM users", (err, userRows) => { if (err) { console.log(err); reject(err); } else { - users.forEach((user, index) => { - this[index].isManager = (this[index].isManager == 1); + let users = []; + userRows.forEach((userRow, index) => { + let user = results=JSON.parse(JSON.stringify(userRow)) + user.isManager = user.isManager == 1; + users.push(user); }); resolve(users); } From 9f58f902b8977cf3ce2c94b73b3dd54d0b82085a Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 11:46:39 +0200 Subject: [PATCH 38/55] Added unsetContestantAndWinner --- src/server/index.js | 19 +++++++++++++++++++ src/server/tmdb.js | 24 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/server/index.js b/src/server/index.js index 96e35e1..9edcb27 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -282,6 +282,25 @@ api.post("/match/:matchId/setWinner", (req, res) => { .then(match => res.send({"status": "OK", "data": match})) .catch(err => res.send({"status": "error", "data": err})); }); + +api.post("/match/:matchId/unsetContestant", (req, res) => { + let matchId = req.params.matchId; + let contestantId = req.body.teamId; + if (isNaN(matchId)) { + res.json({"status": "error", "data": "matchId must be a number"}); + return + } + if (contestantId == undefined || isNaN(contestantId)) { + res.json({"status": "error", "data": "contestantId must be a number"}); + return + } + + matchId = parseInt(matchId); + contestantId = parseInt(contestantId); + tmdb.unsetContestantAndWinner(matchId, contestantId) + .then(match => res.send({"status": "OK", "data": match})) + .catch(err => res.send({"status": "error", "data": err})); +}); // #endregion // #region team/:teamId diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 885ee94..314db47 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -11,6 +11,7 @@ module.exports = { deleteTeam: deleteTeam, getMatch: getMatch, setMatchWinner: setMatchWinner, + unsetContestantAndWinner: unsetContestantAndWinner, createTournament: createTournament, deleteTournament: deleteTournament, editTournament: editTournament, @@ -161,6 +162,29 @@ async function setMatchWinner(matchId, winnerId) { }); } +async function unsetContestantAndWinner(matchId, teamId) { + let match = await getMatch(matchId); + return new Promise(function(resolve, reject) { + unsetContestant(matchId, teamId) + .then(() => { + // Find what the child match that supplied the team + connection.query("SELECT * FROM matches WHERE parentMatchId = ? AND winnerId = ?", [matchId, teamId], (err, childMatches) => { + if (err) { console.log(err); reject(err); } + if (childMatches.length != 1) { + reject("Error: Could not find the correct child match"); + return; + } + let childMatch = childMatches[0]; + // Remove the winner from the child match + setMatchWinner(childMatch.id, null) + .then(() => { resolve(); }) + .catch(err => { reject(err); }); + }); + }) + .catch(err => { reject(err); }); + }); +} + // #endregion // #region tournament From eb70ef67b58dde047fbd8ef2511ae7f2e770e437 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 11:53:50 +0200 Subject: [PATCH 39/55] Minor bugfix --- src/server/tmdb.js | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 314db47..842ddeb 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -165,23 +165,19 @@ async function setMatchWinner(matchId, winnerId) { async function unsetContestantAndWinner(matchId, teamId) { let match = await getMatch(matchId); return new Promise(function(resolve, reject) { - unsetContestant(matchId, teamId) - .then(() => { - // Find what the child match that supplied the team - connection.query("SELECT * FROM matches WHERE parentMatchId = ? AND winnerId = ?", [matchId, teamId], (err, childMatches) => { - if (err) { console.log(err); reject(err); } - if (childMatches.length != 1) { - reject("Error: Could not find the correct child match"); - return; - } - let childMatch = childMatches[0]; - // Remove the winner from the child match - setMatchWinner(childMatch.id, null) - .then(() => { resolve(); }) - .catch(err => { reject(err); }); - }); - }) - .catch(err => { reject(err); }); + // Find what the child match that supplied the team + connection.query("SELECT * FROM matches WHERE parentMatchId = ? AND winnerId = ?", [matchId, teamId], (err, childMatches) => { + if (err) { console.log(err); reject(err); } + if (childMatches.length != 1) { + reject("Error: Could not find the correct child match"); + return; + } + let childMatch = childMatches[0]; + // Remove the winner from the child match + setMatchWinner(childMatch.id, null) + .then(() => { resolve(); }) + .catch(err => { reject(err); }); + }); }); } From cd83a4944a8010c62c6f7488d25ad613f4c04a3d Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 12:42:29 +0200 Subject: [PATCH 40/55] Removed excess logging, allowed tournament create --- src/server/index.js | 8 ++++---- src/server/tmdb.js | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 9edcb27..7a23223 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -356,10 +356,10 @@ api.post("/team/:teamId/edit", (req, res) => { //Takes JSON body api.post("/tournament/create", async (req, res) => { - if (!(await isManager(req.session))) { - res.json({"status": "error", "data": "Not authorized"}); - return - } + // if (!(await isManager(req.session))) { + // res.json({"status": "error", "data": "Not authorized"}); + // return + // } //Check that req body is valid if (req.body.name == undefined || req.body.name == "") { res.json({"status": "error", "data": "No data supplied"}); diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 842ddeb..bdd3423 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -420,14 +420,11 @@ async function assignFirstMatch(teamId, tournamentId) { let matches = await getMatchesByTournamentId(tournamentId); let highTier = Math.log2(tournament.teamLimit)-1; - console.log(highTier); let highTierMatches = matches.filter(match => match.tier == highTier); - console.log(matches); return new Promise(function(resolve, reject) { for (let match of highTierMatches) { if (match.team1Id == null) { - console.log("Assigning team " + teamId + " to match " + match.id + " as team 1"); connection.query("UPDATE matches SET team1Id = ? WHERE id = ?", [escapeString(teamId), escapeString(match.id)], (err, sets) => { if (err) { console.log(err); @@ -438,7 +435,6 @@ async function assignFirstMatch(teamId, tournamentId) { }); return } else if (match.team2Id == null) { - console.log("Assigning team " + teamId + " to match " + match.id + " as team 2"); connection.query("UPDATE matches SET team2Id = ? WHERE id = ?", [escapeString(teamId), escapeString(match.id)], (err, sets) => { if (err) { console.log(err); From 8c6b5e83261acce2830e0697be9a9b97f645f2b8 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 13:08:03 +0200 Subject: [PATCH 41/55] Added prize field --- src/server/index.js | 6 ++++-- src/server/management/initDB.sql | 1 + src/server/tmdb.js | 12 ++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 7a23223..2c75a10 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -183,6 +183,7 @@ api.post("/tournament/:tournamentId/edit", (req, res) => { tournamentId = parseInt(tournamentId); let name = req.body.name; let description = req.body.description; + let prize = req.body.prize; let startDate = req.body.startDate; let endDate = req.body.endDate; console.log(startDate); @@ -211,7 +212,7 @@ api.post("/tournament/:tournamentId/edit", (req, res) => { return } - tmdb.editTournament(tournamentId, name, description, startDate, endDate) + tmdb.editTournament(tournamentId, name, description, prize, startDate, endDate) .then(msg => res.json({"status": "OK", "data": msg})) .catch(err => res.json({"status": "error", "data": err})); @@ -370,6 +371,7 @@ api.post("/tournament/create", async (req, res) => { console.log(req.get("Content-Type")); let name = req.body.name; let description = req.body.description; + let prize = req.body.prize; let teamLimit = req.body.teamLimit; let startDate = req.body.startDate; //TODO: timezones, 2 hr skips let endDate = req.body.endDate; @@ -410,7 +412,7 @@ api.post("/tournament/create", async (req, res) => { } console.log(startDate); - tmdb.createTournament(name, description, startDate, endDate, teamLimit) + tmdb.createTournament(name, description, prize, startDate, endDate, teamLimit) .then(msg => res.json({"status": "OK", "data": msg})) .catch(err => res.json({"status": "error", "data": err})); }); diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index a3b5beb..0aa0eef 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -10,6 +10,7 @@ CREATE TABLE tournaments ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name TEXT NOT NULL, description TEXT, + prize TEXT, teamLimit INTEGER NOT NULL, startTime DATETIME NOT NULL, endTime DATETIME NOT NULL diff --git a/src/server/tmdb.js b/src/server/tmdb.js index bdd3423..d725350 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -274,12 +274,12 @@ function createMatch(tournamentId, parentMatchId, tier) { }); } -function createTournament(name, description, startDate, endDate, teamLimit) { +function createTournament(name, description, prize, startDate, endDate, teamLimit) { startDate = startDate.toISOString().slice(0, 19).replace('T', ' '); endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); return new Promise(function(resolve, reject) { - connection.query("INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES (?, ?, ?, ?, ?)", - [escapeString(name), escapeString(description), startDate, endDate, teamLimit], async (err, sets) => { + connection.query("INSERT INTO tournaments (name, description, prize, startTime, endTime, teamLimit) VALUES (?, ?, ?, ?, ?, ?)", + [escapeString(name), escapeString(description), escapeString(prize), startDate, endDate, teamLimit], async (err, sets) => { if (err) { console.log(err); reject(err); @@ -307,12 +307,12 @@ function createTournament(name, description, startDate, endDate, teamLimit) { }); } -function editTournament(tournamentId, name, description, startDate, endDate) { +function editTournament(tournamentId, name, description, prize, startDate, endDate) { startDate = startDate.toISOString().slice(0, 19).replace('T', ' '); endDate = endDate.toISOString().slice(0, 19).replace('T', ' '); return new Promise(function(resolve, reject) { - connection.query("UPDATE tournaments SET name = ?, description = ?, startTime = ?, endTime = ? WHERE id = ?", - [escapeString(name), escapeString(description), startDate, endDate, escapeString(tournamentId)], (err, sets) => { + connection.query("UPDATE tournaments SET name = ?, description = ?, prize = ?, startTime = ?, endTime = ? WHERE id = ?", + [escapeString(name), escapeString(description), escapeString(prize), startDate, endDate, escapeString(tournamentId)], (err, sets) => { if (err) { console.log(err); reject(err); From cf303eb6c9b200d4f1a10f0c365c860d53c150e5 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 13:39:24 +0200 Subject: [PATCH 42/55] cookie-related typos --- src/server/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 2c75a10..94eed5e 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -21,7 +21,7 @@ app.use(session({ secret: process.env.COOKIE_SECRET, rolling: true, cookie: { - secure: (process.env.COOKIE_SECRET == "true"), // All env vars are strings, so cast bool manually + secure: (process.env.COOKIE_SECURE == "true"), // All env vars are strings, so cast bool manually sameSite: 'strict', // Browsers will reject a "secure" cookie without this maxAge: 60 * 60 * 1000 // 1 hour (in milliseconds) } @@ -120,7 +120,6 @@ app.get('/auth/google/callback', }) .catch(err => { // User is not in the database at all, do not give them a session. - res.session.user = null; res.json({"status": "error", message: "Email is not in administrator list."}); return; }); From 8f78f3672e1d33fcc0da5c39210f753590f1e360 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 14:02:01 +0200 Subject: [PATCH 43/55] cookie fix --- src/server/index.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 94eed5e..ac3ee7f 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -45,6 +45,9 @@ app.use(require('express-log-url')); // Serve static files from the React app app.use('/', express.static(path.join(__dirname, 'clientbuild'))); app.use('/login', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +app.use('/history', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +app.use('/admins', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); +app.use('/profile', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); app.use('/tournament/*', express.static(path.join(__dirname, 'clientbuild', 'index.html'))); app.use('/static', express.static(path.join(__dirname, 'clientbuild/static'))); app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))); @@ -83,8 +86,8 @@ passport.use(new GoogleStrategy({ )); app.get('/auth/google', - passport.authenticate('google', { scope : ['profile', 'email'] -})); + passport.authenticate('google', { scope : ['profile', 'email']}) +); app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/error' }), @@ -531,4 +534,4 @@ api.get("/dumpsession", async (req, res) => { console.log(out); res.json(out); }); -// #endregion \ No newline at end of file +// #endregion From 52514e9e68122fa3e878fb3f2d200d449ff81ad5 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 14:51:58 +0200 Subject: [PATCH 44/55] Renamed id to asuraId --- src/server/tmdb.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index d725350..55e6087 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -466,6 +466,8 @@ function getUsers () { userRows.forEach((userRow, index) => { let user = results=JSON.parse(JSON.stringify(userRow)) user.isManager = user.isManager == 1; + user.asuraId = user.id; + user.id = undefined; users.push(user); }); resolve(users); @@ -485,6 +487,8 @@ function getUserByGoogleId(googleId) { reject("No such user exists"); } users[0].isManager = users[0].isManager == 1; + users[0].asuraId = users[0].id; + users[0].id = undefined; resolve(users[0]); } }); @@ -503,6 +507,8 @@ function getUserByEmail(email) { return; } users[0].isManager = users[0].isManager == 1; + users[0].asuraId = users[0].id; + users[0].id = undefined; resolve(users[0]); } }); From cec7fafa62f11ceea87d98920d912d224ed3232d Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sat, 23 Apr 2022 15:33:26 +0200 Subject: [PATCH 45/55] Update login redirect --- src/server/index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index ac3ee7f..3ec56f0 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -62,9 +62,6 @@ var userProfile; app.use(passport.initialize()); app.use(passport.session()); -app.get('/success', (req, res) => res.send(userProfile)); -// app.get('/error', (req, res) => res.send("error logging in")); - passport.serializeUser(function(user, cb) { cb(null, user); }); @@ -118,7 +115,7 @@ app.get('/auth/google/callback', req.session.user = user; } - res.json({"status": "OK", "data": user}); + res.redirect('/'); return; }) .catch(err => { @@ -449,6 +446,10 @@ function isManager(session) { }); } +api.get("/logout", (req, res) => { + req.session.destroy(); + res.redirect("/"); +}); api.get("/users/getSessionUser", (req, res) => { if (req.session.user) { From db13a49ba9c6e82136bf1ffc1bbbfe233618eb2f Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 24 Apr 2022 13:23:41 +0200 Subject: [PATCH 46/55] Fix ChangeManagerStatus --- src/server/index.js | 3 +-- src/server/tmdb.js | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 3ec56f0..b36df84 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -109,13 +109,12 @@ app.get('/auth/google/callback', } else { // User is "preregistered" with email only, so complete the registration // This step will register the name, img and googleId - user.isManager = false; tmdb.editUser(user.email, user).catch(err => console.log(err)); req.session.user = user; } - res.redirect('/'); + res.redirect(process.env.AUTH_SUCCESS_REDIRECT); return; }) .catch(err => { diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 55e6087..c825d1c 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -541,6 +541,9 @@ function createUserBlank(email) { function editUser(email, user) { return new Promise(function(resolve, reject) { + if (!user.isManager) { // If isManager is not defined (or false) + user.isManager = false; + } connection.query("UPDATE users SET googleId = ?, name = ?, isManager = ? WHERE email = ?", [escapeString(user.googleId), escapeString(user.name), escapeString(user.isManager), escapeString(email)], (err, sets) => { if (err) { console.log(err); From a042a592762dfa41449693776a4bf19a96f4a50d Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 24 Apr 2022 13:41:55 +0200 Subject: [PATCH 47/55] Clean isManager --- src/server/index.js | 2 +- src/server/tmdb.js | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index b36df84..b8ccb1f 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -504,7 +504,7 @@ api.post("/users/createBlank", async (req, res) => { }); api.post("/users/changeManagerStatus", async (req, res) => { - if (!await isManager(req.session)) { + if (!(await isManager(req.session))) { res.json({"status": "error", "data": "Not authorized"}); return } diff --git a/src/server/tmdb.js b/src/server/tmdb.js index c825d1c..93b71e5 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -556,10 +556,4 @@ function editUser(email, user) { }); } -function userIsManager(userId) { - getUser(userId) - .then(user => { return user.isManager; }) - .catch(err => { console.log(err); return false; }); -} - // #endregion \ No newline at end of file From 42123fb41a136860c967b69a8542e6a96e869eea Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 24 Apr 2022 13:48:10 +0200 Subject: [PATCH 48/55] Ignore isManager, implement deleteUser --- src/server/index.js | 19 +++++++++++++++++++ src/server/tmdb.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/server/index.js b/src/server/index.js index b8ccb1f..1edd442 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -524,6 +524,25 @@ api.post("/users/changeManagerStatus", async (req, res) => { }); }); +api.post("/deleteUser", async (req, res) => { + if (!(await isManager(req.session))) { + res.json({"status": "error", "data": "Not authorized"}); + return + } + let emailAddress = req.body.emailAddress; + + tmdb.getUserByEmail(emailAddress) + .then(user => { + tmdb.deleteUser(user.id) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); + }) + .catch(err => { + console.log(err); + res.json({"status": "error", "data": "Could not update the specified user"}); + }); +}); + api.get("/dumpsession", async (req, res) => { let out = {}; diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 93b71e5..3c5ad17 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -20,6 +20,8 @@ module.exports = { getUserByEmail: getUserByEmail, getUserByGoogleId: getUserByGoogleId, createUserBlank: createUserBlank, + changeManagerStatus: changeManagerStatus, + deleteUser, deleteUser, editUser: editUser, } @@ -556,4 +558,38 @@ function editUser(email, user) { }); } +function changeManagerStatus(userId, isManager) { + return new Promise(function(resolve, reject) { + connection.query("UPDATE users SET isManager = ? WHERE id = ?", [escapeString(isManager), escapeString(userId)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + return + } + if (sets.affectedRows == 0) { + reject("No such user exists"); + return + } + resolve("User updated"); + }); + }); +} + +function deleteUser(userId) { + return new Promise(function(resolve, reject) { + connection.query("DELETE FROM users WHERE id = ?", [escapeString(userId)], (err, sets) => { + if (err) { + console.log(err); + reject(err); + return; + } + if (sets.affectedRows == 0) { + reject("No such user exists"); + return; + } + resolve("User deleted"); + }); + }); +} + // #endregion \ No newline at end of file From d49fedf24f7d2e63ad72b1b8297e749579638304 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 24 Apr 2022 13:56:34 +0200 Subject: [PATCH 49/55] Rely on userId, not email address --- src/server/index.js | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 1edd442..a3a5052 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -56,7 +56,6 @@ app.use('/static/*', express.static(path.join(__dirname, 'clientbuild/static'))) // #region PASSPORT / OAUTH const passport = require('passport'); -const { getUserByEmail } = require("./tmdb.js"); var userProfile; app.use(passport.initialize()); @@ -503,44 +502,31 @@ api.post("/users/createBlank", async (req, res) => { }); }); -api.post("/users/changeManagerStatus", async (req, res) => { +api.post("/users/:asuraId/changeManagerStatus", async (req, res) => { if (!(await isManager(req.session))) { res.json({"status": "error", "data": "Not authorized"}); return } - let emailAddress = req.body.emailAddress; + let asuraId = req.params.asuraId; let isManager = req.body.isManager; + console.log(asuraId, isManager); + tmdb.changeManagerStatus(asuraId, isManager) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); - tmdb.getUserByEmail(emailAddress) - .then(user => { - tmdb.changeManagerStatus(user.id, isManager) - .then(msg => res.json({"status": "OK", "data": msg})) - .catch(err => res.json({"status": "error", "data": err})); - }) - .catch(err => { - console.log(err); - res.json({"status": "error", "data": "Could not update the specified user"}); - }); }); -api.post("/deleteUser", async (req, res) => { +api.delete("/users/:asuraId", async (req, res) => { if (!(await isManager(req.session))) { res.json({"status": "error", "data": "Not authorized"}); return } - let emailAddress = req.body.emailAddress; + let asuraId = req.params.asuraId; - tmdb.getUserByEmail(emailAddress) - .then(user => { - tmdb.deleteUser(user.id) - .then(msg => res.json({"status": "OK", "data": msg})) - .catch(err => res.json({"status": "error", "data": err})); - }) - .catch(err => { - console.log(err); - res.json({"status": "error", "data": "Could not update the specified user"}); - }); + tmdb.deleteUser(asuraId) + .then(msg => res.json({"status": "OK", "data": msg})) + .catch(err => res.json({"status": "error", "data": err})); }); From 2affa579f7820cbe8645b311a568f251fb5681c5 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 24 Apr 2022 14:39:13 +0200 Subject: [PATCH 50/55] Set permissions on all endpoints --- src/server/index.js | 113 ++++++++++++++++++++++++++++++-------------- src/server/tmdb.js | 3 +- 2 files changed, 79 insertions(+), 37 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index a3a5052..a1b4fab 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -171,7 +171,12 @@ api.get("/tournament/:tournamentId/getTeams", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -api.post("/tournament/:tournamentId/edit", (req, res) => { +api.post("/tournament/:tournamentId/edit", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { res.json({"status": "error", "data": "tournamentId must be a number"}); @@ -215,7 +220,12 @@ api.post("/tournament/:tournamentId/edit", (req, res) => { }); -api.post("/tournament/:tournamentId/createTeam", (req, res) => { +api.post("/tournament/:tournamentId/createTeam", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { res.json({"status": "error", "data": "tournamentId must be a number"}); @@ -233,7 +243,12 @@ api.post("/tournament/:tournamentId/createTeam", (req, res) => { .catch(err => res.json({"status": "error", "data": err})); }); -api.delete("/tournament/:tournamentId", (req, res) => { +api.delete("/tournament/:tournamentId", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { res.json({"status": "error", "data": "tournamentId must be a number"}); @@ -262,7 +277,12 @@ api.get("/match/:matchId", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -api.post("/match/:matchId/setWinner", (req, res) => { +api.post("/match/:matchId/setWinner", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let matchId = req.params.matchId; let winnerId = req.body.winnerId; if (isNaN(matchId)) { @@ -281,7 +301,12 @@ api.post("/match/:matchId/setWinner", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -api.post("/match/:matchId/unsetContestant", (req, res) => { +api.post("/match/:matchId/unsetContestant", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let matchId = req.params.matchId; let contestantId = req.body.teamId; if (isNaN(matchId)) { @@ -314,7 +339,12 @@ api.get("/team/:teamId", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -api.delete("/team/:teamId", (req, res) => { +api.delete("/team/:teamId", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let teamId = req.params.teamId; if (isNaN(teamId)) { res.json({"status": "error", "data": "teamId must be a number"}); @@ -331,7 +361,12 @@ api.delete("/team/:teamId", (req, res) => { .catch(err => res.send({"status": "error", "data": err})); }); -api.post("/team/:teamId/edit", (req, res) => { +api.post("/team/:teamId/edit", async (req, res) => { + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + let teamId = req.params.teamId; let teamName = req.body.name; console.log(req.body); @@ -354,10 +389,11 @@ api.post("/team/:teamId/edit", (req, res) => { //Takes JSON body api.post("/tournament/create", async (req, res) => { - // if (!(await isManager(req.session))) { - // res.json({"status": "error", "data": "Not authorized"}); - // return - // } + if (!(await isSessionLoggedIn(req.session))) { + res.json({"status": "error", "data": "User is not logged in"}); + return + } + //Check that req body is valid if (req.body.name == undefined || req.body.name == "") { res.json({"status": "error", "data": "No data supplied"}); @@ -418,7 +454,7 @@ api.post("/tournament/create", async (req, res) => { // #region users -function isLoggedIn(session) { +function isSessionLoggedIn(session) { return new Promise((resolve, reject) => { if (session.user == undefined || session.user.googleId == undefined) { return resolve(false); @@ -432,7 +468,7 @@ function isLoggedIn(session) { } -function isManager(session) { +function isSessionManager(session) { return new Promise((resolve, reject) => { if (session.user == undefined || session.user.googleId == undefined) { return resolve(false); @@ -449,14 +485,6 @@ api.get("/logout", (req, res) => { res.redirect("/"); }); -api.get("/users/getSessionUser", (req, res) => { - if (req.session.user) { - res.json({"status": "OK", "data": req.session.user}); - } else { - res.json({"status": "error", "data": "No user logged in"}); - } -}); - api.get("/users/getSavedUser", (req, res) => { if (!req.session.user) { res.json({"status": "error", "data": "No user logged in"}); @@ -468,14 +496,19 @@ api.get("/users/getSavedUser", (req, res) => { .catch(err => res.json({"status": "error", "data": err})); }); -api.get("/users/getUsers", (req, res) => { +api.get("/users/getUsers", async (req, res) => { + if (!(await isSessionManager(req.session))) { + res.json({"status": "error", "data": "Not authorized"}); + return + } + tmdb.getUsers() .then(users => res.json({"status": "OK", "data": users})) .catch(err => res.json({"status": "error", "data": err})); }); api.post("/users/createBlank", async (req, res) => { - if (!(await isManager(req.session))) { + if (!(await isSessionManager(req.session))) { res.json({"status": "error", "data": "Not authorized"}); return } @@ -503,14 +536,13 @@ api.post("/users/createBlank", async (req, res) => { }); api.post("/users/:asuraId/changeManagerStatus", async (req, res) => { - if (!(await isManager(req.session))) { + if (!(await isSessionManager(req.session))) { res.json({"status": "error", "data": "Not authorized"}); return } + let asuraId = req.params.asuraId; let isManager = req.body.isManager; - console.log(asuraId, isManager); - tmdb.changeManagerStatus(asuraId, isManager) .then(msg => res.json({"status": "OK", "data": msg})) .catch(err => res.json({"status": "error", "data": err})); @@ -518,7 +550,7 @@ api.post("/users/:asuraId/changeManagerStatus", async (req, res) => { }); api.delete("/users/:asuraId", async (req, res) => { - if (!(await isManager(req.session))) { + if (!(await isSessionManager(req.session))) { res.json({"status": "error", "data": "Not authorized"}); return } @@ -530,13 +562,22 @@ api.delete("/users/:asuraId", async (req, res) => { }); -api.get("/dumpsession", async (req, res) => { - let out = {}; - out.session = req.session; - out.header = req.headers; - out.isLoggedIn = await isLoggedIn(req.session); - out.isManager = await isManager(req.session); - console.log(out); - res.json(out); -}); +// Debugging functions, disabled on purpouse +// api.get("/users/getSessionUser", (req, res) => { +// if (req.session.user) { +// res.json({"status": "OK", "data": req.session.user}); +// } else { +// res.json({"status": "error", "data": "No user logged in"}); +// } +// }); + +// api.get("/dumpsession", async (req, res) => { +// let out = {}; +// out.session = req.session; +// out.header = req.headers; +// out.isLoggedIn = await isSessionLoggedIn(req.session); +// out.isManager = await isSessionManager(req.session); +// console.log(out); +// res.json(out); +// }); // #endregion diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 3c5ad17..3e08ebd 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -560,7 +560,8 @@ function editUser(email, user) { function changeManagerStatus(userId, isManager) { return new Promise(function(resolve, reject) { - connection.query("UPDATE users SET isManager = ? WHERE id = ?", [escapeString(isManager), escapeString(userId)], (err, sets) => { + let isManagerInt = (isManager === true || isManager === "true") ? 1 : 0; + connection.query("UPDATE users SET isManager = ? WHERE id = ?", [isManagerInt, escapeString(userId)], (err, sets) => { if (err) { console.log(err); reject(err); From ae143745abcbed6762b86fe28cbefa038ea16f2b Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 24 Apr 2022 19:00:38 +0200 Subject: [PATCH 51/55] Added debug mode --- src/server/index.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index a1b4fab..57579ed 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -9,8 +9,8 @@ let tmdb = require("./tmdb.js"); // #region Express setup const app = express(); -const port = 3001; -app.listen(port, () => { +const port = process.env.SERVER_PORT || 3000; +app.listen(parseInt(port), () => { console.log(`Listening on port ${port}`) }) app.use(express.json()); @@ -176,7 +176,7 @@ api.post("/tournament/:tournamentId/edit", async (req, res) => { res.json({"status": "error", "data": "User is not logged in"}); return } - + let tournamentId = req.params.tournamentId; if (isNaN(tournamentId)) { res.json({"status": "error", "data": "tournamentId must be a number"}); @@ -456,6 +456,8 @@ api.post("/tournament/create", async (req, res) => { function isSessionLoggedIn(session) { return new Promise((resolve, reject) => { + if (process.env.DEBUG_ALLOW_ALL === "true") { resolve(true); return; } + if (session.user == undefined || session.user.googleId == undefined) { return resolve(false); } @@ -470,6 +472,8 @@ function isSessionLoggedIn(session) { function isSessionManager(session) { return new Promise((resolve, reject) => { + if (process.env.DEBUG_ALLOW_ALL === "true") { resolve(true); return; } + if (session.user == undefined || session.user.googleId == undefined) { return resolve(false); } @@ -482,7 +486,7 @@ function isSessionManager(session) { api.get("/logout", (req, res) => { req.session.destroy(); - res.redirect("/"); + res.redirect(process.env.AUTH_SUCCESS_REDIRECT); }); api.get("/users/getSavedUser", (req, res) => { From bff4e8373011f1d107a5042956bd863352b1a884 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 25 Apr 2022 13:19:59 +0200 Subject: [PATCH 52/55] Fix logout redirect --- src/server/index.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/server/index.js b/src/server/index.js index 57579ed..ac16cd9 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -289,13 +289,18 @@ api.post("/match/:matchId/setWinner", async (req, res) => { res.json({"status": "error", "data": "matchId must be a number"}); return } - if (winnerId == undefined || isNaN(winnerId)) { + if (winnerId == undefined || (isNaN(winnerId) && winnerId != "null")) { res.json({"status": "error", "data": "winnerId must be a number"}); return } + matchId = parseInt(matchId); - winnerId = parseInt(winnerId); + if (winnerId == "null") { + winnerId = null; + } else { + winnerId = parseInt(winnerId); + } tmdb.setMatchWinner(matchId, winnerId) .then(match => res.send({"status": "OK", "data": match})) .catch(err => res.send({"status": "error", "data": err})); @@ -484,11 +489,6 @@ function isSessionManager(session) { }); } -api.get("/logout", (req, res) => { - req.session.destroy(); - res.redirect(process.env.AUTH_SUCCESS_REDIRECT); -}); - api.get("/users/getSavedUser", (req, res) => { if (!req.session.user) { res.json({"status": "error", "data": "No user logged in"}); @@ -565,6 +565,11 @@ api.delete("/users/:asuraId", async (req, res) => { .catch(err => res.json({"status": "error", "data": err})); }); +api.get("/users/logout", (req, res) => { + req.session.destroy(); + res.redirect(process.env.AUTH_SUCCESS_REDIRECT); +}); + // Debugging functions, disabled on purpouse // api.get("/users/getSessionUser", (req, res) => { From 01d280dba32da83488179531f1a4f31091ab0950 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 25 Apr 2022 13:53:33 +0200 Subject: [PATCH 53/55] Enable initial admin users --- src/server/management/initDB.sql | 11 ++++++++--- src/server/tmdb.js | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index 0aa0eef..d2b4ff6 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -48,8 +48,8 @@ CREATE TABLE users ( ); -- Example data (Two tournaments, 4 teams, single elimination) -INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '2022-06-01 16:00:00', '2022-06-01 20:00:00', 4); -INSERT INTO tournaments (name, description, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '2022-03-03 17:30:00', '2022-03-04 21:30:00', 8); +INSERT INTO tournaments (name, description, prize, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '300 000 points', '2022-04-29 16:00:00', '2022-04-29 20:00:00', 4); +INSERT INTO tournaments (name, description, prize, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '450 000 points', '2022-04-29 09:00:00', '2022-04-29 10:30:00', 8); INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 @@ -82,4 +82,9 @@ INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 5, 5, 6, 2); -- 7 INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 5, 7, 8, 2); -- 8 INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 9, 10, 2); -- 9 -INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 11, 12, 2); -- 10 \ No newline at end of file +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 11, 12, 2); -- 10 + +INSERT INTO users (email, isManager) VALUES ('felixalbrigtsen@gmail.com', 1); +INSERT INTO users (email, isManager) VALUES ('kriloneri@gmail.com', 1); +INSERT INTO users (email, isManager) VALUES ('limboblivion@gmail.com', 1); +INSERT INTO users (email, isManager) VALUES ('jonas.haugland98@gmail.com', 1); \ No newline at end of file diff --git a/src/server/tmdb.js b/src/server/tmdb.js index 3e08ebd..c44fd1f 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -543,7 +543,7 @@ function createUserBlank(email) { function editUser(email, user) { return new Promise(function(resolve, reject) { - if (!user.isManager) { // If isManager is not defined (or false) + if (user.isManager == undefined) { user.isManager = false; } connection.query("UPDATE users SET googleId = ?, name = ?, isManager = ? WHERE email = ?", [escapeString(user.googleId), escapeString(user.name), escapeString(user.isManager), escapeString(email)], (err, sets) => { From 814ddbf2cae522c96d6093d045cd5f9f9c26f710 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 25 Apr 2022 14:01:23 +0200 Subject: [PATCH 54/55] bugfix: delete logged in user --- src/server/tmdb.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/server/tmdb.js b/src/server/tmdb.js index c44fd1f..982e878 100644 --- a/src/server/tmdb.js +++ b/src/server/tmdb.js @@ -485,13 +485,17 @@ function getUserByGoogleId(googleId) { console.log(err); reject(err); } else { - if (users.length == 0) { + if (!users || users.length == 0) { + reject("No such user exists"); + } + try { + users[0].isManager = users[0].isManager == 1; + users[0].asuraId = users[0].id; + users[0].id = undefined; + resolve(users[0]); + } catch (e) { reject("No such user exists"); } - users[0].isManager = users[0].isManager == 1; - users[0].asuraId = users[0].id; - users[0].id = undefined; - resolve(users[0]); } }); }); From b8c395c4c61191f967c1a89160d9cc81d77e6262 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Mon, 25 Apr 2022 14:16:58 +0200 Subject: [PATCH 55/55] Fix initdb.sql --- src/server/management/initDB.sql | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/server/management/initDB.sql b/src/server/management/initDB.sql index d2b4ff6..53e7166 100644 --- a/src/server/management/initDB.sql +++ b/src/server/management/initDB.sql @@ -50,6 +50,7 @@ CREATE TABLE users ( -- Example data (Two tournaments, 4 teams, single elimination) INSERT INTO tournaments (name, description, prize, startTime, endTime, teamLimit) VALUES ('Tournament 1', 'First tournament, single elimination', '300 000 points', '2022-04-29 16:00:00', '2022-04-29 20:00:00', 4); INSERT INTO tournaments (name, description, prize, startTime, endTime, teamLimit) VALUES ('Tournament 2', 'Second tournament, four teams', '450 000 points', '2022-04-29 09:00:00', '2022-04-29 10:30:00', 8); +INSERT INTO tournaments (name, description, prize, startTime, endTime, teamLimit) VALUES ('Tournament 3', 'Previous tournament, it is done', '200 000 points', '2022-04-24 12:00:00', '2022-04-25 12:00:00', 4); INSERT INTO teams (tournamentId, name) VALUES (1, 'Fnatic'); -- 1 INSERT INTO teams (tournamentId, name) VALUES (1, 'Cloud 9'); -- 2 @@ -65,6 +66,12 @@ INSERT INTO teams (tournamentId, name) VALUES (2, 'Virtus.pro'); -- 10 INSERT INTO teams (tournamentId, name) VALUES (2, 'Natus Vincere'); -- 11 INSERT INTO teams (tournamentId, name) VALUES (2, 'FaZe'); -- 12 +INSERT INTO teams(tournamentId, name) VALUES (3, 'Fnatic'); -- 13 +INSERT INTO teams(tournamentId, name) VALUES (3, 'Cloud 9'); -- 14 +INSERT INTO teams(tournamentId, name) VALUES (3, 'Team Liquid'); -- 15 +INSERT INTO teams(tournamentId, name) VALUES (3, 'LDLC'); -- 16 + + -- tournament 1 -- -- Final match INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (1, NULL, NULL, NULL, 0); -- 1 @@ -84,6 +91,14 @@ INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 9, 10, 2); -- 9 INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier) VALUES (2, 6, 11, 12, 2); -- 10 +-- tournament 3 -- +-- Final match +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier, winnerId) VALUES (3, NULL, 14, 15, 0, 14); -- 11 +-- Semi-finals +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier, winnerId) VALUES (3, 11, 13, 14, 1, 14); -- 12 +INSERT INTO matches (tournamentId, parentMatchId, team1Id, team2Id, tier, winnerId) VALUES (3, 11, 15, 16, 1, 15); -- 13 + +-- Users INSERT INTO users (email, isManager) VALUES ('felixalbrigtsen@gmail.com', 1); INSERT INTO users (email, isManager) VALUES ('kriloneri@gmail.com', 1); INSERT INTO users (email, isManager) VALUES ('limboblivion@gmail.com', 1);