Prize distribution for selecting wines.
Moved the same functionality out from lottery.js and simplified a bit. Now the backend also sends with wines to pick from. When hitting the controller we check that the user is the next user in line.
This commit is contained in:
90
api/controllers/prizeDistributionController.js
Normal file
90
api/controllers/prizeDistributionController.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const prizeDistribution = require(path.join(__dirname, "../prizeDistribution"));
|
||||||
|
const winner = require(path.join(__dirname, "../winner"));
|
||||||
|
const message = require(path.join(__dirname, "../message"));
|
||||||
|
|
||||||
|
const start = async (req, res) => {
|
||||||
|
const allWinners = await winners.allWinners();
|
||||||
|
if (allWinners.length === 0) {
|
||||||
|
return res.status(503).send({
|
||||||
|
message: "No winners left.",
|
||||||
|
success: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const laterWinners = allWinners.slice(1);
|
||||||
|
|
||||||
|
return prizeDistribution
|
||||||
|
.notifyNextWinner()
|
||||||
|
.then(_ => message.sendInitialMessageToWinners(laterWinners))
|
||||||
|
.then(_ =>
|
||||||
|
res.send({
|
||||||
|
message: `Send link to first winner and notified everyone else.`,
|
||||||
|
success: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
const { statusCode, message } = error;
|
||||||
|
|
||||||
|
return res.status(statusCode || 500).send({
|
||||||
|
message: message || "Unexpected error occured while starting prize distribution.",
|
||||||
|
success: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPrizesForWinnerById = (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
return prizeDistribution
|
||||||
|
.verifyWinnerNextInLine(id)
|
||||||
|
.then(_ => lottery.allWines())
|
||||||
|
.then(wines =>
|
||||||
|
res.send({
|
||||||
|
wines: wines,
|
||||||
|
message: "Wines to select from",
|
||||||
|
success: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
const { statusCode, message } = error;
|
||||||
|
|
||||||
|
return res.status(statusCode || 500).send({
|
||||||
|
message: message || "Unexpected error occured while fetching prizes.",
|
||||||
|
success: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitPrizeForWinnerById = async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
const { wine } = req.body;
|
||||||
|
|
||||||
|
const winner = await prizeDistribution.verifyWinnerNextInLine(id);
|
||||||
|
const prelotteryWine = await lottery.wineById(wine.id);
|
||||||
|
|
||||||
|
return prizeDistribution
|
||||||
|
.claimPrize(winner, prelotteryWine)
|
||||||
|
.then(_ => prizeDistribution.notifyNextWinner())
|
||||||
|
.then(_ =>
|
||||||
|
res.send({
|
||||||
|
message: `${winner.name} successfully claimed prize: ${wine.name}`,
|
||||||
|
success: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
const { statusCode, message } = error;
|
||||||
|
|
||||||
|
return res.status(statusCode || 500).send({
|
||||||
|
message: message || "Unexpected error occured while claiming prize.",
|
||||||
|
success: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
start,
|
||||||
|
getPrizesForWinnerById,
|
||||||
|
submitPrizeForWinnerById
|
||||||
|
};
|
||||||
109
api/prizeDistribution.js
Normal file
109
api/prizeDistribution.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
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 highscoreRepository = require(path.join(__dirname, "/winner"));
|
||||||
|
const wineRepository = require(path.join(__dirname, "/wine"));
|
||||||
|
const lottery = require(path.join(__dirname, "/lottery"));
|
||||||
|
|
||||||
|
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 (
|
||||||
|
allWinners[0].id != foundWinner.id ||
|
||||||
|
foundWinner.timestamp_limit == undefined ||
|
||||||
|
foundWinner.timestamp_sent == undefined
|
||||||
|
) {
|
||||||
|
throw new WineSelectionWinnerNotNextInLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(foundWinner);
|
||||||
|
};
|
||||||
|
|
||||||
|
const claimPrize = (winner, wine) => {
|
||||||
|
return wineRepository
|
||||||
|
.addWine(wine)
|
||||||
|
.then(_ => lottery.deleteWineById(wine.id)) // prelotteryWine.deleteById
|
||||||
|
.then(_ => highscoreRepository.addWinnerWithWine(winner, wine)) // wines.js : addWine
|
||||||
|
.then(_ => lottery.addWinnerWithWine(winner, wine))
|
||||||
|
.then(_ => message.sendWineConfirmation(winner, wine));
|
||||||
|
};
|
||||||
|
|
||||||
|
const notifyNextWinner = async () => {
|
||||||
|
let nextWinner = undefined;
|
||||||
|
|
||||||
|
const winnersLeft = await VirtualWinner.find().sort({ timestamp_drawn: 1 });
|
||||||
|
const winesLeft = await PreLotteryWine.find();
|
||||||
|
|
||||||
|
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(nextWinner, wine);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 });
|
||||||
|
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();
|
||||||
|
|
||||||
|
findAndNotifyNextWinner();
|
||||||
|
}, minutesForTimeout * minute);
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
verifyWinnerNextInLine,
|
||||||
|
claimPrize,
|
||||||
|
notifyNextWinner
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user