From 1d714d1e5a62c9437a53645af722470c58438cc8 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Sun, 6 Sep 2020 14:14:26 +0200 Subject: [PATCH] Removed router, refactored virtual functoinality. - Removed the router from virtualRegistration so router.js handles routing and virtualRegistration only exports functions. - Refactored what code is in each of the virtual(Lottery/Registration) files. /finish in Lottery now only sends update to all winners and delegates sending to next winner in line, and setting timeout to virtualRegistration. - Better error handling and all responses from virtualRegistration has message in json response. --- api/virtualLottery.js | 252 ++++++++++++++++--------------------- api/virtualRegistration.js | 175 ++++++++++++++++---------- 2 files changed, 212 insertions(+), 215 deletions(-) diff --git a/api/virtualLottery.js b/api/virtualLottery.js index 9bde0d2..81107dc 100644 --- a/api/virtualLottery.js +++ b/api/virtualLottery.js @@ -1,37 +1,14 @@ -const express = require("express"); const path = require("path"); -const router = express.Router(); const crypto = require("crypto"); -const mongoose = require("mongoose"); -mongoose.connect("mongodb://localhost:27017/vinlottis", { - useNewUrlParser: true -}); const config = require(path.join(__dirname + "/../config/defaults/lottery")); +const Message = require(path.join(__dirname + "/message")); +const { findAndNotifyNextWinner } = require(path.join(__dirname + "/virtualRegistration")); const Attendee = require(path.join(__dirname + "/../schemas/Attendee")); -const VirtualWinner = require(path.join( - __dirname + "/../schemas/VirtualWinner" -)); -const PreLotteryWine = require(path.join( - __dirname + "/../schemas/PreLotteryWine" -)); +const VirtualWinner = require(path.join(__dirname + "/../schemas/VirtualWinner")); +const PreLotteryWine = require(path.join(__dirname + "/../schemas/PreLotteryWine")); -const Message = require(path.join(__dirname + "/../api/message")); - -const removeWinners = async (req, res) => { - await VirtualWinner.deleteMany(); - var io = req.app.get('socketio'); - io.emit("refresh_data", {}); - return res.json(true); -}; - -const deleteAttendees = req, res) => { - await Attendee.deleteMany(); - var io = req.app.get('socketio'); - io.emit("refresh_data", {}); - return res.json(true); -}; const winners = async (req, res) => { let winners = await VirtualWinner.find(); @@ -51,13 +28,76 @@ const winnersSecure = async (req, res) => { let winners = await VirtualWinner.find(); return res.json(winners); -}); +}; -const winner = async (req, res) => { +const deleteWinners = async (req, res) => { + await VirtualWinner.deleteMany(); + var io = req.app.get('socketio'); + io.emit("refresh_data", {}); + return res.json(true); +}; + +const attendees = async (req, res) => { + let attendees = await Attendee.find(); + let attendeesRedacted = []; + let attendee; + for (let i = 0; i < attendees.length; i++) { + attendee = attendees[i]; + attendeesRedacted.push({ + name: attendee.name, + ballots: attendee.red + attendee.blue + attendee.yellow + attendee.green, + red: attendee.red, + blue: attendee.blue, + green: attendee.green, + yellow: attendee.yellow + }); + } + return res.json(attendeesRedacted); +}; + +const attendeesSecure = async (req, res) => { + let attendees = await Attendee.find(); + + return res.json(attendees); +}; + +const addAttendee = async (req, res) => { + const attendee = req.body; + const { red, blue, yellow, green } = attendee; + + let newAttendee = new Attendee({ + name: attendee.name, + red, + blue, + green, + yellow, + phoneNumber: attendee.phoneNumber, + winner: false + }); + await newAttendee.save(); + + + var io = req.app.get('socketio'); + io.emit("new_attendee", {}); + + return res.send(true); +}; + +const deleteAttendees = async (req, res) => { + await Attendee.deleteMany(); + var io = req.app.get('socketio'); + io.emit("refresh_data", {}); + return res.json(true); +}; + +const drawWinner = async (req, res) => { let allContestants = await Attendee.find({ winner: false }); + if (allContestants.length == 0) { - return res.json(false); - return; + return res.json({ + success: false, + message: "No attendees left that have not won." + }); } let ballotColors = []; for (let i = 0; i < allContestants.length; i++) { @@ -150,6 +190,38 @@ const winner = async (req, res) => { return res.json(winner); }; +const finish = async (req, res) => { + if (!config.gatewayToken) { + return res.json({ + message: "Missing api token for sms gateway.", + success: false + }); + } + + let winners = await VirtualWinner.find({ timestamp_sent: undefined }).sort({ + timestamp_drawn: 1 + }); + + if (winners.length == 0) { + return res.json({ + message: "No winners to draw from.", + success: false + }); + } + + Message.sendInitialMessageToWinners(winners.slice(1)); + + return findAndNotifyNextWinner() + .then(() => res.json({ + success: true, + message: "Sent wine select message to first winner and update message to rest of winners." + })) + .catch(error => res.json({ + message: error["message"] || "Unable to send message to first winner.", + success: false + })) +}; + const genRandomString = function(length) { return crypto .randomBytes(Math.ceil(length / 2)) @@ -164,84 +236,6 @@ const sha512 = function(password, salt) { return value; }; -const finish = async (req, res) => { - if (!config.gatewayToken) { - return res.json(false); - } - let winners = await VirtualWinner.find({ timestamp_sent: undefined }).sort({ - timestamp_drawn: 1 - }); - - if (winners.length == 0) { - return res.json(false); - } - - let firstWinner = winners[0]; - messageSent = false; - try { - let messageSent = await Message.sendMessage(firstWinner); - Message.sendUpdate(winners.slice(1)); - if (!messageSent) { - return res.json(false); - } - } catch (e) { - return res.json(false); - } - - firstWinner.timestamp_sent = new Date().getTime(); - firstWinner.timestamp_limit = new Date().getTime() + 600000; - - await firstWinner.save(); - startTimeout(firstWinner.id); - return res.json(true); -}; - -const attendees = async (req, res) => { - let attendees = await Attendee.find(); - let attendeesRedacted = []; - let attendee; - for (let i = 0; i < attendees.length; i++) { - attendee = attendees[i]; - attendeesRedacted.push({ - name: attendee.name, - ballots: attendee.red + attendee.blue + attendee.yellow + attendee.green, - red: attendee.red, - blue: attendee.blue, - green: attendee.green, - yellow: attendee.yellow - }); - } - return res.json(attendeesRedacted); -}; - -const attendeesSecure = async (req, res) => { - let attendees = await Attendee.find(); - - return res.json(attendees); -}); - -return addAttendee = async (req, res) => { - const attendee = req.body; - const { red, blue, yellow, green } = attendee; - - let newAttendee = new Attendee({ - name: attendee.name, - red, - blue, - green, - yellow, - phoneNumber: attendee.phoneNumber, - winner: false - }); - await newAttendee.save(); - - - var io = req.app.get('socketio'); - io.emit("new_attendee", {}); - - return res.send(true); -}); - function shuffle(array) { let currentIndex = array.length, temporaryValue, @@ -262,48 +256,12 @@ function shuffle(array) { return array; } - -function startTimeout(id) { - console.log(`Starting timeout for user ${id}.`); - setTimeout(async () => { - let virtualWinner = await VirtualWinner.findOne({ id: id }); - if (!virtualWinner) { - console.log( - `Timeout done for user ${id}, but user has already sent data.` - ); - return; - } - console.log(`Timeout done for user ${id}, sending update to user.`); - - Message.sendMessageTooLate(virtualWinner); - - virtualWinner.timestamp_drawn = new Date().getTime(); - virtualWinner.timestamp_limit = null; - virtualWinner.timestamp_sent = null; - - await virtualWinner.save(); - - let prelotteryWine = await PreLotteryWine.find(); - let nextWinner = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); - if (nextWinner.length == 1 && prelotteryWine.length == 1) { - chooseForUser(nextWinner[0], prelotteryWine[0]); - } else { - nextWinner[0].timestamp_sent = new Date().getTime(); - nextWinner[0].timestamp_limit = new Date().getTime() + 600000; - await nextWinner[0].save(); - Message.sendMessage(nextWinner[0]); - startTimeout(nextWinner[0].id); - } - - }, 600000); -} - module.exports = { - removeWinners, + deleteWinners, deleteAttendees, winners, winnersSecure, - winner, + drawWinner, finish, attendees, attendeesSecure, diff --git a/api/virtualRegistration.js b/api/virtualRegistration.js index b3c128e..473d827 100644 --- a/api/virtualRegistration.js +++ b/api/virtualRegistration.js @@ -1,11 +1,4 @@ -const express = require("express"); const path = require("path"); -const router = express.Router(); -const mongoose = require("mongoose"); - -mongoose.connect("mongodb://localhost:27017/vinlottis", { - useNewUrlParser: true -}); const _wineFunctions = require(path.join(__dirname + "/../api/wine")); const _personFunctions = require(path.join(__dirname + "/../api/person")); @@ -17,72 +10,70 @@ const PreLotteryWine = require(path.join( __dirname + "/../schemas/PreLotteryWine" )); -router.use((req, res, next) => { - next(); -}); -router.route("/winner/:id").get((req, res) => { - res.redirect(`/#/winner/${req.params.id}`); -}); - -router.route("/:id").get(async (req, res) => { +const getWinesToWinnerById = async (req, res) => { let id = req.params.id; let foundWinner = await VirtualWinner.findOne({ id: id }); if (!foundWinner) { - res.json({ + return res.json({ + success: false, + message: "No winner with this id.", existing: false, turn: false }); - return; } let allWinners = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); - if ( allWinners[0].id != foundWinner.id || foundWinner.timestamp_limit == undefined || foundWinner.timestamp_sent == undefined ) { - res.json({ existing: true, turn: false }); - return; + return res.json({ + success: false, + message: "Not the winner next in line!", + existing: true, + turn: false + }); } - res.json({ + return res.json({ + success: true, existing: true, turn: true, name: foundWinner.name, color: foundWinner.color }); - return; -}); +}; -router.route("/:id").post(async (req, res) => { +const registerWinnerSelection = async (req, res) => { let id = req.params.id; let wineName = req.body.wineName; let foundWinner = await VirtualWinner.findOne({ id: id }); if (!foundWinner) { - res.json(false); - return; + return res.json({ + success: false, + message: "No winner with this id." + }) + } else if (foundWinner.timestamp_limit < new Date().getTime()) { + return res.json({ + success: false, + message: "Timelimit expired, you will receive a wine after other users have chosen.", + limit: true + }) } - if (foundWinner.timestamp_limit < new Date().getTime()) { - res.json({ - success: false, - limit: true - }); - return; - } let date = new Date(); date.setHours(5, 0, 0, 0); - let prelotteryWine = await PreLotteryWine.findOne({ name: wineName }); if (!prelotteryWine) { - res.json({ + return res.json({ success: false, - wine: true + message: "No wine with this name.", + wine: false }); } @@ -91,31 +82,78 @@ router.route("/:id").post(async (req, res) => { await _personFunctions.findSavePerson(foundWinner, wonWine, date); await foundWinner.delete(); + console.info("Saved winners choice."); - let nextWineBottle = await PreLotteryWine.find(); - let nextWinner = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); - if (nextWinner.length > 1 && nextWineBottle.length > 1) { - Message.sendMessage(nextWinner[0]); - startTimeout(id); - } else if (nextWinner.length == 1 && nextWineBottle.length == 1) { - chooseForUser(nextWinner[0], nextWineBottle[0]); - } + return findAndNotifyNextWinner() + .then(() => res.json({ + message: "Choice saved and next in line notified.", + success: true + })) + .catch(error => res.json({ + message: error["message"] || "Error when notifing next winner.", + success: false + })) +}; - res.json({ - success: true - }); - return; -}); - -async function chooseForUser(winner, prelotteryWine) { +const chooseLastWineForUser = (winner, prelotteryWine) => { let date = new Date(); date.setHours(5, 0, 0, 0); - let wonWine = await _wineFunctions.findSaveWine(prelotteryWine); - await _personFunctions.findSavePerson(winner, wonWine, date); - await prelotteryWine.delete(); - await Message.sendWonWineMessage(winner, prelotteryWine); - await winner.delete(); + return _wineFunctions.findSaveWine(preLotteryWine) + .then(wonWine => _personFunctions.findSavePerson(winner, wonWine, date)) + .then(() => prelotteryWine.delete()) + .then(() => Message.sendLastWinnerMessage(winner, preLotteryWine)) + .then(() => winner.delete()); +} + +const findAndNotifyNextWinner = async () => { + let nextWinner = undefined; + + let winnersLeft = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); + let winesLeft = await PreLotteryWine.find(); + + if (winnersLeft.length > 1) { + nextWinner = winnersLeft[0]; // multiple winners left, choose next in line + } else if (winnersLeft.length == 1 && winesLeft.length > 1) { + nextWinner = winnersLeft[0] // one winner left, but multiple wines + } else if (winnersLeft.length == 1 && winesLeft.length == 1) { + nextWinner = winnersLeft[0] // one winner and one wine left, choose for user + wine = winesLeft[0] + return chooseLastWineForUser(nextWinner, wine); + } + + if (nextWinner) { + return Message.sendWineSelectMessage(nextWinner) + .then(messageResponse => startTimeout(nextWinner.id)) + } else { + console.info("All winners notified. Could start cleanup here."); + return Promise.resolve({ + message: "All winners notified." + }) + } +}; + +const sendNotificationToWinnerById = async (req, res) => { + const { id } = req.params; + let winner = await VirtualWinner.findOne({ id: id }); + + if (!winner) { + return res.json({ + message: "No winner with this id.", + success: false + }) + } + + return Message.sendWineSelectMessage(winner) + .then(success => res.json({ + success: success, + message: `Message sent to winner ${id} successfully!` + })) + .catch(err => res.json({ + success: false, + message: "Error while trying to send sms.", + error: err + })) } function startTimeout(id) { @@ -123,27 +161,28 @@ function startTimeout(id) { setTimeout(async () => { let virtualWinner = await VirtualWinner.findOne({ id: id }); if (!virtualWinner) { - console.log( - `Timeout done for user ${id}, but user has already sent data.` - ); + console.log(`Timeout done for user ${id}, but user has already sent data.`); return; } console.log(`Timeout done for user ${id}, sending update to user.`); - Message.sendMessageTooLate(virtualWinner); + Message.sendWineSelectMessageTooLate(virtualWinner); virtualWinner.timestamp_drawn = new Date().getTime(); virtualWinner.timestamp_limit = null; virtualWinner.timestamp_sent = null; - await virtualWinner.save(); - let prelotteryWine = await PreLotteryWine.find(); - let nextWinner = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); - if (nextWinner.length == 1 && prelotteryWine.length == 1) { - chooseForUser(nextWinner[0], prelotteryWine[0]); - } - }, 600000); + findAndNotifyNextWinner(); + }, 60000); + + return Promise.resolve() } -module.exports = router; +module.exports = { + getWinesToWinnerById, + registerWinnerSelection, + findAndNotifyNextWinner, + + sendNotificationToWinnerById +};