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:
		
							
								
								
									
										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