From ce480e790a3c2c04f25f8a74eca953c1277eaba4 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Tue, 26 Jan 2021 23:01:49 +0100 Subject: [PATCH] Replaced for clearer project structure & new ctrls. These files where directly called from the api endpoints. Now all functoins have been replaced with a controller interfacing to the endpoint and a repository file for each of the functions. --- api/retrieve.js | 154 -------------------- api/update.js | 142 ------------------- api/virtualLottery.js | 281 ------------------------------------- api/virtualRegistration.js | 200 -------------------------- 4 files changed, 777 deletions(-) delete mode 100644 api/retrieve.js delete mode 100644 api/update.js delete mode 100644 api/virtualLottery.js delete mode 100644 api/virtualRegistration.js diff --git a/api/retrieve.js b/api/retrieve.js deleted file mode 100644 index c29133a..0000000 --- a/api/retrieve.js +++ /dev/null @@ -1,154 +0,0 @@ -const path = require("path"); - -const Purchase = require(path.join(__dirname, "/schemas/Purchase")); -const Wine = require(path.join(__dirname, "/schemas/Wine")); -const Highscore = require(path.join(__dirname, "/schemas/Highscore")); -const PreLotteryWine = require(path.join( - __dirname, "/schemas/PreLotteryWine" -)); - -const prelotteryWines = async (req, res) => { - let wines = await PreLotteryWine.find(); - return res.json(wines); -}; - -const allPurchase = async (req, res) => { - let purchases = await Purchase.find() - .populate("wines") - .sort({ date: 1 }); - return res.json(purchases); -}; - -const purchaseByColor = async (req, res) => { - const countColor = await Purchase.find(); - let red = 0; - let blue = 0; - let yellow = 0; - let green = 0; - let stolen = 0; - for (let i = 0; i < countColor.length; i++) { - let element = countColor[i]; - red += element.red; - blue += element.blue; - yellow += element.yellow; - green += element.green; - if (element.stolen != undefined) { - stolen += element.stolen; - } - } - - const highscore = await Highscore.find(); - let redWin = 0; - let blueWin = 0; - let yellowWin = 0; - let greenWin = 0; - for (let i = 0; i < highscore.length; i++) { - let element = highscore[i]; - for (let y = 0; y < element.wins.length; y++) { - let currentWin = element.wins[y]; - switch (currentWin.color) { - case "blue": - blueWin += 1; - break; - case "red": - redWin += 1; - break; - case "yellow": - yellowWin += 1; - break; - case "green": - greenWin += 1; - break; - } - } - } - - const total = red + yellow + blue + green; - - return res.json({ - red: { - total: red, - win: redWin - }, - blue: { - total: blue, - win: blueWin - }, - green: { - total: green, - win: greenWin - }, - yellow: { - total: yellow, - win: yellowWin - }, - stolen: stolen, - total: total - }); -}; - -const highscore = async (req, res) => { - const highscore = await Highscore.find().populate("wins.wine"); - - return res.json(highscore); -}; - -const allWines = async (req, res) => { - const wines = await Wine.find(); - - return res.json(wines); -}; - -const allWinesSummary = async (req, res) => { - const highscore = await Highscore.find().populate("wins.wine"); - let wines = {}; - - for (let i = 0; i < highscore.length; i++) { - let person = highscore[i]; - for (let y = 0; y < person.wins.length; y++) { - let wine = person.wins[y].wine; - let date = person.wins[y].date; - let color = person.wins[y].color; - - if (wines[wine._id] == undefined) { - wines[wine._id] = { - name: wine.name, - occurences: wine.occurences, - vivinoLink: wine.vivinoLink, - rating: wine.rating, - image: wine.image, - id: wine.id, - _id: wine._id, - dates: [date], - winners: [person.name], - red: 0, - blue: 0, - green: 0, - yellow: 0 - }; - wines[wine._id][color] += 1; - } else { - wines[wine._id].dates.push(date); - wines[wine._id].winners.push(person.name); - if (wines[wine._id][color] == undefined) { - wines[wine._id][color] = 1; - } else { - wines[wine._id][color] += 1; - } - } - } - } - - wines = Object.values(wines).reverse() - - return res.json(wines); -}; - -module.exports = { - prelotteryWines, - allPurchase, - purchaseByColor, - highscore, - allWines, - allWinesSummary -}; diff --git a/api/update.js b/api/update.js deleted file mode 100644 index 88df56a..0000000 --- a/api/update.js +++ /dev/null @@ -1,142 +0,0 @@ -const express = require("express"); -const path = require("path"); - -const sub = require(path.join(__dirname, "/subscriptions")); - -const _wineFunctions = require(path.join(__dirname, "/wine")); -const _personFunctions = require(path.join(__dirname, "/person")); -const Subscription = require(path.join(__dirname, "/schemas/Subscription")); -const Lottery = require(path.join(__dirname, "/schemas/Purchase")); -const PreLotteryWine = require(path.join( - __dirname, "/schemas/PreLotteryWine" -)); - -const submitWines = async (req, res) => { - const wines = req.body; - for (let i = 0; i < wines.length; i++) { - let wine = wines[i]; - let newWonWine = new PreLotteryWine({ - name: wine.name, - vivinoLink: wine.vivinoLink, - rating: wine.rating, - image: wine.image, - price: wine.price, - country: wine.country, - id: wine.id - }); - await newWonWine.save(); - } - - let subs = await Subscription.find(); - console.log("Sending new wines w/ push notification to all subscribers.") - for (let i = 0; i < subs.length; i++) { - let subscription = subs[i]; //get subscription from your databse here. - - const message = JSON.stringify({ - message: "Dagens vin er lagt til, se den på lottis.vin/dagens!", - title: "Ny vin!", - link: "/#/dagens" - }); - - try { - sub.sendNotification(subscription, message); - } catch (error) { - console.error("Error when trying to send push notification to subscriber."); - console.error(error); - } - } - - return res.send({ - message: "Submitted and notified push subscribers of new wines!", - success: true - }); -}; - -const schema = async (req, res) => { - let schema = { ...PreLotteryWine.schema.obj }; - let nulledSchema = Object.keys(schema).reduce((accumulator, current) => { - accumulator[current] = ""; - return accumulator - }, {}); - - return res.send(nulledSchema); -} - -// TODO IMPLEMENT WITH FRONTEND (unused) -const submitWinesToLottery = async (req, res) => { - const { lottery } = req.body; - const { date, wines } = lottery; - const wineObjects = await Promise.all(wines.map(async (wine) => await _wineFunctions.findSaveWine(wine))) - - return Lottery.findOneAndUpdate({ date: date }, { - date: date, - wines: wineObjects - }, { - upsert: true - }).then(_ => res.send(true)) - .catch(err => res.status(500).send({ message: 'Unexpected error while updating/saving wine to lottery.', - success: false, - exception: err.message })); -} - - /** - * @apiParam (Request body) {Array} winners List of winners - */ -const submitWinnersToLottery = async (req, res) => { - const { lottery } = req.body; - const { winners, date } = lottery; - - for (let i = 0; i < winners.length; i++) { - let currentWinner = winners[i]; - let wonWine = await _wineFunctions.findSaveWine(currentWinner.wine); // TODO rename to findAndSaveWineToLottery - await _personFunctions.findSavePerson(currentWinner, wonWine, date); // TODO rename to findAndSaveWineToPerson - } - - return res.json(true); -} - - /** - * @apiParam (Request body) {Date} date Date of lottery - * @apiParam (Request body) {Number} blue Number of blue tickets - * @apiParam (Request body) {Number} red Number of red tickets - * @apiParam (Request body) {Number} green Number of green tickets - * @apiParam (Request body) {Number} yellow Number of yellow tickets - * @apiParam (Request body) {Number} bought Number of tickets bought - * @apiParam (Request body) {Number} stolen Number of tickets stolen - */ -const submitLottery = async (req, res) => { - const { lottery } = req.body - - const { date, - blue, - red, - yellow, - green, - bought, - stolen } = lottery; - - return Lottery.findOneAndUpdate({ date: date }, { - date: date, - blue: blue, - yellow: yellow, - red: red, - green: green, - bought: bought, - stolen: stolen - }, { - upsert: true - }).then(_ => res.send(true)) - .catch(err => res.status(500).send({ message: 'Unexpected error while updating/saving lottery.', - success: false, - exception: err.message })); - - return res.send(true); -}; - -module.exports = { - submitWines, - schema, - submitLottery, - submitWinnersToLottery, - submitWinesToLottery -}; diff --git a/api/virtualLottery.js b/api/virtualLottery.js deleted file mode 100644 index 706016b..0000000 --- a/api/virtualLottery.js +++ /dev/null @@ -1,281 +0,0 @@ -const path = require("path"); -const crypto = require("crypto"); - -const config = require(path.join(__dirname, "/../config/defaults/lottery")); -const Message = require(path.join(__dirname, "/message")); -const { findAndNotifyNextWinner } = require(path.join(__dirname, "/virtualRegistration")); - -const Attendee = require(path.join(__dirname, "/schemas/Attendee")); -const VirtualWinner = require(path.join(__dirname, "/schemas/VirtualWinner")); -const PreLotteryWine = require(path.join(__dirname, "/schemas/PreLotteryWine")); - - -const winners = async (req, res) => { - let winners = await VirtualWinner.find(); - let winnersRedacted = []; - let winner; - for (let i = 0; i < winners.length; i++) { - winner = winners[i]; - winnersRedacted.push({ - name: winner.name, - color: winner.color - }); - } - res.json(winnersRedacted); -}; - -const winnersSecure = async (req, res) => { - let winners = await VirtualWinner.find(); - - return res.json(winners); -}; - -const deleteWinners = async (req, res) => { - await VirtualWinner.deleteMany(); - var io = req.app.get('socketio'); - io.emit("refresh_data", {}); - return res.json(true); -}; - -const attendees = async (req, res) => { - let attendees = await Attendee.find(); - let attendeesRedacted = []; - let attendee; - for (let i = 0; i < attendees.length; i++) { - attendee = attendees[i]; - attendeesRedacted.push({ - name: attendee.name, - raffles: attendee.red + attendee.blue + attendee.yellow + attendee.green, - red: attendee.red, - blue: attendee.blue, - green: attendee.green, - yellow: attendee.yellow - }); - } - return res.json(attendeesRedacted); -}; - -const attendeesSecure = async (req, res) => { - let attendees = await Attendee.find(); - - return res.json(attendees); -}; - -const addAttendee = async (req, res) => { - const attendee = req.body; - const { red, blue, yellow, green } = attendee; - - let newAttendee = new Attendee({ - name: attendee.name, - red, - blue, - green, - yellow, - phoneNumber: attendee.phoneNumber, - winner: false - }); - await newAttendee.save(); - - - var io = req.app.get('socketio'); - io.emit("new_attendee", {}); - - return res.send(true); -}; - -const deleteAttendees = async (req, res) => { - await Attendee.deleteMany(); - var io = req.app.get('socketio'); - io.emit("refresh_data", {}); - return res.json(true); -}; - -const drawWinner = async (req, res) => { - let allContestants = await Attendee.find({ winner: false }); - - if (allContestants.length == 0) { - return res.json({ - success: false, - message: "No attendees left that have not won." - }); - } - 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) { - return res.status(404).send({ - success: false, - message: `Klarte ikke trekke en vinner etter ${maxTries} forsøk.` - }); - } - - 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 - }); - - var io = req.app.get('socketio'); - io.emit("winner", { - color: colorToChooseFrom, - name: winner.name, - winner_count: winners.length + 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 Attendee.update( - { name: winner.name, phoneNumber: winner.phoneNumber }, - { $set: { winner: true } } - ); - - await newWinnerElement.save(); - return res.json({ - success: true, - winner - }); -}; - -const finish = async (req, res) => { - if (!config.gatewayToken) { - return res.json({ - message: "Missing api token for sms gateway.", - success: false - }); - } - - let winners = await VirtualWinner.find({ timestamp_sent: undefined }).sort({ - timestamp_drawn: 1 - }); - - if (winners.length == 0) { - return res.json({ - message: "No winners to draw from.", - success: false - }); - } - - Message.sendInitialMessageToWinners(winners.slice(1)); - - return findAndNotifyNextWinner() - .then(() => res.json({ - success: true, - message: "Sent wine select message to first winner and update message to rest of winners." - })) - .catch(error => res.json({ - message: error["message"] || "Unable to send message to first winner.", - success: false - })) -}; - -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 = { - deleteWinners, - deleteAttendees, - winners, - winnersSecure, - drawWinner, - finish, - attendees, - attendeesSecure, - addAttendee -} - diff --git a/api/virtualRegistration.js b/api/virtualRegistration.js deleted file mode 100644 index ec869a3..0000000 --- a/api/virtualRegistration.js +++ /dev/null @@ -1,200 +0,0 @@ -const path = require("path"); - -const _wineFunctions = require(path.join(__dirname, "/wine")); -const _personFunctions = require(path.join(__dirname, "/person")); -const Message = require(path.join(__dirname, "/message")); -const VirtualWinner = require(path.join( - __dirname, "/schemas/VirtualWinner" -)); -const PreLotteryWine = require(path.join( - __dirname, "/schemas/PreLotteryWine" -)); - - -const getWinesToWinnerById = async (req, res) => { - let id = req.params.id; - let foundWinner = await VirtualWinner.findOne({ id: id }); - - if (!foundWinner) { - return res.json({ - success: false, - message: "No winner with this id.", - existing: false, - turn: false - }); - } - - let allWinners = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); - if ( - allWinners[0].id != foundWinner.id || - foundWinner.timestamp_limit == undefined || - foundWinner.timestamp_sent == undefined - ) { - return res.json({ - success: false, - message: "Not the winner next in line!", - existing: true, - turn: false - }); - } - - return res.json({ - success: true, - existing: true, - turn: true, - name: foundWinner.name, - color: foundWinner.color - }); -}; - -const registerWinnerSelection = async (req, res) => { - let id = req.params.id; - let wineName = req.body.wineName; - let foundWinner = await VirtualWinner.findOne({ id: id }); - - if (!foundWinner) { - return res.json({ - success: false, - message: "No winner with this id." - }) - } else if (foundWinner.timestamp_limit < new Date().getTime()) { - return res.json({ - success: false, - message: "Timelimit expired, you will receive a wine after other users have chosen.", - limit: true - }) - } - - let date = new Date(); - date.setHours(5, 0, 0, 0); - let prelotteryWine = await PreLotteryWine.findOne({ name: wineName }); - - if (!prelotteryWine) { - return res.json({ - success: false, - message: "No wine with this name.", - wine: false - }); - } - - let wonWine = await _wineFunctions.findSaveWine(prelotteryWine); - await prelotteryWine.delete(); - await _personFunctions.findSavePerson(foundWinner, wonWine, date); - await Message.sendWineConfirmation(foundWinner, wonWine, date); - - await foundWinner.delete(); - console.info("Saved winners choice."); - - return findAndNotifyNextWinner() - .then(() => res.json({ - message: "Choice saved and next in line notified.", - success: true - })) - .catch(error => res.json({ - message: error["message"] || "Error when notifing next winner.", - success: false - })) -}; - -const chooseLastWineForUser = (winner, preLotteryWine) => { - let date = new Date(); - date.setHours(5, 0, 0, 0); - - return _wineFunctions.findSaveWine(preLotteryWine) - .then(wonWine => _personFunctions.findSavePerson(winner, wonWine, date)) - .then(() => preLotteryWine.delete()) - .then(() => Message.sendLastWinnerMessage(winner, preLotteryWine)) - .then(() => winner.delete()) - .catch(err => { - console.log("Error thrown from chooseLastWineForUser: " + err); - throw err; - }) -} - -const findAndNotifyNextWinner = async () => { - let nextWinner = undefined; - - let winnersLeft = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); - let 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 chooseLastWineForUser(nextWinner, wine); - } - - if (nextWinner) { - return Message.sendWineSelectMessage(nextWinner) - .then(messageResponse => startTimeout(nextWinner.id)) - } else { - console.info("All winners notified. Could start cleanup here."); - return Promise.resolve({ - message: "All winners notified." - }) - } -}; - -const sendNotificationToWinnerById = async (req, res) => { - const { id } = req.params; - let winner = await VirtualWinner.findOne({ id: id }); - - if (!winner) { - return res.json({ - message: "No winner with this id.", - success: false - }) - } - - return Message.sendWineSelectMessage(winner) - .then(success => res.json({ - success: success, - message: `Message sent to winner ${id} successfully!` - })) - .catch(err => res.json({ - success: false, - message: "Error while trying to send sms.", - error: err - })) -} - -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 = { - getWinesToWinnerById, - registerWinnerSelection, - findAndNotifyNextWinner, - - sendNotificationToWinnerById -};