Files
vinlottis/api/prizeDistribution.js
KevinMidboe 70c80849df No longer delete winner as part of selecting prize.
Winners are rather marked with prize_selected and have it's own endpoint
to remove all winners.
2021-02-18 20:54:15 +01:00

111 lines
3.8 KiB
JavaScript

const path = require("path");
const Wine = require(path.join(__dirname, "/schemas/Wine"));
const PreLotteryWine = require(path.join(__dirname, "/schemas/PreLotteryWine"));
const VirtualWinner = require(path.join(__dirname, "/schemas/VirtualWinner"));
const message = require(path.join(__dirname, "/message"));
const historyRepository = require(path.join(__dirname, "/history"));
const winnerRepository = require(path.join(__dirname, "/winner"));
const wineRepository = require(path.join(__dirname, "/wine"));
const prelotteryWineRepository = require(path.join(__dirname, "/prelotteryWine"));
const { WinnerNotFound, WineSelectionWinnerNotNextInLine, WinnersTimelimitExpired } = require(path.join(
__dirname,
"/vinlottisErrors"
));
const verifyWinnerNextInLine = async id => {
let foundWinner = await VirtualWinner.findOne({ id: id });
if (!foundWinner) {
throw new WinnerNotFound();
} else if (foundWinner.timestamp_limit < new Date().getTime()) {
throw new WinnersTimelimitExpired();
}
let allWinners = await VirtualWinner.find().sort({ timestamp_drawn: 1 });
if (
foundWinner.timestamp_limit == undefined ||
foundWinner.timestamp_sent == undefined ||
foundWinner.prize_selected == true
) {
throw new WineSelectionWinnerNotNextInLine();
}
return Promise.resolve(foundWinner);
};
const claimPrize = (wine, winner) => {
return wineRepository
.addWine(wine)
.then(_ => prelotteryWineRepository.addWinnerToWine(wine, winner)) // prelotteryWine.deleteById
.then(_ => historyRepository.addWinnerWithWine(winner, wine)) // wines.js : addWine
.then(_ => message.sendWineConfirmation(winner, wine));
};
const notifyNextWinner = async () => {
let nextWinner = undefined;
const winnersLeft = await VirtualWinner.find({ prize_selected: false }).sort({ timestamp_drawn: 1 });
const winesLeft = await PreLotteryWine.find({ winner: { $exists: false } });
if (winnersLeft.length > 1) {
console.log("multiple winners left, choose next in line");
nextWinner = winnersLeft[0]; // multiple winners left, choose next in line
} else if (winnersLeft.length == 1 && winesLeft.length > 1) {
console.log("one winner left, but multiple wines");
nextWinner = winnersLeft[0]; // one winner left, but multiple wines
} else if (winnersLeft.length == 1 && winesLeft.length == 1) {
console.log("one winner and one wine left, choose for user");
nextWinner = winnersLeft[0]; // one winner and one wine left, choose for user
wine = winesLeft[0];
return claimPrize(wine, nextWinner);
}
if (nextWinner) {
return message.sendPrizeSelectionLink(nextWinner).then(_ => startTimeout(nextWinner.id));
} else {
console.info("All winners notified. Could start cleanup here.");
return Promise.resolve({
message: "All winners notified."
});
}
};
// these need to be register somewhere to cancel if something
// goes wrong and we want to start prize distribution again
function startTimeout(id) {
const minute = 60000;
const minutesForTimeout = 10;
console.log(`Starting timeout for user ${id}.`);
console.log(`Timeout duration: ${minutesForTimeout * minute}`);
setTimeout(async () => {
let virtualWinner = await VirtualWinner.findOne({ id: id, prize_selected: false });
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.sendWineSelectMessageTooLate(virtualWinner);
virtualWinner.timestamp_drawn = new Date().getTime();
virtualWinner.timestamp_limit = null;
virtualWinner.timestamp_sent = null;
await virtualWinner.save();
notifyNextWinner();
}, minutesForTimeout * minute);
return Promise.resolve();
}
module.exports = {
verifyWinnerNextInLine,
claimPrize,
notifyNextWinner
};