const express = require("express"); const router = express.Router(); const mongo = require("mongodb"); const MongoClient = mongo.MongoClient; const connectionUrl = process.env.MONGO_CONNECTION_STRING; const functions = require("./functions"); router.get("/round/:roundId", (req, res) => { // Connect to database MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } // Using the database gameWare and collection rounds const db = client.db("gameWare"); const collection = "rounds"; let id = undefined; try { id = mongo.ObjectID(req.params.roundId); // get roundId } catch (error) { res.status(404).send("No document with specified id was found"); return; } db.collection(collection) .findOne({ _id: id, }) .then((result) => { if (!result) { res.status(404).send("No document with specified id found"); return; } res.json(result); client.close(); }) .catch((err) => console.log(err)); } ); }); function updateHighscore(client, gameid, playerid, value) { return new Promise((resolve, reject) => { const db = client.db("gameWare"); const collection = "highscores"; db.collection(collection).updateOne( { gameId: mongo.ObjectID(gameid), playerId: mongo.ObjectID(playerid), }, { $max: { value: value } }, { upsert: true }, (err, result) => { if (err) { resolve(500); return; } resolve(result); } ); }); } router.get("/latestpoints/:tournamentId/:playerId", (req, res) => { // Connect to database MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } // Using the database gameWare and collection rounds const db = client.db("gameWare"); const collection = "rounds"; try { tournamentid = mongo.ObjectID(req.params.tournamentId); // get tournamentId playerid = mongo.ObjectID(req.params.playerId); // get playerId } catch (error) { res.status(404).send("Invalid IDs"); return; } db.collection(collection) .find({ tournamentId: tournamentid, playerId: playerid, tournamentPoints: { $gt: 0 }, }) .sort({ roundNr: -1 }) .limit(1) .project({ tournamentPoints: 1 }) .toArray((err, result) => { if (err) { res.sendStatus(500); //console.log(err); return; } res.json(result); client.close(); }); } ); }); router.get("/tournamentpoints/:tournamentId/:playerId", (req, res) => { // Connect to database MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } // Using the database gameWare and collection rounds const db = client.db("gameWare"); const collection = "rounds"; try { tournamentid = mongo.ObjectID(req.params.tournamentId); // get tournamentId playerid = mongo.ObjectID(req.params.playerId); // get playerId } catch (error) { res.status(404).send("Invalid IDs"); return; } db.collection(collection) .find({ tournamentId: tournamentid, playerId: playerid, }) .toArray((err, result) => { if (err) { res.sendStatus(500); //console.log(err); return; } let sum = 0; for (let i = 0; i < result.length; i++) { sum += result[i].tournamentPoints; } res.json({ tournamentPoints: sum }); client.close(); }); } ); }); router.get("/all/:tournamentId", (req, res) => { MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } const db = client.db("gameWare"); const collection = "rounds"; try { tournamentid = mongo.ObjectID(req.params.tournamentId); // get tournamentId } catch (error) { res.status(400).send("Invalid ID"); return; } if (tournamentid == null) { res.status(400).send("Missing fields"); return; } db.collection(collection) .find({ tournamentId: tournamentid, }) .sort({ roundNr: -1, }) .project({ playerId: 1, tournamentPoints: 1, }) .toArray((err, result) => { if (err) { res.sendStatus(500); //console.log(err); return; } let uniqueIds = []; let idobjects = []; let object = []; for (let i = 0; i < result.length; i++) { if (!uniqueIds.includes(String(result[i].playerId))) { uniqueIds.push(String(result[i].playerId)); idobjects.push(result[i].playerId); } } db.collection("players") .find({ _id: { $in: idobjects }, }) .project({ name: 1 }) .toArray((err, nameresult) => { if (err) { res.sendStatus(500); //console.log(err); return; } for (let i = 0; i < uniqueIds.length; i++) { player = uniqueIds[i]; let total = 0; let latest = 0; for (let j = 0; j < result.length; j++) { if (String(result[j].playerId) == player) { let points = result[j].tournamentPoints; if (points != 0 && latest == 0) { latest = points; } total += points; } } let name; for (let j = 0; j < nameresult.length; j++) { if (String(nameresult[j]._id) === player) { name = nameresult[j].name; } } object.push({ id: player, name: name, totalPoints: total, latestPoints: latest, }); } object.sort((a, b) => (a.totalPoints > b.totalPoints ? -1 : 1)); res.json(object); client.close(); }); }); } ); }); router.get("/specific/:tournamentId/:playerId/:roundNr", (req, res) => { // Connect to database MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } // Using the database gameWare and collection rounds const db = client.db("gameWare"); const collection = "rounds"; let tournamentId, playerId, roundNr = undefined; try { tournamentId = mongo.ObjectID(req.params.tournamentId); // get tournamentId playerId = mongo.ObjectID(req.params.playerId); // get playerId roundNr = parseInt(req.params.roundNr); // get roundNr } catch (error) { res.status(404).send("No document with specified params found"); return; } db.collection(collection) .findOne({ tournamentId, playerId, roundNr, }) .then((result) => { if (!result) { res.status(404).send("No document with specified id params found"); return; } res.json(result); client.close(); }) .catch((err) => res.sendStatus(500)); } ); }); router.post("/", (req, res) => { // Connect to database MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } // Using the database gameWare and collection rounds const db = client.db("gameWare"); const collection = "rounds"; const values = { tournamentId: null, playerId: null, gameId: null, roundNr: null, deadlineDate: null, }; try { values.tournamentId = mongo.ObjectID(req.body.tournamentId); values.playerId = mongo.ObjectID(req.body.playerId); values.gameId = mongo.ObjectID(req.body.gameId); values.roundNr = !isNaN(parseInt(req.body.roundNr)) ? parseInt(req.body.roundNr) : null; values.deadlineDate = getDate(req.body.deadlineDate); } catch (error) { res.status(404).send("No document with specified id was found"); console.log(error); return; } // validating body Object.keys(values).forEach((val) => { if (!req.body[val]) { values[val] = null; } }); // values contains a null field if (Object.values(values).some((x) => x === null)) { res.status(404).send("Missing fields in request"); return; } values.scoreValue = 0; values.hasPlayed = false; db.collection(collection).insertOne(values, (err, result) => { if (err) { res.sendStatus(500); // Internal server error return; } res.json(result.ops[0]); client.close(); }); } ); }); router.put("/:roundid/:tournamentid", (req, res) => { // Connect to database MongoClient.connect( connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => { // Unable to connect to database if (err) { res.sendStatus(500); // Internal server error return; } // Using the database gameWare and collection rounds const db = client.db("gameWare"); const collection = "rounds"; let id, scoreValue, tournament = null; try { id = mongo.ObjectID(req.params.roundid); // get roundId tournament = mongo.ObjectID(req.params.tournamentid); scoreValue = !isNaN(parseInt(req.body.scoreValue)) ? parseInt(req.body.scoreValue) : null; } catch (error) { res.status(400).send("No document with specified id was found"); return; } if (!id || !tournament || scoreValue === null) { res.status(400).send("Request body not valid"); return; } db.collection(collection) .findOneAndUpdate( { _id: id, scoreValue: 0, hasPlayed: false }, { $set: { scoreValue: scoreValue, hasPlayed: true } }, { returnOriginal: false } ) .then((updatedDocument) => { if (updatedDocument.value) { //console.log("Successfully updated document"); updateHighscore( client, updatedDocument.value.gameId, updatedDocument.value.playerId, updatedDocument.value.scoreValue ); roundcheck(client, tournament, id).then((checkresult) => { res.json(checkresult); client.close(); return; }); // Return updated document } else { //console.log("Failed to update doucment"); res.status(404).send("No document with specified id was found"); client.close(); } }) .catch((err) => console.log(err)); } ); }); function roundcheck(client, tournament, roundid) { return new Promise((resolve, reject) => { functions.getCurrentRound(client, tournament).then((roundResult) => { // gets the current round of the tournament if (roundResult == 500) { resolve(500); } const active = roundResult.currentRound; const start = roundResult.startTime; const maxPlayers = roundResult.maxPlayers; const currentPlayers = roundResult.currentPlayers; const name = roundResult.name; functions.fetchRounds(client, tournament, active).then((rounds) => { // fetched the round objects of the active round let activePlayer; for (let i = 0; i < rounds.length; i++) { if (String(rounds[i]._id) == String(roundid)) { activePlayer = rounds[i].playerId; break; } } functions .checkRounds(rounds, start, maxPlayers, active, currentPlayers) .then((resultarray) => { // check to find out if [0] tournament will move on, [1] which players are timed out // [2] which players are still in the tournament let result = resultarray[0]; let timedOut = resultarray[1]; let left = resultarray[2]; let timedOutRounds = resultarray[3]; let end = false; if ((left.length < 2 && active != 1) || left.length == 0) { end = true; //if there are less then two people left in the first round, or zero people left in the first round //the tournament ends } functions .timeOut(client, tournament, timedOut, timedOutRounds) .then( //updates the state of the tournament and ends it if necessary () => { functions .notifyPlayers(client, timedOut, true, tournament, name) .then(() => { const indeks = left.indexOf(activePlayer); left.splice(indeks, 1); if (end) { functions .notifyPlayers(client, left, false, tournament, name) .then(() => { functions .endTournament(client, tournament) .then(() => { getRound(client, roundid).then((round) => { resolve({ round: round, roundCheck: { active: false, nextRound: false, }, }); }); }); }); } else if (result) { //Tournament moves on to next round let eligibleRounds = []; for (let i = 0; i < rounds.length; i++) { let round = rounds[i]; if (round.hasPlayed === true) { eligibleRounds.push(round); } } //Here we find the rounds that were actually completed for (let i = 0; i < eligibleRounds.length; i++) { let round = eligibleRounds[i]; functions.updateScore( client, round._id, i + 1, eligibleRounds.length ); //And here we update the tournament score } functions .updateTournamentRound(client, tournament) .then((result) => { //updates the tournaments round if there are more rounds left if (result.value) { tourny = result.value; const game = tourny.games[ (tourny.currentRound - 1) % tourny.games.length ]; const date = new Date(); date.setTime( date.getTime() + tourny.timePerRound * 24 * 60 * 60 * 1000 ); functions .newRound( client, tournament, tourny.players, game, tourny.currentRound, date ) .then(() => { getRound(client, roundid).then((round) => { resolve({ round: round, roundCheck: { active: true, nextRound: true, }, }); }); }); // created new rounds for all the players left } else { // if the tournament now is done we simply end it functions .endTournament(client, tournament) .then(() => { functions .notifyPlayers( client, left, false, tournament, name ) .then(() => { getRound(client, roundid).then( (round) => { resolve({ round: round, roundCheck: { active: false, nextRound: false, }, }); } ); }); }); } }); } else { getRound(client, roundid).then((round) => { resolve({ round: round, roundCheck: { // Tournament still waiting for other players active: true, nextRound: false, }, }); }); } }); } ); }); }); }); }); } function getRound(client, id) { return new Promise((resolve, reject) => { const db = client.db("gameWare"); const collection = "rounds"; db.collection(collection).findOne({ _id: id }, (err, result) => { if (err) { resolve(500); // Internal server error return; } resolve(result); return; }); }); } // Export API routes module.exports = router; function getDate(dateString) { date = new Date(dateString); if (isNaN(date.getTime())) { return null; } return date; }