diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..4943080 --- /dev/null +++ b/.babelrc @@ -0,0 +1,15 @@ +{ + presets: [ + [ + "@babel/preset-env", + { + modules: false, + targets: { + browsers: ["IE 11", "> 5%"] + }, + useBuiltIns: "usage", + corejs: "3" + } + ] + ] +} \ No newline at end of file diff --git a/api/chatHistory.js b/api/chatHistory.js index dc1862c..ae3e0ba 100644 --- a/api/chatHistory.js +++ b/api/chatHistory.js @@ -1,33 +1,29 @@ -const express = require("express"); const path = require("path"); -const router = express.Router(); - const { history, clearHistory } = require(path.join(__dirname + "/../api/redis")); -router.use((req, res, next) => { - next(); -}); - -router.route("/chat/history").get(async (req, res) => { +const getAllHistory = (req, res) => { let { skip, take } = req.query; skip = !isNaN(skip) ? Number(skip) : undefined; take = !isNaN(take) ? Number(take) : undefined; - try { - const messages = await history(skip, take); - res.json(messages) - } catch(error) { - res.status(500).send(error); - } -}); + return history(skip, take) + .then(messages => res.json(messages)) + .catch(error => res.status(500).json({ + message: error.message, + success: false + })); +}; -router.route("/chat/history").delete(async (req, res) => { - try { - const messages = await clearHistory(); - res.json(messages) - } catch(error) { - res.status(500).send(error); - } -}); +const deleteHistory = (req, res) => { + return clearHistory() + .then(message => res.json(message)) + .catch(error => res.status(500).json({ + message: error.message, + success: false + })); +}; -module.exports = router; +module.exports = { + getAllHistory, + deleteHistory +}; diff --git a/api/login.js b/api/login.js deleted file mode 100644 index fa99099..0000000 --- a/api/login.js +++ /dev/null @@ -1,59 +0,0 @@ -const passport = require("passport"); -const path = require("path"); -const User = require(path.join(__dirname + "/../schemas/User")); -const router = require("express").Router(); - -router.get("/", function(req, res) { - res.sendFile(path.join(__dirname + "/../public/index.html")); -}); - -router.get("/register", function(req, res) { - res.sendFile(path.join(__dirname + "/../public/index.html")); -}); - -// router.post("/register", function(req, res, next) { -// User.register( -// new User({ username: req.body.username }), -// req.body.password, -// function(err) { -// if (err) { -// if (err.name == "UserExistsError") -// res.status(409).send({ success: false, message: err.message }) -// else if (err.name == "MissingUsernameError" || err.name == "MissingPasswordError") -// res.status(400).send({ success: false, message: err.message }) -// return next(err); -// } - -// return res.status(200).send({ message: "Bruker registrert. Velkommen " + req.body.username, success: true }) -// } -// ); -// }); - -router.get("/login", function(req, res) { - res.sendFile(path.join(__dirname + "/../public/index.html")); -}); - -router.post("/login", function(req, res, next) { - passport.authenticate("local", function(err, user, info) { - if (err) { - if (err.name == "MissingUsernameError" || err.name == "MissingPasswordError") - return res.status(400).send({ message: err.message, success: false }) - return next(err); - } - - if (!user) return res.status(404).send({ message: "Incorrect username or password", success: false }) - - req.logIn(user, (err) => { - if (err) { return next(err) } - - return res.status(200).send({ message: "Velkommen " + user.username, success: true }) - }) - })(req, res, next); -}); - -router.get("/logout", function(req, res) { - req.logout(); - res.redirect("/"); -}); - -module.exports = router; diff --git a/api/lottery.js b/api/lottery.js index 0f7d218..6783a8c 100644 --- a/api/lottery.js +++ b/api/lottery.js @@ -1,7 +1,7 @@ const path = require('path'); -const Highscore = require(path.join(__dirname + '/../schemas/Highscore')); -const Wine = require(path.join(__dirname + '/../schemas/Wine')); +const Highscore = require(path.join(__dirname, '/schemas/Highscore')); +const Wine = require(path.join(__dirname, '/schemas/Wine')); // Utils const epochToDateString = date => new Date(parseInt(date)).toDateString(); diff --git a/middleware/mustBeAuthenticated.js b/api/middleware/mustBeAuthenticated.js similarity index 61% rename from middleware/mustBeAuthenticated.js rename to api/middleware/mustBeAuthenticated.js index 70c90e1..a173fb2 100644 --- a/middleware/mustBeAuthenticated.js +++ b/api/middleware/mustBeAuthenticated.js @@ -1,5 +1,9 @@ const mustBeAuthenticated = (req, res, next) => { - console.log(req.isAuthenticated()); + if (process.env.NODE_ENV == "development") { + console.info(`Restricted endpoint ${req.originalUrl}, but running in dev mode.`) + return next(); + } + if (!req.isAuthenticated()) { return res.status(401).send({ success: false, diff --git a/middleware/setAdminHeaderIfAuthenticated.js b/api/middleware/setAdminHeaderIfAuthenticated.js similarity index 100% rename from middleware/setAdminHeaderIfAuthenticated.js rename to api/middleware/setAdminHeaderIfAuthenticated.js diff --git a/api/middleware/setupCORS.js b/api/middleware/setupCORS.js new file mode 100644 index 0000000..9d50803 --- /dev/null +++ b/api/middleware/setupCORS.js @@ -0,0 +1,6 @@ +const openCORS = (req, res, next) => { + res.set("Access-Control-Allow-Origin", "*") + return next(); +}; + +module.exports = openCORS; diff --git a/api/middleware/setupHeaders.js b/api/middleware/setupHeaders.js new file mode 100644 index 0000000..cd0abfa --- /dev/null +++ b/api/middleware/setupHeaders.js @@ -0,0 +1,37 @@ +const camelToKebabCase = str => str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`); + +const mapFeaturePolicyToString = (features) => { + return Object.entries(features).map(([key, value]) => { + key = camelToKebabCase(key) + value = value == "*" ? value : `'${ value }'` + return `${key} ${value}` + }).join("; ") +} + +const setupHeaders = (req, res, next) => { + res.set("Access-Control-Allow-Headers", "Content-Type") + + // Security + res.set("X-Content-Type-Options", "nosniff"); + res.set("X-XSS-Protection", "1; mode=block"); + res.set("X-Frame-Options", "SAMEORIGIN"); + res.set("X-DNS-Prefetch-Control", "off"); + res.set("X-Download-Options", "noopen"); + res.set("Strict-Transport-Security", "max-age=15552000; includeSubDomains") + + // Feature policy + const features = { + fullscreen: "*", + payment: "none", + microphone: "none", + camera: "self", + speaker: "*", + syncXhr: "self" + } + const featureString = mapFeaturePolicyToString(features); + res.set("Feature-Policy", featureString) + + return next(); +} + +module.exports = setupHeaders; \ No newline at end of file diff --git a/api/person.js b/api/person.js index 8a10879..03aee27 100644 --- a/api/person.js +++ b/api/person.js @@ -1,5 +1,5 @@ const path = require("path"); -const Highscore = require(path.join(__dirname + "/../schemas/Highscore")); +const Highscore = require(path.join(__dirname, "/schemas/Highscore")); async function findSavePerson(foundWinner, wonWine, date) { let person = await Highscore.findOne({ diff --git a/api/redis.js b/api/redis.js index 88c5d13..7b596ed 100644 --- a/api/redis.js +++ b/api/redis.js @@ -1,11 +1,12 @@ let client; try { const redis = require("redis"); - console.log("trying to create redis"); + console.log("Trying to establish connection with redis."); client = redis.createClient(); client.on("error", function(err) { client.quit(); console.error("Missing redis-configurations.."); + client = { rpush: function() { console.log("redis-dummy lpush", arguments); diff --git a/api/request.js b/api/request.js index 210c3e0..60388fa 100644 --- a/api/request.js +++ b/api/request.js @@ -1,10 +1,10 @@ const express = require("express"); const path = require("path"); const RequestedWine = require(path.join( - __dirname + "/../schemas/RequestedWine" + __dirname, "/schemas/RequestedWine" )); const Wine = require(path.join( - __dirname + "/../schemas/Wine" + __dirname, "/schemas/Wine" )); const deleteRequestedWineById = async (req, res) => { diff --git a/api/retrieve.js b/api/retrieve.js index a90b95f..c29133a 100644 --- a/api/retrieve.js +++ b/api/retrieve.js @@ -1,10 +1,10 @@ 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 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" + __dirname, "/schemas/PreLotteryWine" )); const prelotteryWines = async (req, res) => { diff --git a/api/router.js b/api/router.js index 668e76a..4d57057 100644 --- a/api/router.js +++ b/api/router.js @@ -1,22 +1,21 @@ const express = require("express"); const path = require("path"); -// Middleware -const mustBeAuthenticated = require(__dirname + "/../middleware/mustBeAuthenticated"); -const setAdminHeaderIfAuthenticated = require(__dirname + "/../middleware/setAdminHeaderIfAuthenticated"); +const mustBeAuthenticated = require(path.join(__dirname, "/middleware/mustBeAuthenticated")); +const setAdminHeaderIfAuthenticated = require(path.join(__dirname, "/middleware/setAdminHeaderIfAuthenticated")); -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 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 userApi = require(path.join(__dirname, "/user")); +const wineinfo = require(path.join(__dirname, "/wineinfo")); +const virtualApi = require(path.join(__dirname, "/virtualLottery")); const virtualRegistrationApi = require(path.join( - __dirname + "/virtualRegistration" + __dirname, "/virtualRegistration" )); -const lottery = require(path.join(__dirname + "/lottery")); - +const lottery = require(path.join(__dirname, "/lottery")); +const chatHistoryApi = require(path.join(__dirname, "/chatHistory")); const router = express.Router(); @@ -61,10 +60,11 @@ router.post('/winner/notify/:id', virtualRegistrationApi.sendNotificationToWinne 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); +router.get('/chat/history', chatHistoryApi.getAllHistory) +router.delete('/chat/history', mustBeAuthenticated, chatHistoryApi.deleteHistory) + +router.post('/login', userApi.login); +router.post('/register', mustBeAuthenticated, userApi.register); +router.get('/logout', userApi.logout); module.exports = router; diff --git a/schemas/Attendee.js b/api/schemas/Attendee.js similarity index 100% rename from schemas/Attendee.js rename to api/schemas/Attendee.js diff --git a/schemas/Highscore.js b/api/schemas/Highscore.js similarity index 100% rename from schemas/Highscore.js rename to api/schemas/Highscore.js diff --git a/schemas/PreLotteryWine.js b/api/schemas/PreLotteryWine.js similarity index 100% rename from schemas/PreLotteryWine.js rename to api/schemas/PreLotteryWine.js diff --git a/schemas/Purchase.js b/api/schemas/Purchase.js similarity index 100% rename from schemas/Purchase.js rename to api/schemas/Purchase.js diff --git a/schemas/RequestedWine.js b/api/schemas/RequestedWine.js similarity index 100% rename from schemas/RequestedWine.js rename to api/schemas/RequestedWine.js diff --git a/schemas/Subscription.js b/api/schemas/Subscription.js similarity index 100% rename from schemas/Subscription.js rename to api/schemas/Subscription.js diff --git a/schemas/User.js b/api/schemas/User.js similarity index 100% rename from schemas/User.js rename to api/schemas/User.js diff --git a/schemas/VirtualWinner.js b/api/schemas/VirtualWinner.js similarity index 100% rename from schemas/VirtualWinner.js rename to api/schemas/VirtualWinner.js diff --git a/schemas/Wine.js b/api/schemas/Wine.js similarity index 100% rename from schemas/Wine.js rename to api/schemas/Wine.js diff --git a/api/subscriptions.js b/api/subscriptions.js index 1d61a08..7fc7366 100644 --- a/api/subscriptions.js +++ b/api/subscriptions.js @@ -5,11 +5,11 @@ const webpush = require("web-push"); //requiring the web-push module const schedule = require("node-schedule"); const mustBeAuthenticated = require(path.join( - __dirname + "/../middleware/mustBeAuthenticated" + __dirname, "/middleware/mustBeAuthenticated" )); const config = require(path.join(__dirname + "/../config/defaults/push")); -const Subscription = require(path.join(__dirname + "/../schemas/Subscription")); +const Subscription = require(path.join(__dirname, "/schemas/Subscription")); const lotteryConfig = require(path.join( __dirname + "/../config/defaults/lottery" )); diff --git a/api/update.js b/api/update.js index c3fa4d1..88df56a 100644 --- a/api/update.js +++ b/api/update.js @@ -1,14 +1,14 @@ const express = require("express"); const path = require("path"); -const sub = require(path.join(__dirname + "/../api/subscriptions")); +const sub = require(path.join(__dirname, "/subscriptions")); -const _wineFunctions = require(path.join(__dirname + "/../api/wine")); -const _personFunctions = require(path.join(__dirname + "/../api/person")); -const Subscription = require(path.join(__dirname + "/../schemas/Subscription")); -const Lottery = require(path.join(__dirname + "/../schemas/Purchase")); +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" + __dirname, "/schemas/PreLotteryWine" )); const submitWines = async (req, res) => { diff --git a/api/user.js b/api/user.js new file mode 100644 index 0000000..7a2ce9e --- /dev/null +++ b/api/user.js @@ -0,0 +1,51 @@ +const passport = require("passport"); +const path = require("path"); +const User = require(path.join(__dirname, "/schemas/User")); +const router = require("express").Router(); + +const register = (req, res, next) => { + User.register( + new User({ username: req.body.username }), + req.body.password, + function(err) { + if (err) { + if (err.name == "UserExistsError") + res.status(409).send({ success: false, message: err.message }) + else if (err.name == "MissingUsernameError" || err.name == "MissingPasswordError") + res.status(400).send({ success: false, message: err.message }) + return next(err); + } + + return res.status(200).send({ message: "Bruker registrert. Velkommen " + req.body.username, success: true }) + } + ); +}; + +const login = (req, res, next) => { + passport.authenticate("local", function(err, user, info) { + if (err) { + if (err.name == "MissingUsernameError" || err.name == "MissingPasswordError") + return res.status(400).send({ message: err.message, success: false }) + return next(err); + } + + if (!user) return res.status(404).send({ message: "Incorrect username or password", success: false }) + + req.logIn(user, (err) => { + if (err) { return next(err) } + + return res.status(200).send({ message: "Velkommen " + user.username, success: true }) + }) + })(req, res, next); +}; + +const logout = (req, res) => { + req.logout(); + res.redirect("/"); +}; + +module.exports = { + register, + login, + logout +}; diff --git a/api/virtualLottery.js b/api/virtualLottery.js index 74224d6..cad4924 100644 --- a/api/virtualLottery.js +++ b/api/virtualLottery.js @@ -1,13 +1,13 @@ 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 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 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) => { diff --git a/api/virtualRegistration.js b/api/virtualRegistration.js index 4e5e895..ec869a3 100644 --- a/api/virtualRegistration.js +++ b/api/virtualRegistration.js @@ -1,13 +1,13 @@ const path = require("path"); -const _wineFunctions = require(path.join(__dirname + "/../api/wine")); -const _personFunctions = require(path.join(__dirname + "/../api/person")); -const Message = require(path.join(__dirname + "/../api/message")); +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" + __dirname, "/schemas/VirtualWinner" )); const PreLotteryWine = require(path.join( - __dirname + "/../schemas/PreLotteryWine" + __dirname, "/schemas/PreLotteryWine" )); diff --git a/api/wine.js b/api/wine.js index e844867..d953013 100644 --- a/api/wine.js +++ b/api/wine.js @@ -1,5 +1,5 @@ const path = require("path"); -const Wine = require(path.join(__dirname + "/../schemas/Wine")); +const Wine = require(path.join(__dirname, "/schemas/Wine")); async function findSaveWine(prelotteryWine) { let wonWine = await Wine.findOne({ name: prelotteryWine.name }); diff --git a/config/env/lottery.config.example.js b/config/env/lottery.config.example.js index 98b8d4d..46232dc 100644 --- a/config/env/lottery.config.example.js +++ b/config/env/lottery.config.example.js @@ -7,5 +7,7 @@ module.exports = { hours: 15, apiUrl: undefined, gatewayToken: undefined, - vinmonopoletToken: undefined + vinmonopoletToken: undefined, + googleanalytics_trackingId: undefined, + googleanalytics_cookieLifetime: 60 * 60 * 24 * 14 }; \ No newline at end of file diff --git a/config/service-worker.config.js b/config/service-worker.config.js index d54fe56..63921cd 100644 --- a/config/service-worker.config.js +++ b/config/service-worker.config.js @@ -2,7 +2,7 @@ const webpack = require("webpack"); const helpers = require("./helpers"); -const UglifyJSPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); const ServiceWorkerConfig = { resolve: { @@ -31,11 +31,10 @@ const ServiceWorkerConfig = { //filename: "js/[name].bundle.js" }, optimization: { + minimize: true, minimizer: [ - new UglifyJSPlugin({ - cache: true, - parallel: false, - sourceMap: false + new TerserPlugin({ + test: /\.js(\?.*)?$/i, }) ] }, diff --git a/config/vinlottis.config.js b/config/vinlottis.config.js deleted file mode 100644 index 2fd4d84..0000000 --- a/config/vinlottis.config.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; - -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const helpers = require("./helpers"); - -const VinlottisConfig = { - entry: { - vinlottis: ["@babel/polyfill", helpers.root("src", "vinlottis-init")] - }, - optimization: { - minimizer: [ - new HtmlWebpackPlugin({ - chunks: ["vinlottis"], - filename: "../index.html", - template: "./src/templates/Create.html", - inject: true, - minify: { - removeComments: true, - collapseWhitespace: false, - preserveLineBreaks: true, - removeAttributeQuotes: true - } - }) - ] - } -}; - -module.exports = VinlottisConfig; diff --git a/config/webpack.config.common.js b/config/webpack.config.common.js index 50680e6..6c89940 100644 --- a/config/webpack.config.common.js +++ b/config/webpack.config.common.js @@ -15,6 +15,12 @@ const webpackConfig = function(isDev) { "@": helpers.root("src") } }, + entry: { + vinlottis: helpers.root("src", "vinlottis-init") + }, + externals: { + moment: 'moment' // comes with chart.js + }, module: { rules: [ { @@ -33,7 +39,7 @@ const webpackConfig = function(isDev) { }, { test: /\.js$/, - loader: "babel-loader", + use: [ "babel-loader" ], include: [helpers.root("src")] }, { @@ -61,7 +67,11 @@ const webpackConfig = function(isDev) { }, { test: /\.woff(2)?(\?[a-z0-9]+)?$/, - loader: "url-loader?limit=10000&mimetype=application/font-woff" + loader: "url-loader", + options: { + limit: 10000, + mimetype: "application/font-woff" + } }, { test: /\.(ttf|eot|svg)(\?[a-z0-9]+)?$/, @@ -72,6 +82,7 @@ const webpackConfig = function(isDev) { plugins: [ new VueLoaderPlugin(), new webpack.DefinePlugin({ + __ENV__: JSON.stringify(process.env.NODE_ENV), __NAME__: JSON.stringify(env.name), __PHONE__: JSON.stringify(env.phone), __PRICE__: env.price, @@ -79,7 +90,9 @@ const webpackConfig = function(isDev) { __DATE__: env.date, __HOURS__: env.hours, __APIURL__: JSON.stringify(env.apiUrl), - __PUSHENABLED__: JSON.stringify(require("./defaults/push") != false) + __PUSHENABLED__: JSON.stringify(require("./defaults/push") != false), + __GA_TRACKINGID__: JSON.stringify(env.googleanalytics_trackingId), + __GA_COOKIELIFETIME__: env.googleanalytics_cookieLifetime }) ] }; diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index ca13cfb..7f2ca10 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -3,14 +3,14 @@ const webpack = require("webpack"); const merge = require("webpack-merge"); const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); -const HtmlPlugin = require("html-webpack-plugin"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); const helpers = require("./helpers"); const commonConfig = require("./webpack.config.common"); const environment = require("./env/dev.env"); let webpackConfig = merge(commonConfig(true), { mode: "development", - devtool: "cheap-module-eval-source-map", + devtool: "eval-cheap-module-source-map", output: { path: helpers.root("dist"), publicPath: "/", @@ -40,13 +40,9 @@ let webpackConfig = merge(commonConfig(true), { }); webpackConfig = merge(webpackConfig, { - entry: { - main: ["@babel/polyfill", helpers.root("src", "vinlottis-init")] - }, plugins: [ new HtmlPlugin({ - template: "src/templates/Create.html", - chunksSortMode: "dependency" + template: "src/templates/Index.html" }) ] }); diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index a38b84c..abaf0c4 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -4,11 +4,14 @@ const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const path = require("path"); const webpack = require("webpack"); const merge = require("webpack-merge"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); const MiniCSSExtractPlugin = require("mini-css-extract-plugin"); -const UglifyJSPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); + const helpers = require("./helpers"); const commonConfig = require("./webpack.config.common"); + const isProd = process.env.NODE_ENV === "production"; const environment = isProd ? require("./env/prod.env") @@ -16,11 +19,11 @@ const environment = isProd const webpackConfig = merge(commonConfig(false), { mode: "production", + stats: { children: false }, output: { path: helpers.root("public/dist"), - publicPath: "/dist/", + publicPath: "/public/dist/", filename: "js/[name].bundle.[hash:7].js" - //filename: "js/[name].bundle.js" }, optimization: { splitChunks: { @@ -33,25 +36,35 @@ const webpackConfig = merge(commonConfig(false), { } } }, + minimize: true, minimizer: [ + new HtmlWebpackPlugin({ + chunks: ["vinlottis"], + filename: "index.html", + template: "./src/templates/Index.html", + inject: true, + minify: { + removeComments: true, + collapseWhitespace: false, + preserveLineBreaks: true, + removeAttributeQuotes: true + } + }), new OptimizeCSSAssetsPlugin({ cssProcessorPluginOptions: { preset: ["default", { discardComments: { removeAll: true } }] } }), - new UglifyJSPlugin({ - cache: true, - parallel: false, - sourceMap: !isProd + new TerserPlugin({ + test: /\.js(\?.*)?$/i, }) ] }, plugins: [ - new CleanWebpackPlugin(), + new CleanWebpackPlugin(), // clean output folder new webpack.EnvironmentPlugin(environment), new MiniCSSExtractPlugin({ filename: "css/[name].[hash:7].css" - //filename: "css/[name].css" }) ] }); diff --git a/package.json b/package.json index 35a92cb..8707e98 100644 --- a/package.json +++ b/package.json @@ -4,33 +4,26 @@ "description": "", "main": "server.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js", + "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", "dev": "cross-env NODE_ENV=development webpack-dev-server", + "start-dev": "cross-env NODE_ENV=development node server.js", + "test": "echo \"Error: no test specified\" && exit 1" "build": "cross-env NODE_ENV=production webpack --hide-modules" }, "author": "", "license": "ISC", "dependencies": { - "@babel/polyfill": "~7.2", "@sentry/browser": "^5.27.4", "@sentry/integrations": "^5.27.4", - "@sentry/tracing": "^5.27.4", "@zxing/library": "^0.15.2", - "body-parser": "^1.19.0", "canvas-confetti": "^1.2.0", "chart.js": "^2.9.3", - "clean-webpack-plugin": "^3.0.0", - "compression": "^1.7.4", "connect-mongo": "^3.2.0", - "cors": "^2.8.5", "express": "^4.17.1", "express-session": "^1.17.0", - "extract-text-webpack-plugin": "^3.0.2", - "feature-policy": "^0.4.0", - "helmet": "^3.21.2", "moment": "^2.24.0", - "mongoose": "^5.8.7", + "mongoose": "^5.10.9", "node-fetch": "^2.6.0", "node-sass": "^4.13.0", "node-schedule": "^1.3.2", @@ -38,46 +31,36 @@ "passport-local": "^1.0.0", "passport-local-mongoose": "^6.0.1", "qrcode": "^1.4.4", - "referrer-policy": "^1.2.0", "socket.io": "^2.3.0", "socket.io-client": "^2.3.0", "vue": "~2.6", - "vue-analytics": "^5.22.1", "vue-router": "~3.0", "vuex": "^3.1.1", "web-push": "^3.4.3" }, "devDependencies": { - "@babel/core": "~7.2", - "@babel/plugin-proposal-class-properties": "~7.3", - "@babel/plugin-proposal-decorators": "~7.3", - "@babel/plugin-proposal-json-strings": "~7.2", - "@babel/plugin-syntax-dynamic-import": "~7.2", - "@babel/plugin-syntax-import-meta": "~7.2", - "@babel/preset-env": "~7.3", + "@babel/core": "~7.12", + "@babel/preset-env": "~7.12", "babel-loader": "~8.0", - "compression-webpack-plugin": "^3.1.0", + "clean-webpack-plugin": "^3.0.0", + "core-js": "3", "cross-env": "^6.0.3", "css-loader": "^3.2.0", - "file-loader": "^4.2.0", + "file-loader": "^6.2.0", "friendly-errors-webpack-plugin": "~1.7", "google-maps-api-loader": "^1.1.1", - "html-webpack-plugin": "~3.2", - "mini-css-extract-plugin": "~0.5", - "optimize-css-assets-webpack-plugin": "~3.2", - "pm2": "^4.2.3", + "html-webpack-plugin": "~4.5", + "mini-css-extract-plugin": "~1.3.1", + "optimize-css-assets-webpack-plugin": "~5.0.4", "redis": "^3.0.2", - "sass-loader": "~7.1", - "uglifyjs-webpack-plugin": "~1.2", - "url-loader": "^2.2.0", - "vue-loader": "~15.6", + "sass-loader": "~10.1.0", + "url-loader": "^4.1.1", + "vue-loader": "~15.9.5", "vue-style-loader": "~4.1", - "vue-template-compiler": "~2.6", - "webpack": "~4.41.5", + "webpack": "~5.6.0", "webpack-bundle-analyzer": "^3.6.0", - "webpack-cli": "~3.2", - "webpack-dev-server": "~3.1", - "webpack-hot-middleware": "~2.24", + "webpack-cli": "~4.2.0", + "webpack-dev-server": "~3.11", "webpack-merge": "~4.2" } } diff --git a/pm2.json b/pm2.json deleted file mode 100644 index d571254..0000000 --- a/pm2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "apps": [ - { - "name": "vinlottis", - "script": "./server.js", - "watch": true, - "instances": "max", - "exec_mode": "cluster", - "ignore_watch": ["./node_modules", "./public/assets/"] - } - ] -} diff --git a/public/analytics.js b/public/analytics.js new file mode 100644 index 0000000..f83a1a2 --- /dev/null +++ b/public/analytics.js @@ -0,0 +1,88 @@ +// https://www.google-analytics.com/analytics.js - 24.11.2020 +(function(){/* + + Copyright The Closure Library Authors. + SPDX-License-Identifier: Apache-2.0 +*/ +var l=this||self,m=function(a,b){a=a.split(".");var c=l;a[0]in c||"undefined"==typeof c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)a.length||void 0===b?c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}:c[d]=b};var q=function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])},r=function(a){for(var b in a)if(a.hasOwnProperty(b))return!0;return!1};var t=/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;var u=window,v=document,w=function(a,b){v.addEventListener?v.addEventListener(a,b,!1):v.attachEvent&&v.attachEvent("on"+a,b)};var x={},y=function(){x.TAGGING=x.TAGGING||[];x.TAGGING[1]=!0};var z=/:[0-9]+$/,A=function(a,b,c){a=a.split("&");for(var d=0;dd?a.href:a.href.substr(0,d));a=d;break;case "protocol":a=f;break;case "host":a=a.hostname.replace(z,"").toLowerCase();c&&(d=/^www\d*\./.exec(a))&&d[0]&&(a=a.substr(d[0].length));break;case "port":a=String(Number(a.port)||("http"==f?80:"https"==f?443:""));break;case "path":a.pathname|| +a.hostname||y();a="/"==a.pathname.substr(0,1)?a.pathname:"/"+a.pathname;a=a.split("/");a:if(d=d||[],c=a[a.length-1],Array.prototype.indexOf)d=d.indexOf(c),d="number"==typeof d?d:-1;else{for(e=0;e>2;f=(f&3)<<4|g>>4;g=(g&15)<<2|h>>6;h&=63;e||(h=64,d||(g=64));b.push(G[k],G[f],G[g],G[h])}return b.join("")} +function K(a){function b(k){for(;d>4);64!=g&&(c+=String.fromCharCode(f<<4&240|g>>2),64!=h&&(c+=String.fromCharCode(g<<6&192|h)))}};var L;var N=function(){var a=aa,b=ba,c=M(),d=function(g){a(g.target||g.srcElement||{})},e=function(g){b(g.target||g.srcElement||{})};if(!c.init){w("mousedown",d);w("keyup",d);w("submit",e);var f=HTMLFormElement.prototype.submit;HTMLFormElement.prototype.submit=function(){b(this);f.call(this)};c.init=!0}},O=function(a,b,c,d,e){a={callback:a,domains:b,fragment:2===c,placement:c,forms:d,sameHost:e};M().decorators.push(a)},P=function(a,b,c){for(var d=M().decorators,e={},f=0;fc;c++){for(var d=c,e=0;8>e;e++)d=d&1?d>>>1^ +3988292384:d>>>1;b[c]=d}}L=b;b=4294967295;for(c=0;c>>8^L[(b^a.charCodeAt(c))&255];return((b^-1)>>>0).toString(36)},fa=function(a){return function(b){var c=E(u.location.href),d=c.search.replace("?","");var e=A(d,"_gl",!0);b.query=T(e||"")||{};e=D(c,"fragment");var f=e.match(Q("_gl"));b.fragment=T(f&&f[3]||"")||{};a&&ea(c,d,e)}};function U(a,b){if(a=Q(a).exec(b)){var c=a[2],d=a[4];b=a[1];d&&(b=b+c+d)}return b} +var ea=function(a,b,c){function d(f,g){f=U("_gl",f);f.length&&(f=g+f);return f}if(u.history&&u.history.replaceState){var e=Q("_gl");if(e.test(b)||e.test(c))a=D(a,"path"),b=d(b,"?"),c=d(c,"#"),u.history.replaceState({},void 0,""+a+b+c)}},T=function(a){var b=void 0===b?3:b;try{if(a){a:{for(var c=0;3>c;++c){var d=ca.exec(a);if(d){var e=d;break a}a=decodeURIComponent(a)}e=void 0}if(e&&"1"===e[1]){var f=e[2],g=e[3];a:{for(e=0;e>21:b}return b};/* + + Copyright The Closure Library Authors. + SPDX-License-Identifier: Apache-2.0 +*/ +var $c=function(a){this.C=a||[]};$c.prototype.set=function(a){this.C[a]=!0};$c.prototype.encode=function(){for(var a=[],b=0;b\x3c/script>')}else c=M.createElement("script"),c.type="text/javascript",c.async=!0,c.src=a,b&&(c.id=b),d&&c.setAttribute("nonce",d),a=M.getElementsByTagName("script")[0],a.parentNode.insertBefore(c,a)}},be=function(a,b){return E(M.location[b?"href":"search"],a)},E=function(a,b){return(a=a.match("(?:&|#|\\?)"+K(b).replace(/([.*+?^=!:${}()|\[\]\/\\])/g, +"\\$1")+"=([^&#]*)"))&&2==a.length?a[1]:""},xa=function(){var a=""+M.location.hostname;return 0==a.indexOf("www.")?a.substring(4):a},de=function(a,b){var c=a.indexOf(b);if(5==c||6==c)if(a=a.charAt(c+b.length),"/"==a||"?"==a||""==a||":"==a)return!0;return!1},ya=function(a,b){var c=M.referrer;if(/^(https?|android-app):\/\//i.test(c)){if(a)return c;a="//"+M.location.hostname;if(!de(c,a))return b&&(b=a.replace(/\./g,"-")+".cdn.ampproject.org",de(c,b))?void 0:c}},za=function(a,b){if(1==b.length&&null!= +b[0]&&"object"===typeof b[0])return b[0];for(var c={},d=Math.min(a.length+1,b.length),e=0;e=b.length)wc(a,b,c);else if(8192>=b.length)x(a,b,c)||wd(a,b,c)||wc(a,b,c);else throw ge("len",b.length),new Da(b.length);},pe=function(a,b, +c,d){d=d||ua;wd(a+"?"+b,"",d,c)},wc=function(a,b,c){var d=ta(a+"?"+b);d.onload=d.onerror=function(){d.onload=null;d.onerror=null;c()}},wd=function(a,b,c,d){var e=O.XMLHttpRequest;if(!e)return!1;var g=new e;if(!("withCredentials"in g))return!1;a=a.replace(/^http:/,"https:");g.open("POST",a,!0);g.withCredentials=!0;g.setRequestHeader("Content-Type","text/plain");g.onreadystatechange=function(){if(4==g.readyState){if(d&&"text/plain"===g.getResponseHeader("Content-Type"))try{Ea(d,g.responseText,c)}catch(ca){ge("xhr", +"rsp"),c()}else c();g=null}};g.send(b);return!0},Ea=function(a,b,c){if(1>b.length)ge("xhr","ver","0"),c();else if(3=100*R(a,Ka))throw"abort";}function Ma(a){if(G(P(a,Na)))throw"abort";}function Oa(){var a=M.location.protocol;if("http:"!=a&&"https:"!=a)throw"abort";} +function Pa(a){try{O.navigator.sendBeacon?J(42):O.XMLHttpRequest&&"withCredentials"in new O.XMLHttpRequest&&J(40)}catch(c){}a.set(ld,Td(a),!0);a.set(Ac,R(a,Ac)+1);var b=[];ue.map(function(c,d){d.F&&(c=a.get(c),void 0!=c&&c!=d.defaultValue&&("boolean"==typeof c&&(c*=1),b.push(d.F+"="+K(""+c))))});!1===a.get(xe)&&b.push("npa=1");b.push("z="+Bd());a.set(Ra,b.join("&"),!0)} +function Sa(a){var b=P(a,fa);!b&&a.get(Vd)&&(b="beacon");var c=P(a,gd),d=P(a,oe),e=c||(d||bd(!1)+"")+"/collect";switch(P(a,ad)){case "d":e=c||(d||bd(!1)+"")+"/j/collect";b=a.get(qe)||void 0;pe(e,P(a,Ra),b,a.Z(Ia));break;default:b?(c=P(a,Ra),d=(d=a.Z(Ia))||ua,"image"==b?wc(e,c,d):"xhr"==b&&wd(e,c,d)||"beacon"==b&&x(e,c,d)||ba(e,c,d)):ba(e,P(a,Ra),a.Z(Ia))}e=P(a,Na);e=h(e);b=e.hitcount;e.hitcount=b?b+1:1;e.first_hit||(e.first_hit=(new Date).getTime());e=P(a,Na);delete h(e).pending_experiments;a.set(Ia, +ua,!0)}function Hc(a){qc().expId&&a.set(Nc,qc().expId);qc().expVar&&a.set(Oc,qc().expVar);var b=P(a,Na);if(b=h(b).pending_experiments){var c=[];for(d in b)b.hasOwnProperty(d)&&b[d]&&c.push(encodeURIComponent(d)+"."+encodeURIComponent(b[d]));var d=c.join("!")}else d=void 0;d&&((b=a.get(m))&&(d=b+"!"+d),a.set(m,d,!0))}function cd(){if(O.navigator&&"preview"==O.navigator.loadPurpose)throw"abort";} +function yd(a){var b=O.gaDevIds||[];if(ka(b)){var c=a.get("&did");qa(c)&&0=c)throw"abort";a.set(Wa,--c)}a.set(Ua,++b)};var Ya=function(){this.data=new ee};Ya.prototype.get=function(a){var b=$a(a),c=this.data.get(a);b&&void 0==c&&(c=ea(b.defaultValue)?b.defaultValue():b.defaultValue);return b&&b.Z?b.Z(this,a,c):c};var P=function(a,b){a=a.get(b);return void 0==a?"":""+a},R=function(a,b){a=a.get(b);return void 0==a||""===a?0:Number(a)};Ya.prototype.Z=function(a){return(a=this.get(a))&&ea(a)?a:ua}; +Ya.prototype.set=function(a,b,c){if(a)if("object"==typeof a)for(var d in a)a.hasOwnProperty(d)&&ab(this,d,a[d],c);else ab(this,a,b,c)};var ab=function(a,b,c,d){if(void 0!=c)switch(b){case Na:wb.test(c)}var e=$a(b);e&&e.o?e.o(a,b,c,d):a.data.set(b,c,d)};var ue=new ee,ve=[],bb=function(a,b,c,d,e){this.name=a;this.F=b;this.Z=d;this.o=e;this.defaultValue=c},$a=function(a){var b=ue.get(a);if(!b)for(var c=0;c=b?!1:!0},gc=function(a){var b={};if(Ec(b)||Fc(b)){var c=b[Eb];void 0==c||Infinity==c||isNaN(c)||(0c)a[b]=void 0},Fd=function(a){return function(b){if("pageview"==b.get(Va)&&!a.I){a.I=!0;var c=aa(b),d=0a.length)J(12);else{for(var d=[],e=0;e=a&&d.push({hash:ca[0],R:e[g],O:ca})}if(0!=d.length)return 1==d.length?d[0]:Zc(b,d)||Zc(c,d)||Zc(null,d)||d[0]}function Zc(a,b){if(null==a)var c=a=1;else c=La(a),a=La(D(a,".")?a.substring(1):"."+a);for(var d=0;darguments.length)){if("string"===typeof arguments[0]){var b=arguments[0];var c=[].slice.call(arguments,1)}else b=arguments[0]&&arguments[0][Va],c=arguments;b&&(c=za(me[b]||[],c),c[Va]=b,this.model.set(c,void 0,!0),this.filters.D(this.model),this.model.data.m={})}};pc.prototype.ma=function(a,b){var c=this;u(a,c,b)||(v(a,function(){u(a,c,b)}),y(String(c.get(V)),a,void 0,b,!0))}; +var td=function(a,b){var c=P(a,U);a.data.set(la,"_ga"==c?"_gid":c+"_gid");if("cookie"==P(a,ac)){hc=!1;c=Ca(P(a,U));c=Xd(a,c);if(!c){c=P(a,W);var d=P(a,$b)||xa();c=Xc("__utma",d,c);void 0!=c?(J(10),c=c.O[1]+"."+c.O[2]):c=void 0}c&&(hc=!0);if(d=c&&!a.get(Hd))if(d=c.split("."),2!=d.length)d=!1;else if(d=Number(d[1])){var e=R(a,Zb);d=d+e<(new Date).getTime()/1E3}else d=!1;d&&(c=void 0);c&&(a.data.set(xd,c),a.data.set(Q,c),(c=uc(a))&&a.data.set(I,c));if(a.get(je)&&(c=a.get(ce),d=a.get(ie),!c||d&&"aw.ds"!= +d)){c={};if(M){d=[];e=M.cookie.split(";");for(var g=/^\s*_gac_(UA-\d+-\d+)=\s*(.+?)\s*$/,ca=0;ca=ca[0]||0>=ca[1]?"":ca.join("x");a.set(rb,c);a.set(tb,fc());a.set(ob,M.characterSet||M.charset);a.set(sb,b&&"function"===typeof b.javaEnabled&&b.javaEnabled()||!1);a.set(nb,(b&&(b.language||b.browserLanguage)||"").toLowerCase());a.data.set(ce,be("gclid",!0));a.data.set(ie,be("gclsrc",!0));a.data.set(fe,Math.round((new Date).getTime()/1E3));if(d&&a.get(cc)&&(b=M.location.hash)){b=b.split(/[?&#]+/);d=[];for(c=0;ca.split("/")[0].indexOf(":")&&(a=ca+e[2].substring(0,e[2].lastIndexOf("/"))+"/"+a);c.href=a;d=b(c);return{protocol:(c.protocol||"").toLowerCase(),host:d[0],port:d[1],path:d[2],query:c.search||"",url:a||""}};var Z={ga:function(){Z.f=[]}};Z.ga();Z.D=function(a){var b=Z.J.apply(Z,arguments);b=Z.f.concat(b);for(Z.f=[];0c;c++){var d=b[c].src;if(d&&0==d.indexOf(bd(!0)+ +"/analytics")){b=!0;break a}}b=!1}b&&(Ba=!0)}(O.gaplugins=O.gaplugins||{}).Linker=Dc;b=Dc.prototype;C("linker",Dc);X("decorate",b,b.ca,20);X("autoLink",b,b.S,25);X("passthrough",b,b.$,25);C("displayfeatures",fd);C("adfeatures",fd);a=a&&a.q;ka(a)?Z.D.apply(N,a):J(50)}};var Oe=N.N,Pe=O[gb];Pe&&Pe.r?Oe():z(Oe);z(function(){Z.D(["provide","render",ua])});})(window); diff --git a/server.js b/server.js index c26c7b8..8741610 100644 --- a/server.js +++ b/server.js @@ -4,59 +4,40 @@ const server = require("http").Server(app); const io = require("socket.io")(server); const path = require("path"); const session = require("express-session"); -const User = require(path.join(__dirname + "/schemas/User")); +const User = require(path.join(__dirname + "/api/schemas/User")); const apiRouter = require(path.join(__dirname + "/api/router.js")); - -const loginApi = require(path.join(__dirname + "/api/login")); const subscriptionApi = require(path.join(__dirname + "/api/subscriptions")); //This is required for the chat to work const chat = require(path.join(__dirname + "/api/chat"))(io); -const chatHistory = require(path.join(__dirname + "/api/chatHistory")); - -const bodyParser = require("body-parser"); const mongoose = require("mongoose"); const MongoStore = require("connect-mongo")(session); -const cors = require("cors"); -const referrerPolicy = require("referrer-policy"); -const helmet = require("helmet"); -const featurePolicy = require("feature-policy"); - -const compression = require("compression"); -app.use(compression()); - -app.use( - featurePolicy({ - features: { - fullscreen: ["*"], - //vibrate: ["'none'"], - payment: ["'none'"], - microphone: ["'none'"], - camera: ["'self'"], - speaker: ["*"], - syncXhr: ["'self'"] - //notifications: ["'self'"] - } - }) -); -app.use(helmet()); -app.use(helmet.frameguard({ action: "sameorigin" })); -app.use(referrerPolicy({ policy: "origin" })); - -app.use(cors()); +// mongoose / database mongoose.promise = global.Promise; -mongoose.connect("mongodb://localhost/vinlottis"); -mongoose.set("debug", true); +mongoose.connect("mongodb://localhost/vinlottis", { + useCreateIndex: true, + useNewUrlParser: true, + useUnifiedTopology: true, + serverSelectionTimeoutMS: 10000 // initial connection timeout +}).then(_ => console.log("Mongodb connection established!")) +.catch(err => { + console.log(err); + console.error("ERROR! Mongodb required to run."); + process.exit(1); +}) +mongoose.set("debug", process.env.NODE_ENV === "development"); -app.use( - bodyParser.urlencoded({ - extended: true - }) -); -app.use(bodyParser.json()); +// middleware +const setupCORS = require(path.join(__dirname, "/api/middleware/setupCORS")); +const setupHeaders = require(path.join(__dirname, "/api/middleware/setupHeaders")); +app.use(setupCORS) +app.use(setupHeaders) + +// parse application/json +app.use(express.json()); app.use( session({ @@ -70,36 +51,34 @@ app.use( }) ); -app.set('socketio', io); +app.set('socketio', io); // set io instance to key "socketio" const passport = require("passport"); const LocalStrategy = require("passport-local"); - app.use(passport.initialize()); app.use(passport.session()); + // use static authenticate method of model in LocalStrategy passport.use(new LocalStrategy(User.authenticate())); - // use static serialize and deserialize of model for passport session support passport.serializeUser(User.serializeUser()); passport.deserializeUser(User.deserializeUser()); +// files app.use("/public", express.static(path.join(__dirname, "public"))); -app.use("/dist", express.static(path.join(__dirname, "public/dist"))); -app.use("/", loginApi); -app.use("/api/", chatHistory); +app.use("/service-worker.js", express.static(path.join(__dirname, "public/sw/serviceWorker.js"))); + +// api endpoints app.use("/api/", apiRouter); + +// redirects +app.get("/dagens", (req, res) => res.redirect("/#/dagens")); +app.get("/winner/:id", (req, res) => res.redirect("/#/winner/" + req.params.id)); + +// push-notifications app.use("/subscription", subscriptionApi); -app.get("/dagens", function(req, res) { - res.redirect("/#/dagens"); -}); -app.get("/winner/:id", function(req, res) { - res.redirect("/#/winner/" + req.params.id); -}); - -app.use("/service-worker.js", function(req, res) { - res.sendFile(path.join(__dirname, "public/sw/serviceWorker.js")); -}); +// No other route defined, return index file +app.use("/", (req, res) => res.sendFile(path.join(__dirname + "/public/dist/index.html"))); server.listen(30030); diff --git a/src/Vinlottis.vue b/src/Vinlottis.vue index c468a14..9c76db5 100644 --- a/src/Vinlottis.vue +++ b/src/Vinlottis.vue @@ -86,16 +86,16 @@ export default { @font-face { font-family: "knowit"; font-weight: 600; - src: url("/../public/assets/fonts/bold.woff"), - url("/../public/assets/fonts/bold.woff") format("woff"), local("Arial"); + src: url("/public/assets/fonts/bold.woff"), + url("/public/assets/fonts/bold.woff") format("woff"), local("Arial"); font-display: swap; } @font-face { font-family: "knowit"; font-weight: 300; - src: url("/../public/assets/fonts/regular.eot"), - url("/../public/assets/fonts/regular.woff") format("woff"), local("Arial"); + src: url("/public/assets/fonts/regular.eot"), + url("/public/assets/fonts/regular.woff") format("woff"), local("Arial"); font-display: swap; } diff --git a/src/api.js b/src/api.js index 3c2baf1..35a2109 100644 --- a/src/api.js +++ b/src/api.js @@ -243,7 +243,7 @@ const handleErrors = async resp => { }; const login = (username, password) => { - const url = new URL("/login", BASE_URL); + const url = new URL("/api/login", BASE_URL); const options = { headers: { "Content-Type": "application/json" @@ -262,7 +262,7 @@ const login = (username, password) => { }; const register = (username, password) => { - const url = new URL("/register", BASE_URL); + const url = new URL("/api/register", BASE_URL); const options = { headers: { "Content-Type": "application/json" diff --git a/src/components/AllRequestedWines.vue b/src/components/AllRequestedWines.vue index 67a54a0..a2996d1 100644 --- a/src/components/AllRequestedWines.vue +++ b/src/components/AllRequestedWines.vue @@ -39,8 +39,8 @@ export default { diff --git a/src/templates/Index.html b/src/templates/Index.html index 6c217c6..857f0e5 100644 --- a/src/templates/Index.html +++ b/src/templates/Index.html @@ -1 +1,73 @@ -
+ + + + + Vinlottis + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/src/ui/RaffleGenerator.vue b/src/ui/RaffleGenerator.vue index 455f755..7ba51c3 100644 --- a/src/ui/RaffleGenerator.vue +++ b/src/ui/RaffleGenerator.vue @@ -112,13 +112,11 @@ export default { this.emitColors() - if (window.location.hostname == "localhost") { - return; - } - this.$ga.event({ + window.ga('send', { + hitType: "event", eventCategory: "Raffles", eventAction: "Generate", - eventValue: JSON.stringify(this.colors) + eventLabel: JSON.stringify(this.colors) }); return; } @@ -292,9 +290,9 @@ label .text { width: 150px; height: 150px; margin: 20px; - -webkit-mask-image: url(/../../public/assets/images/lodd.svg); + -webkit-mask-image: url(/public/assets/images/lodd.svg); background-repeat: no-repeat; - mask-image: url(/../../public/assets/images/lodd.svg); + mask-image: url(/public/assets/images/lodd.svg); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; diff --git a/src/ui/RequestedWineCard.vue b/src/ui/RequestedWineCard.vue index addabe5..3ba985a 100644 --- a/src/ui/RequestedWineCard.vue +++ b/src/ui/RequestedWineCard.vue @@ -77,7 +77,7 @@ export default {