count game history stats for users

This commit is contained in:
Nathaniel Tampus
2023-04-02 18:24:21 +08:00
parent 92dfc0c778
commit 577cba6ff4
6 changed files with 94 additions and 26 deletions

View File

@@ -119,6 +119,10 @@ export const registerUser = async (req: Request, res: Response) => {
throw new Error("Failed to create user"); throw new Error("Failed to create user");
} }
const publicUser = {
id: newUser.id,
name: newUser.name
};
if (req.session.user?.id && typeof req.session.user.id === "string") { if (req.session.user?.id && typeof req.session.user.id === "string") {
const game = activeGames.find( const game = activeGames.find(
(g) => (g) =>
@@ -128,17 +132,17 @@ export const registerUser = async (req: Request, res: Response) => {
); );
if (game) { if (game) {
if (game.host?.id === req.session.user.id) { if (game.host?.id === req.session.user.id) {
game.host = newUser; game.host = publicUser;
} }
if (game.white && game.white?.id === req.session.user.id) { if (game.white && game.white?.id === req.session.user.id) {
game.white = newUser; game.white = publicUser;
} else if (game.black && game.black?.id === req.session.user.id) { } else if (game.black && game.black?.id === req.session.user.id) {
game.black = newUser; game.black = publicUser;
} else { } else {
const observer = game.observers?.find((o) => o.id === req.session.user.id); const observer = game.observers?.find((o) => o.id === req.session.user.id);
if (observer) { if (observer) {
observer.id = newUser.id; observer.id = publicUser.id;
observer.name = newUser.name; observer.name = publicUser.name;
} }
} }
io.to(game.code as string).emit("receivedLatestGame", game); io.to(game.code as string).emit("receivedLatestGame", game);
@@ -180,10 +184,9 @@ export const loginUser = async (req: Request, res: Response) => {
return; return;
} }
const newUser = { const publicUser = {
id: users[0].id, id: users[0].id,
name: users[0].name, name: users[0].name
email: users[0].email
}; };
if (req.session.user?.id && typeof req.session.user.id === "string") { if (req.session.user?.id && typeof req.session.user.id === "string") {
@@ -195,17 +198,17 @@ export const loginUser = async (req: Request, res: Response) => {
); );
if (game) { if (game) {
if (game.host?.id === req.session.user.id) { if (game.host?.id === req.session.user.id) {
game.host = newUser; game.host = publicUser;
} }
if (game.white && game.white?.id === req.session.user.id) { if (game.white && game.white?.id === req.session.user.id) {
game.white = newUser; game.white = publicUser;
} else if (game.black && game.black?.id === req.session.user.id) { } else if (game.black && game.black?.id === req.session.user.id) {
game.black = newUser; game.black = publicUser;
} else { } else {
const observer = game.observers?.find((o) => o.id === req.session.user.id); const observer = game.observers?.find((o) => o.id === req.session.user.id);
if (observer) { if (observer) {
observer.id = newUser.id; observer.id = publicUser.id;
observer.name = newUser.name; observer.name = publicUser.name;
} }
} }
io.to(game.code as string).emit("receivedLatestGame", game); io.to(game.code as string).emit("receivedLatestGame", game);
@@ -214,7 +217,11 @@ export const loginUser = async (req: Request, res: Response) => {
req.session.user = { req.session.user = {
id: users[0].id, id: users[0].id,
name: users[0].name name: users[0].name,
email: users[0].email,
wins: users[0].wins,
losses: users[0].losses,
draws: users[0].draws
}; };
req.session.save(() => { req.session.save(() => {
res.status(200).json(req.session.user); res.status(200).json(req.session.user);
@@ -263,6 +270,35 @@ export const updateUser = async (req: Request, res: Response) => {
throw new Error("Failed to update user"); throw new Error("Failed to update user");
} }
const publicUser = {
id: updatedUser.id,
name: updatedUser.name
};
const game = activeGames.find(
(g) =>
g.white?.id === req.session.user.id ||
g.black?.id === req.session.user.id ||
g.observers?.find((o) => o.id === req.session.user.id)
);
if (game) {
if (game.host?.id === req.session.user.id) {
game.host = publicUser;
}
if (game.white && game.white?.id === req.session.user.id) {
game.white = publicUser;
} else if (game.black && game.black?.id === req.session.user.id) {
game.black = publicUser;
} else {
const observer = game.observers?.find((o) => o.id === req.session.user.id);
if (observer) {
observer.id = publicUser.id;
observer.name = publicUser.name;
}
}
io.to(game.code as string).emit("receivedLatestGame", game);
}
req.session.user = updatedUser; req.session.user = updatedUser;
req.session.save(() => { req.session.save(() => {
res.status(200).json(req.session.user); res.status(200).json(req.session.user);

View File

@@ -8,6 +8,9 @@ export const INIT_TABLES = /* sql */ `
name VARCHAR(128) UNIQUE NOT NULL, name VARCHAR(128) UNIQUE NOT NULL,
email VARCHAR(128), email VARCHAR(128),
password TEXT, password TEXT,
wins INTEGER DEFAULT 0,
losses INTEGER DEFAULT 0,
draws INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); );
CREATE TABLE IF NOT EXISTS "game" ( CREATE TABLE IF NOT EXISTS "game" (

View File

@@ -5,7 +5,7 @@ export const activeGames: Array<Game> = [];
// todo: join user and game relationship // todo: join user and game relationship
export const create = async (game: Game) => { export const save = async (game: Game) => {
try { try {
const white: User = {}; const white: User = {};
const black: User = {}; const black: User = {};
@@ -31,6 +31,28 @@ export const create = async (game: Game) => {
black.name || null black.name || null
] ]
); );
if (black.id || white.id) {
// draws
if (game.winner === "draw") {
if (white.id) {
await db.query(`UPDATE "user" SET draws = draws + 1 WHERE id = $1`, [white.id]);
}
if (black.id) {
await db.query(`UPDATE "user" SET draws = draws + 1 WHERE id = $1`, [black.id]);
}
} else {
const winner = game.winner === "white" ? white : black;
const loser = game.winner === "white" ? black : white;
if (winner.id) {
await db.query(`UPDATE "user" SET wins = wins + 1 WHERE id = $1`, [winner.id]);
}
if (loser.id) {
await db.query(`UPDATE "user" SET losses = losses + 1 WHERE id = $1`, [
loser.id
]);
}
}
}
return { return {
id: res.rows[0].id, id: res.rows[0].id,
winner: res.rows[0].winner, winner: res.rows[0].winner,
@@ -135,7 +157,7 @@ export const remove = async (id: number) => {
}; };
const GameModel = { const GameModel = {
create, save,
findById, findById,
findByUserId, findByUserId,
update, update,

View File

@@ -8,7 +8,7 @@ export const create = async (user: User, password: string) => {
try { try {
const res = await db.query( const res = await db.query(
`INSERT INTO "user"(name, email, password) VALUES($1, $2, $3) RETURNING id, name, email`, `INSERT INTO "user"(name, email, password) VALUES($1, $2, $3) RETURNING id, name, email, wins, losses, draws`,
[user.name, user.email || null, password] [user.name, user.email || null, password]
); );
return res.rows[0] as User; return res.rows[0] as User;
@@ -23,7 +23,10 @@ export const findById = async (id: number) => {
return null; return null;
} }
try { try {
const res = await db.query(`SELECT id, name, email FROM "user" WHERE id=$1`, [id]); const res = await db.query(
`SELECT id, name, email, wins, losses, draws FROM "user" WHERE id=$1`,
[id]
);
if (res.rowCount) { if (res.rowCount) {
return res.rows[0] as User; return res.rows[0] as User;
} else return null; } else return null;
@@ -37,9 +40,10 @@ export const findByNameEmail = async (user: User, includePassword = false, limit
// if user is not specified, get all users // if user is not specified, get all users
if (!user) { if (!user) {
try { try {
const res = await db.query(`SELECT id, name, email FROM "user" LIMIT $1`, [ const res = await db.query(
limit ?? 10 `SELECT id, name, email, wins, losses, draws FROM "user" LIMIT $1`,
]); [limit ?? 10]
);
return res.rows as Array<User & { password?: string }>; return res.rows as Array<User & { password?: string }>;
} catch (err: unknown) { } catch (err: unknown) {
console.log(err); console.log(err);
@@ -49,7 +53,7 @@ export const findByNameEmail = async (user: User, includePassword = false, limit
try { try {
const res = await db.query( const res = await db.query(
`SELECT id, name, email${ `SELECT id, name, email, wins, losses, draws${
includePassword ? `, password` : "" includePassword ? `, password` : ""
} FROM "user" WHERE name=$1 OR email=$2 LIMIT $3`, } FROM "user" WHERE name=$1 OR email=$2 LIMIT $3`,
[user.name, user.email, limit ?? 1] [user.name, user.email, limit ?? 1]
@@ -67,11 +71,11 @@ export const update = async (id: number, updatedUser: User & { password?: string
} }
try { try {
let query = `UPDATE "user" SET name=$1, email=$2 WHERE id=$3 RETURNING id, name, email`; let query = `UPDATE "user" SET name=$1, email=$2 WHERE id=$3 RETURNING id, name, email, wins, losses, draws`;
let values = [updatedUser.name, updatedUser.email, id]; let values = [updatedUser.name, updatedUser.email, id];
if (updatedUser.password) { if (updatedUser.password) {
query = `UPDATE "user" SET name=$1, email=$2, password=$3 WHERE id=$4 RETURNING id, name, email`; query = `UPDATE "user" SET name=$1, email=$2, password=$3 WHERE id=$4 RETURNING id, name, email, wins, losses, draws`;
values = [updatedUser.name, updatedUser.email, updatedUser.password, id]; values = [updatedUser.name, updatedUser.email, updatedUser.password, id];
} }
const res = await db.query(query, values); const res = await db.query(query, values);

View File

@@ -138,7 +138,7 @@ export async function claimAbandoned(this: Socket, type: "win" | "draw") {
game.winner = "black"; game.winner = "black";
} }
const { id } = (await GameModel.create(game)) as Game; const { id } = (await GameModel.save(game)) as Game;
game.id = id; game.id = id;
const gameOver = { const gameOver = {
@@ -202,7 +202,7 @@ export async function sendMove(this: Socket, m: { from: string; to: string; prom
} }
game.endReason = reason; game.endReason = reason;
const { id } = (await GameModel.create(game)) as Game; // save game to db const { id } = (await GameModel.save(game)) as Game; // save game to db
game.id = id; game.id = id;
io.to(game.code as string).emit("gameOver", { reason, winnerName, winnerSide, id }); io.to(game.code as string).emit("gameOver", { reason, winnerName, winnerSide, id });
} }

3
types/index.d.ts vendored
View File

@@ -16,6 +16,9 @@ export interface User {
id?: number | string; // string for guest IDs id?: number | string; // string for guest IDs
name?: string | null; name?: string | null;
email?: string; email?: string;
wins?: number;
losses?: number;
draws?: number;
// mainly for players, not spectators // mainly for players, not spectators
connected?: boolean; connected?: boolean;