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.
This commit is contained in:
		| @@ -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, | ||||
|   | ||||
| @@ -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 | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user