Get/add/update/delete winners from lottery.

This commit is contained in:
2021-01-24 14:01:36 +01:00
parent fac50805bd
commit 53135acc05
2 changed files with 323 additions and 14 deletions

View File

@@ -0,0 +1,101 @@
const path = require("path");
const lotteryRepository = require(path.join(__dirname, "../lottery"));
const allWinners = (req, res) => {
const isAdmin = req.isAuthenticated() || true;
return lotteryRepository
.allWinners(isAdmin)
.then(winners =>
res.send({
winners: winners,
success: true
})
)
.catch(error => {
const { statusCode, message } = error;
return res.status(statusCode || 500).send({
success: false,
message: message || "Unable to fetch lottery winners."
});
});
};
const winnerById = (req, res) => {
const { id } = req.params;
return lotteryRepository
.winnerById(id)
.then(winner =>
res.send({
winner,
success: true
})
)
.catch(error => {
const { statusCode, message } = error;
return res.status(statusCode || 500).send({
message: message || "Unexpected error occured, unable to fetch winner by id.",
success: false
});
});
};
const deleteWinnerById = (req, res) => {
const isAdmin = req.isAuthenticated() || true;
const { id } = req.params;
return lotteryRepository
.deleteWinnerById(id, isAdmin)
.then(removedWinner => {
var io = req.app.get("socketio");
io.emit("refresh_data", {});
return removedWinner;
})
.then(winner =>
res.send({
message: `Removed winner: ${winner.name}`,
success: true
})
)
.catch(error => {
const { statusCode, message } = error;
return res.status(statusCode || 500).send({
message: message || "Unexpected error occured while deleteing wine by id.",
success: false
});
});
};
const deleteWinners = (req, res) => {
return lotteryRepository
.deleteWinners()
.then(_ => {
var io = req.app.get("socketio");
io.emit("refresh_data", {});
})
.then(_ =>
res.send({
message: "Removed all winners.",
success: true
})
)
.catch(error => {
const { statusCode, message } = error;
return res.status(statusCode || 500).send({
message: message || "Unexpected error occured while deleting wines",
success: false
});
});
};
module.exports = {
allWinners,
winnerById,
deleteWinnerById,
deleteWinners
};

View File

@@ -1,6 +1,10 @@
const path = require("path");
const Attendee = require(path.join(__dirname, "/schemas/Attendee"));
const PreLotteryWine = require(path.join(__dirname, "/schemas/PreLotteryWine"));
const VirtualWinner = require(path.join(__dirname, "/schemas/VirtualWinner"));
const crypto = require("crypto");
class UserNotFound extends Error {
constructor(message = "User not found.") {
@@ -22,6 +26,33 @@ class WineNotFound extends Error {
// TODO log missing user
}
class WinnerNotFound extends Error {
constructor(message = "Winner not found.") {
super(message);
this.name = "WinnerNotFound";
this.statusCode = 404;
}
// TODO log missing user
}
class NoMoreAttendeesToWinError extends Error {
constructor(message = "No more attendees left to drawn from.") {
super(message);
this.name = "NoMoreAttendeesToWinError";
this.statusCode = 404;
}
}
class CouldNotFindNewWinnerAfterNTriesError extends Error {
constructor(tries) {
let message = `Could not a new winner after ${tries} tries.`;
super(message);
this.name = "CouldNotFindNewWinnerAfterNTriesError";
this.statusCode = 404;
}
}
const redactAttendeeInfoMapper = attendee => {
return {
name: attendee.name,
@@ -33,6 +64,13 @@ const redactAttendeeInfoMapper = attendee => {
};
};
const redactWinnerInfoMapper = winner => {
return {
name: winner.name,
color: winner.color
};
};
const allAttendees = isAdmin => {
if (!isAdmin) {
return Attendee.find().then(attendees => attendees.map(redactAttendeeInfoMapper));
@@ -63,15 +101,20 @@ const updateAttendeeById = (id, updateModel) => {
throw new UserNotFound();
}
console.log(updateModel);
const updatedAttendee = {
name: updateModel.name || attendee.name,
green: updateModel.green || attendee.green,
red: updateModel.red || attendee.red,
blue: updateModel.blue || attendee.blue,
yellow: updateModel.yellow || attendee.yellow,
phoneNumber: updateModel.phoneNumber || attendee.phoneNumber
name: updateModel.name != null ? updateModel.name : attendee.name,
green: updateModel.green != null ? updateModel.green : attendee.green,
red: updateModel.red != null ? updateModel.red : attendee.red,
blue: updateModel.blue != null ? updateModel.blue : attendee.blue,
yellow: updateModel.yellow != null ? updateModel.yellow : attendee.yellow,
phoneNumber: updateModel.phoneNumber != null ? updateModel.phoneNumber : attendee.phoneNumber,
winner: updateModel.winner != null ? updateModel.winner : attendee.winner
};
console.log(updatedAttendee);
return Attendee.updateOne({ _id: id }, updatedAttendee).then(_ => updatedAttendee);
});
};
@@ -119,13 +162,13 @@ const updateWineById = (id, updateModel) => {
}
const updatedWine = {
name: updateModel.name || wine.name,
vivinoLink: updateModel.vivinoLink || wine.vivinoLink,
rating: updateModel.rating || wine.rating,
image: updateModel.image || wine.image,
price: updateModel.price || wine.price,
country: updateModel.country || wine.country,
id: updateModel.id || wine.id
name: updateModel.name != null ? updateModel.name : wine.name,
vivinoLink: updateModel.vivinoLink != null ? updateModel.vivinoLink : wine.vivinoLink,
rating: updateModel.rating != null ? updateModel.rating : wine.rating,
image: updateModel.image != null ? updateModel.image : wine.image,
price: updateModel.price != null ? updateModel.price : wine.price,
country: updateModel.country != null ? updateModel.country : wine.country,
id: updateModel.id != null ? updateModel.id : wine.id
};
return PreLotteryWine.updateOne({ _id: id }, updatedWine).then(_ => updatedWine);
@@ -146,6 +189,166 @@ const deleteWines = () => {
return PreLotteryWine.deleteMany();
};
const allWinners = isAdmin => {
if (!isAdmin) {
return VirtualWinner.find().then(winners => winners.map(redactWinnerInfoMapper));
} else {
return VirtualWinner.find();
}
};
const winnerById = (id, isAdmin) => {
return VirtualWinner.findOne({ _id: id }).then(winner => {
if (winner == null) {
throw new WinnerNotFound();
}
if (!isAdmin) {
return redactWinnerInfoMapper(winner);
} else {
return winner;
}
});
};
const deleteWinnerById = id => {
return VirtualWinner.findOne({ _id: id }).then(winner => {
if (winner == null) {
throw new WinnerNotFound();
}
return VirtualWinner.deleteOne({ _id: id }).then(_ => winner);
});
};
const deleteWinners = () => {
return VirtualWinner.deleteMany();
};
const drawWinner = async () => {
let allContestants = await Attendee.find({ winner: false });
if (allContestants.length == 0) {
throw new NoMoreAttendeesToWinError();
}
let raffleColors = [];
for (let i = 0; i < allContestants.length; i++) {
let currentContestant = allContestants[i];
for (let blue = 0; blue < currentContestant.blue; blue++) {
raffleColors.push("blue");
}
for (let red = 0; red < currentContestant.red; red++) {
raffleColors.push("red");
}
for (let green = 0; green < currentContestant.green; green++) {
raffleColors.push("green");
}
for (let yellow = 0; yellow < currentContestant.yellow; yellow++) {
raffleColors.push("yellow");
}
}
raffleColors = shuffle(raffleColors);
let colorToChooseFrom = raffleColors[Math.floor(Math.random() * raffleColors.length)];
let findObject = { winner: false };
findObject[colorToChooseFrom] = { $gt: 0 };
let tries = 0;
const maxTries = 3;
let contestantsToChooseFrom = undefined;
while (contestantsToChooseFrom == undefined && tries < maxTries) {
const hit = await Attendee.find(findObject);
if (hit && hit.length) {
contestantsToChooseFrom = hit;
break;
}
tries++;
}
if (contestantsToChooseFrom == undefined) {
throw new CouldNotFindNewWinnerAfterNTriesError(maxTries);
}
let attendeeListDemocratic = [];
let currentContestant;
for (let i = 0; i < contestantsToChooseFrom.length; i++) {
currentContestant = contestantsToChooseFrom[i];
for (let y = 0; y < currentContestant[colorToChooseFrom]; y++) {
attendeeListDemocratic.push({
name: currentContestant.name,
phoneNumber: currentContestant.phoneNumber,
red: currentContestant.red,
blue: currentContestant.blue,
green: currentContestant.green,
yellow: currentContestant.yellow
});
}
}
attendeeListDemocratic = shuffle(attendeeListDemocratic);
let winner = attendeeListDemocratic[Math.floor(Math.random() * attendeeListDemocratic.length)];
let winners = await VirtualWinner.find({ timestamp_sent: undefined }).sort({
timestamp_drawn: 1
});
let newWinnerElement = new VirtualWinner({
name: winner.name,
phoneNumber: winner.phoneNumber,
color: colorToChooseFrom,
red: winner.red,
blue: winner.blue,
green: winner.green,
yellow: winner.yellow,
id: sha512(winner.phoneNumber, genRandomString(10)),
timestamp_drawn: new Date().getTime()
});
await newWinnerElement.save();
await Attendee.updateOne({ name: winner.name, phoneNumber: winner.phoneNumber }, { $set: { winner: true } });
return { winner, color: colorToChooseFrom, winners };
};
/** - - UTILS - - **/
const genRandomString = function(length) {
return crypto
.randomBytes(Math.ceil(length / 2))
.toString("hex") /** convert to hexadecimal format */
.slice(0, length); /** return required number of characters */
};
const sha512 = function(password, salt) {
var hash = crypto.createHmac("md5", salt); /** Hashing algorithm sha512 */
hash.update(password);
var value = hash.digest("hex");
return value;
};
function shuffle(array) {
let currentIndex = array.length,
temporaryValue,
randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
module.exports = {
allAttendees,
addAttendee,
@@ -156,5 +359,10 @@ module.exports = {
addWines,
updateWineById,
deleteWineById,
deleteWines
deleteWines,
allWinners,
winnerById,
deleteWinnerById,
deleteWinners,
drawWinner
};