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