Reorganised some routing logic. Added separate views for SPAs and reorganised static folders to be globally accessible, so that the separate views can access the right folder. Language can be permanently changed for account.

This commit is contained in:
Daniel Ledda
2020-05-24 11:33:25 +02:00
parent 83844588df
commit 3a7e7de3d4
17 changed files with 1447 additions and 3537 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
node_modules node_modules
dist dist
static/semantic static/semantic
static/frontend
static/game

2
.idea/modules.xml generated
View File

@@ -3,7 +3,7 @@
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/kadi_backend.iml" filepath="$PROJECT_DIR$/.idea/kadi_backend.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/kadi_backend.iml" filepath="$PROJECT_DIR$/.idea/kadi_backend.iml" />
<module fileurl="file://$PROJECT_DIR$/../kadi_frontend/.idea/kniffel.iml" filepath="$PROJECT_DIR$/../kadi_frontend/.idea/kniffel.iml" /> <module fileurl="file://$PROJECT_DIR$/../kadi_frontend/.idea/kadi_frontendä.iml" filepath="$PROJECT_DIR$/../kadi_frontend/.idea/kadi_frontendä.iml" />
<module fileurl="file://$PROJECT_DIR$/../kadi_game/.idea/kadi_game.iml" filepath="$PROJECT_DIR$/../kadi_game/.idea/kadi_game.iml" /> <module fileurl="file://$PROJECT_DIR$/../kadi_game/.idea/kadi_game.iml" filepath="$PROJECT_DIR$/../kadi_game/.idea/kadi_game.iml" />
<module fileurl="file://$PROJECT_DIR$/../../../.idea/www.iml" filepath="$PROJECT_DIR$/../../../.idea/www.iml" /> <module fileurl="file://$PROJECT_DIR$/../../../.idea/www.iml" filepath="$PROJECT_DIR$/../../../.idea/www.iml" />
</modules> </modules>

4807
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,9 @@
"express-session": "^1.17.1", "express-session": "^1.17.1",
"mongoose": "^5.9.11", "mongoose": "^5.9.11",
"passport": "^0.4.1", "passport": "^0.4.1",
"passport-local": "^1.0.0" "passport-local": "^1.0.0",
"diff": ">=3.5.0",
"lodash.template": ">=4.5.0"
}, },
"devDependencies": { "devDependencies": {
"@types/bcrypt": "^3.0.0", "@types/bcrypt": "^3.0.0",

View File

@@ -1,14 +1,17 @@
import passport from "passport"; import {IDbUserDoc} from "../models/dbUser";
import DbUser, {IDbUser, IDbUserDoc} from "../models/dbUser";
import {RequestHandler} from "express"; import {RequestHandler} from "express";
import SavedGame from "../models/savedGame";
export const whoAmI: RequestHandler = async (req, res) => { export const whoAmI: RequestHandler = async (req, res) => {
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
const user = req.user as IDbUserDoc; const user = req.user as IDbUserDoc;
res.json({loggedIn: true, username: user.username}); res.json({loggedIn: true, username: user.username, lang: user.lang});
} }
else { else {
res.json({loggedIn: false}); res.json({loggedIn: false});
} }
}; };
export const changeLang: RequestHandler = async (req, res) => {
const user = (req.user as IDbUserDoc);
user.changeLang(req.body.lang);
};

View File

@@ -7,6 +7,7 @@ export const listGames: RequestHandler = async (req, res) => {
const user = (req.user as IDbUserDoc); const user = (req.user as IDbUserDoc);
const dbUser = await DbUser.findById(user._id, {"savedGames.game": 1, "savedGames.createdAt": 1}); const dbUser = await DbUser.findById(user._id, {"savedGames.game": 1, "savedGames.createdAt": 1});
if (dbUser) { if (dbUser) {
console.log(dbUser.savedGames);
res.json({games: dbUser.savedGames}); res.json({games: dbUser.savedGames});
} }
else { else {
@@ -16,25 +17,5 @@ export const listGames: RequestHandler = async (req, res) => {
export const saveGame: RequestHandler = async (req, res) => { export const saveGame: RequestHandler = async (req, res) => {
const user = (req.user as IDbUserDoc); const user = (req.user as IDbUserDoc);
const handleError = (err: string) => { await user.addGame(req.body);
res.send({error: true, message: err});
};
DbUser.findById(user, (err, user) => {
if (err) {
handleError(err);
}
else if (user) {
const newGame = new SavedGame();
newGame.game = req.body;
user.savedGames.push(newGame);
user.save((err) => {
if (err) {
return handleError(err);
}
else {
res.send("Thanks for submitting your game, " + user.username + "!");
}
})
}
});
}; };

5
src/enums.ts Normal file
View File

@@ -0,0 +1,5 @@
export enum SupportedLang {
gb = "gb",
de = "de",
it = "it",
}

View File

@@ -5,7 +5,6 @@ import Settings from "./server-config.json";
import flash from "express-flash"; import flash from "express-flash";
import passport from "passport"; import passport from "passport";
import session from "express-session"; import session from "express-session";
import * as path from "path";
import MainRouter from "./routers/mainRouter"; import MainRouter from "./routers/mainRouter";
// MongoDB Setup // MongoDB Setup
@@ -23,6 +22,7 @@ const app = express();
app.use(express.json()); app.use(express.json());
app.set("port", process.env.PORT || 3000); app.set("port", process.env.PORT || 3000);
app.set("view-engine", "ejs"); app.set("view-engine", "ejs");
app.set("views", "views");
app.use(express.urlencoded({ extended: false})); app.use(express.urlencoded({ extended: false}));
app.use(flash()); app.use(flash());
app.use(session({ app.use(session({
@@ -39,7 +39,11 @@ app.locals = {
initialisePassport(); initialisePassport();
app.use(passport.initialize()); app.use(passport.initialize());
app.use(passport.session()); app.use(passport.session());
app.use((req, res, next) => {
console.log(req.originalUrl);
next();
});
app.use(Settings.serverRoot + "/static", express.static("static"));
app.use(Settings.serverRoot, MainRouter); app.use(Settings.serverRoot, MainRouter);
const server = app.listen(app.get("port"), () => { const server = app.listen(app.get("port"), () => {

View File

@@ -1,8 +1,9 @@
import mongoose from "mongoose"; import mongoose from "mongoose";
import Player, {IPlayer, IPlayerDoc, PlayerSchema} from "./player"; import Player, {IPlayer, IPlayerDoc, PlayerSchema} from "./player";
import {AccountStats, AccountStatsSchema, IAccountStats, IAccountStatsDoc} from "./stats"; import {AccountStats, AccountStatsSchema, IAccountStats, IAccountStatsDoc} from "./stats";
import {ISavedGame, ISavedGameDoc, SavedGameSchema} from "./savedGame"; import SavedGame, {ISavedGame, ISavedGameDoc, SavedGameSchema} from "./savedGame";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import {SupportedLang} from "../enums";
export class CredentialsTakenError extends Error { export class CredentialsTakenError extends Error {
public emailExists: boolean; public emailExists: boolean;
@@ -19,6 +20,7 @@ export interface IDbUser {
username: string; username: string;
email: string; email: string;
password: string; password: string;
lang?: SupportedLang;
friends?: IDbUser[]; friends?: IDbUser[];
player?: IPlayer; player?: IPlayer;
guests?: IPlayer[]; guests?: IPlayer[];
@@ -30,11 +32,14 @@ export interface IDbUserDoc extends mongoose.Document {
username: string; username: string;
email: string; email: string;
password: string; password: string;
lang: SupportedLang;
friends: IDbUserDoc[]; friends: IDbUserDoc[];
player: IPlayerDoc; player: IPlayerDoc;
guests: IPlayerDoc[]; guests: IPlayerDoc[];
accountStats: IAccountStatsDoc; accountStats: IAccountStatsDoc;
savedGames: ISavedGameDoc[]; savedGames: ISavedGameDoc[];
changeLang(lang: SupportedLang): void;
addGame(game: any): Promise<string | null>;
} }
export interface IDbUserModel extends mongoose.Model<IDbUserDoc> { export interface IDbUserModel extends mongoose.Model<IDbUserDoc> {
@@ -49,11 +54,12 @@ export const DbUserSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true }, username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true },
password: { type: String, required: true }, password: { type: String, required: true },
friends: {type: [mongoose.Schema.Types.ObjectId], required: true, default: []}, lang: { type: String, required: true },
friends: {type: [mongoose.Schema.Types.ObjectId], default: []},
player: {type: PlayerSchema, required: true, unique: true}, player: {type: PlayerSchema, required: true, unique: true},
guests: {type: [PlayerSchema], required: true, default: []}, guests: {type: [PlayerSchema], default: []},
accountStats: {type: AccountStatsSchema, required: true, default: () => ({}) }, accountStats: {type: AccountStatsSchema, default: () => ({}) },
savedGames: {type: [SavedGameSchema], required: true, default: []}, savedGames: {type: [SavedGameSchema], default: []},
}); });
DbUserSchema.statics.findByEmail = async function (emailQuery: string) { DbUserSchema.statics.findByEmail = async function (emailQuery: string) {
@@ -66,6 +72,7 @@ DbUserSchema.statics.addNewUser = async function (user: IDbUser) {
username: user.username, username: user.username,
email: user.email, email: user.email,
password: user.password, password: user.password,
lang: SupportedLang.gb,
player player
}); });
}; };
@@ -90,5 +97,19 @@ DbUserSchema.statics.userWithUsernameExists = async function (username: string)
return this.exists({username}); return this.exists({username});
}; };
DbUserSchema.methods.addGame = function (game: any): void {
const newGame = new SavedGame();
newGame.game = game;
DbUser.updateOne(this, {$push: {savedGames: newGame}}, (err) => {
console.log(err);
});
};
DbUserSchema.methods.changeLang = function (lang: SupportedLang): void {
if (lang in SupportedLang) {
DbUser.updateOne(this, {lang: lang});
}
};
const DbUser = mongoose.model<IDbUserDoc, IDbUserModel>("DbUser", DbUserSchema); const DbUser = mongoose.model<IDbUserDoc, IDbUserModel>("DbUser", DbUserSchema);
export default DbUser; export default DbUser;

View File

@@ -45,7 +45,7 @@ export const initialisePassport = () => {
done(null, user._id) done(null, user._id)
}); });
passport.deserializeUser(async (id: string, done) => { passport.deserializeUser(async (id: string, done) => {
const user: IDbUserDoc | null = await DbUser.findById(id); const user: IDbUserDoc | null = await DbUser.findById(id, {username: 1, password: 1, lang: 1, email: 1});
done(null, user); done(null, user);
}); });
}; };

View File

@@ -1,11 +1,12 @@
import express from "express"; import express from "express";
import {requireAuthenticated, requireNotAuthenticated} from "../passport-config"; import {requireAuthenticated} from "../passport-config";
import * as stats from "../controllers/statsController"; import * as stats from "../controllers/statsController";
import * as dbUser from "../controllers/dbUserController" import * as dbUser from "../controllers/dbUserController"
const router = express.Router(); const router = express.Router();
router.get("/user", dbUser.whoAmI); router.get("/user", dbUser.whoAmI);
router.post("/changeLang", requireAuthenticated, dbUser.changeLang);
router.get("/games", requireAuthenticated, stats.listGames); router.get("/games", requireAuthenticated, stats.listGames);
router.post("/savegame", requireAuthenticated, stats.saveGame); router.post("/savegame", requireAuthenticated, stats.saveGame);

View File

@@ -1,23 +1,25 @@
import express from "express"; import express from "express";
import {requireAuthenticated, requireNotAuthenticated} from "../passport-config"; import {requireAuthenticated} from "../passport-config";
import routers from "./routers"; import routers from "./routers";
import {IDbUser} from "../models/dbUser"; import {IDbUser} from "../models/dbUser";
import * as path from "path";
const router = express.Router(); const router = express.Router();
router.use("/account", routers.signup); router.use("/account", routers.signup);
router.use("/api", routers.api); router.use("/api", routers.api);
router.use("/game/static", express.static(path.join(__dirname, "../game/static")));
router.use("/static", express.static(path.join(__dirname, "../frontend/static")));
router.use("/static", express.static("static"));
// General Endpoints
router.get("/game", requireAuthenticated, (req, res) => { router.get("/game", requireAuthenticated, (req, res) => {
res.sendFile(path.join(__dirname + "/../game/index.html")); res.render("gameIndex.ejs", {
username: (req.user as IDbUser).username,
rootUrl: req.app.locals.rootUrl
});
}); });
router.get("", requireAuthenticated, (req, res) => {
res.sendFile(path.join(__dirname + "/../frontend/index.html"), {username: (req.user as IDbUser).username}); router.get("/**", requireAuthenticated, (req, res) => {
res.render("frontendIndex.ejs", {
username: (req.user as IDbUser).username,
rootUrl: req.app.locals.rootUrl
});
}); });
export default router; export default router;

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

22
views/frontendIndex.ejs Executable file
View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href=<%= rootUrl + "/static/favicon.ico" %> />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Score dice games with K A D I"
/>
<link rel="manifest" href=<%= rootUrl + "/static/frontend/manifest.json" %> />
<title>K A D I - Digital Dice</title>
</head>
<body>
<div id="root"></div>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<script src=<%= rootUrl + "/static/frontend/bundle.js" %>></script>
</body>
</html>

22
views/gameIndex.ejs Executable file
View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href=<%= rootUrl + "/static/favicon.ico" %> />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Score dice games with K A D I"
/>
<link rel="manifest" href=<%= rootUrl + "/static/game/manifest.json" %> />
<title>K A D I - Digital Dice</title>
</head>
<body>
<div id="root"></div>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<script src=<%= rootUrl + "/static/game/bundle.js" %>></script>
</body>
</html>

View File

@@ -1,6 +1,7 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<link rel="icon" href="<%= rootUrl %>/static/favicon.ico" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

View File

@@ -1,6 +1,7 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<link rel="icon" href="<%= rootUrl %>/static/favicon.ico" />
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">