From 163fccb9b26d52264e3e6a784f8b7f5bae719b89 Mon Sep 17 00:00:00 2001 From: Jonas Kappa Date: Thu, 1 Jan 2026 13:26:27 +0100 Subject: [PATCH] Added wall creation, deletion and fetching --- src/games.js | 337 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 327 insertions(+), 10 deletions(-) diff --git a/src/games.js b/src/games.js index 78ea626..2d3434d 100644 --- a/src/games.js +++ b/src/games.js @@ -4,7 +4,70 @@ import { checkStringProp } from './util.js'; /** * @type {Collection} */ -let games; +let cGames; +/** + * @type {Collection} + */ +let cWalls; +/** + * @type {Collection} + */ +let cCategories; +/** + * @type {Collection} + */ +let cQuestions; + +const QuestionType = { + SIMPLE: 'SIMPLE', + MULTIPLE_CHOICE: 'MULTIPLE_CHOICE', + IMAGE: 'IMAGE', + IMAGE_MULTIPLE_CHOICE: 'IMAGE_MULTIPLE_CHOICE', + AUDIO: 'AUDIO', + AUDIO_MULTIPLE_CHOICE: 'AUDIO_MULTIPLE_CHOICE', +}; + +/** + * + * @param {number} points + * @param {string} question + * @param {string} answer + * @param {ObjectId} owner + * @returns + */ +function createSimpleQuestion(points, question, answer, owner) { + return { + owner, + points, + type: QuestionType.SIMPLE, + data: createSimpleData(question, answer), + }; +} + +/** + * + * @param {string} question + * @param {string} answer + * @returns + */ +function createSimpleData(question, answer) { + return { + question, + answer, + }; +} + +/** + * + * @param {ObjectId[]} ids + */ +function splitQuestionIds(ids) { + let res = []; + for (let i = 0; i < ids.length; i += 5) { + res.push(ids.slice(i, i + 5)); + } + return res; +} /** * @@ -12,11 +75,19 @@ let games; * @param {Db} db */ export function initGames(app, db) { - games = db.collection('games'); + cGames = db.collection('games'); + cWalls = db.collection('walls'); + cCategories = db.collection('categories'); + cQuestions = db.collection('questions'); app.get('/game', fetchGame); app.post('/game', createGame); - app.delete('/game/:gameid', deleteGame); + app.delete('/game/:gameid', deleteGameRoute); app.get('/games', fetchGames); + + app.get('/wall', fetchWall); + app.get('/walls/:gameid', fetchWalls); + app.post('/wall', createWall); + app.delete('/wall/:wallid', deleteWallRoute); } /** @@ -32,7 +103,7 @@ async function createGame(req, res) { const name = req.body.name; - games + cGames .insertOne({ name, walls: [], @@ -53,7 +124,7 @@ async function createGame(req, res) { * @param {import('express').Response} res */ async function fetchGames(req, res) { - let list = games.find({ + let list = cGames.find({ owner: req.user._id, }); @@ -73,7 +144,7 @@ async function fetchGame(req, res) { const id = new ObjectId(req.query.id); - let game = await games.findOne({ + let game = await cGames.findOne({ _id: id, owner: req.user._id, }); @@ -90,8 +161,8 @@ async function fetchGame(req, res) { * @param {import('express').Request} req * @param {import('express').Response} res */ -async function deleteGame(req, res) { - let game = await games.findOne({ +async function deleteGameRoute(req, res) { + let game = await cGames.findOne({ owner: req.user._id, _id: new ObjectId(req.params.gameid), }); @@ -101,8 +172,7 @@ async function deleteGame(req, res) { return; } - games - .deleteOne({ _id: game._id }) + deleteGame(game._id) .then(() => { res.sendStatus(200); }) @@ -111,3 +181,250 @@ async function deleteGame(req, res) { res.sendStatus(500); }); } + +/** + * + * @param {import('express').Request} req + * @param {import('express').Response} res + */ +async function fetchWall(req, res) { + if (req.query.id === undefined || req.query.id.length <= 0) { + res.sendStatus(400); + return; + } + + const id = new ObjectId(req.query.id); + + let wall = await cWalls.findOne({ + _id: id, + owner: req.user._id, + }); + + if (wall) { + res.status(200).send(wall); + } else { + res.sendStatus(404); + } +} + +/** + * + * @param {import('express').Request} req + * @param {import('express').Response} res + */ +async function fetchWalls(req, res) { + let game = await cGames.findOne({ + owner: req.user._id, + _id: new ObjectId(req.params.gameid), + }); + + if (!game) { + res.sendStatus(404); + return; + } + + let fetchedWalls = cWalls.find({ + _id: { + $in: game.walls, + }, + }); + + res.status(200).send(await fetchedWalls.toArray()); +} + +/** + * + * @param {import('express').Request} req + * @param {import('express').Response} res + */ +async function createWall(req, res) { + if ( + !checkStringProp(req.body, 'gameid') && + !checkStringProp(req.body, 'name') + ) { + res.sendStatus(400); + return; + } + + /** + * @type {string} + */ + const gameid = req.body.gameid; + /** + * @type {string} + */ + const wallname = req.body.name; + + let game = await cGames.findOne({ + owner: req.user._id, + _id: new ObjectId(gameid), + }); + + if (!game) { + res.sendStatus(404); + return; + } + + let newQuestions = []; + + for (let id = 0; id < 25; id++) { + newQuestions.push( + createSimpleQuestion(-1, 'Frage', 'Antwort', req.user._id), + ); + } + + cQuestions + .insertMany(newQuestions) + .then((insertedQuestions) => { + let questionsIds = splitQuestionIds( + Object.values(insertedQuestions.insertedIds), + ); + let newCategories = []; + + for (let i = 1; i <= 5; i++) { + newCategories.push({ + name: `Kategorie ${i}`, + questions: questionsIds[i - 1], + owner: req.user._id, + }); + } + + return cCategories.insertMany(newCategories); + }) + .then((insertedCategories) => { + return cWalls.insertOne({ + name: wallname, + categories: Object.values(insertedCategories.insertedIds), + owner: req.user._id, + }); + }) + .then((insertedWall) => { + return cGames.updateOne( + { + _id: game._id, + }, + { + $push: { + walls: insertedWall.insertedId, + }, + }, + ); + }) + .then(() => { + res.sendStatus(200); + }) + .catch((err) => { + console.error(err); + res.sendStatus(500); + }); +} + +/** + * + * @param {import('express').Request} req + * @param {import('express').Response} res + */ +async function deleteWallRoute(req, res) { + let wall = await cWalls.findOne({ + _id: new ObjectId(req.params.wallid), + owner: req.user._id, + }); + + if (!wall) { + res.sendStatus(404); + return; + } + + let game = await cGames.findOne({ + owner: req.user._id, + walls: wall._id, + }); + + if (!game) { + res.sendStatus(404); + return; + } + + deleteWall(wall._id) + .then(() => { + return cGames.updateOne( + { + _id: game._id, + }, + { + $pull: { + walls: wall._id, + }, + }, + ); + }) + .then(() => { + res.sendStatus(200); + }) + .catch((err) => { + console.error(err); + res.sendStatus(500); + }); +} + +/** + * + * @param {ObjectId} _id + */ +function deleteGame(_id) { + return cGames + .findOne({ _id }) + .then((game) => { + let wallDeletions = []; + for (const wallId of game.walls) { + wallDeletions.push(deleteWall(wallId)); + } + + return Promise.all(wallDeletions); + }) + .then(() => { + return cGames.deleteOne({ _id }); + }); +} + +/** + * + * @param {ObjectId} _id + */ +function deleteWall(_id) { + return cWalls + .findOne({ _id }) + .then((wall) => { + let categoryDeletions = []; + for (const catId of wall.categories) { + categoryDeletions.push(deleteCategory(catId)); + } + return Promise.all(categoryDeletions); + }) + .then(() => { + return cWalls.deleteOne({ _id: _id }); + }); +} + +/** + * + * @param {ObjectId} _id + */ +function deleteCategory(_id) { + return cCategories + .findOne({ + _id, + }) + .then((category) => { + return cQuestions.deleteMany({ + _id: { + $in: category.questions, + }, + }); + }) + .then(() => { + return cCategories.deleteOne({ + _id, + }); + }); +}