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:
2020-09-06 14:14:26 +02:00
parent 4f054a0437
commit 1d714d1e5a
2 changed files with 212 additions and 215 deletions

View File

@@ -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,

View File

@@ -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
};