diff --git a/api/Classes/Games.js b/api/Classes/Games.js index 79f81fa..52d8df1 100644 --- a/api/Classes/Games.js +++ b/api/Classes/Games.js @@ -7,6 +7,27 @@ class Game { this.questions = []; } + async get() { + try { + const [rows] = await pool.execute( + 'SELECT * FROM games WHERE id = ? AND player = ? LIMIT 1', [this.id, this.player], + ); + if (!rows.length) return false; + const [questions] = await pool.execute( + 'SELECT * FROM games_questions WHERE game = ?', [this.id], + ); + questions.forEach(q => { + const question = new Question(q.id, q.question); + this.questions.push(question); + }); + return true; + } + catch (error) { + console.error(error); + return false; + } + } + async create() { try { const [rows] = await pool.execute( @@ -62,6 +83,20 @@ class Question { return false; } } + + async verifyAnswer(answerId) { + try { + const [rows] = await pool.execute( + 'SELECT * FROM answers WHERE question = ? AND id = ? AND correct = 1', [this.id, answerId], + ); + if (!rows.length) return false; + return true; + } + catch (error) { + console.error(error); + return false; + } + } } class Answer { diff --git a/api/database.sql b/api/database.sql index f00b371..6c0ab08 100644 --- a/api/database.sql +++ b/api/database.sql @@ -17,4 +17,34 @@ CREATE TABLE users ( score INT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (id), INDEX ur_username_idx (username) +) ENGINE=InnoDB; + +CREATE TABLE games ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + player INT UNSIGNED NOT NULL, + PRIMARY KEY (id), + INDEX g_player_idx (player), +) ENGINE=InnoDB; + +CREATE TABLE themes ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + theme VARCHAR(255) NOT NULL, + PRIMARY KEY (id), +) ENGINE=InnoDB; + +CREATE TABLE questions ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + theme INT UNSIGNED NOT NULL, + question VARCHAR(255) NOT NULL, + PRIMARY KEY (id), + INDEX q_theme_idx (theme), +) ENGINE=InnoDB; + +CREATE TABLE answers ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + question INT UNSIGNED NOT NULL, + answer VARCHAR(255) NOT NULL, + correct BOOLEAN NOT NULL DEFAULT FALSE, + PRIMARY KEY (id), + INDEX a_question_idx (question), ) ENGINE=InnoDB; \ No newline at end of file diff --git a/api/routes/games.js b/api/routes/games.js new file mode 100644 index 0000000..1db9f16 --- /dev/null +++ b/api/routes/games.js @@ -0,0 +1,37 @@ +import express from 'express'; +import { verifyToken } from '../modules/token.js'; +import { respondWithStatusJSON } from '../modules/requestHandler.js'; +import { Game } from '../Classes/Games.js'; + +const router = express.Router(); + +router.post('/create/:theme', verifyToken, async (req, res) => { + const game = new Game(null, req.user.id); + await game.create(); + await game.generateQuestions(req.params.theme); + return await respondWithStatusJSON(res, 200, { + message: 'Successfully created game', + game, + }); +}); + +router.post('/verify/:game', verifyToken, async (req, res) => { + const { question, answer } = req.body; + const game = new Game(req.params.game, req.userId); + await game.get(); + + const foundQuestion = game.questions.find(q => q.id === question); + if (foundQuestion && foundQuestion.verifyAnswer(answer)) { + res.status(200).json({ + message: 'Answer is correct', + }); + } + else { + res.status(200).json({ + message: 'Answer is incorrect', + }); + } +}); + + +export default router; \ No newline at end of file diff --git a/api/routes/themes.js b/api/routes/themes.js new file mode 100644 index 0000000..76ce3a2 --- /dev/null +++ b/api/routes/themes.js @@ -0,0 +1,16 @@ +import express from 'express'; +import { verifyToken } from '../modules/token.js'; +import { respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler.js'; +import { pool } from '../modules/database.js'; + +const router = express.Router(); + +// send list of themes +router.post('/', verifyToken, async (req, res) => { + const [rows] = await pool.execute('SELECT * FROM themes'); + if (!rows.length) return await respondWithStatus(res, 404, 'There are no themes'); + return await respondWithStatusJSON(res, 200, { + message: 'Successfully retrieved themes', + themes: rows, + }); +}); \ No newline at end of file diff --git a/api/routes/users.js b/api/routes/users.js index adc23b6..4d32964 100644 --- a/api/routes/users.js +++ b/api/routes/users.js @@ -16,13 +16,10 @@ router.post('/register', requestLimiter, async (req, res) => { } const hashedPassword = await Bun.password.hash(password); - const [result] = await pool.execute( - 'INSERT INTO users (username, password) VALUES (?, ?)', [ username, hashedPassword ], - ); - if (result.affectedRows === 0) { - return await respondWithStatus(res, 500, 'Error storing user'); - } - return await respondWithStatus(res, 200, 'Successfully registered'); + const [result] = await pool.execute('INSERT INTO users (username, password) VALUES (?, ?)', [ username, hashedPassword ]); + if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error storing user'); + const token = await generateToken(result[0].insertId, password); + return await respondWithStatusJSON(res, 200, { message: 'Successfully registered', token }); } catch (error) { console.error(error); @@ -41,20 +38,12 @@ router.post('/login', requestLimiter, async (req, res) => { const [rows] = await pool.execute( 'SELECT * FROM users WHERE username = ? LIMIT 1', [username], ); - if (!rows.length) { - return await respondWithStatus(res, 404, 'Incorrect username or email'); - } + if (!rows.length) return await respondWithStatus(res, 404, 'Incorrect username or email'); const user = rows[0]; const passwordMatch = await Bun.password.verify(password, user.password); if (!passwordMatch) return await respondWithStatus(res, 401, 'Incorrect password'); const token = await generateToken(user.id, password); - res.cookie('token', token, { - expires: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000), - httpOnly: true, - secure: true, - sameSite: 'strict', - }); return await respondWithStatusJSON(res, 200, { message: 'Login successful', token: token,