diff --git a/backend/api/src/app.ts b/backend/api/src/app.ts index ca51deb..fcd485a 100644 --- a/backend/api/src/app.ts +++ b/backend/api/src/app.ts @@ -6,10 +6,11 @@ import {leaderboardRoute} from "./leaderboardRoute.js"; import {userRoute} from "./userRoute.js"; import {gameRoute} from "./gameRoute.js"; -// TODO: Rename variables --> Responsotory + Comments +// initialize express const app = express() const port = 3000 +// use needed middlewares app.use(helmet()) app.use(cors()) diff --git a/backend/api/src/gameRoute.ts b/backend/api/src/gameRoute.ts index 1b2c581..2ac9175 100644 --- a/backend/api/src/gameRoute.ts +++ b/backend/api/src/gameRoute.ts @@ -2,34 +2,32 @@ 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"; +import {body, validationResult} from "express-validator"; +import {TIME_VALIDATION_REGEX, userWithIdExists} from "./validators.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"), + .matches(TIME_VALIDATION_REGEX), body('date') .isDate(), body('userId') .isInt({min: 1}) .custom(userWithIdExists), + /** + * After processing the errors of express-validator, inserts the game into the DB + * @param req + * body { + * playtime: string, + * date: Date, + * userId: int + * } + * @param res json: Game + */ async (req, res) => { try { //region validate parameters diff --git a/backend/api/src/leaderboardRoute.ts b/backend/api/src/leaderboardRoute.ts index 01940ae..e77fb2e 100644 --- a/backend/api/src/leaderboardRoute.ts +++ b/backend/api/src/leaderboardRoute.ts @@ -7,10 +7,16 @@ import {HighscoreLeaderboard, TimeLeaderboard} from "./model/Leaderboard.js"; export const leaderboardRoute = express.Router() -leaderboardRoute.get('/highscore', async (req, res) => { +leaderboardRoute.get('/highscore', + /** + * Returns the highscore leaderboard as JSON response, fetched from DB + * @param req + * @param res json: HighscoreLeaderboard + */ + async (req, res) => { try { - const highscoreLeaderboardManager: HighscoreLeaderboardRepository = new HighscoreLeaderboardPgPromiseRepository; - const highscoreLeaderboard: HighscoreLeaderboard = await highscoreLeaderboardManager.getAll(); + const highscoreLeaderboardRepo: HighscoreLeaderboardRepository = new HighscoreLeaderboardPgPromiseRepository; + const highscoreLeaderboard: HighscoreLeaderboard = await highscoreLeaderboardRepo.getAll(); res.send(highscoreLeaderboard); } catch (error) { // handle errors @@ -19,10 +25,16 @@ leaderboardRoute.get('/highscore', async (req, res) => { } }) -leaderboardRoute.get('/totalplaytime', async (req, res) => { +leaderboardRoute.get('/totalplaytime', + /** + * Returns the total playtime leaderboard as JSON response, fetched from DB + * @param req + * @param res json: TimeLeaderboard + */ + async (req, res) => { try { - const timeLeaderboardManager: TimeLeaderboardRepository = new TimeLeaderboardPgPromiseRepository; - const timeLeaderboard: TimeLeaderboard = await timeLeaderboardManager.getAll(); + const timeLeaderboardRepo: TimeLeaderboardRepository = new TimeLeaderboardPgPromiseRepository; + const timeLeaderboard: TimeLeaderboard = await timeLeaderboardRepo.getAll(); res.send(timeLeaderboard); } catch (error) { // handle errors diff --git a/backend/api/src/userRoute.ts b/backend/api/src/userRoute.ts index 638665e..e87056f 100644 --- a/backend/api/src/userRoute.ts +++ b/backend/api/src/userRoute.ts @@ -1,20 +1,32 @@ import express from "express"; -import { body, param, validationResult } from 'express-validator'; +import {body, param, validationResult} from 'express-validator'; 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"; +import {USERNAME_VALIDATION_REGEX, userWithIdExists, userWithNameDoesNotExists} from "./validators.js"; export const userRoute = express.Router() userRoute.use(express.json()) + userRoute.post( '/register', body('name') .isString() .isLength({min: 3, max: 32}) - .matches('[a-zA-Z0-9_.\\- ]*'), + .matches(USERNAME_VALIDATION_REGEX) + .custom(userWithNameDoesNotExists), + /** + * After processing the errors of express-validator, inserts the user into DB + * Returns the inserted user + * @param req + * body { + * name: string + * } + * @param res json: User + */ async (req, res) => { try { //region validate parameters @@ -24,14 +36,10 @@ userRoute.post( } //endregion const username: string = req.body.name; - const userManager: UserRepository = new UserPgPromiseRepository(); + const userRepo: UserRepository = new UserPgPromiseRepository(); - // check if username already exists - if (await userManager.withNameExists(username)) { - return res.status(400).json({ errors: [{msg: `User with name '${username}' already exists.`}] }) - } // insert & return user - const inserted: User = await userManager.insert({name: username}); + const inserted: User = await userRepo.insert({name: username}); res.json(inserted); } catch (error) { // handle errors @@ -42,8 +50,18 @@ userRoute.post( ) userRoute.get('/:userId/scores', - // TODO: With id exists --> cusotm validator - param('userId').isInt({min: 1}), + param('userId') + .isInt({min: 1}) + .custom(userWithIdExists), + /** + * After processing the errors of express-validator, fetches the scores from the DB + * Returns user scores + * @param req + * params { + * userId: number + * } + * @param res json: UserScores + */ async (req, res) => { //region validate parameters const errors = validationResult(req); @@ -53,16 +71,11 @@ userRoute.get('/:userId/scores', //endregion const userId: number = req.params.userId; - const userManager: UserRepository = new UserPgPromiseRepository; try { - // check if user with given id exists - if (!await userManager.withIdExists(userId)) { - return res.status(400).json({ errors: [{msg: `User with id ${userId} does not exist.`}] }) - } // get & return data - const userScoresManager: UserScoresRepository = new UserScoresPgPromiseRepository; - const userScores = await userScoresManager.getById(userId); + const userScoresRepo: UserScoresRepository = new UserScoresPgPromiseRepository; + const userScores = await userScoresRepo.getById(userId); res.json(userScores); } catch (error) { // handle errors diff --git a/backend/api/src/validators.ts b/backend/api/src/validators.ts new file mode 100644 index 0000000..4cff047 --- /dev/null +++ b/backend/api/src/validators.ts @@ -0,0 +1,36 @@ +import {CustomValidator} from "express-validator"; +import {UserRepository} from "./repositories/UserRepository.js"; +import {UserPgPromiseRepository} from "./repositories/pgPromise/UserPgPromiseRepository.js"; + +export const USERNAME_VALIDATION_REGEX: string = '[a-zA-Z0-9_.\\- ]*'; +export const TIME_VALIDATION_REGEX: string = '([0-5]\\d:)?[0-5]\\d:[0-5]\\d'; + +/** + * Custom express-validator to ensure that the user with given ID exists + * @param userId + */ +export 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); + } +} + +/** + * Custom express-validator to ensure that the user with given name does not exist yet + * @param username + */ +export const userWithNameDoesNotExists: CustomValidator = username => { + try { + const userRepo: UserRepository = new UserPgPromiseRepository; + return userRepo.withNameExists(username).then(exists => { + if (exists) return Promise.reject("User with given name already exists"); + }); + } catch (error) { + console.log(error); + } +} \ No newline at end of file diff --git a/frontend/game.ts b/frontend/game.ts index f0ef45a..3d679ad 100644 --- a/frontend/game.ts +++ b/frontend/game.ts @@ -19,6 +19,7 @@ function setup() { createCanvas(2000, 1000); obstacleOffset = width / 3; Obstacle.distanceBetweenPipes = height / 2.5 + Obstacle.startX = width; textSize(150); textFont("resources/PressStart2P-Regular.ttf"); diff --git a/frontend/model/Entity.ts b/frontend/model/Entity.ts index 745f71a..07d8c95 100644 --- a/frontend/model/Entity.ts +++ b/frontend/model/Entity.ts @@ -54,8 +54,14 @@ abstract class Entity { this._showHitbox = false; } + /** + * Updates the entity. + */ public abstract update(): void; + /** + * Draws the entity. + */ public draw(): void { push(); fill(this.fill); diff --git a/frontend/model/Obstacle.ts b/frontend/model/Obstacle.ts index 670b027..24a85b1 100644 --- a/frontend/model/Obstacle.ts +++ b/frontend/model/Obstacle.ts @@ -5,7 +5,11 @@ class Obstacle extends Entity implements Collidable { private readonly padding: number = 150; private readonly speed: number = 3; - private static startX: number; + private static _startX: number; + + static set startX(value: number) { + this._startX = value; + } static set distanceBetweenPipes(value: number) { this._distanceBetweenPipes = value; @@ -42,8 +46,8 @@ class Obstacle extends Entity implements Collidable { * Randomizes the height of the pipes */ public randomizeHeight(): void { - this.pipeTop.height = this.randomRange(this.padding, height - this.padding - Obstacle.distanceBetweenPipes); - this.pipeBottom.position.y = this.pipeTop.height + Obstacle.distanceBetweenPipes; + this.pipeTop.height = this.randomRange(this.padding, height - this.padding - Obstacle._distanceBetweenPipes); + this.pipeBottom.position.y = this.pipeTop.height + Obstacle._distanceBetweenPipes; this.pipeBottom.height = height - this.pipeTop.height - this.padding; } @@ -57,8 +61,9 @@ class Obstacle extends Entity implements Collidable { } public update(): void { - this.pipeTop.move(this.speed); - this.pipeBottom.move(this.speed); + // TODO: Put into pipe.update + this.pipeTop.position.x -= this.speed; + this.pipeBottom.position.x -= this.speed; this.position.x = this.pipeTop.position.x; }