Moved all logic related to lotteryAttendees, lotteryWinners and prelotteryWines into each their repository and controller. Now only holds draw, archive and get archived lotteries.
206 lines
5.3 KiB
JavaScript
206 lines
5.3 KiB
JavaScript
const path = require("path");
|
|
const crypto = require("crypto");
|
|
|
|
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 Lottery = require(path.join(__dirname, "/schemas/Purchase"));
|
|
|
|
const Message = require(path.join(__dirname, "/message"));
|
|
const {
|
|
WinnerNotFound,
|
|
NoMoreAttendeesToWin,
|
|
CouldNotFindNewWinnerAfterNTries,
|
|
LotteryByDateNotFound
|
|
} = require(path.join(__dirname, "/vinlottisErrors"));
|
|
|
|
const archive = (date, raffles, stolen, wines) => {
|
|
const { blue, red, yellow, green } = raffles;
|
|
const bought = blue + red + yellow + green;
|
|
date = date.setHours(0, 0, 0, 0);
|
|
|
|
return Lottery.findOneAndUpdate(
|
|
{ date },
|
|
{
|
|
date,
|
|
blue,
|
|
red,
|
|
yellow,
|
|
green,
|
|
bought,
|
|
stolen,
|
|
wines
|
|
},
|
|
{ upsert: true }
|
|
);
|
|
};
|
|
|
|
const lotteryByDate = date => {
|
|
const startOfDay = new Date(date.setHours(0, 0, 0, 0));
|
|
const endOfDay = new Date(date.setHours(24, 59, 59, 99));
|
|
|
|
const query = [
|
|
{
|
|
$match: {
|
|
date: {
|
|
$gte: startOfDay,
|
|
$lte: endOfDay
|
|
}
|
|
}
|
|
},
|
|
{
|
|
$lookup: {
|
|
from: "wines",
|
|
localField: "wines",
|
|
foreignField: "_id",
|
|
as: "wines"
|
|
}
|
|
}
|
|
];
|
|
|
|
const aggregateLottery = Lottery.aggregate(query);
|
|
return aggregateLottery.project("-_id -__v").then(lotteries => {
|
|
if (lotteries.length == 0) {
|
|
throw new LotteryByDateNotFound(date);
|
|
}
|
|
return lotteries[0];
|
|
});
|
|
};
|
|
|
|
const allLotteries = () => {
|
|
return Lottery.find()
|
|
.select("-_id -__v")
|
|
.populate("wines");
|
|
};
|
|
|
|
const drawWinner = async () => {
|
|
let allContestants = await Attendee.find({ winner: false });
|
|
|
|
if (allContestants.length == 0) {
|
|
throw new NoMoreAttendeesToWin();
|
|
}
|
|
|
|
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 CouldNotFindNewWinnerAfterNTries(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 = {
|
|
drawWinner,
|
|
archive,
|
|
lotteryByDate,
|
|
allLotteries
|
|
};
|