added /game/add, API hopefully finished

This commit is contained in:
j-weissen 2023-01-03 23:42:07 +01:00
parent fff55edf79
commit 5f9a484285
19 changed files with 143 additions and 100 deletions

View file

@ -3,6 +3,7 @@ import helmet from "helmet";
import morgan from 'morgan';
import {leaderboardRoute} from "./leaderboardRoute.js";
import {userRoute} from "./userRoute.js";
import {gameRoute} from "./gameRoute.js";
const app = express()
@ -10,24 +11,13 @@ const port = 3000
app.use(helmet())
// configure & use logger
let morganFormatted = morgan('[:date[iso]] :method :url - :status')
app.use(morganFormatted);
app.use(express.json())
app.use('/leaderboard', leaderboardRoute)
app.use('/user', userRoute)
app.get('/helloworld', (req, res) => {
res.json({message: "Hello World!"})
})
app.post('/echo', async (req, res) => {
res.json(req.body)
})
app.use('/game', gameRoute)
app.listen(port, () => {

View file

@ -0,0 +1,50 @@
import express from "express";
import {GameRepository} from "./repositories/GameRepository.js";
import {GamePgPromiseRepository} from "./repositories/pgPromise/GamePgPromiseRepository.js";
import {Game} from "./model/Game.js";
import {body, CustomValidator, validationResult} from "express-validator";
import {UserRepository} from "./repositories/UserRepository.js";
import {UserPgPromiseRepository} from "./repositories/pgPromise/UserPgPromiseRepository.js";
export const gameRoute = express.Router()
gameRoute.use(express.json())
const userWithIdExists: CustomValidator = userId => {
try {
const userRepo: UserRepository = new UserPgPromiseRepository;
return userRepo.withIdExists(userId).then(exists => {
if (!exists) return Promise.reject("User does not exist");
});
} catch (error) {
console.log(error);
}
}
gameRoute.post(
'/add',
body('playtime')
.matches("([0-5]\\d:)?[0-5]\\d:[0-5]\\d"),
body('date')
.isDate(),
body('userId')
.isInt({min: 1})
.custom(userWithIdExists),
async (req, res) => {
try {
//region validate parameters
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
//endregion
let game: Game = req.body;
const gameRepo: GameRepository = new GamePgPromiseRepository;
const inserted: Game = await gameRepo.insert(game);
res.send(inserted);
} catch (error) {
// handle errors
console.log(error)
res.status(500).json({ errors: [{msg: "Internal server error"}]})
}
})

View file

@ -1,16 +1,15 @@
import express from 'express';
import {TimeLeaderboardManager} from "./manager/TimeLeaderboardManager.js";
import {TimeLeaderboardPgPromiseManager} from "./manager/pgPromise/TimeLeaderboardPgPromiseManager.js";
import {HighscoreLeaderboardPgPromiseManager} from "./manager/pgPromise/HighscoreLeaderboardPgPromiseManager.js";
import {HighscoreLeaderboardManager} from "./manager/HighscoreLeaderboardManager.js";
import {TimeLeaderboardRepository} from "./repositories/TimeLeaderboardRepository.js";
import {TimeLeaderboardPgPromiseRepository} from "./repositories/pgPromise/TimeLeaderboardPgPromiseRepository.js";
import {HighscoreLeaderboardPgPromiseRepository} from "./repositories/pgPromise/HighscoreLeaderboardPgPromiseRepository.js";
import {HighscoreLeaderboardRepository} from "./repositories/HighscoreLeaderboardRepository.js";
import {HighscoreLeaderboard, TimeLeaderboard} from "./model/Leaderboard.js";
export const leaderboardRoute = express.Router()
leaderboardRoute.get('/highscore', async (req, res) => {
try {
const highscoreLeaderboardManager: HighscoreLeaderboardManager = new HighscoreLeaderboardPgPromiseManager;
const highscoreLeaderboardManager: HighscoreLeaderboardRepository = new HighscoreLeaderboardPgPromiseRepository;
const highscoreLeaderboard: HighscoreLeaderboard = await highscoreLeaderboardManager.getAll();
res.send(highscoreLeaderboard);
} catch (error) {
@ -22,7 +21,7 @@ leaderboardRoute.get('/highscore', async (req, res) => {
leaderboardRoute.get('/totalplaytime', async (req, res) => {
try {
const timeLeaderboardManager: TimeLeaderboardManager = new TimeLeaderboardPgPromiseManager;
const timeLeaderboardManager: TimeLeaderboardRepository = new TimeLeaderboardPgPromiseRepository;
const timeLeaderboard: TimeLeaderboard = await timeLeaderboardManager.getAll();
res.send(timeLeaderboard);
} catch (error) {

View file

@ -1,6 +0,0 @@
import {HighscoreLeaderboard} from "../model/Leaderboard.js";
import {Manager} from "./Manager.js";
export abstract class HighscoreLeaderboardManager extends Manager<HighscoreLeaderboard>{
abstract getAll(): Promise<HighscoreLeaderboard>;
}

View file

@ -1,7 +0,0 @@
export abstract class Manager<T> {
//region getter&setter
protected abstract serialize(raw: any): T;
protected abstract deserialize(parsed: T): any;
//endregion
}

View file

@ -1,6 +0,0 @@
import {Manager} from "./Manager.js";
import {TimeLeaderboard} from "../model/Leaderboard.js";
export abstract class TimeLeaderboardManager extends Manager<TimeLeaderboard>{
abstract getAll(): Promise<TimeLeaderboard>;
}

View file

@ -1,29 +0,0 @@
import {HighscoreLeaderboardManager} from "../HighscoreLeaderboardManager.js";
import {HighscoreLeaderboard, LeaderboardEntry} from "../../model/Leaderboard.js";
import {Database} from "../../Database.js";
export class HighscoreLeaderboardPgPromiseManager extends HighscoreLeaderboardManager{
async getAll(): Promise<HighscoreLeaderboard> {
const raw: any = await Database.db.manyOrNone(
'SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY RANK;'
);
return this.serialize(raw);
}
//region serialization
protected serialize(raw: any): HighscoreLeaderboard {
return raw.map((item) => {
let newItem: LeaderboardEntry<number> = {
rank: item.rank,
username: item.name,
score: item.highscore,
}
return newItem;
});
}
protected deserialize(parsed: HighscoreLeaderboard): any {
throw new Error("Mthod not implemented.");
}
//endregion
}

View file

@ -0,0 +1,7 @@
export interface Game {
id?: number,
score: number,
playtime: string,
date: Date,
userId: number,
}

View file

@ -0,0 +1,5 @@
import {Game} from "../model/Game.js";
export abstract class GameRepository {
abstract insert(game: Game): Promise<Game>;
}

View file

@ -0,0 +1,5 @@
import {HighscoreLeaderboard} from "../model/Leaderboard.js";
export abstract class HighscoreLeaderboardRepository {
abstract getAll(): Promise<HighscoreLeaderboard>;
}

View file

@ -0,0 +1,5 @@
import {TimeLeaderboard} from "../model/Leaderboard.js";
export abstract class TimeLeaderboardRepository {
abstract getAll(): Promise<TimeLeaderboard>;
}

View file

@ -1,7 +1,6 @@
import {Manager} from "./Manager.js";
import {User} from "../model/User.js";
export abstract class UserManager extends Manager<User>{
export abstract class UserRepository {
abstract getById(id: number): Promise<User>;
abstract getByName(name: string): Promise<User>;
abstract withIdExists(userId: number): Promise<boolean>;

View file

@ -1,6 +1,5 @@
import {UserScores} from "../model/UserScores.js";
import {Manager} from "./Manager.js";
export abstract class UserScoresManager extends Manager<UserScores>{
export abstract class UserScoresRepository {
abstract getById(userId: number): Promise<UserScores>;
}

View file

@ -0,0 +1,24 @@
import {GameRepository} from "../GameRepository.js";
import {Game} from "../../model/Game.js";
import {Database} from "../../Database.js";
export class GamePgPromiseRepository extends GameRepository{
public async insert(game: Game): Promise<Game> {
const raw: any = await Database.db.oneOrNone(
'INSERT INTO game (score, playtime, date, user_id) VALUES ($(score), $(playtime), $(date), $(userId)) RETURNING *;',
game
);
return this.serialize(raw);
}
serialize(raw: any): Game {
return {
id: raw.id,
score: raw.score,
playtime: raw.playtime,
date: raw.date,
userId: raw.userId,
};
}
}

View file

@ -0,0 +1,23 @@
import {HighscoreLeaderboardRepository} from "../HighscoreLeaderboardRepository.js";
import {HighscoreLeaderboard, LeaderboardEntry} from "../../model/Leaderboard.js";
import {Database} from "../../Database.js";
export class HighscoreLeaderboardPgPromiseRepository extends HighscoreLeaderboardRepository {
async getAll(): Promise<HighscoreLeaderboard> {
const raw: any = await Database.db.manyOrNone(
'SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY RANK;'
);
return this.serialize(raw);
}
protected serialize(raw: any): HighscoreLeaderboard {
return raw.map((item) => {
let newItem: LeaderboardEntry<number> = {
rank: item.rank,
username: item.name,
score: item.highscore,
}
return newItem;
});
}
}

View file

@ -1,8 +1,8 @@
import {TimeLeaderboardManager} from "../TimeLeaderboardManager.js";
import {TimeLeaderboardRepository} from "../TimeLeaderboardRepository.js";
import {LeaderboardEntry, TimeLeaderboard} from "../../model/Leaderboard.js";
import {Database} from "../../Database.js";
export class TimeLeaderboardPgPromiseManager extends TimeLeaderboardManager {
export class TimeLeaderboardPgPromiseRepository extends TimeLeaderboardRepository {
async getAll(): Promise<TimeLeaderboard> {
const raw: any = await Database.db.manyOrNone(
'SELECT * FROM lb_total_playtime INNER JOIN "user" ON user_id = id ORDER BY RANK;'
@ -11,10 +11,6 @@ export class TimeLeaderboardPgPromiseManager extends TimeLeaderboardManager {
}
//region serialization
protected deserialize(parsed: TimeLeaderboard): any {
throw new Error("Method not implemented.")
}
protected serialize(raw: any): TimeLeaderboard {
return raw.map((item) => {
let newItem: LeaderboardEntry<string> = {

View file

@ -1,8 +1,8 @@
import {UserManager} from "../UserManager.js";
import {UserRepository} from "../UserRepository.js";
import {User} from "../../model/User.js";
import {Database} from "../../Database.js";
export class UserPgPromiseManager extends UserManager {
export class UserPgPromiseRepository extends UserRepository {
async getById(id: number): Promise<User> {
const raw = await Database.db.oneOrNone(
'SELECT * FROM "user" WHERE id = $1;', id
@ -38,16 +38,10 @@ export class UserPgPromiseManager extends UserManager {
return this.serialize(raw);
}
//region serialization
protected serialize(raw: any): User {
return {
id: raw.id,
name: raw.name
};
}
protected deserialize(parsed: User): any {
throw new Error("Method not implemented.")
}
//endregion
}

View file

@ -1,8 +1,8 @@
import {UserScoresManager} from "../UserScoresManager.js";
import {UserScoresRepository} from "../UserScoresRepository.js";
import {UserScores} from "../../model/UserScores.js";
import {Database} from "../../Database.js";
export class UserScoresPgPromiseManager extends UserScoresManager {
export class UserScoresPgPromiseRepository extends UserScoresRepository {
public async getById(id: number): Promise<UserScores> {
const raw = await Database.db.oneOrNone(
'SELECT * FROM user_scores WHERE user_id = $1;', id
@ -20,8 +20,4 @@ export class UserScoresPgPromiseManager extends UserScoresManager {
gamesPlayed: raw.games_played,
};
}
protected deserialize(parsed: UserScores): any {
throw new Error("Method not implemented.")
}
}

View file

@ -1,13 +1,13 @@
import express from "express";
import { body, param, validationResult } from 'express-validator';
import {UserScoresPgPromiseManager} from "./manager/pgPromise/UserScoresPgPromiseManager.js";
import {UserPgPromiseManager} from "./manager/pgPromise/UserPgPromiseManager.js";
import {UserManager} from "./manager/UserManager.js";
import {UserScoresManager} from "./manager/UserScoresManager.js";
import {UserScoresPgPromiseRepository} from "./repositories/pgPromise/UserScoresPgPromiseRepository.js";
import {UserPgPromiseRepository} from "./repositories/pgPromise/UserPgPromiseRepository.js";
import {UserRepository} from "./repositories/UserRepository.js";
import {UserScoresRepository} from "./repositories/UserScoresRepository.js";
import {User} from "./model/User.js";
export const userRoute = express.Router()
userRoute.use(express.json())
userRoute.post(
'/register',
@ -23,9 +23,8 @@ userRoute.post(
return res.status(400).json({ errors: errors.array() });
}
//endregion
const username: string = req.body.name;
const userManager: UserManager = new UserPgPromiseManager();
const userManager: UserRepository = new UserPgPromiseRepository();
// check if username already exists
if (await userManager.withNameExists(username)) {
@ -53,7 +52,7 @@ userRoute.get('/:userId/scores',
//endregion
const userId: number = req.params.userId;
const userManager: UserManager = new UserPgPromiseManager;
const userManager: UserRepository = new UserPgPromiseRepository;
try {
// check if user with given id exists
@ -61,7 +60,7 @@ userRoute.get('/:userId/scores',
return res.status(400).json({ errors: [{msg: `User with id ${userId} does not exist.`}] })
}
// get & return data
const userScoresManager: UserScoresManager = new UserScoresPgPromiseManager;
const userScoresManager: UserScoresRepository = new UserScoresPgPromiseRepository;
const userScores = await userScoresManager.getById(userId);
res.json(userScores);
} catch (error) {