fix conflicts and rework routes

This commit is contained in:
Adrian Thompson
2020-09-07 14:49:24 +02:00
27 changed files with 6208 additions and 4055 deletions

View File

@@ -1,21 +1,13 @@
const express = require('express');
const path = require('path'); const path = require('path');
const router = express.Router();
const mongoose = require('mongoose'); const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/vinlottis', { mongoose.connect('mongodb://localhost:27017/vinlottis', {
useNewUrlParser: true useNewUrlParser: true
}) })
const mustBeAuthenticated = require(path.join(
__dirname + '/../middleware/mustBeAuthenticated'
));
const config = require(path.join(__dirname + '/../config/defaults/lottery'));
const Highscore = require(path.join(__dirname + '/../schemas/Highscore')); const Highscore = require(path.join(__dirname + '/../schemas/Highscore'));
const Wine = require(path.join(__dirname + '/../schemas/Wine')); const Wine = require(path.join(__dirname + '/../schemas/Wine'));
// Utils // Utils
const epochToDateString = date => new Date(parseInt(date)).toDateString(); const epochToDateString = date => new Date(parseInt(date)).toDateString();
@@ -62,7 +54,7 @@ const resolveWineReferences = listWithWines => {
} }
// Routes // Routes
router.route('/all').get((req, res) => { const all = (req, res) => {
return Highscore.find() return Highscore.find()
.then(highscore => getHighscoreByDates(highscore)) .then(highscore => getHighscoreByDates(highscore))
.then(groupedLotteries => groupedHighscoreToSortedList(groupedLotteries)) .then(groupedLotteries => groupedHighscoreToSortedList(groupedLotteries))
@@ -70,9 +62,19 @@ router.route('/all').get((req, res) => {
message: "Lotteries by date!", message: "Lotteries by date!",
lotteries lotteries
})) }))
}) }
router.route('/by-date/:date').get((req, res) => { const latest = (req, res) => {
return Highscore.find()
.then(highscore => getHighscoreByDates(highscore))
.then(groupedLotteries => groupedHighscoreToSortedList(groupedLotteries))
.then(lotteries => res.send({
message: "Latest lottery!",
lottery: lotteries.slice(-1).pop()
}))
}
const byEpochDate = (req, res) => {
const { date } = req.params; const { date } = req.params;
const dateString = epochToDateString(date); const dateString = epochToDateString(date);
@@ -92,10 +94,10 @@ router.route('/by-date/:date').get((req, res) => {
}) })
} }
}) })
}) }
router.route("/by-name").get((req, res) => { const byName = (req, res) => {
const { name } = req.query; const { name } = req.params;
return Highscore.find({ name }) return Highscore.find({ name })
.then(async (highscore) => { .then(async (highscore) => {
@@ -113,6 +115,11 @@ router.route("/by-name").get((req, res) => {
}) })
} }
}) })
}) }
module.exports = router; module.exports = {
all,
latest,
byEpochDate,
byName
};

View File

@@ -1,92 +1,109 @@
const request = require("request"); const https = require("https");
const path = require("path"); const path = require("path");
const config = require(path.join(__dirname + "/../config/defaults/lottery")); const config = require(path.join(__dirname + "/../config/defaults/lottery"));
async function sendMessage(winnerObject) { async function sendWineSelectMessage(winnerObject) {
winnerObject.timestamp_sent = new Date().getTime(); winnerObject.timestamp_sent = new Date().getTime();
winnerObject.timestamp_limit = new Date().getTime() * 600000; winnerObject.timestamp_limit = new Date().getTime() * 600000;
await winnerObject.save(); await winnerObject.save();
let url = new URL(`/#/winner/${winnerObject.id}`, "https://lottis.vin"); let url = new URL(`/#/winner/${winnerObject.id}`, "https://lottis.vin");
await sendMessageToUser( return sendMessageToUser(
winnerObject.phoneNumber, winnerObject.phoneNumber,
`Gratulerer som heldig vinner av vinlotteriet ${winnerObject.name}! Her er linken for å velge hva slags vin du vil ha, du har 10 minutter på å velge ut noe før du blir lagt bakerst i køen. ${url.href}. (Hvis den siden kommer opp som tom må du prøve å refreshe siden noen ganger.)` `Gratulerer som heldig vinner av vinlotteriet ${winnerObject.name}! Her er linken for å velge hva slags vin du vil ha, du har 10 minutter på å velge ut noe før du blir lagt bakerst i køen. ${url.href}. (Hvis den siden kommer opp som tom må du prøve å refreshe siden noen ganger.)`
); )
return true;
} }
async function sendWonWineMessage(winnerObject, wineObject) { async function sendLastWinnerMessage(winnerObject, wineObject) {
console.log( console.log(`User ${winnerObject.id} is only one left, chosing wine for him/her.`);
`User ${winnerObject.id} is only one left, chosing wine for him/her.`
);
winnerObject.timestamp_sent = new Date().getTime(); winnerObject.timestamp_sent = new Date().getTime();
winnerObject.timestamp_limit = new Date().getTime(); winnerObject.timestamp_limit = new Date().getTime();
await winnerObject.save(); await winnerObject.save();
await sendMessageToUser( return sendMessageToUser(
winnerObject.phoneNumber, winnerObject.phoneNumber,
`Gratulerer som heldig vinner av vinlotteriet ${winnerObject.name}! Du har vunnet vinen ${wineObject.name}, og vil få nærmere info om hvordan/hvor du kan hente vinen snarest. Ha en ellers fin helg!` `Gratulerer som heldig vinner av vinlotteriet ${winnerObject.name}! Du har vunnet vinen ${wineObject.name}, og vil få nærmere info om hvordan/hvor du kan hente vinen snarest. Ha en ellers fin helg!`
); );
return true;
} }
async function sendMessageTooLate(winnerObject) { async function sendWineSelectMessageTooLate(winnerObject) {
await sendMessageToUser( return sendMessageToUser(
winnerObject.phoneNumber, winnerObject.phoneNumber,
`Hei ${winnerObject.name}, du har dessverre brukt mer enn 10 minutter på å velge premie og blir derfor puttet bakerst i køen. Du vil få en ny SMS når det er din tur igjen.` `Hei ${winnerObject.name}, du har dessverre brukt mer enn 10 minutter på å velge premie og blir derfor puttet bakerst i køen. Du vil få en ny SMS når det er din tur igjen.`
); );
} }
async function sendMessageToUser(phoneNumber, message) { async function sendMessageToUser(phoneNumber, message) {
try { console.log(`Attempting to send message to ${ phoneNumber }.`)
request.post(
{ const body = {
url: `https://gatewayapi.com/rest/mtsms?token=${config.gatewayToken}`, sender: "Vinlottis",
json: true, message: message,
body: { recipients: [{ msisdn: `47${ phoneNumber }`}]
sender: "Vinlottis", };
message: message,
recipients: [{ msisdn: `47${phoneNumber}` }] return gatewayRequest(body);
}
},
function(err, r, body) {
console.log(err ? err : body);
if(err) {
console.log(phoneNumber, message);
}
}
);
} catch(e) {
console.log(phoneNumber, message);
}
} }
async function sendUpdate(winners) {
async function sendInitialMessageToWinners(winners) {
let numbers = []; let numbers = [];
for (let i = 0; i < winners.length; i++) { for (let i = 0; i < winners.length; i++) {
numbers.push({ msisdn: `47${winners[i].phoneNumber}` }); numbers.push({ msisdn: `47${winners[i].phoneNumber}` });
} }
request.post(
{ const body = {
url: `https://gatewayapi.com/rest/mtsms?token=${config.gatewayToken}`, sender: "Vinlottis",
json: true, message:
body: { "Gratulerer som vinner av vinlottisen! Du vil snart få en SMS med oppdatering om hvordan gangen går!",
sender: "Vinlottis", recipients: numbers
message: }
"Gratulerer som vinner av vinlottisen! Du vil snart få en SMS med oppdatering om hvordan gangen går!",
recipients: numbers return gatewayRequest(body);
}
},
function(err, r, body) {
console.log(err ? err : body);
}
);
} }
module.exports.sendUpdate = sendUpdate; async function gatewayRequest(body) {
module.exports.sendMessage = sendMessage; return new Promise((resolve, reject) => {
module.exports.sendMessageTooLate = sendMessageTooLate; const options = {
module.exports.sendWonWineMessage = sendWonWineMessage; hostname: "gatewayapi.com",
post: 443,
path: `/rest/mtsms?token=${ config.gatewayToken }`,
method: "POST",
headers: {
"Content-Type": "application/json"
}
}
const req = https.request(options, (res) => {
console.log(`statusCode: ${ res.statusCode }`);
console.log(`statusMessage: ${ res.statusMessage }`);
res.setEncoding('utf8');
if (res.statusCode == 200) {
res.on("data", (d) => resolve(JSON.parse(d)));
} else {
res.on("data", (data) => {
data = JSON.parse(data);
return reject('Gateway error: ' + data['message'] || data)
});
}
})
req.on("error", (error) => {
console.error(`Error from sms service: ${ error }`);
reject(`Error from sms service: ${ error }`);
})
req.write(JSON.stringify(body));
req.end();
});
}
module.exports = {
sendWineSelectMessage,
sendLastWinnerMessage,
sendWineSelectMessageTooLate,
sendInitialMessageToWinners
}

View File

@@ -1,43 +1,41 @@
const express = require("express"); const express = require("express");
const path = require("path"); const path = require("path");
const router = express.Router();
const fetch = require('node-fetch');
const { send } = require("process");
const RequestedWine = require(path.join( const RequestedWine = require(path.join(
__dirname + "/../schemas/RequestedWine" __dirname + "/../schemas/RequestedWine"
)); ));
const Wine = require(path.join( const Wine = require(path.join(
__dirname + "/../schemas/Wine" __dirname + "/../schemas/Wine"
)); ));
const mustBeAuthenticated = require(path.join(
__dirname + "/../middleware/mustBeAuthenticated"
));
router.use((req, res, next) => { const deleteRequestedWineById = async (req, res) => {
next(); const { id } = req.params;
}); if(id == null){
return res.json({
message: "Id er ikke definert",
success: false
})
}
router.route("/request/").delete(mustBeAuthenticated, async (req, res) => { await RequestedWine.deleteOne({wineId: id})
await RequestedWine.deleteOne({wineId: req.body.id}) return res.json({
res.json(true); message: `Slettet vin med id: ${id}`,
}) success: true
});
}
router.route("/request").get(async (req, res) => { const getAllRequestedWines = async (req, res) => {
const rWines = await RequestedWine.find({}).populate("wine")
return res.send(rWines)
})
router.route("/request/all").get(async (req, res) => {
const allWines = await RequestedWine.find({}).populate("wine"); const allWines = await RequestedWine.find({}).populate("wine");
return res.json(allWines);
}
res.json(allWines); const requestNewWine = async (req, res) => {
});
router.route("/request").post(async (req, res) => {
const {wine} = req.body const {wine} = req.body
console.log(req.body)
let thisWineIsLOKO = await Wine.findOne({id: wine.id}) let thisWineIsLOKO = await Wine.findOne({id: wine.id})
if(thisWineIsLOKO == undefined){ if(thisWineIsLOKO == undefined){
thisWineIsLOKO = new Wine({ thisWineIsLOKO = new Wine({
name: wine.name, name: wine.name,
@@ -49,7 +47,7 @@ router.route("/request").post(async (req, res) => {
}); });
await thisWineIsLOKO.save() await thisWineIsLOKO.save()
} }
let requestedWine = await RequestedWine.findOne({ "wineId": wine.id}) let requestedWine = await RequestedWine.findOne({ "wineId": wine.id})
if(requestedWine == undefined){ if(requestedWine == undefined){
@@ -62,9 +60,12 @@ router.route("/request").post(async (req, res) => {
requestedWine.count += 1; requestedWine.count += 1;
} }
await requestedWine.save() await requestedWine.save()
return res.send(requestedWine);
}
res.send(requestedWine); module.exports = {
requestNewWine,
}); getAllRequestedWines,
deleteRequestedWineById
module.exports = router; };

View File

@@ -1,6 +1,6 @@
const express = require("express"); const express = require("express");
const path = require("path"); const path = require("path");
const router = express.Router(); // const router = express.Router();
const mongoose = require("mongoose"); const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/vinlottis", { mongoose.connect("mongodb://localhost:27017/vinlottis", {
useNewUrlParser: true useNewUrlParser: true
@@ -13,23 +13,19 @@ const PreLotteryWine = require(path.join(
__dirname + "/../schemas/PreLotteryWine" __dirname + "/../schemas/PreLotteryWine"
)); ));
router.use((req, res, next) => { const prelotteryWines = async (req, res) => {
next();
});
router.route("/wines/prelottery").get(async (req, res) => {
let wines = await PreLotteryWine.find(); let wines = await PreLotteryWine.find();
res.json(wines); return res.json(wines);
}); };
router.route("/purchase/statistics").get(async (req, res) => { const allPurchase = async (req, res) => {
let purchases = await Purchase.find() let purchases = await Purchase.find()
.populate("wines") .populate("wines")
.sort({ date: 1 }); .sort({ date: 1 });
res.json(purchases); return res.json(purchases);
}); };
router.route("/purchase/statistics/color").get(async (req, res) => { const purchaseByColor = async (req, res) => {
const countColor = await Purchase.find(); const countColor = await Purchase.find();
let red = 0; let red = 0;
let blue = 0; let blue = 0;
@@ -75,7 +71,7 @@ router.route("/purchase/statistics/color").get(async (req, res) => {
const total = red + yellow + blue + green; const total = red + yellow + blue + green;
res.json({ return res.json({
red: { red: {
total: red, total: red,
win: redWin win: redWin
@@ -95,22 +91,21 @@ router.route("/purchase/statistics/color").get(async (req, res) => {
stolen: stolen, stolen: stolen,
total: total total: total
}); });
}); };
router.route("/highscore/statistics").get(async (req, res) => { const highscore = async (req, res) => {
const highscore = await Highscore.find().populate("wins.wine"); const highscore = await Highscore.find().populate("wins.wine");
res.json(highscore); return res.json(highscore);
}); };
const allWines = async (req, res) => {
router.route("/wines/statistics").get(async (req, res) => {
const wines = await Wine.find(); const wines = await Wine.find();
res.json(wines); return res.json(wines);
}); };
router.route("/wines/statistics/overall").get(async (req, res) => { const allWinesSummary = async (req, res) => {
const highscore = await Highscore.find().populate("wins.wine"); const highscore = await Highscore.find().populate("wins.wine");
let wines = {}; let wines = {};
@@ -150,7 +145,14 @@ router.route("/wines/statistics/overall").get(async (req, res) => {
} }
} }
res.json(Object.values(wines)); return res.json(Object.values(wines));
}); };
module.exports = router; module.exports = {
prelotteryWines,
allPurchase,
purchaseByColor,
highscore,
allWines,
allWinesSummary
};

69
api/router.js Normal file
View File

@@ -0,0 +1,69 @@
const express = require("express");
const path = require("path");
// Middleware
const mustBeAuthenticated = require(__dirname + "/../middleware/mustBeAuthenticated");
const update = require(path.join(__dirname + "/update"));
const retrieve = require(path.join(__dirname + "/retrieve"));
const request = require(path.join(__dirname + "/request"));
const subscriptionApi = require(path.join(__dirname + "/subscriptions"));
const loginApi = require(path.join(__dirname + "/login"));
const wineinfo = require(path.join(__dirname + "/wineinfo"));
const virtualApi = require(path.join(__dirname + "/virtualLottery"));
const virtualRegistrationApi = require(path.join(
__dirname + "/virtualRegistration"
));
const lottery = require(path.join(__dirname + "/lottery"));
const router = express.Router();
router.get("/wineinfo/search", wineinfo.wineSearch);
router.get("/request/all", request.getAllRequestedWines);
router.post("/request/new-wine", request.requestNewWine);
router.delete("/request/:id", request.deleteRequestedWineById);
router.get("/wineinfo/schema", mustBeAuthenticated, update.schema);
router.get("/wineinfo/:ean", wineinfo.byEAN);
router.post("/log/wines", mustBeAuthenticated, update.submitWines);
router.post("/lottery", update.submitLottery);
router.post("/lottery/wines", update.submitWinesToLottery);
// router.delete("/lottery/wine/:id", update.deleteWineFromLottery);
router.post("/lottery/winners", update.submitWinnersToLottery);
router.get("/wines/prelottery", retrieve.prelotteryWines);
router.get("/purchase/statistics", retrieve.allPurchase);
router.get("/purchase/statistics/color", retrieve.purchaseByColor);
router.get("/highscore/statistics", retrieve.highscore)
router.get("/wines/statistics", retrieve.allWines);
router.get("/wines/statistics/overall", retrieve.allWinesSummary);
router.get("/lottery/all", lottery.all);
router.get("/lottery/latest", lottery.latest);
router.get("/lottery/by-date/:date", lottery.byEpochDate);
router.get("/lottery/by-name/:name", lottery.byName);
router.delete('/virtual/winner/all', mustBeAuthenticated, virtualApi.deleteWinners);
router.delete('/virtual/attendee/all', mustBeAuthenticated, virtualApi.deleteAttendees);
router.get('/virtual/winner/draw', virtualApi.drawWinner);
router.get('/virtual/winner/all', virtualApi.winners);
router.get('/virtual/winner/all/secure', mustBeAuthenticated, virtualApi.winnersSecure);
router.post('/virtual/finish', mustBeAuthenticated, virtualApi.finish);
router.get('/virtual/attendee/all', virtualApi.attendees);
router.get('/virtual/attendee/all/secure', mustBeAuthenticated, virtualApi.attendeesSecure);
router.post('/virtual/attendee/add', mustBeAuthenticated, virtualApi.addAttendee);
router.post('/winner/notify/:id', virtualRegistrationApi.sendNotificationToWinnerById);
router.get('/winner/:id', virtualRegistrationApi.getWinesToWinnerById);
router.post('/winner/:id', virtualRegistrationApi.registerWinnerSelection);
// router.use("/api/", updateApi);
// router.use("/api/", retrieveApi);
// router.use("/api/", wineinfoApi);
// router.use("/api/lottery", lottery);
// router.use("/virtual-registration/", virtualRegistrationApi);
module.exports = router;

View File

@@ -1,29 +1,21 @@
const express = require("express"); const express = require("express");
const path = require("path"); const path = require("path");
const router = express.Router();
const mongoose = require("mongoose"); const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/vinlottis", { mongoose.connect("mongodb://localhost:27017/vinlottis", {
useNewUrlParser: true useNewUrlParser: true
}); });
const sub = require(path.join(__dirname + "/../api/subscriptions")); const sub = require(path.join(__dirname + "/../api/subscriptions"));
const mustBeAuthenticated = require(path.join(
__dirname + "/../middleware/mustBeAuthenticated"
));
const _wineFunctions = require(path.join(__dirname + "/../api/wine")); const _wineFunctions = require(path.join(__dirname + "/../api/wine"));
const _personFunctions = require(path.join(__dirname + "/../api/person")); const _personFunctions = require(path.join(__dirname + "/../api/person"));
const Subscription = require(path.join(__dirname + "/../schemas/Subscription")); const Subscription = require(path.join(__dirname + "/../schemas/Subscription"));
const Purchase = require(path.join(__dirname + "/../schemas/Purchase")); const Lottery = require(path.join(__dirname + "/../schemas/Purchase"));
const PreLotteryWine = require(path.join( const PreLotteryWine = require(path.join(
__dirname + "/../schemas/PreLotteryWine" __dirname + "/../schemas/PreLotteryWine"
)); ));
router.use((req, res, next) => { const submitWines = async (req, res) => {
next();
});
router.route("/log/wines").post(mustBeAuthenticated, async (req, res) => {
const wines = req.body; const wines = req.body;
for (let i = 0; i < wines.length; i++) { for (let i = 0; i < wines.length; i++) {
let wine = wines[i]; let wine = wines[i];
@@ -40,69 +32,115 @@ router.route("/log/wines").post(mustBeAuthenticated, async (req, res) => {
} }
let subs = await Subscription.find(); let subs = await Subscription.find();
console.log("Sending new wines w/ push notification to all subscribers.")
for (let i = 0; i < subs.length; i++) { for (let i = 0; i < subs.length; i++) {
let subscription = subs[i]; //get subscription from your databse here. let subscription = subs[i]; //get subscription from your databse here.
const message = JSON.stringify({ const message = JSON.stringify({
message: "Dagens vin er lagt til, se den på lottis.vin/dagens!", message: "Dagens vin er lagt til, se den på lottis.vin/dagens!",
title: "Ny vin!", title: "Ny vin!",
link: "/#/dagens" link: "/#/dagens"
}); });
sub.sendNotification(subscription, message);
try {
sub.sendNotification(subscription, message);
} catch (error) {
console.error("Error when trying to send push notification to subscriber.");
console.error(error);
}
} }
res.send(true); return res.send({
}); message: "Submitted and notified push subscribers of new wines!",
success: true
});
};
router.route("/log/schema").get(mustBeAuthenticated, async (req, res) => { const schema = async (req, res) => {
let schema = { ...PreLotteryWine.schema.obj }; let schema = { ...PreLotteryWine.schema.obj };
let nulledSchema = Object.keys(schema).reduce((accumulator, current) => { let nulledSchema = Object.keys(schema).reduce((accumulator, current) => {
accumulator[current] = ""; accumulator[current] = "";
return accumulator; return accumulator
}, {}); }, {});
res.send(nulledSchema); return res.send(nulledSchema);
}); }
router.route("/log").post(mustBeAuthenticated, async (req, res) => { // TODO IMPLEMENT WITH FRONTEND (unused)
await PreLotteryWine.deleteMany(); 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)))
const purchaseBody = req.body.purchase; return Lottery.findOneAndUpdate({ date: date }, {
const winnersBody = req.body.winners; 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 }));
}
const date = purchaseBody.date; /**
const blue = purchaseBody.blue; * @apiParam (Request body) {Array} winners List of winners
const red = purchaseBody.red; */
const yellow = purchaseBody.yellow; const submitWinnersToLottery = async (req, res) => {
const green = purchaseBody.green; const { lottery } = req.body;
const { winners, date } = lottery;
const bought = purchaseBody.bought; for (let i = 0; i < winners.length; i++) {
const stolen = purchaseBody.stolen; let currentWinner = winners[i];
let wonWine = await _wineFunctions.findSaveWine(currentWinner.wine); // TODO rename to findAndSaveWineToLottery
const winesThisDate = []; await _personFunctions.findSavePerson(currentWinner, wonWine, date); // TODO rename to findAndSaveWineToPerson
for (let i = 0; i < winnersBody.length; i++) {
let currentWinner = winnersBody[i];
let wonWine = await _wineFunctions.findSaveWine(currentWinner);
winesThisDate.push(wonWine);
await _personFunctions.findSavePerson(currentWinner, wonWine, date);
} }
let purchase = new Purchase({ return res.json(true);
date: date, }
blue: blue,
yellow: yellow,
red: red,
green: green,
wines: winesThisDate,
bought: bought,
stolen: stolen
});
await purchase.save(); /**
* @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
res.send(true); const { date,
}); blue,
red,
yellow,
green,
bought,
stolen } = lottery;
module.exports = router; 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
};

View File

@@ -1,44 +1,16 @@
const express = require("express");
const path = require("path"); const path = require("path");
const router = express.Router();
const crypto = require("crypto"); const crypto = require("crypto");
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/vinlottis", {
useNewUrlParser: true
});
let io;
const mustBeAuthenticated = require(path.join(
__dirname + "/../middleware/mustBeAuthenticated"
));
const config = require(path.join(__dirname + "/../config/defaults/lottery")); 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 Attendee = require(path.join(__dirname + "/../schemas/Attendee"));
const VirtualWinner = require(path.join( const VirtualWinner = require(path.join(__dirname + "/../schemas/VirtualWinner"));
__dirname + "/../schemas/VirtualWinner" const PreLotteryWine = require(path.join(__dirname + "/../schemas/PreLotteryWine"));
));
const PreLotteryWine = require(path.join(
__dirname + "/../schemas/PreLotteryWine"
));
const Message = require(path.join(__dirname + "/../api/message"));
router.use((req, res, next) => { const winners = async (req, res) => {
next();
});
router.route("/winners").delete(mustBeAuthenticated, async (req, res) => {
await VirtualWinner.deleteMany();
io.emit("refresh_data", {});
res.json(true);
});
router.route("/attendees").delete(mustBeAuthenticated, async (req, res) => {
await Attendee.deleteMany();
io.emit("refresh_data", {});
res.json(true);
});
router.route("/winners").get(async (req, res) => {
let winners = await VirtualWinner.find(); let winners = await VirtualWinner.find();
let winnersRedacted = []; let winnersRedacted = [];
let winner; let winner;
@@ -50,19 +22,82 @@ router.route("/winners").get(async (req, res) => {
}); });
} }
res.json(winnersRedacted); res.json(winnersRedacted);
}); };
router.route("/winners/secure").get(mustBeAuthenticated, async (req, res) => { const winnersSecure = async (req, res) => {
let winners = await VirtualWinner.find(); let winners = await VirtualWinner.find();
res.json(winners); return res.json(winners);
}); };
router.route("/winner").get(mustBeAuthenticated, async (req, res) => { 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,
ballots: 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 }); let allContestants = await Attendee.find({ winner: false });
if (allContestants.length == 0) { if (allContestants.length == 0) {
res.json(false); return res.json({
return; success: false,
message: "No attendees left that have not won."
});
} }
let ballotColors = []; let ballotColors = [];
for (let i = 0; i < allContestants.length; i++) { for (let i = 0; i < allContestants.length; i++) {
@@ -131,6 +166,7 @@ router.route("/winner").get(mustBeAuthenticated, async (req, res) => {
Math.floor(Math.random() * attendeeListDemocratic.length) Math.floor(Math.random() * attendeeListDemocratic.length)
]; ];
var io = req.app.get('socketio');
io.emit("winner", { color: colorToChooseFrom, name: winner.name }); io.emit("winner", { color: colorToChooseFrom, name: winner.name });
let newWinnerElement = new VirtualWinner({ let newWinnerElement = new VirtualWinner({
@@ -151,8 +187,40 @@ router.route("/winner").get(mustBeAuthenticated, async (req, res) => {
); );
await newWinnerElement.save(); await newWinnerElement.save();
res.json(winner); return res.json(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) { const genRandomString = function(length) {
return crypto return crypto
@@ -168,87 +236,6 @@ const sha512 = function(password, salt) {
return value; return value;
}; };
router.route("/finish").get(mustBeAuthenticated, async (req, res) => {
if (!config.gatewayToken) {
res.json(false);
return;
}
let winners = await VirtualWinner.find({ timestamp_sent: undefined }).sort({
timestamp_drawn: 1
});
if (winners.length == 0) {
res.json(false);
return;
}
let firstWinner = winners[0];
messageSent = false;
try {
let messageSent = await Message.sendMessage(firstWinner);
Message.sendUpdate(winners.slice(1));
if (!messageSent) {
res.json(false);
return;
}
} catch (e) {
res.json(false);
return;
}
firstWinner.timestamp_sent = new Date().getTime();
firstWinner.timestamp_limit = new Date().getTime() + 600000;
await firstWinner.save();
startTimeout(firstWinner.id);
res.json(true);
return;
});
router.route("/attendees").get(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,
ballots: attendee.red + attendee.blue + attendee.yellow + attendee.green,
red: attendee.red,
blue: attendee.blue,
green: attendee.green,
yellow: attendee.yellow
});
}
res.json(attendeesRedacted);
});
router.route("/attendees/secure").get(mustBeAuthenticated, async (req, res) => {
let attendees = await Attendee.find();
res.json(attendees);
});
router.route("/attendee").post(mustBeAuthenticated, 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();
io.emit("new_attendee", {});
res.send(true);
});
function shuffle(array) { function shuffle(array) {
let currentIndex = array.length, let currentIndex = array.length,
temporaryValue, temporaryValue,
@@ -269,43 +256,15 @@ function shuffle(array) {
return array; return array;
} }
module.exports = {
function startTimeout(id) { deleteWinners,
console.log(`Starting timeout for user ${id}.`); deleteAttendees,
setTimeout(async () => { winners,
let virtualWinner = await VirtualWinner.findOne({ id: id }); winnersSecure,
if (!virtualWinner) { drawWinner,
console.log( finish,
`Timeout done for user ${id}, but user has already sent data.` attendees,
); attendeesSecure,
return; addAttendee
}
console.log(`Timeout done for user ${id}, sending update to user.`);
Message.sendMessageTooLate(virtualWinner);
virtualWinner.timestamp_drawn = new Date().getTime();
virtualWinner.timestamp_limit = null;
virtualWinner.timestamp_sent = null;
await virtualWinner.save();
let prelotteryWine = await PreLotteryWine.find();
let nextWinner = await VirtualWinner.find().sort({ timestamp_drawn: 1 });
if (nextWinner.length == 1 && prelotteryWine.length == 1) {
chooseForUser(nextWinner[0], prelotteryWine[0]);
} else {
nextWinner[0].timestamp_sent = new Date().getTime();
nextWinner[0].timestamp_limit = new Date().getTime() + 600000;
await nextWinner[0].save();
Message.sendMessage(nextWinner[0]);
startTimeout(nextWinner[0].id);
}
}, 600000);
} }
module.exports = function(_io) {
io = _io;
return router;
};

View File

@@ -1,11 +1,4 @@
const express = require("express");
const path = require("path"); const path = require("path");
const router = express.Router();
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/vinlottis", {
useNewUrlParser: true
});
const _wineFunctions = require(path.join(__dirname + "/../api/wine")); const _wineFunctions = require(path.join(__dirname + "/../api/wine"));
const _personFunctions = require(path.join(__dirname + "/../api/person")); const _personFunctions = require(path.join(__dirname + "/../api/person"));
@@ -17,72 +10,70 @@ const PreLotteryWine = require(path.join(
__dirname + "/../schemas/PreLotteryWine" __dirname + "/../schemas/PreLotteryWine"
)); ));
router.use((req, res, next) => {
next();
});
router.route("/winner/:id").get((req, res) => { const getWinesToWinnerById = async (req, res) => {
res.redirect(`/#/winner/${req.params.id}`);
});
router.route("/:id").get(async (req, res) => {
let id = req.params.id; let id = req.params.id;
let foundWinner = await VirtualWinner.findOne({ id: id }); let foundWinner = await VirtualWinner.findOne({ id: id });
if (!foundWinner) { if (!foundWinner) {
res.json({ return res.json({
success: false,
message: "No winner with this id.",
existing: false, existing: false,
turn: false turn: false
}); });
return;
} }
let allWinners = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); let allWinners = await VirtualWinner.find().sort({ timestamp_drawn: 1 });
if ( if (
allWinners[0].id != foundWinner.id || allWinners[0].id != foundWinner.id ||
foundWinner.timestamp_limit == undefined || foundWinner.timestamp_limit == undefined ||
foundWinner.timestamp_sent == undefined foundWinner.timestamp_sent == undefined
) { ) {
res.json({ existing: true, turn: false }); return res.json({
return; success: false,
message: "Not the winner next in line!",
existing: true,
turn: false
});
} }
res.json({ return res.json({
success: true,
existing: true, existing: true,
turn: true, turn: true,
name: foundWinner.name, name: foundWinner.name,
color: foundWinner.color color: foundWinner.color
}); });
return; };
});
router.route("/:id").post(async (req, res) => { const registerWinnerSelection = async (req, res) => {
let id = req.params.id; let id = req.params.id;
let wineName = req.body.wineName; let wineName = req.body.wineName;
let foundWinner = await VirtualWinner.findOne({ id: id }); let foundWinner = await VirtualWinner.findOne({ id: id });
if (!foundWinner) { if (!foundWinner) {
res.json(false); return res.json({
return; 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
})
} }
if (foundWinner.timestamp_limit < new Date().getTime()) {
res.json({
success: false,
limit: true
});
return;
}
let date = new Date(); let date = new Date();
date.setHours(5, 0, 0, 0); date.setHours(5, 0, 0, 0);
let prelotteryWine = await PreLotteryWine.findOne({ name: wineName }); let prelotteryWine = await PreLotteryWine.findOne({ name: wineName });
if (!prelotteryWine) { if (!prelotteryWine) {
res.json({ return res.json({
success: false, success: false,
wine: true message: "No wine with this name.",
wine: false
}); });
} }
@@ -91,31 +82,78 @@ router.route("/:id").post(async (req, res) => {
await _personFunctions.findSavePerson(foundWinner, wonWine, date); await _personFunctions.findSavePerson(foundWinner, wonWine, date);
await foundWinner.delete(); await foundWinner.delete();
console.info("Saved winners choice.");
let nextWineBottle = await PreLotteryWine.find(); return findAndNotifyNextWinner()
let nextWinner = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); .then(() => res.json({
if (nextWinner.length > 1 && nextWineBottle.length > 1) { message: "Choice saved and next in line notified.",
Message.sendMessage(nextWinner[0]); success: true
startTimeout(id); }))
} else if (nextWinner.length == 1 && nextWineBottle.length == 1) { .catch(error => res.json({
chooseForUser(nextWinner[0], nextWineBottle[0]); message: error["message"] || "Error when notifing next winner.",
} success: false
}))
};
res.json({ const chooseLastWineForUser = (winner, prelotteryWine) => {
success: true
});
return;
});
async function chooseForUser(winner, prelotteryWine) {
let date = new Date(); let date = new Date();
date.setHours(5, 0, 0, 0); date.setHours(5, 0, 0, 0);
let wonWine = await _wineFunctions.findSaveWine(prelotteryWine);
await _personFunctions.findSavePerson(winner, wonWine, date);
await prelotteryWine.delete(); return _wineFunctions.findSaveWine(preLotteryWine)
await Message.sendWonWineMessage(winner, prelotteryWine); .then(wonWine => _personFunctions.findSavePerson(winner, wonWine, date))
await winner.delete(); .then(() => prelotteryWine.delete())
.then(() => Message.sendLastWinnerMessage(winner, preLotteryWine))
.then(() => winner.delete());
}
const findAndNotifyNextWinner = async () => {
let nextWinner = undefined;
let winnersLeft = await VirtualWinner.find().sort({ timestamp_drawn: 1 });
let winesLeft = await PreLotteryWine.find();
if (winnersLeft.length > 1) {
nextWinner = winnersLeft[0]; // multiple winners left, choose next in line
} else if (winnersLeft.length == 1 && winesLeft.length > 1) {
nextWinner = winnersLeft[0] // one winner left, but multiple wines
} else if (winnersLeft.length == 1 && winesLeft.length == 1) {
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) { function startTimeout(id) {
@@ -123,27 +161,28 @@ function startTimeout(id) {
setTimeout(async () => { setTimeout(async () => {
let virtualWinner = await VirtualWinner.findOne({ id: id }); let virtualWinner = await VirtualWinner.findOne({ id: id });
if (!virtualWinner) { if (!virtualWinner) {
console.log( console.log(`Timeout done for user ${id}, but user has already sent data.`);
`Timeout done for user ${id}, but user has already sent data.`
);
return; return;
} }
console.log(`Timeout done for user ${id}, sending update to user.`); console.log(`Timeout done for user ${id}, sending update to user.`);
Message.sendMessageTooLate(virtualWinner); Message.sendWineSelectMessageTooLate(virtualWinner);
virtualWinner.timestamp_drawn = new Date().getTime(); virtualWinner.timestamp_drawn = new Date().getTime();
virtualWinner.timestamp_limit = null; virtualWinner.timestamp_limit = null;
virtualWinner.timestamp_sent = null; virtualWinner.timestamp_sent = null;
await virtualWinner.save(); await virtualWinner.save();
let prelotteryWine = await PreLotteryWine.find(); findAndNotifyNextWinner();
let nextWinner = await VirtualWinner.find().sort({ timestamp_drawn: 1 }); }, 60000);
if (nextWinner.length == 1 && prelotteryWine.length == 1) {
chooseForUser(nextWinner[0], prelotteryWine[0]); return Promise.resolve()
}
}, 600000);
} }
module.exports = router; module.exports = {
getWinesToWinnerById,
registerWinnerSelection,
findAndNotifyNextWinner,
sendNotificationToWinnerById
};

View File

@@ -1,15 +1,8 @@
const express = require("express");
const path = require("path");
const router = express.Router();
const fetch = require('node-fetch') const fetch = require('node-fetch')
const path = require('path')
const config = require(path.join(__dirname + "/../config/env/lottery.config")); const config = require(path.join(__dirname + "/../config/env/lottery.config"));
const mustBeAuthenticated = require(path.join(__dirname + "/../middleware/mustBeAuthenticated")) const mustBeAuthenticated = require(path.join(__dirname + "/../middleware/mustBeAuthenticated"))
router.use((req, res, next) => {
next();
});
const convertToOurWineObject = wine => { const convertToOurWineObject = wine => {
if(wine.basic.ageLimit === "18"){ if(wine.basic.ageLimit === "18"){
return { return {
@@ -25,11 +18,11 @@ const convertToOurWineObject = wine => {
} }
} }
router.route("/wineinfo/search").get(async (req, res) => { const wineSearch = async (req, res) => {
const {query} = req.query const {query} = req.query
let url = new URL(`https://apis.vinmonopolet.no/products/v0/details-normal?productShortNameContains=test&maxResults=15`) let url = new URL(`https://apis.vinmonopolet.no/products/v0/details-normal?productShortNameContains=test&maxResults=15`)
url.searchParams.set('productShortNameContains', query) url.searchParams.set('productShortNameContains', query)
const vinmonopoletResponse = await fetch(url, { const vinmonopoletResponse = await fetch(url, {
headers: { headers: {
"Ocp-Apim-Subscription-Key": config.vinmonopoletToken "Ocp-Apim-Subscription-Key": config.vinmonopoletToken
@@ -37,8 +30,8 @@ router.route("/wineinfo/search").get(async (req, res) => {
}) })
.then(resp => resp.json()) .then(resp => resp.json())
.catch(err => console.error(err)) .catch(err => console.error(err))
if (vinmonopoletResponse.errors != null) { if (vinmonopoletResponse.errors != null) {
return vinmonopoletResponse.errors.map(error => { return vinmonopoletResponse.errors.map(error => {
if (error.type == "UnknownProductError") { if (error.type == "UnknownProductError") {
@@ -51,12 +44,11 @@ router.route("/wineinfo/search").get(async (req, res) => {
}) })
} }
const winesConverted = vinmonopoletResponse.map(convertToOurWineObject).filter(Boolean) const winesConverted = vinmonopoletResponse.map(convertToOurWineObject).filter(Boolean)
res.send(winesConverted);
});
return res.send(winesConverted);
}
const byEAN = async (req, res) => {
router.route("/wineinfo/:ean").get(async (req, res) => {
const vinmonopoletResponse = await fetch("https://app.vinmonopolet.no/vmpws/v2/vmp/products/barCodeSearch/" + req.params.ean) const vinmonopoletResponse = await fetch("https://app.vinmonopolet.no/vmpws/v2/vmp/products/barCodeSearch/" + req.params.ean)
.then(resp => resp.json()) .then(resp => resp.json())
@@ -72,7 +64,10 @@ router.route("/wineinfo/:ean").get(async (req, res) => {
}) })
} }
res.send(vinmonopoletResponse); return res.send(vinmonopoletResponse);
}); };
module.exports = router; module.exports = {
byEAN,
wineSearch
};

5052
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js", "start": "node server.js",
"dev": "cross-env NODE_ENV=development webpack-dev-server --progress", "dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules" "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
}, },
"author": "", "author": "",
@@ -35,7 +35,6 @@
"passport-local-mongoose": "^6.0.1", "passport-local-mongoose": "^6.0.1",
"qrcode": "^1.4.4", "qrcode": "^1.4.4",
"referrer-policy": "^1.2.0", "referrer-policy": "^1.2.0",
"request": "^2.88.2",
"socket.io": "^2.3.0", "socket.io": "^2.3.0",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"vue": "~2.6", "vue": "~2.6",

View File

@@ -6,17 +6,13 @@ const path = require("path");
const session = require("express-session"); const session = require("express-session");
const User = require(path.join(__dirname + "/schemas/User")); const User = require(path.join(__dirname + "/schemas/User"));
const updateApi = require(path.join(__dirname + "/api/update")); const apiRouter = require(path.join(__dirname + "/api/router.js"));
const retrieveApi = require(path.join(__dirname + "/api/retrieve"));
const subscriptionApi = require(path.join(__dirname + "/api/subscriptions"));
const loginApi = require(path.join(__dirname + "/api/login")); const loginApi = require(path.join(__dirname + "/api/login"));
const wineinfoApi = require(path.join(__dirname + "/api/wineinfo")); const wineinfoApi = require(path.join(__dirname + "/api/wineinfo"));
const requestApi = require(path.join(__dirname + "/api/request")); const requestApi = require(path.join(__dirname + "/api/request"));
const virtualApi = require(path.join(__dirname + "/api/virtualLottery")); const virtualApi = require(path.join(__dirname + "/api/virtualLottery"));
const virtualRegistrationApi = require(path.join( const subscriptionApi = require(path.join(__dirname + "/api/subscriptions"));
__dirname + "/api/virtualRegistration"
));
const lottery = require(path.join(__dirname + "/api/lottery"));
//This is required for the chat to work //This is required for the chat to work
const chat = require(path.join(__dirname + "/api/chat"))(io); const chat = require(path.join(__dirname + "/api/chat"))(io);
@@ -77,6 +73,8 @@ app.use(
}) })
); );
app.set('socketio', io);
const passport = require("passport"); const passport = require("passport");
const LocalStrategy = require("passport-local"); const LocalStrategy = require("passport-local");
@@ -92,19 +90,20 @@ passport.deserializeUser(User.deserializeUser());
app.use("/public", express.static(path.join(__dirname, "public"))); app.use("/public", express.static(path.join(__dirname, "public")));
app.use("/dist", express.static(path.join(__dirname, "public/dist"))); app.use("/dist", express.static(path.join(__dirname, "public/dist")));
app.use("/", loginApi); app.use("/", loginApi);
app.use("/api/", updateApi); // app.use("/api/", updateApi);
app.use("/api/", retrieveApi); // app.use("/api/", retrieveApi);
app.use("/api/", wineinfoApi); // app.use("/api/", wineinfoApi);
app.use("/api/", requestApi); // app.use("/api/", requestApi);
app.use("/api/", chatHistory); app.use("/api/", chatHistory);
app.use("/api/lottery", lottery); app.use("/api/", apiRouter);
app.use("/api/virtual/", virtualApi(io));
app.use("/api/virtual-registration/", virtualRegistrationApi);
app.use("/subscription", subscriptionApi); app.use("/subscription", subscriptionApi);
app.get("/dagens", function(req, res) { app.get("/dagens", function(req, res) {
res.redirect("/#/dagens"); res.redirect("/#/dagens");
}); });
app.get("/winner/:id", function(req, res) {
res.redirect("/#/winner/" + req.params.id);
});
app.use("/service-worker.js", function(req, res) { app.use("/service-worker.js", function(req, res) {
res.sendFile(path.join(__dirname, "public/sw/serviceWorker.js")); res.sendFile(path.join(__dirname, "public/sw/serviceWorker.js"));

View File

@@ -52,6 +52,7 @@ export default {
<style lang="scss"> <style lang="scss">
@import "./styles/global.scss"; @import "./styles/global.scss";
@import "./styles/positioning.scss";
@font-face { @font-face {
font-family: "knowit"; font-family: "knowit";
font-weight: 600; font-weight: 600;

View File

@@ -1,3 +1,5 @@
import fetch from "node-fetch";
const BASE_URL = __APIURL__ || window.location.origin; const BASE_URL = __APIURL__ || window.location.origin;
const statistics = () => { const statistics = () => {
@@ -48,8 +50,22 @@ const prelottery = () => {
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const log = sendObject => { const sendLottery = sendObject => {
const url = new URL("/api/log", BASE_URL); const url = new URL("/api/lottery", BASE_URL);
const options = {
headers: {
"Content-Type": "application/json"
},
method: "POST",
body: JSON.stringify(sendObject)
};
return fetch(url.href, options).then(resp => resp.json());
};
const sendLotteryWinners = sendObject => {
const url = new URL("/api/lottery/winners", BASE_URL);
const options = { const options = {
headers: { headers: {
@@ -63,7 +79,7 @@ const log = sendObject => {
}; };
const addAttendee = sendObject => { const addAttendee = sendObject => {
const url = new URL("/api/virtual/attendee", BASE_URL); const url = new URL("/api/virtual/attendee/add", BASE_URL);
const options = { const options = {
headers: { headers: {
@@ -77,32 +93,32 @@ const addAttendee = sendObject => {
}; };
const getVirtualWinner = () => { const getVirtualWinner = () => {
const url = new URL("/api/virtual/winner", BASE_URL); const url = new URL("/api/virtual/winner/draw", BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const attendeesSecure = () => { const attendeesSecure = () => {
const url = new URL("/api/virtual/attendees/secure", BASE_URL); const url = new URL("/api/virtual/attendee/all/secure", BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const winnersSecure = () => { const winnersSecure = () => {
const url = new URL("/api/virtual/winners/secure", BASE_URL); const url = new URL("/api/virtual/winner/all/secure", BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const winners = () => { const winners = () => {
const url = new URL("/api/virtual/winners", BASE_URL); const url = new URL("/api/virtual/winner/all", BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const deleteRequestedWine = wineToBeDeleted => { const deleteRequestedWine = wineToBeDeleted => {
const url = new URL("api/request", BASE_URL); const url = new URL("api/request/"+ wineToBeDeleted._id, BASE_URL);
const options = { const options = {
headers: { headers: {
@@ -116,7 +132,7 @@ const deleteRequestedWine = wineToBeDeleted => {
} }
const deleteWinners = () => { const deleteWinners = () => {
const url = new URL("/api/virtual/winners", BASE_URL); const url = new URL("/api/virtual/winner/all", BASE_URL);
const options = { const options = {
headers: { headers: {
@@ -129,7 +145,7 @@ const deleteWinners = () => {
}; };
const deleteAttendees = () => { const deleteAttendees = () => {
const url = new URL("/api/virtual/attendees", BASE_URL); const url = new URL("/api/virtual/attendee/all", BASE_URL);
const options = { const options = {
headers: { headers: {
@@ -142,11 +158,28 @@ const deleteAttendees = () => {
}; };
const attendees = () => { const attendees = () => {
const url = new URL("/api/virtual/attendees", BASE_URL); const url = new URL("/api/virtual/attendee/all", BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const requestNewWine = (wine) => {
const options = {
body: JSON.stringify({
wine: wine
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "post"
}
const url = new URL("/api/request/new-wine", BASE_URL)
return fetch(url.href, options).then(resp => resp.json())
}
const logWines = wines => { const logWines = wines => {
const url = new URL("/api/log/wines", BASE_URL); const url = new URL("/api/log/wines", BASE_URL);
@@ -162,7 +195,7 @@ const logWines = wines => {
}; };
const wineSchema = () => { const wineSchema = () => {
const url = new URL("/api/log/schema", BASE_URL); const url = new URL("/api/wineinfo/schema", BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
@@ -253,17 +286,20 @@ const getChatHistory = (skip = null, take = null) => {
const finishedDraw = () => { const finishedDraw = () => {
const url = new URL("/api/virtual/finish", BASE_URL); const url = new URL("/api/virtual/finish", BASE_URL);
const options = {
method: 'POST'
}
return fetch(url.href).then(resp => resp.json()); return fetch(url.href, options).then(resp => resp.json());
}; };
const getAmIWinner = id => { const getAmIWinner = id => {
const url = new URL(`/api/virtual-registration/${id}`, BASE_URL); const url = new URL(`/api/winner/${id}`, BASE_URL);
return fetch(url.href).then(resp => resp.json()); return fetch(url.href).then(resp => resp.json());
}; };
const postWineChosen = (id, wineName) => { const postWineChosen = (id, wineName) => {
const url = new URL(`/api/virtual-registration/${id}`, BASE_URL); const url = new URL(`/api/winner/${id}`, BASE_URL);
const options = { const options = {
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
@@ -301,11 +337,13 @@ export {
chartWinsByColor, chartWinsByColor,
chartPurchaseByColor, chartPurchaseByColor,
prelottery, prelottery,
log, sendLottery,
sendLotteryWinners,
logWines, logWines,
wineSchema, wineSchema,
barcodeToVinmonopolet, barcodeToVinmonopolet,
searchForWine, searchForWine,
requestNewWine,
allRequestedWines, allRequestedWines,
login, login,
register, register,

View File

@@ -78,6 +78,10 @@
</div> </div>
</div> </div>
<div class="button-container">
<button class="vin-button" @click="submitLottery">Send inn lotteri</button>
</div>
<h3>Vinnere</h3> <h3>Vinnere</h3>
<a class="wine-link" @click="fetchColorsAndWinners()">Refresh data fra virtuelt lotteri</a> <a class="wine-link" @click="fetchColorsAndWinners()">Refresh data fra virtuelt lotteri</a>
<div class="winner-container" v-if="winners.length > 0"> <div class="winner-container" v-if="winners.length > 0">
@@ -130,8 +134,8 @@
</div> </div>
</wine> </wine>
<div class="button-container"> <div class="button-container column">
<button class="vin-button" @click="sendInfo">Send inn vinnere</button> <button class="vin-button" @click="submitLotteryWinners">Send inn vinnere</button>
<button class="vin-button" @click="resetWinnerDataInStorage">Reset local wines</button> <button class="vin-button" @click="resetWinnerDataInStorage">Reset local wines</button>
</div> </div>
</div> </div>
@@ -142,9 +146,11 @@
<script> <script>
import eventBus from "@/mixins/EventBus"; import eventBus from "@/mixins/EventBus";
import { dateString } from '@/utils'
import { import {
prelottery, prelottery,
log, sendLotteryWinners,
sendLottery,
logWines, logWines,
wineSchema, wineSchema,
winnersSecure, winnersSecure,
@@ -306,7 +312,7 @@ export default {
}, },
sendWines: async function() { sendWines: async function() {
let response = await logWines(this.wines); let response = await logWines(this.wines);
if (response == true) { if (response.success == true) {
alert("Sendt!"); alert("Sendt!");
window.location.reload(); window.location.reload();
} else { } else {
@@ -324,7 +330,7 @@ export default {
} }
}); });
}, },
sendInfo: async function(event) { submitLottery: async function(event) {
const colors = { const colors = {
red: this.lotteryColors.filter(c => c.css == "red")[0].value, red: this.lotteryColors.filter(c => c.css == "red")[0].value,
green: this.lotteryColors.filter(c => c.css == "green")[0].value, green: this.lotteryColors.filter(c => c.css == "green")[0].value,
@@ -333,48 +339,63 @@ export default {
}; };
let sendObject = { let sendObject = {
purchase: { lottery: {
date: new Date(), date: dateString(new Date()),
...colors ...colors
}, }
winners: this.winners
}; };
if (sendObject.purchase.red == undefined) { if (sendObject.lottery.red == undefined) {
alert("Rød må defineres"); alert("Rød må defineres");
return; return;
} }
if (sendObject.purchase.green == undefined) { if (sendObject.lottery.green == undefined) {
alert("Grønn må defineres"); alert("Grønn må defineres");
return; return;
} }
if (sendObject.purchase.yellow == undefined) { if (sendObject.lottery.yellow == undefined) {
alert("Gul må defineres"); alert("Gul må defineres");
return; return;
} }
if (sendObject.purchase.blue == undefined) { if (sendObject.lottery.blue == undefined) {
alert("Blå må defineres"); alert("Blå må defineres");
return; return;
} }
sendObject.purchase.bought = sendObject.lottery.bought =
parseInt(colors.blue) + parseInt(colors.blue) +
parseInt(colors.red) + parseInt(colors.red) +
parseInt(colors.green) + parseInt(colors.green) +
parseInt(colors.yellow); parseInt(colors.yellow);
const stolen = sendObject.purchase.bought - parseInt(this.payed) / 10; const stolen = sendObject.lottery.bought - parseInt(this.payed) / 10;
if (isNaN(stolen) || stolen == undefined) { if (isNaN(stolen) || stolen == undefined) {
alert("Betalt må registreres"); alert("Betalt må registreres");
return; return;
} }
sendObject.purchase.stolen = stolen; sendObject.lottery.stolen = stolen;
if (sendObject.winners.length == 0) { let response = await sendLottery(sendObject);
if (response == true) {
alert("Sendt!");
window.location.reload();
} else {
alert(response.message || "Noe gikk galt under innsending");
}
},
submitLotteryWinners: async function(event) {
let sendObject = {
lottery: {
date: dateString(new Date()),
winners: this.winners
}
}
if (sendObject.lottery.winners.length == 0) {
alert("Det må være med vinnere"); alert("Det må være med vinnere");
return; return;
} }
for (let i = 0; i < sendObject.winners.length; i++) { for (let i = 0; i < sendObject.lottery.winners.length; i++) {
let currentWinner = sendObject.winners[i]; let currentWinner = sendObject.lottery.winners[i];
if (currentWinner.name == undefined || currentWinner.name == "") { if (currentWinner.name == undefined || currentWinner.name == "") {
alert("Navn må defineres"); alert("Navn må defineres");
@@ -386,7 +407,7 @@ export default {
} }
} }
let response = await log(sendObject); let response = await sendLotteryWinners(sendObject);
if (response == true) { if (response == true) {
alert("Sendt!"); alert("Sendt!");
window.location.reload(); window.location.reload();
@@ -613,7 +634,7 @@ hr {
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
max-width: 1400px; max-width: 1400px;
margin: 3rem auto 0; margin: 3rem auto 1rem;
@include mobile { @include mobile {
margin: 1.8rem auto 0; margin: 1.8rem auto 0;

View File

@@ -95,7 +95,7 @@ export default {
method: "post" method: "post"
} }
fetch("http://localhost:30030/api/request", options) fetch("http://localhost:30030/api/request/new-wine", options)
.then(res => res.json()) .then(res => res.json())
.then(() => this.showModal = true) .then(() => this.showModal = true)
}, },

View File

@@ -106,6 +106,8 @@
</div> </div>
<br /> <br />
<button class="vin-button" @click="sendAttendee">Send deltaker</button> <button class="vin-button" @click="sendAttendee">Send deltaker</button>
<TextToast v-if="showToast" :text="toastText" v-on:closeToast="showToast = false" />
</div> </div>
</template> </template>
@@ -119,13 +121,16 @@ import {
winnersSecure, winnersSecure,
deleteWinners, deleteWinners,
deleteAttendees, deleteAttendees,
finishedDraw finishedDraw,
prelottery
} from "@/api"; } from "@/api";
import TextToast from "@/ui/TextToast";
import RaffleGenerator from "@/ui/RaffleGenerator"; import RaffleGenerator from "@/ui/RaffleGenerator";
export default { export default {
components: { components: {
RaffleGenerator RaffleGenerator,
TextToast
}, },
data() { data() {
return { return {
@@ -144,7 +149,9 @@ export default {
drawTime: 20, drawTime: 20,
currentWinners: 1, currentWinners: 1,
numberOfWinners: 4, numberOfWinners: 4,
socket: null socket: null,
toastText: undefined,
showToast: false
}; };
}, },
mounted() { mounted() {
@@ -168,13 +175,21 @@ export default {
}); });
window.finishedDraw = finishedDraw; window.finishedDraw = finishedDraw;
console.log("here");
}, },
methods: { methods: {
setWithRandomColors(colors) { setWithRandomColors(colors) {
Object.keys(colors).forEach(color => (this[color] = colors[color])); Object.keys(colors).forEach(color => (this[color] = colors[color]));
}, },
sendAttendee: async function() { sendAttendee: async function() {
if (this.red == 0 && this.blue == 0 && this.green == 0 && this.yellow == 0) {
alert('Ingen farger valgt!')
return;
}
if (this.name == 0 && this.phoneNumber) {
alert('Ingen navn eller tlf satt!')
return;
}
let response = await addAttendee({ let response = await addAttendee({
name: this.name, name: this.name,
phoneNumber: this.phoneNumber, phoneNumber: this.phoneNumber,
@@ -184,10 +199,15 @@ export default {
yellow: this.yellow, yellow: this.yellow,
ballots: this.ballots ballots: this.ballots
}); });
if (response == true) { if (response == true) {
alert("Sendt inn deltaker!"); this.toastText = `Sendt inn deltaker: ${this.name}`;
this.showToast = true;
this.name = null; this.name = null;
this.phoneNumber = null; this.phoneNumber = null;
this.yellow = 0;
this.green = 0;
this.red = 0; this.red = 0;
this.blue = 0; this.blue = 0;
@@ -208,6 +228,7 @@ export default {
if (window.confirm("Er du sikker på at du vil trekke vinnere?")) { if (window.confirm("Er du sikker på at du vil trekke vinnere?")) {
this.drawingWinner = true; this.drawingWinner = true;
let response = await getVirtualWinner(); let response = await getVirtualWinner();
if (response) { if (response) {
if (this.currentWinners < this.numberOfWinners) { if (this.currentWinners < this.numberOfWinners) {
this.countdown(); this.countdown();

View File

@@ -62,11 +62,9 @@ export default {
this.name = winnerObject.name; this.name = winnerObject.name;
const _wines = await fetch("/api/wines/prelottery"); const _wines = await fetch("/api/wines/prelottery");
this.wines = await _wines.json(); this.wines = await _wines.json();
console.log(this.wines);
}, },
methods: { methods: {
chosenWine: async function(name) { chosenWine: async function(name) {
console.log("chosen a wine");
let posted = await postWineChosen(this.id, name); let posted = await postWineChosen(this.id, name);
console.log("response", posted); console.log("response", posted);
if (posted.success) { if (posted.success) {
@@ -82,7 +80,8 @@ export default {
.container { .container {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-top: 4rem; margin-top: 2rem;
padding: 2rem;
} }
.sent-container { .sent-container {
width: 100%; width: 100%;

View File

@@ -74,6 +74,16 @@ body {
margin-right: 2rem; margin-right: 2rem;
} }
&.column {
flex-direction: column;
align-items: center;
> * {
margin-right: unset;
margin-bottom: 1rem;
}
}
@include mobile { @include mobile {
&:not(.row) { &:not(.row) {
flex-direction: column; flex-direction: column;
@@ -108,6 +118,7 @@ textarea {
border: 0; border: 0;
width: fit-content; width: fit-content;
font-size: 1.3rem; font-size: 1.3rem;
line-height: 1.3rem;
height: 4rem; height: 4rem;
max-height: 4rem; max-height: 4rem;
cursor: pointer; cursor: pointer;

View File

@@ -0,0 +1,7 @@
.flex {
display: flex;
&-column {
flex-direction: column;
}
}

View File

@@ -56,13 +56,13 @@ export default {
}, },
method: "post" method: "post"
} }
fetch("http://localhost:30030/api/request", options) fetch("http://localhost:30030/api/request/new-wine", options)
.then(res => res.json()) .then(res => res.json())
}, },
async deleteWine(wine) { async deleteWine(wine) {
if (window.confirm("Er du sikker på at du vil slette vinen?")) { if (window.confirm("Er du sikker på at du vil slette vinen?")) {
let response = await deleteRequestedWine(wine); let response = await deleteRequestedWine(wine);
if (response) { if (response['success'] == true) {
this.$emit('wineDeleted', wine); this.$emit('wineDeleted', wine);
} else { } else {
alert("Klarte ikke slette vinen"); alert("Klarte ikke slette vinen");

View File

@@ -22,6 +22,7 @@
:href="wine.vivinoLink" :href="wine.vivinoLink"
class="wine-link" class="wine-link"
>Les mer {{ hostname(wine.vivinoLink) }}</a> >Les mer {{ hostname(wine.vivinoLink) }}</a>
<button <button
v-if="winner" v-if="winner"
@click="choseWine(wine.name)" @click="choseWine(wine.name)"
@@ -174,4 +175,8 @@ a:visited {
color: $red; color: $red;
} }
} }
.vin-button {
margin-top: 1rem;
}
</style> </style>

View File

@@ -34,8 +34,10 @@ h2 {
.winners { .winners {
display: flex; display: flex;
flex-flow: wrap;
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
flex-wrap: wrap;
} }
.ballot-element { .ballot-element {

12
src/utils.js Normal file
View File

@@ -0,0 +1,12 @@
const dateString = (date) => {
const ye = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(date)
const mo = new Intl.DateTimeFormat('en', { month: '2-digit' }).format(date)
const da = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(date)
return `${ye}-${mo}-${da}`
}
module.exports = {
dateString
}

View File

@@ -1,6 +1,6 @@
import Vue from "vue"; import Vue from "vue";
import VueRouter from "vue-router"; import VueRouter from "vue-router";
import { routes } from "@/routes/vinlottisRouter"; import { routes } from "@/router.js";
import Vinlottis from "@/Vinlottis"; import Vinlottis from "@/Vinlottis";
import VueAnalytics from "vue-analytics"; import VueAnalytics from "vue-analytics";

3983
yarn.lock

File diff suppressed because it is too large Load Diff