Big update
This commit is contained in:
@@ -27,7 +27,7 @@ export const changeLang: RequestHandler = async (req, res) => {
|
|||||||
export const addGuest: RequestHandler = async (req, res) => {
|
export const addGuest: RequestHandler = async (req, res) => {
|
||||||
const user = (req.user as KadiUser);
|
const user = (req.user as KadiUser);
|
||||||
if (req.body.guestName) {
|
if (req.body.guestName) {
|
||||||
const newGuest: Player = await KadiUserCollection.addGuestForUser(user, req.body.guestName);
|
const newGuest: Player = await KadiUserCollection().addGuestForUser(user, req.body.guestName);
|
||||||
res.send({
|
res.send({
|
||||||
username: user.getUsername(),
|
username: user.getUsername(),
|
||||||
userId: user.getId(),
|
userId: user.getId(),
|
||||||
@@ -47,9 +47,9 @@ export const updateGuest: RequestHandler = async (req, res) => {
|
|||||||
const {id: guestId} = req.params;
|
const {id: guestId} = req.params;
|
||||||
if (req.body.newName) {
|
if (req.body.newName) {
|
||||||
const {newName} = req.body;
|
const {newName} = req.body;
|
||||||
const guest = await PlayerCollection.read(guestId);
|
const guest = await PlayerCollection().read(guestId);
|
||||||
guest.setNick(newName);
|
guest.setNick(newName);
|
||||||
const updatedGuest = await PlayerCollection.save(guest);
|
const updatedGuest = await PlayerCollection().save(guest);
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
userId: user.getId(),
|
userId: user.getId(),
|
||||||
username: user.getUsername(),
|
username: user.getUsername(),
|
||||||
@@ -67,7 +67,7 @@ export const updateGuest: RequestHandler = async (req, res) => {
|
|||||||
export const getGuest: RequestHandler = async (req, res) => {
|
export const getGuest: RequestHandler = async (req, res) => {
|
||||||
const user = (req.user as KadiUser);
|
const user = (req.user as KadiUser);
|
||||||
const {id: guestId} = req.params;
|
const {id: guestId} = req.params;
|
||||||
const guest = await PlayerCollection.read(guestId);
|
const guest = await PlayerCollection().read(guestId);
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
userId: user.getId(),
|
userId: user.getId(),
|
||||||
username: user.getUsername(),
|
username: user.getUsername(),
|
||||||
@@ -78,7 +78,7 @@ export const getGuest: RequestHandler = async (req, res) => {
|
|||||||
export const deleteGuest: RequestHandler = async (req, res) => {
|
export const deleteGuest: RequestHandler = async (req, res) => {
|
||||||
const user = (req.user as KadiUser);
|
const user = (req.user as KadiUser);
|
||||||
const {id: guestId} = req.params;
|
const {id: guestId} = req.params;
|
||||||
const deletedGuest = await KadiUserCollection.deleteGuestFromUser(user, guestId);
|
const deletedGuest = await KadiUserCollection().deleteGuestFromUser(user, guestId);
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
userId: user.getId(),
|
userId: user.getId(),
|
||||||
username: user.getUsername(),
|
username: user.getUsername(),
|
||||||
@@ -88,7 +88,7 @@ export const deleteGuest: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
export const getGuests: RequestHandler = async (req, res) => {
|
export const getGuests: RequestHandler = async (req, res) => {
|
||||||
const user = (req.user as KadiUser);
|
const user = (req.user as KadiUser);
|
||||||
const guests = await KadiUserCollection.getAllGuestsForUser(user);
|
const guests = await KadiUserCollection().getAllGuestsForUser(user);
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
userId: user.getId(),
|
userId: user.getId(),
|
||||||
username: user.getUsername(),
|
username: user.getUsername(),
|
||||||
@@ -98,7 +98,7 @@ export const getGuests: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
export const getAllPlayersAssociatedWithAccount: RequestHandler = async (req, res) => {
|
export const getAllPlayersAssociatedWithAccount: RequestHandler = async (req, res) => {
|
||||||
const user = (req.user as KadiUser);
|
const user = (req.user as KadiUser);
|
||||||
const guests = await KadiUserCollection.getAllGuestsForUser(user);
|
const guests = await KadiUserCollection().getAllGuestsForUser(user);
|
||||||
const mainPlayer = await KadiUserCollection.getMainPlayerForUser(user);
|
const mainPlayer = await KadiUserCollection().getMainPlayerForUser(user);
|
||||||
res.status(200).send({guests, mainPlayer});
|
res.status(200).send({guests, mainPlayer});
|
||||||
};
|
};
|
||||||
7
src/Controllers/rulesetController.ts
Normal file
7
src/Controllers/rulesetController.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import {RequestHandler} from "express";
|
||||||
|
import RulesetCollection from "../ObjectCollections/RulesetCollection";
|
||||||
|
|
||||||
|
export const getRuleset: RequestHandler = async (req, res) => {
|
||||||
|
const ruleset = await RulesetCollection().read(req.params.id);
|
||||||
|
res.json(ruleset.getSchemaJSON());
|
||||||
|
};
|
||||||
@@ -24,7 +24,7 @@ export const showRegistrationPage: RequestHandler = (req, res) => {
|
|||||||
export const registerNewUser: RequestHandler = async (req, res) => {
|
export const registerNewUser: RequestHandler = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const loginDetails: LoginDetails = req.body as LoginDetails;
|
const loginDetails: LoginDetails = req.body as LoginDetails;
|
||||||
const newUser = await KadiUserCollection.registerUser(loginDetails);
|
const newUser = await KadiUserCollection().registerUser(loginDetails);
|
||||||
req.login(newUser, (err) => {
|
req.login(newUser, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -54,7 +54,7 @@ export const logoutUser: RequestHandler = (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const authenticateKadiUser: VerifyFunction = async (email, password, done) => {
|
export const authenticateKadiUser: VerifyFunction = async (email, password, done) => {
|
||||||
const user = await KadiUserCollection.findByEmail(email);
|
const user = await KadiUserCollection().findByEmail(email);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return done(null, false, { message: "A user with that email does not exist."} );
|
return done(null, false, { message: "A user with that email does not exist."} );
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,6 @@ export async function serializeKadiUser(user: KadiUser, done: (err: any, id?: un
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function deserializeKadiUser(id: string, done: (err: any, id?: unknown) => void): Promise<void> {
|
export async function deserializeKadiUser(id: string, done: (err: any, id?: unknown) => void): Promise<void> {
|
||||||
const user: KadiUser | null = await KadiUserCollection.getSerializedAuthUser(id);
|
const user: KadiUser | null = await KadiUserCollection().read(id);
|
||||||
done(null, user);
|
done(null, user);
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,18 @@ import RulesetCollection from "../ObjectCollections/RulesetCollection";
|
|||||||
import Ruleset from "../Objects/Ruleset";
|
import Ruleset from "../Objects/Ruleset";
|
||||||
import {OutcomeType} from "../Objects/DefaultStatsMongoData";
|
import {OutcomeType} from "../Objects/DefaultStatsMongoData";
|
||||||
|
|
||||||
export interface GameSubmission {
|
interface GameSubmission {
|
||||||
rulesetId: string;
|
ruleset: string;
|
||||||
players: { id: string; nick: string }[];
|
players: { id: string; nick: string }[];
|
||||||
results: PlayerGameResult[];
|
results: PlayerGameResult[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProcessedGameSubmission {
|
||||||
|
ruleset: string;
|
||||||
|
players: {id: string, nick: string}[];
|
||||||
|
results: ScoredResultsWithOutcome[];
|
||||||
|
}
|
||||||
|
|
||||||
type PlayerGameResult = { playerId: string; blocks: Record<string, Block> };
|
type PlayerGameResult = { playerId: string; blocks: Record<string, Block> };
|
||||||
type Block = { cells: Record<string, Cell> };
|
type Block = { cells: Record<string, Cell> };
|
||||||
type Cell = { value: CellValue };
|
type Cell = { value: CellValue };
|
||||||
@@ -27,11 +33,11 @@ enum ResultType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ScoredResults = {score: number, results: PlayerGameResult};
|
type ScoredResults = {score: number, results: PlayerGameResult};
|
||||||
type ScoredResultsWithOutcome = {score: number, results: PlayerGameResult & {outcome: OutcomeType}};
|
export type ScoredResultsWithOutcome = {score: number, results: PlayerGameResult & {outcome: OutcomeType}};
|
||||||
|
|
||||||
export const listGames: RequestHandler = async (req, res) => {
|
export const listGames: RequestHandler = async (req, res) => {
|
||||||
const user = req.user as KadiUser;
|
const user = req.user as KadiUser;
|
||||||
const gamesList = await KadiUserCollection.getSavedGamesForUser(user);
|
const gamesList = await KadiUserCollection().getSavedGamesForUser(user);
|
||||||
if (gamesList) {
|
if (gamesList) {
|
||||||
res.json({ games: gamesList });
|
res.json({ games: gamesList });
|
||||||
}
|
}
|
||||||
@@ -47,17 +53,32 @@ export const saveGame: RequestHandler = async (req, res) => {
|
|||||||
if (newGuests.length > 0) {
|
if (newGuests.length > 0) {
|
||||||
fillOutSubmissionWithNewIds(submission, newGuests);
|
fillOutSubmissionWithNewIds(submission, newGuests);
|
||||||
}
|
}
|
||||||
const newGame = await KadiUserCollection.addGameForUser(user, submission);
|
const rulesetUsed = await RulesetCollection().read(submission.ruleset);
|
||||||
processStats(await RulesetCollection.read(submission.rulesetId), submission.results, user);
|
const scoredResultsWithOutcomes = await processStats(rulesetUsed, submission.results, user);
|
||||||
|
const newGame = await KadiUserCollection().addGameForUser(user, {...submission, results: scoredResultsWithOutcomes});
|
||||||
res.send({ message: "Game submitted successfully!", newGame: newGame });
|
res.send({ message: "Game submitted successfully!", newGame: newGame });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getStats: RequestHandler = async (req, res) => {
|
||||||
|
const user = req.user as KadiUser;
|
||||||
|
const stats = await KadiUserCollection().getAllStatsForUser(user);
|
||||||
|
if (stats) {
|
||||||
|
res.json({
|
||||||
|
pStats: stats.pStats.map(pStats => ({...pStats, stats: pStats.stats.getData()})),
|
||||||
|
accStats: stats.accStats.getData()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.sendStatus(404);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
async function addNewGuests(submission: GameSubmission, user: KadiUser): Promise<Player[]> {
|
async function addNewGuests(submission: GameSubmission, user: KadiUser): Promise<Player[]> {
|
||||||
const newGuestIds: Player[] = [];
|
const newGuestIds: Player[] = [];
|
||||||
for (const playerDetails of submission.players) {
|
for (const playerDetails of submission.players) {
|
||||||
const isNewPlayer = playerDetails.id === playerDetails.nick;
|
const isNewPlayer = playerDetails.id === playerDetails.nick;
|
||||||
if (isNewPlayer) {
|
if (isNewPlayer) {
|
||||||
const newGuest: Player = await KadiUserCollection.addGuestForUser(user, playerDetails.nick);
|
const newGuest: Player = await KadiUserCollection().addGuestForUser(user, playerDetails.nick);
|
||||||
newGuestIds.push(newGuest);
|
newGuestIds.push(newGuest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,17 +89,17 @@ function fillOutSubmissionWithNewIds(submission: GameSubmission, newGuestList: P
|
|||||||
for (const newGuest of newGuestList) {
|
for (const newGuest of newGuestList) {
|
||||||
const gameResultsFromNewGuest = submission.results.find((result) => result.playerId === newGuest.getNick());
|
const gameResultsFromNewGuest = submission.results.find((result) => result.playerId === newGuest.getNick());
|
||||||
if (gameResultsFromNewGuest) {
|
if (gameResultsFromNewGuest) {
|
||||||
gameResultsFromNewGuest.playerId = newGuest.getId();
|
gameResultsFromNewGuest.playerId = newGuest.getId().toString();
|
||||||
}
|
}
|
||||||
const playerEntryForNewGuest = submission.players.find((player) => player.id === newGuest.getNick());
|
const playerEntryForNewGuest = submission.players.find((player) => player.id === newGuest.getNick());
|
||||||
if (playerEntryForNewGuest) {
|
if (playerEntryForNewGuest) {
|
||||||
playerEntryForNewGuest.id = newGuest.getId();
|
playerEntryForNewGuest.id = newGuest.getId().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return submission;
|
return submission;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processStats(ruleset: Ruleset, results: PlayerGameResult[], account: KadiUser) {
|
async function processStats(ruleset: Ruleset, results: PlayerGameResult[], account: KadiUser): Promise<ScoredResultsWithOutcome[]> {
|
||||||
const calc = new ScoreCalculator(ruleset);
|
const calc = new ScoreCalculator(ruleset);
|
||||||
let playerScoreList: ScoredResults[] = [];
|
let playerScoreList: ScoredResults[] = [];
|
||||||
for (const result of results) {
|
for (const result of results) {
|
||||||
@@ -88,59 +109,60 @@ async function processStats(ruleset: Ruleset, results: PlayerGameResult[], accou
|
|||||||
results: result
|
results: result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const playerScoreListWithOutcomes = updateScoreListWithOutcomes(playerScoreList, ruleset);
|
const playerScoreListWithOutcomes = updateScoreListWithOutcomes(playerScoreList);
|
||||||
updateStatsForIndividualPlayers(playerScoreListWithOutcomes, ruleset);
|
await updateStatsForIndividualPlayers(playerScoreListWithOutcomes, ruleset);
|
||||||
const gameResults = playerScoreListWithOutcomes.map(scoredResults => scoredResults.results);
|
const gameResults = playerScoreListWithOutcomes.map(scoredResults => scoredResults.results);
|
||||||
await KadiUserCollection.updateAccountStats(account.getId(), gameResults, ruleset);
|
await KadiUserCollection().updateAccountStats(account.getId(), gameResults, ruleset);
|
||||||
|
return playerScoreListWithOutcomes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScoreListWithOutcomes(playerScoreList: ScoredResults[], rulesetUsed: Ruleset): ScoredResultsWithOutcome[] {
|
function updateScoreListWithOutcomes(scoreResultsList: ScoredResults[]): ScoredResultsWithOutcome[] {
|
||||||
playerScoreList = sortDescendingByScore(playerScoreList);
|
scoreResultsList = sortDescendingByScore(scoreResultsList);
|
||||||
const playerScoreListWithOutcomes: ScoredResultsWithOutcome[] = playerScoreList.map(scoredResults => {
|
const playerScoreListWithOutcomes: ScoredResultsWithOutcome[] = scoreResultsList.map(scoredResults => {
|
||||||
const newResults = {...scoredResults.results, outcome: OutcomeType.loss};
|
const newResults = {...scoredResults.results, outcome: OutcomeType.loss};
|
||||||
return {...scoredResults, results: newResults};
|
return {...scoredResults, results: newResults};
|
||||||
});
|
});
|
||||||
let runnerUpsStart: number;
|
let runnerUpsStart: number;
|
||||||
if (playerScoreListWithOutcomes[0].score !== playerScoreListWithOutcomes[1].score) {
|
if (playerScoreListWithOutcomes[0].score !== playerScoreListWithOutcomes[1].score) {
|
||||||
playerScoreListWithOutcomes[0].results.outcome = OutcomeType.win;
|
playerScoreListWithOutcomes[0].results.outcome = OutcomeType.win;
|
||||||
|
|
||||||
runnerUpsStart = 1;
|
runnerUpsStart = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
runnerUpsStart = updateScoreListWithDraws(playerScoreListWithOutcomes, rulesetUsed);
|
runnerUpsStart = updateScoreListWithDraws(playerScoreListWithOutcomes);
|
||||||
}
|
}
|
||||||
const losersStart = updateScoreListWithRunnerUps(playerScoreListWithOutcomes.slice(runnerUpsStart), rulesetUsed);
|
const losersStart = updateScoreListWithRunnerUps(playerScoreListWithOutcomes, runnerUpsStart);
|
||||||
updateScoreListWithLosses(playerScoreListWithOutcomes.slice(losersStart), rulesetUsed);
|
updateScoreListWithLosses(playerScoreListWithOutcomes, losersStart);
|
||||||
return playerScoreListWithOutcomes;
|
return playerScoreListWithOutcomes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScoreListWithDraws(playerScoreList: ScoredResultsWithOutcome[], rulesetUsed: Ruleset): number {
|
function updateScoreListWithDraws(scoreResultsList: ScoredResultsWithOutcome[]): number {
|
||||||
for (let i = 0; i < playerScoreList.length; i++) {
|
for (let i = 0; i < scoreResultsList.length; i++) {
|
||||||
if (playerScoreList[i].score === playerScoreList[0].score) {
|
if (scoreResultsList[i].score === scoreResultsList[0].score) {
|
||||||
playerScoreList[i].results.outcome = OutcomeType.draw;
|
scoreResultsList[i].results.outcome = OutcomeType.draw;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return playerScoreList.length;
|
return scoreResultsList.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScoreListWithRunnerUps(playerScoreList: ScoredResultsWithOutcome[], rulesetUsed: Ruleset): number {
|
function updateScoreListWithRunnerUps(scoreResultsList: ScoredResultsWithOutcome[], runnerUpsStartIndex: number): number {
|
||||||
for (let i = 0; i < playerScoreList.length; i++) {
|
scoreResultsList[runnerUpsStartIndex].results.outcome = OutcomeType.runnerUp;
|
||||||
if (playerScoreList[i].score === playerScoreList[0].score) {
|
for (let i = runnerUpsStartIndex + 1; i < scoreResultsList.length; i++) {
|
||||||
playerScoreList[i].results.outcome = OutcomeType.runnerUp;
|
if (scoreResultsList[i].score === scoreResultsList[i - 1].score) {
|
||||||
|
scoreResultsList[i].results.outcome = OutcomeType.runnerUp;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return playerScoreList.length;
|
return scoreResultsList.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScoreListWithLosses(scoreResultsList: ScoredResultsWithOutcome[], rulesetUsed: Ruleset) {
|
function updateScoreListWithLosses(scoreResultsList: ScoredResultsWithOutcome[], losersStartIndex: number) {
|
||||||
for (const lostPlayerResults of scoreResultsList) {
|
for (let i = losersStartIndex; i < scoreResultsList.length; i++) {
|
||||||
lostPlayerResults.results.outcome = OutcomeType.loss;
|
scoreResultsList[i].results.outcome = OutcomeType.loss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +170,9 @@ function sortDescendingByScore(playerScoreList: ScoredResults[]) {
|
|||||||
return playerScoreList.sort((a, b) => b.score - a.score);
|
return playerScoreList.sort((a, b) => b.score - a.score);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateStatsForIndividualPlayers(playerScoreListWithOutcomes: ScoredResultsWithOutcome[], rulesetUsed: Ruleset): void {
|
async function updateStatsForIndividualPlayers(playerScoreListWithOutcomes: ScoredResultsWithOutcome[], rulesetUsed: Ruleset): Promise<void> {
|
||||||
for (const scoredResults of playerScoreListWithOutcomes) {
|
for (const scoredResults of playerScoreListWithOutcomes) {
|
||||||
PlayerCollection.updateStatsForPlayer(
|
await PlayerCollection().updateStatsForPlayer(
|
||||||
scoredResults.results.playerId,
|
scoredResults.results.playerId,
|
||||||
{...scoredResults.results, outcome: scoredResults.results.outcome},
|
{...scoredResults.results, outcome: scoredResults.results.outcome},
|
||||||
rulesetUsed);
|
rulesetUsed);
|
||||||
1
src/ObjectCollections/CollectionRegistry.ts
Normal file
1
src/ObjectCollections/CollectionRegistry.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import {CredentialsTakenError, GenericPersistenceError} from "../errors";
|
import {CredentialsTakenError} from "../errors";
|
||||||
import mongo from "mongodb";
|
|
||||||
import bcrypt from "bcrypt";
|
import bcrypt from "bcrypt";
|
||||||
import {SupportedLang} from "../enums";
|
import {SupportedLang} from "../enums";
|
||||||
import {AccountStatsMongoData, defaultAccountStatsMongoData, OutcomeType, PlayerGameResults} from "../Objects/DefaultStatsMongoData";
|
import {AccountStatsMongoData, defaultAccountStatsMongoData, OutcomeType, PlayerGameResults} from "../Objects/DefaultStatsMongoData";
|
||||||
@@ -11,13 +10,14 @@ import SavedGameCollection from "./SavedGameCollection";
|
|||||||
import SavedGame from "../Objects/SavedGame";
|
import SavedGame from "../Objects/SavedGame";
|
||||||
import PlayerCollection from "../ObjectCollections/PlayerCollection";
|
import PlayerCollection from "../ObjectCollections/PlayerCollection";
|
||||||
import Player from "../Objects/Player";
|
import Player from "../Objects/Player";
|
||||||
import {GameSubmission} from "../controllers/statsController";
|
import {ProcessedGameSubmission} from "../Controllers/statsController";
|
||||||
import Ruleset from "../Objects/Ruleset";
|
import Ruleset from "../Objects/Ruleset";
|
||||||
import RulesetCollection from "./RulesetCollection";
|
import RulesetCollection from "./RulesetCollection";
|
||||||
import AccountStats from "../Objects/AccountStats";
|
import AccountStats from "../Objects/AccountStats";
|
||||||
|
import PlayerStats from "../Objects/PlayerStats";
|
||||||
|
|
||||||
export interface KadiUserMongoData {
|
export interface KadiUserMongoData {
|
||||||
id: string;
|
id: ActiveRecordId;
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
@@ -30,8 +30,20 @@ export interface KadiUserMongoData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KadiUserCollection extends MongoStoredObjectCollection<KadiUserMongoData> {
|
class KadiUserCollection extends MongoStoredObjectCollection<KadiUserMongoData> {
|
||||||
constructor(collectionClient: mongo.Collection) {
|
private static instance?: KadiUserCollection;
|
||||||
super(collectionClient);
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
static getInstance(): KadiUserCollection {
|
||||||
|
if (KadiUserCollection.instance === undefined) {
|
||||||
|
KadiUserCollection.instance = new KadiUserCollection();
|
||||||
|
}
|
||||||
|
return KadiUserCollection.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.mongoDbClientCollection = getMongoObjectCollection("users")
|
||||||
}
|
}
|
||||||
|
|
||||||
private kadiUserFrom(data: KadiUserMongoData): KadiUser {
|
private kadiUserFrom(data: KadiUserMongoData): KadiUser {
|
||||||
@@ -70,7 +82,7 @@ class KadiUserCollection extends MongoStoredObjectCollection<KadiUserMongoData>
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async addNewUser(loginDetails: LoginDetails): Promise<KadiUser> {
|
private async addNewUser(loginDetails: LoginDetails): Promise<KadiUser> {
|
||||||
const newPlayer = await PlayerCollection.create(loginDetails.username);
|
const newPlayer = await PlayerCollection().create(loginDetails.username);
|
||||||
const securePassword = await this.makePasswordSecure(loginDetails.password);
|
const securePassword = await this.makePasswordSecure(loginDetails.password);
|
||||||
const newUser = await this.mongoCreate({
|
const newUser = await this.mongoCreate({
|
||||||
username: loginDetails.username,
|
username: loginDetails.username,
|
||||||
@@ -96,58 +108,52 @@ class KadiUserCollection extends MongoStoredObjectCollection<KadiUserMongoData>
|
|||||||
return object !== null;
|
return object !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSerializedAuthUser(id: string): Promise<KadiUser> {
|
|
||||||
const foundUser = await this.mongoRead(id);
|
|
||||||
if (foundUser) {
|
|
||||||
return this.kadiUserFrom(foundUser);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new GenericPersistenceError("User not found!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async makePasswordSecure(password: string): Promise<string> {
|
async makePasswordSecure(password: string): Promise<string> {
|
||||||
return bcrypt.hash(password, 10);
|
return bcrypt.hash(password, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addGuestForUser(userOrId: OrId<KadiUser>, newGuestNick: string): Promise<Player> {
|
async addGuestForUser(userOrId: OrId<KadiUser>, newGuestNick: string): Promise<Player> {
|
||||||
const newGuest = await PlayerCollection.create(newGuestNick);
|
const newGuest = await PlayerCollection().create(newGuestNick);
|
||||||
await this.mongoDbClientCollection.findOneAndUpdate(
|
await this.mongoDbClientCollection!.findOneAndUpdate(
|
||||||
{_id: this.idFromRecordOrId(userOrId)},
|
{_id: this.idFromRecordOrId(userOrId)},
|
||||||
{$push: {guests: newGuest.getId()}});
|
{$push: {guests: newGuest.getId()}});
|
||||||
return newGuest;
|
return newGuest;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteGuestFromUser(userOrId: OrId<KadiUser>, guestOrGuestId: OrId<Player>): Promise<Player> {
|
async deleteGuestFromUser(userOrId: OrId<KadiUser>, guestOrGuestId: OrId<Player>): Promise<Player> {
|
||||||
const deletedGuest = await PlayerCollection.delete(this.idFromRecordOrId(guestOrGuestId));
|
const deletedGuest = await PlayerCollection().delete(this.idFromRecordOrId(guestOrGuestId));
|
||||||
await this.mongoDbClientCollection.findOneAndUpdate(
|
await this.mongoDbClientCollection!.findOneAndUpdate(
|
||||||
{_id: this.idFromRecordOrId(userOrId)},
|
{_id: this.idFromRecordOrId(userOrId)},
|
||||||
{$pull: {guests: this.idFromRecordOrId(guestOrGuestId)}});
|
{$pull: {guests: this.idFromRecordOrId(deletedGuest)}});
|
||||||
return deletedGuest;
|
return deletedGuest;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllGuestsForUser(userOrId: OrId<KadiUser>): Promise<Promise<Player>[]> {
|
async getAllGuestsForUser(userOrId: OrId<KadiUser>): Promise<Player[]> {
|
||||||
const guestIdList = (await this.mongoRead(this.idFromRecordOrId(userOrId)))?.guests;
|
const guestIdList = (await this.mongoRead(this.idFromRecordOrId(userOrId)))?.guests;
|
||||||
return guestIdList.map(async (guestId) => {
|
return Promise.all<Player>(
|
||||||
return await PlayerCollection.read(guestId);
|
guestIdList.map(async (guestId) => {
|
||||||
});
|
return await PlayerCollection().read(guestId);
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMainPlayerForUser(userOrId: OrId<KadiUser>): Promise<Player> {
|
async getMainPlayerForUser(userOrId: OrId<KadiUser>): Promise<Player> {
|
||||||
const userData = await this.mongoRead(this.idFromRecordOrId(userOrId));
|
const userData = await this.mongoRead(this.idFromRecordOrId(userOrId));
|
||||||
return PlayerCollection.read(userData?.player);
|
return PlayerCollection().read(userData?.player);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSavedGamesForUser(userOrId: OrId<KadiUser>): Promise<Promise<SavedGame>[]> {
|
async getSavedGamesForUser(userOrId: OrId<KadiUser>): Promise<SavedGame[]> {
|
||||||
const savedGameIds = (await this.mongoRead(this.idFromRecordOrId(userOrId)))?.savedGames;
|
const savedGameIds = (await this.mongoRead(this.idFromRecordOrId(userOrId)))?.savedGames;
|
||||||
return savedGameIds.map(async (savedGameId) => {
|
return Promise.all<SavedGame>(
|
||||||
return await SavedGameCollection.read(savedGameId);
|
savedGameIds.map(async (savedGameId) => {
|
||||||
});
|
return await SavedGameCollection().read(savedGameId);
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
async addGameForUser(userOrId: OrId<KadiUser>, gameSubmission: GameSubmission): Promise<SavedGame> {
|
async addGameForUser(userOrId: OrId<KadiUser>, submission: ProcessedGameSubmission): Promise<SavedGame> {
|
||||||
const newGame = await SavedGameCollection.create(gameSubmission);
|
const newGame = await SavedGameCollection().create(submission);
|
||||||
await this.mongoDbClientCollection.findOneAndUpdate(
|
await this.mongoDbClientCollection!.findOneAndUpdate(
|
||||||
{_id: this.idFromRecordOrId(userOrId)},
|
{_id: this.idFromRecordOrId(userOrId)},
|
||||||
{$push: {savedGames: newGame.getId()}});
|
{$push: {savedGames: newGame.getId()}});
|
||||||
return newGame;
|
return newGame;
|
||||||
@@ -155,16 +161,36 @@ class KadiUserCollection extends MongoStoredObjectCollection<KadiUserMongoData>
|
|||||||
|
|
||||||
async updateAccountStats(userOrId: OrId<KadiUser>, gameResults: (PlayerGameResults & {outcome: OutcomeType})[], rulesetUsedOrId: OrId<Ruleset>): Promise<void> {
|
async updateAccountStats(userOrId: OrId<KadiUser>, gameResults: (PlayerGameResults & {outcome: OutcomeType})[], rulesetUsedOrId: OrId<Ruleset>): Promise<void> {
|
||||||
const userId = this.idFromRecordOrId(userOrId);
|
const userId = this.idFromRecordOrId(userOrId);
|
||||||
const rulesetUsed = rulesetUsedOrId instanceof Ruleset ? rulesetUsedOrId : await RulesetCollection.read(rulesetUsedOrId);
|
const rulesetUsed = rulesetUsedOrId instanceof Ruleset ? rulesetUsedOrId : await RulesetCollection().read(rulesetUsedOrId);
|
||||||
const accountStatsMongoData = await this.mongoRead(userId);
|
const accountStatsMongoData = (await this.mongoRead(userId)).accountStats;
|
||||||
const accountStatsObject = new AccountStats(accountStatsMongoData.accountStats);
|
const accountStatsObject = new AccountStats(accountStatsMongoData);
|
||||||
accountStatsObject.updateStats(gameResults, rulesetUsed);
|
accountStatsObject.updateStats(gameResults, rulesetUsed);
|
||||||
this.mongoUpdate({
|
this.mongoUpdate({
|
||||||
id: this.idFromRecordOrId(userId),
|
id: userId,
|
||||||
accountStats: accountStatsObject.getData()
|
accountStats: accountStatsObject.getData()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllStatsForUser(userOrId: OrId<KadiUser>): Promise<StatsListing> {
|
||||||
|
const players = [...(await this.getAllGuestsForUser(userOrId)), await this.getMainPlayerForUser(userOrId)];
|
||||||
|
const playerStats = players.map(player => ({
|
||||||
|
nick: player.getNick(),
|
||||||
|
playerId: player.getId(),
|
||||||
|
stats: player.getStats()
|
||||||
|
}));
|
||||||
|
const accountStatsMongoData = (await this.mongoRead(this.idFromRecordOrId(userOrId))).accountStats;
|
||||||
|
const accountStats = new AccountStats(accountStatsMongoData);
|
||||||
|
return {pStats: playerStats, accStats: accountStats};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KadiUserCollectionSingleton = new KadiUserCollection(getMongoObjectCollection("users"));
|
export interface StatsListing {
|
||||||
export default KadiUserCollectionSingleton;
|
accStats: AccountStats;
|
||||||
|
pStats: {
|
||||||
|
nick: string,
|
||||||
|
playerId: ActiveRecordId,
|
||||||
|
stats: PlayerStats
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KadiUserCollection.getInstance;
|
||||||
@@ -5,35 +5,47 @@ import ActiveRecord, {ActiveRecordId} from "../Objects/ActiveRecord";
|
|||||||
|
|
||||||
|
|
||||||
abstract class MongoStoredObjectCollection<IRawData extends {id: ActiveRecordId}> {
|
abstract class MongoStoredObjectCollection<IRawData extends {id: ActiveRecordId}> {
|
||||||
|
protected mongoDbClientCollection?: mongo.Collection;
|
||||||
|
protected constructor() {}
|
||||||
|
|
||||||
protected constructor(protected mongoDbClientCollection: mongo.Collection) {}
|
abstract init(): Promise<void>;
|
||||||
|
|
||||||
protected async mongoCreate(objectData: Omit<IRawData, "id">): Promise<IRawData> {
|
protected async mongoCreate(objectData: Omit<IRawData, "id">): Promise<IRawData> {
|
||||||
return tryQuery(async () => {
|
return tryQuery(async () => {
|
||||||
const insertOneWriteOpResult = await this.mongoDbClientCollection.insertOne(objectData);
|
const insertOneWriteOpResult = await this.mongoDbClientCollection!.insertOne(objectData);
|
||||||
if (insertOneWriteOpResult.result.ok === 1) {
|
if (insertOneWriteOpResult.result.ok === 1) {
|
||||||
return insertOneWriteOpResult.ops[0]
|
const newObject = insertOneWriteOpResult.ops[0];
|
||||||
|
newObject.id = newObject._id;
|
||||||
|
newObject._id = undefined;
|
||||||
|
return insertOneWriteOpResult.ops[0];
|
||||||
} else {
|
} else {
|
||||||
throw new MongoError(`Error creating the object: ${JSON.stringify(objectData)}`);
|
throw new MongoError(`Error creating the object: ${JSON.stringify(objectData)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async mongoRead(id: string): Promise<IRawData> {
|
protected async mongoRead(id: ActiveRecordId): Promise<IRawData> {
|
||||||
return tryQuery(async () => {
|
return tryQuery(async () => {
|
||||||
const result = await this.mongoDbClientCollection.findOne({_id: id});
|
const result = await this.mongoDbClientCollection!.findOne({_id: new mongo.ObjectID(id)});
|
||||||
if (result) {
|
if (result) {
|
||||||
|
result.id = result._id;
|
||||||
|
result._id = undefined;
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidIdError(`Object in collection "${typeof this}" with id ${JSON.stringify(id)} not found!`);
|
throw new InvalidIdError(`Object in collection "${this.constructor.name}" with id ${JSON.stringify(id)} not found!`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async mongoFindByAttribute(attribute: string, value: any): Promise<IRawData | null> {
|
protected async mongoFindByAttribute(attribute: string, value: any): Promise<IRawData | null> {
|
||||||
return tryQuery(async () =>
|
return tryQuery(async () => {
|
||||||
await this.mongoDbClientCollection.findOne({[attribute]: value})
|
const result = await this.mongoDbClientCollection!.findOne({[attribute]: value});
|
||||||
);
|
if (result) {
|
||||||
|
result.id = result._id;
|
||||||
|
result._id = undefined;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async mongoDelete(objectId: ActiveRecordId, returnObject?: boolean): Promise<IRawData | void> {
|
protected async mongoDelete(objectId: ActiveRecordId, returnObject?: boolean): Promise<IRawData | void> {
|
||||||
@@ -41,7 +53,7 @@ abstract class MongoStoredObjectCollection<IRawData extends {id: ActiveRecordId}
|
|||||||
if (returnObject ?? true) {
|
if (returnObject ?? true) {
|
||||||
deletedObject = await this.mongoRead(objectId);
|
deletedObject = await this.mongoRead(objectId);
|
||||||
}
|
}
|
||||||
const deleteWriteOpResult = await this.mongoDbClientCollection.deleteOne({_id: objectId});
|
const deleteWriteOpResult = await this.mongoDbClientCollection!.deleteOne({_id: objectId});
|
||||||
if (deleteWriteOpResult.result.ok === 1) {
|
if (deleteWriteOpResult.result.ok === 1) {
|
||||||
return deletedObject;
|
return deletedObject;
|
||||||
} else {
|
} else {
|
||||||
@@ -49,16 +61,17 @@ abstract class MongoStoredObjectCollection<IRawData extends {id: ActiveRecordId}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async mongoUpdate(object: Partial<IRawData> & {id: ActiveRecordId}) {
|
protected async mongoUpdate(object: Partial<IRawData>) {
|
||||||
await tryQuery(() =>
|
await tryQuery(() =>
|
||||||
this.mongoDbClientCollection.findOneAndUpdate({_id: object.id}, {$set: {...object, id: undefined}})
|
this.mongoDbClientCollection!.findOneAndUpdate({_id: object.id}, {$set: {...object, id: undefined}})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected idFromRecordOrId<T extends ActiveRecord>(recordOrRecordId: T | ActiveRecordId): ActiveRecordId {
|
protected idFromRecordOrId<T extends ActiveRecord>(recordOrRecordId: T | ActiveRecordId): ActiveRecordId {
|
||||||
return typeof recordOrRecordId === "string" ? recordOrRecordId : recordOrRecordId.getId();
|
return recordOrRecordId instanceof mongo.ObjectId || typeof recordOrRecordId === "string" ?
|
||||||
|
recordOrRecordId :
|
||||||
|
recordOrRecordId.getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default MongoStoredObjectCollection;
|
export default MongoStoredObjectCollection;
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import MongoStoredObjectCollection from "./MongoStoredObjectCollection";
|
import MongoStoredObjectCollection from "./MongoStoredObjectCollection";
|
||||||
import mongo from "mongodb";
|
|
||||||
import {
|
import {
|
||||||
defaultPlayerStatsMongoData,
|
defaultPlayerStatsMongoData,
|
||||||
OutcomeType,
|
OutcomeType,
|
||||||
@@ -14,18 +13,30 @@ import Ruleset from "../Objects/Ruleset";
|
|||||||
import RulesetCollection from "./RulesetCollection";
|
import RulesetCollection from "./RulesetCollection";
|
||||||
|
|
||||||
export interface PlayerMongoData {
|
export interface PlayerMongoData {
|
||||||
id: string;
|
id: ActiveRecordId;
|
||||||
nick: string;
|
nick: string;
|
||||||
stats?: PlayerStatsMongoData;
|
stats: PlayerStatsMongoData;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PlayerCollection extends MongoStoredObjectCollection<PlayerMongoData> {
|
class PlayerCollection extends MongoStoredObjectCollection<PlayerMongoData> {
|
||||||
constructor(collectionClient: mongo.Collection) {
|
private static instance?: PlayerCollection;
|
||||||
super(collectionClient);
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
static getInstance(): PlayerCollection {
|
||||||
|
if (PlayerCollection.instance === undefined) {
|
||||||
|
PlayerCollection.instance = new PlayerCollection();
|
||||||
|
}
|
||||||
|
return PlayerCollection.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.mongoDbClientCollection = getMongoObjectCollection("players");
|
||||||
}
|
}
|
||||||
|
|
||||||
private playerFrom(data: PlayerMongoData): Player {
|
private playerFrom(data: PlayerMongoData): Player {
|
||||||
return new Player(data.id, data.nick, data.stats ? new PlayerStats(data.stats) : undefined);
|
return new Player(data.id, data.nick, new PlayerStats(data.stats));
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(nick: string): Promise<Player> {
|
async create(nick: string): Promise<Player> {
|
||||||
@@ -47,16 +58,15 @@ class PlayerCollection extends MongoStoredObjectCollection<PlayerMongoData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateStatsForPlayer(playerOrId: OrId<Player>, gameResults: PlayerGameResults & {outcome: OutcomeType}, rulesetUsedOrId: OrId<Ruleset>): Promise<void> {
|
async updateStatsForPlayer(playerOrId: OrId<Player>, gameResults: PlayerGameResults & {outcome: OutcomeType}, rulesetUsedOrId: OrId<Ruleset>): Promise<void> {
|
||||||
playerOrId = playerOrId instanceof Player ? playerOrId : await this.read(playerOrId);
|
const player = playerOrId instanceof Player ? playerOrId : await this.read(playerOrId);
|
||||||
rulesetUsedOrId = rulesetUsedOrId instanceof Ruleset ? rulesetUsedOrId : await RulesetCollection.read(rulesetUsedOrId);
|
const ruleset = rulesetUsedOrId instanceof Ruleset ? rulesetUsedOrId : await RulesetCollection().read(rulesetUsedOrId);
|
||||||
playerOrId.updateStats(gameResults, rulesetUsedOrId);
|
player.updateStats(gameResults, ruleset);
|
||||||
this.mongoUpdate({
|
this.mongoUpdate({
|
||||||
id: this.idFromRecordOrId(playerOrId),
|
id: this.idFromRecordOrId(player),
|
||||||
stats: playerOrId.getStats()?.getData()
|
stats: player.getStats()?.getData()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const PlayerCollectionSingleton = new PlayerCollection(getMongoObjectCollection("players"));
|
export default PlayerCollection.getInstance;
|
||||||
export default PlayerCollectionSingleton;
|
|
||||||
@@ -1,21 +1,33 @@
|
|||||||
import MongoStoredObjectCollection from "./MongoStoredObjectCollection";
|
import MongoStoredObjectCollection from "./MongoStoredObjectCollection";
|
||||||
import mongo from "mongodb";
|
|
||||||
import {DEFAULT_RULESET, DEFAULT_RULESET_NAME, RulesetSchema} from "../rulesets";
|
import {DEFAULT_RULESET, DEFAULT_RULESET_NAME, RulesetSchema} from "../rulesets";
|
||||||
import {getMongoObjectCollection} from "../database";
|
import {getMongoObjectCollection} from "../database";
|
||||||
import Ruleset from "../Objects/Ruleset";
|
import Ruleset from "../Objects/Ruleset";
|
||||||
|
import {ActiveRecordId} from "../Objects/ActiveRecord";
|
||||||
|
|
||||||
type RulesetMongoData = RulesetSchema;
|
type RulesetMongoData = RulesetSchema & {id: ActiveRecordId};
|
||||||
|
|
||||||
class RulesetCollection extends MongoStoredObjectCollection<RulesetMongoData> {
|
class RulesetCollection extends MongoStoredObjectCollection<RulesetMongoData> {
|
||||||
constructor(collectionClient: mongo.Collection) {
|
private static instance?: RulesetCollection;
|
||||||
super(collectionClient);
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
static getInstance(): RulesetCollection {
|
||||||
|
if (RulesetCollection.instance === undefined) {
|
||||||
|
RulesetCollection.instance = new RulesetCollection();
|
||||||
|
}
|
||||||
|
return RulesetCollection.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.mongoDbClientCollection = getMongoObjectCollection("rulesets");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async rulesetFrom(data: RulesetMongoData): Promise<Ruleset> {
|
private async rulesetFrom(data: RulesetMongoData): Promise<Ruleset> {
|
||||||
return new Ruleset(data.id, data);
|
return new Ruleset(data.id, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async read(id: string): Promise<Ruleset> {
|
async read(id: ActiveRecordId): Promise<Ruleset> {
|
||||||
if (id === DEFAULT_RULESET_NAME) {
|
if (id === DEFAULT_RULESET_NAME) {
|
||||||
return new Ruleset(DEFAULT_RULESET_NAME, DEFAULT_RULESET);
|
return new Ruleset(DEFAULT_RULESET_NAME, DEFAULT_RULESET);
|
||||||
}
|
}
|
||||||
@@ -26,5 +38,4 @@ class RulesetCollection extends MongoStoredObjectCollection<RulesetMongoData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RulesetCollectionSingleton = new RulesetCollection(getMongoObjectCollection("users"));
|
export default RulesetCollection.getInstance;
|
||||||
export default RulesetCollectionSingleton;
|
|
||||||
@@ -1,54 +1,63 @@
|
|||||||
import MongoStoredObjectCollection from "./MongoStoredObjectCollection";
|
import MongoStoredObjectCollection from "./MongoStoredObjectCollection";
|
||||||
import mongo from "mongodb";
|
|
||||||
import {ActiveRecordId} from "../Objects/ActiveRecord";
|
import {ActiveRecordId} from "../Objects/ActiveRecord";
|
||||||
import PlayerCollection from "./PlayerCollection";
|
import PlayerCollection from "./PlayerCollection";
|
||||||
import SavedGame from "../Objects/SavedGame";
|
import SavedGame from "../Objects/SavedGame";
|
||||||
import {getMongoObjectCollection} from "../database";
|
import {getMongoObjectCollection} from "../database";
|
||||||
import {PlayerGameResults} from "../Objects/DefaultStatsMongoData";
|
|
||||||
import RulesetCollection from "./RulesetCollection";
|
import RulesetCollection from "./RulesetCollection";
|
||||||
import {GameSubmission} from "../controllers/statsController";
|
import {ProcessedGameSubmission, ScoredResultsWithOutcome} from "../Controllers/statsController";
|
||||||
|
|
||||||
export interface SavedGameMongoData {
|
export interface SavedGameMongoData {
|
||||||
id: string;
|
id: string;
|
||||||
rulesetUsed: ActiveRecordId;
|
ruleset: ActiveRecordId;
|
||||||
players: ActiveRecordId[];
|
players: ActiveRecordId[];
|
||||||
results: PlayerGameResults[];
|
results: ScoredResultsWithOutcome[];
|
||||||
}
|
}
|
||||||
|
|
||||||
class SavedGameCollection extends MongoStoredObjectCollection<SavedGameMongoData> {
|
class SavedGameCollection extends MongoStoredObjectCollection<SavedGameMongoData> {
|
||||||
constructor(collectionClient: mongo.Collection) {
|
private static instance?: SavedGameCollection;
|
||||||
super(collectionClient);
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
static getInstance(): SavedGameCollection {
|
||||||
|
if (SavedGameCollection.instance === undefined) {
|
||||||
|
SavedGameCollection.instance = new SavedGameCollection();
|
||||||
|
}
|
||||||
|
return SavedGameCollection.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.mongoDbClientCollection = getMongoObjectCollection("savedGames");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async savedGameFrom(data: SavedGameMongoData): Promise<SavedGame> {
|
private async savedGameFrom(data: SavedGameMongoData): Promise<SavedGame> {
|
||||||
const playerList: {name: string, id: ActiveRecordId}[] = [];
|
const playerList: {name: string, id: ActiveRecordId}[] = [];
|
||||||
for (const playerId of data.players) {
|
for (const playerId of data.players) {
|
||||||
const player = await PlayerCollection.read(playerId);
|
const player = await PlayerCollection().read(playerId);
|
||||||
playerList.push({name: player.getNick(), id: playerId})
|
playerList.push({name: player.getNick(), id: playerId})
|
||||||
}
|
}
|
||||||
const rulesetUsed = await RulesetCollection.read(data.rulesetUsed);
|
const rulesetUsed = await RulesetCollection().read(data.ruleset);
|
||||||
return new SavedGame(
|
return new SavedGame(
|
||||||
data.id,
|
data.id,
|
||||||
{name: rulesetUsed.getName(), id: data.rulesetUsed},
|
{name: rulesetUsed.getName(), id: data.ruleset},
|
||||||
playerList,
|
playerList,
|
||||||
data.results);
|
data.results);
|
||||||
}
|
}
|
||||||
|
|
||||||
async read(id: string): Promise<SavedGame> {
|
async read(id: ActiveRecordId): Promise<SavedGame> {
|
||||||
const foundGame = await this.mongoRead(id);
|
const foundGame = await this.mongoRead(id);
|
||||||
return this.savedGameFrom(foundGame);
|
return this.savedGameFrom(foundGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(gameSubmission: GameSubmission): Promise<SavedGame> {
|
async create(submission: ProcessedGameSubmission): Promise<SavedGame> {
|
||||||
const pids = gameSubmission.players.map(playerIdAndNick => playerIdAndNick.id);
|
const pids = submission.players.map(playerIdAndNick => playerIdAndNick.id);
|
||||||
return this.savedGameFrom(
|
return this.savedGameFrom(
|
||||||
await this.mongoCreate({
|
await this.mongoCreate({
|
||||||
rulesetUsed: gameSubmission.rulesetId,
|
ruleset: submission.ruleset,
|
||||||
players: pids,
|
players: pids,
|
||||||
results: gameSubmission.results})
|
results: submission.results})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SavedGameCollectionSingleton = new SavedGameCollection(getMongoObjectCollection("users"));
|
export default SavedGameCollection.getInstance;
|
||||||
export default SavedGameCollectionSingleton;
|
|
||||||
@@ -10,6 +10,7 @@ class AccountStats {
|
|||||||
constructor(data: AccountStatsMongoData) {
|
constructor(data: AccountStatsMongoData) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.updater = new StatsUpdater();
|
this.updater = new StatsUpdater();
|
||||||
|
this.updater.use(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
use(data: AccountStatsMongoData) {
|
use(data: AccountStatsMongoData) {
|
||||||
@@ -21,8 +22,8 @@ class AccountStats {
|
|||||||
if (this.data) {
|
if (this.data) {
|
||||||
for (const playerGameResult of playerGameResults) {
|
for (const playerGameResult of playerGameResults) {
|
||||||
this.updater.updateStats(playerGameResult, ruleset);
|
this.updater.updateStats(playerGameResult, ruleset);
|
||||||
this.data.gamesPlayed += 1;
|
|
||||||
}
|
}
|
||||||
|
this.data.gamesPlayed += 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UpdateError(`Cannot update without data! Call the use() method to hydrate the updater with data
|
throw new UpdateError(`Cannot update without data! Call the use() method to hydrate the updater with data
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
export type ActiveRecordId = string;
|
import mongo from "mongodb";
|
||||||
|
|
||||||
|
export type ActiveRecordId = mongo.ObjectId | string;
|
||||||
export type OrId<T extends ActiveRecord> = T | ActiveRecordId;
|
export type OrId<T extends ActiveRecord> = T | ActiveRecordId;
|
||||||
|
|
||||||
interface ActiveRecord {
|
interface ActiveRecord {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import {CellDef, DEFAULT_RULESET, DEFAULT_RULESET_NAME, RulesetSchema} from "../rulesets";
|
import {CellDef, DEFAULT_RULESET, DEFAULT_RULESET_NAME, RulesetSchema} from "../rulesets";
|
||||||
import {FieldType} from "../enums";
|
import {FieldType} from "../enums";
|
||||||
|
|
||||||
|
|
||||||
export enum OutcomeType {
|
export enum OutcomeType {
|
||||||
win,
|
win = "win",
|
||||||
loss,
|
loss = "loss",
|
||||||
runnerUp,
|
runnerUp = "runnerUp",
|
||||||
draw,
|
draw = "draw",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayerStatsMongoData extends BaseStatsMongoData {}
|
export interface PlayerStatsMongoData extends BaseStatsMongoData {}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export type LoginDetails = { username: string, email: string, password: string }
|
|||||||
|
|
||||||
class KadiUser implements ActiveRecord {
|
class KadiUser implements ActiveRecord {
|
||||||
constructor(
|
constructor(
|
||||||
private id: string,
|
private id: ActiveRecordId,
|
||||||
private username: string,
|
private username: string,
|
||||||
private email: string,
|
private email: string,
|
||||||
private password: string,
|
private password: string,
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
import {CellValue} from "../controllers/statsController";
|
|
||||||
import {RulesetSchema} from "../rulesets";
|
|
||||||
import ActiveRecord, {ActiveRecordId} from "./ActiveRecord";
|
import ActiveRecord, {ActiveRecordId} from "./ActiveRecord";
|
||||||
import {UpdateError} from "../errors";
|
import {UpdateError} from "../errors";
|
||||||
import {OutcomeType, PlayerGameResults} from "./DefaultStatsMongoData";
|
import {OutcomeType, PlayerGameResults} from "./DefaultStatsMongoData";
|
||||||
import PlayerStats from "./PlayerStats";
|
import PlayerStats from "./PlayerStats";
|
||||||
import Ruleset from "./Ruleset";
|
import Ruleset from "./Ruleset";
|
||||||
|
|
||||||
export interface CellDetails {
|
|
||||||
id: string;
|
|
||||||
value: CellValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Player implements ActiveRecord {
|
export class Player implements ActiveRecord {
|
||||||
constructor(
|
constructor(
|
||||||
private id: ActiveRecordId,
|
private id: ActiveRecordId,
|
||||||
private nick: string,
|
private nick: string,
|
||||||
private stats?: PlayerStats
|
private stats: PlayerStats
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getId(): ActiveRecordId {
|
getId(): ActiveRecordId {
|
||||||
@@ -30,7 +23,7 @@ export class Player implements ActiveRecord {
|
|||||||
this.nick = newNick;
|
this.nick = newNick;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStats(): PlayerStats | undefined {
|
getStats(): PlayerStats {
|
||||||
return this.stats;
|
return this.stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class PlayerStats {
|
|||||||
constructor(data: PlayerStatsMongoData) {
|
constructor(data: PlayerStatsMongoData) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.updater = new StatsUpdater();
|
this.updater = new StatsUpdater();
|
||||||
|
this.updater.use(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
use(data: PlayerStatsMongoData) {
|
use(data: PlayerStatsMongoData) {
|
||||||
@@ -18,6 +19,7 @@ class PlayerStats {
|
|||||||
|
|
||||||
updateStats(playerGameResults: PlayerGameResults & {outcome: OutcomeType}, ruleset: Ruleset): void {
|
updateStats(playerGameResults: PlayerGameResults & {outcome: OutcomeType}, ruleset: Ruleset): void {
|
||||||
this.updater.updateStats(playerGameResults, ruleset);
|
this.updater.updateStats(playerGameResults, ruleset);
|
||||||
|
this.data.gamesPlayed += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
getData(): PlayerStatsMongoData {
|
getData(): PlayerStatsMongoData {
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ export class Ruleset implements ActiveRecord {
|
|||||||
getCellsInBlock(blockId: string): Record<string, CellDef> {
|
getCellsInBlock(blockId: string): Record<string, CellDef> {
|
||||||
return Object.assign({}, this.schema.blocks[blockId].cells);
|
return Object.assign({}, this.schema.blocks[blockId].cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSchemaJSON(): RulesetSchema {
|
||||||
|
return Object.assign({}, this.schema);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Ruleset;
|
export default Ruleset;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import ActiveRecord, {ActiveRecordId} from "./ActiveRecord";
|
import ActiveRecord, {ActiveRecordId} from "./ActiveRecord";
|
||||||
import {PlayerGameResults} from "./DefaultStatsMongoData";
|
import {ScoredResultsWithOutcome} from "../Controllers/statsController";
|
||||||
|
|
||||||
class SavedGame implements ActiveRecord {
|
class SavedGame implements ActiveRecord {
|
||||||
constructor(
|
constructor(
|
||||||
private id: string,
|
private id: string,
|
||||||
private rulesetUsed: {name: string, id: ActiveRecordId},
|
private rulesetUsed: {name: string, id: ActiveRecordId},
|
||||||
private players: {name: string, id: ActiveRecordId}[],
|
private players: {name: string, id: ActiveRecordId}[],
|
||||||
private results: PlayerGameResults[],
|
private results: ScoredResultsWithOutcome[],
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getId() {
|
getId() {
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ abstract class ScoreCellCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hydrateWithJSON(jsonRep: ScoreCellJSONRepresentation): void {
|
hydrateWithJSON(jsonRep: ScoreCellJSONRepresentation): void {
|
||||||
|
this.reset();
|
||||||
if (jsonRep.value === CellFlag.strike) {
|
if (jsonRep.value === CellFlag.strike) {
|
||||||
this.struck = true;
|
this.struck = true;
|
||||||
}
|
}
|
||||||
@@ -67,6 +68,11 @@ abstract class ScoreCellCalculator {
|
|||||||
this.value = jsonRep.value;
|
this.value = jsonRep.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.struck = false;
|
||||||
|
this.value = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NumberScoreCell extends ScoreCellCalculator {
|
class NumberScoreCell extends ScoreCellCalculator {
|
||||||
@@ -78,7 +84,12 @@ class NumberScoreCell extends ScoreCellCalculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getScore(): number {
|
getScore(): number {
|
||||||
return this.value as number;
|
if (this.isStruck()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this.value as number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +112,11 @@ class BoolScoreCell extends ScoreCellCalculator {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
super.reset();
|
||||||
|
this.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SuperkadiScoreCell extends ScoreCellCalculator {
|
class SuperkadiScoreCell extends ScoreCellCalculator {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import {RulesetSchema} from "../rulesets";
|
|
||||||
import ScoreCalculator, {ScoreCardJSONRepresentation} from "./ScoreCalculator";
|
import ScoreCalculator, {ScoreCardJSONRepresentation} from "./ScoreCalculator";
|
||||||
import {UpdateError} from "../errors";
|
import {UpdateError} from "../errors";
|
||||||
import {FieldType} from "../enums";
|
import {FieldType} from "../enums";
|
||||||
@@ -8,7 +7,8 @@ import {
|
|||||||
BoolFieldStatsMongoData,
|
BoolFieldStatsMongoData,
|
||||||
CellStatsMongoData,
|
CellStatsMongoData,
|
||||||
OutcomeType,
|
OutcomeType,
|
||||||
PlayerGameResults, RulesetStatsMongoData,
|
PlayerGameResults,
|
||||||
|
RulesetStatsMongoData,
|
||||||
TotalFieldStatsMongoData
|
TotalFieldStatsMongoData
|
||||||
} from "./DefaultStatsMongoData";
|
} from "./DefaultStatsMongoData";
|
||||||
import Ruleset from "./Ruleset";
|
import Ruleset from "./Ruleset";
|
||||||
@@ -30,15 +30,15 @@ class StatsUpdater {
|
|||||||
this.validationRuleset = ruleset;
|
this.validationRuleset = ruleset;
|
||||||
this.calculator = new ScoreCalculator(ruleset);
|
this.calculator = new ScoreCalculator(ruleset);
|
||||||
this.calculator.hydrateWithJSON(playerGameResults as ScoreCardJSONRepresentation);
|
this.calculator.hydrateWithJSON(playerGameResults as ScoreCardJSONRepresentation);
|
||||||
this.currentStatsObject = this.data.statsByRuleset[ruleset.getId()];
|
this.currentStatsObject = this.data.statsByRuleset[ruleset.getId().toString()];
|
||||||
for (const blockId in ruleset.getBlocks()) {
|
for (const blockId in ruleset.getBlocks()) {
|
||||||
this.updateBlockStats(blockId);
|
this.updateBlockStats(blockId);
|
||||||
}
|
}
|
||||||
this.updateTotalFieldStats(this.currentStatsObject.grandTotal, this.calculator.getTotal());
|
this.updateTotalFieldStats(this.currentStatsObject.grandTotal, this.calculator.getTotal());
|
||||||
this.currentStatsObject.wins += Number(playerGameResults.outcome === "win");
|
this.currentStatsObject.wins += Number(playerGameResults.outcome === OutcomeType.win);
|
||||||
this.currentStatsObject.draws += Number(playerGameResults.outcome === "draw");
|
this.currentStatsObject.draws += Number(playerGameResults.outcome === OutcomeType.draw);
|
||||||
this.currentStatsObject.runnerUps += Number(playerGameResults.outcome === "runnerUp");
|
this.currentStatsObject.runnerUps += Number(playerGameResults.outcome === OutcomeType.runnerUp);
|
||||||
this.currentStatsObject.losses += Number(playerGameResults.outcome === "loss");
|
this.currentStatsObject.losses += Number(playerGameResults.outcome === OutcomeType.loss);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UpdateError(`Cannot update without data! Call the use() method to hydrate the updater with data
|
throw new UpdateError(`Cannot update without data! Call the use() method to hydrate the updater with data
|
||||||
@@ -66,9 +66,10 @@ class StatsUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateCellStatsByIds(ids: {cellId: string, blockId: string}) {
|
private updateCellStatsByIds(ids: {cellId: string, blockId: string}) {
|
||||||
const cellStats = this.getCellStatsByIds({...ids, rulesetId: this.validationRuleset!.getId()});
|
const cellStats = this.getCellStatsByIds({...ids, rulesetId: this.validationRuleset!.getId().toString()});
|
||||||
const cellFieldType = this.validationRuleset?.getBlocks()[ids.blockId].cells[ids.cellId].fieldType;
|
const cellFieldType = this.validationRuleset?.getBlocks()[ids.blockId].cells[ids.cellId].fieldType;
|
||||||
const cellScore = this.calculator!.getCellScoreByLocation({...ids});
|
const cellScore = this.calculator!.getCellScoreByLocation({...ids});
|
||||||
|
cellStats.runningTotal += cellScore;
|
||||||
if (cellScore > 0 && cellFieldType === FieldType.bool) {
|
if (cellScore > 0 && cellFieldType === FieldType.bool) {
|
||||||
(cellStats as BoolFieldStatsMongoData).total += 1;
|
(cellStats as BoolFieldStatsMongoData).total += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import * as statsController from "../controllers/statsController";
|
import * as statsController from "../Controllers/statsController";
|
||||||
import * as KadiUserController from "../controllers/kadiUserController"
|
import * as KadiUserController from "../Controllers/kadiUserController"
|
||||||
import {requireAuthenticated} from "./routerMiddleware";
|
import {requireAuthenticated} from "./routerMiddleware";
|
||||||
|
import * as rulesetController from "../Controllers/rulesetController";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -21,4 +22,8 @@ router.delete("/guest/:id", requireAuthenticated, KadiUserController.deleteGuest
|
|||||||
router.get("/games", requireAuthenticated, statsController.listGames);
|
router.get("/games", requireAuthenticated, statsController.listGames);
|
||||||
router.post("/games", requireAuthenticated, statsController.saveGame);
|
router.post("/games", requireAuthenticated, statsController.saveGame);
|
||||||
|
|
||||||
|
//Stats
|
||||||
|
router.get("/stats", requireAuthenticated, statsController.getStats);
|
||||||
|
router.get("/ruleset/:id", rulesetController.getRuleset);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import express, {NextFunction} from "express";
|
import express from "express";
|
||||||
import routers from "./routers";
|
import routers from "./routers";
|
||||||
import {LoginDetails} from "../Objects/KadiUser";
|
import {LoginDetails} from "../Objects/KadiUser";
|
||||||
import {requireAuthenticated} from "./routerMiddleware";
|
import {requireAuthenticated} from "./routerMiddleware";
|
||||||
@@ -22,6 +22,7 @@ router.get("/**", requireAuthenticated, (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const topLevelErrorHandler: express.ErrorRequestHandler = (err, req, res, next) => {
|
const topLevelErrorHandler: express.ErrorRequestHandler = (err, req, res, next) => {
|
||||||
|
console.log(err.message);
|
||||||
if (err instanceof GenericPersistenceError) {
|
if (err instanceof GenericPersistenceError) {
|
||||||
res.status(500).send({message: "An internal error occurred accessing the database."});
|
res.status(500).send({message: "An internal error occurred accessing the database."});
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,13 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import {requireAuthenticated, requireNotAuthenticated} from "../passport-config";
|
import * as signup from "../Controllers/signupController";
|
||||||
import * as signup from "../controllers/signupController";
|
import {requireAuthenticated, requireNotAuthenticated} from "./routerMiddleware";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/login", requireNotAuthenticated, signup.showLoginPage);
|
router.get("/login", requireNotAuthenticated, signup.showLoginPage);
|
||||||
|
|
||||||
router.post("/login", requireNotAuthenticated, signup.loginUser);
|
router.post("/login", requireNotAuthenticated, signup.loginUser);
|
||||||
|
|
||||||
router.get("/register", requireNotAuthenticated, signup.showRegistrationPage);
|
router.get("/register", requireNotAuthenticated, signup.showRegistrationPage);
|
||||||
|
|
||||||
router.post("/register", requireNotAuthenticated, signup.registerNewUser);
|
router.post("/register", requireNotAuthenticated, signup.registerNewUser);
|
||||||
|
|
||||||
router.get("/logout", requireAuthenticated, signup.logoutUser);
|
router.get("/logout", requireAuthenticated, signup.logoutUser);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import {MongoClient, Db} from "mongodb";
|
import {MongoClient, Db} from "mongodb";
|
||||||
import Settings from "./server-config.json";
|
import Settings from "./server-config.json";
|
||||||
import {GenericPersistenceError, MongoError} from "./errors";
|
import {GenericPersistenceError, MongoError} from "./errors";
|
||||||
|
import KadiUserCollection from "./ObjectCollections/KadiUserCollection";
|
||||||
|
import PlayerCollection from "./ObjectCollections/PlayerCollection";
|
||||||
|
import RulesetCollection from "./ObjectCollections/RulesetCollection";
|
||||||
|
import SavedGameCollection from "./ObjectCollections/SavedGameCollection";
|
||||||
|
|
||||||
let SessionDbClient: Db;
|
let SessionDbClient: Db;
|
||||||
|
|
||||||
@@ -21,6 +25,13 @@ export function getMongoObjectCollection(collectionName: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function initCollections() {
|
||||||
|
KadiUserCollection().init();
|
||||||
|
PlayerCollection().init();
|
||||||
|
SavedGameCollection().init();
|
||||||
|
RulesetCollection().init();
|
||||||
|
}
|
||||||
|
|
||||||
type CallbackWrapper = <T>(query: () => T) => Promise<T>;
|
type CallbackWrapper = <T>(query: () => T) => Promise<T>;
|
||||||
export const tryQuery: CallbackWrapper = async (cb) => {
|
export const tryQuery: CallbackWrapper = async (cb) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import express, {NextFunction, Request, Response} from "express";
|
import express from "express";
|
||||||
import Settings from "./server-config.json";
|
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 MainRouter from "./routers/mainRouter";
|
import MainRouter from "./Routers/mainRouter";
|
||||||
import {initMongoSessionClient} from "./database";
|
import {initCollections, initMongoSessionClient} from "./database";
|
||||||
import {Strategy as LocalStrategy} from "passport-local";
|
import {Strategy as LocalStrategy} from "passport-local";
|
||||||
import {authenticateKadiUser, deserializeKadiUser, serializeKadiUser} from "./controllers/signupController";
|
import {authenticateKadiUser, deserializeKadiUser, serializeKadiUser} from "./Controllers/signupController";
|
||||||
|
|
||||||
async function startApp() {
|
async function startApp() {
|
||||||
await initMongoSessionClient();
|
await initMongoSessionClient();
|
||||||
|
await initCollections();
|
||||||
passport.use(new LocalStrategy({ usernameField: "email" }, authenticateKadiUser));
|
passport.use(new LocalStrategy({ usernameField: "email" }, authenticateKadiUser));
|
||||||
passport.serializeUser(serializeKadiUser);
|
passport.serializeUser(serializeKadiUser);
|
||||||
passport.deserializeUser(deserializeKadiUser);
|
passport.deserializeUser(deserializeKadiUser);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
"target": "ES5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
|
|||||||
Reference in New Issue
Block a user