diff --git a/client/src/pages/Student/JoinRoom/JoinRoom.tsx b/client/src/pages/Student/JoinRoom/JoinRoom.tsx index f0ac8d7..f6a4343 100644 --- a/client/src/pages/Student/JoinRoom/JoinRoom.tsx +++ b/client/src/pages/Student/JoinRoom/JoinRoom.tsx @@ -53,7 +53,7 @@ const JoinRoom: React.FC = () => { setQuestions(questions); setQuestion(questions[0]); }); - socket.on('end-quiz', () => { + socket.on('end-questionnaire', () => { disconnect(); }); socket.on('join-failure', (message) => { diff --git a/client/src/services/WebsocketService.tsx b/client/src/services/WebsocketService.tsx index 87cb188..8ee4b9c 100644 --- a/client/src/services/WebsocketService.tsx +++ b/client/src/services/WebsocketService.tsx @@ -66,7 +66,7 @@ class WebSocketService { endQuiz(roomName: string) { if (this.socket) { - this.socket.emit('end-quiz', { roomName }); + this.socket.emit('end-questionnaire', { roomName }); } } diff --git a/server/app.js b/server/app.js index 570ee8b..f8b261e 100644 --- a/server/app.js +++ b/server/app.js @@ -10,10 +10,10 @@ const { Server } = require("socket.io"); // instantiate the db const db = require('./config/db.js'); // instantiate the models -const quiz = require('./models/quiz.js'); -const quizModel = new quiz(db); +const questionnaires = require('./models/questionnaires.js'); +const questionnaireModel = new questionnaires(db); const folders = require('./models/folders.js'); -const foldersModel = new folders(db, quizModel); +const foldersModel = new folders(db, questionnaireModel); const users = require('./models/users.js'); const userModel = new users(db, foldersModel); const images = require('./models/images.js'); @@ -24,21 +24,21 @@ const usersController = require('./controllers/users.js'); const usersControllerInstance = new usersController(userModel); const foldersController = require('./controllers/folders.js'); const foldersControllerInstance = new foldersController(foldersModel); -const quizController = require('./controllers/quiz.js'); -const quizControllerInstance = new quizController(quizModel, foldersModel); +const questionnaireController = require('./controllers/questionnaire.js'); +const questionnaireControllerInstance = new questionnaireController(questionnaireModel, foldersModel); const imagesController = require('./controllers/images.js'); const imagesControllerInstance = new imagesController(imageModel); // export the controllers module.exports.users = usersControllerInstance; module.exports.folders = foldersControllerInstance; -module.exports.quizzes = quizControllerInstance; +module.exports.questionnaires = questionnaireControllerInstance; module.exports.images = imagesControllerInstance; //import routers (instantiate controllers as side effect) const userRouter = require('./routers/users.js'); const folderRouter = require('./routers/folders.js'); -const quizRouter = require('./routers/quiz.js'); +const questionnaireRouter = require('./routers/questionnaires.js'); const imagesRouter = require('./routers/images.js'); // Setup environment @@ -82,7 +82,7 @@ app.use(bodyParser.json()); // Create routes app.use('/api/user', userRouter); app.use('/api/folder', folderRouter); -app.use('/api/quiz', quizRouter); +app.use('/api/questionnaire', questionnaireRouter); app.use('/api/image', imagesRouter); app.use(errorHandler); diff --git a/server/config/email.js b/server/config/email.js index e31c5f3..9c18013 100644 --- a/server/config/email.js +++ b/server/config/email.js @@ -35,12 +35,12 @@ class Emailer { }); } - quizShare(email, link) { + questionnaireShare(email, link) { this.transporter.sendMail({ from: this.senderEmail, to: email, - subject: 'Un quiz vous a été transféré !', - text: 'Veuillez suivre ce lien pour ajouter ce quiz à votre compte. '+ link + subject: 'Un questionnaire vous a été transféré !', + text: 'Veuillez suivre ce lien pour ajouter ce questionnaire à votre compte. '+ link }); } diff --git a/server/constants/errorCodes.js b/server/constants/errorCodes.js index 41147ae..5fc6f37 100644 --- a/server/constants/errorCodes.js +++ b/server/constants/errorCodes.js @@ -38,36 +38,36 @@ exports.IMAGE_NOT_FOUND = { code: 404 } -exports.QUIZ_NOT_FOUND = { - message: 'Aucun quiz portant cet identifiant n\'a été trouvé.', +exports.QUESTIONNAIRE_NOT_FOUND = { + message: 'Aucun questionnaire portant cet identifiant n\'a été trouvé.', code: 404 } -exports.QUIZ_ALREADY_EXISTS = { - message: 'Le quiz existe déjà.', +exports.QUESTIONNAIRE_ALREADY_EXISTS = { + message: 'Le questionnaire existe déjà.', code: 400 } -exports.UPDATE_QUIZ_ERROR = { - message: 'Une erreur s\'est produite lors de la mise à jour du quiz.', +exports.UPDATE_QUESTIONNAIRE_ERROR = { + message: 'Une erreur s\'est produite lors de la mise à jour du questionnaire.', code: 400 } -exports.DELETE_QUIZ_ERROR = { - message: 'Une erreur s\'est produite lors de la suppression du quiz.', +exports.DELETE_QUESTIONNAIRE_ERROR = { + message: 'Une erreur s\'est produite lors de la suppression du questionnaire.', code: 400 } -exports.GETTING_QUIZ_ERROR = { - message: 'Une erreur s\'est produite lors de la récupération du quiz.', +exports.GETTING_QUESTIONNAIRE_ERROR = { + message: 'Une erreur s\'est produite lors de la récupération du questionnaire.', code: 400 } -exports.MOVING_QUIZ_ERROR = { - message: 'Une erreur s\'est produite lors du déplacement du quiz.', +exports.MOVING_QUESTIONNAIRE_ERROR = { + message: 'Une erreur s\'est produite lors du déplacement du questionnaire.', code: 400 } -exports.DUPLICATE_QUIZ_ERROR = { - message: 'Une erreur s\'est produite lors de la duplication du quiz.', +exports.DUPLICATE_QUESTIONNAIRE_ERROR = { + message: 'Une erreur s\'est produite lors de la duplication du questionnaire.', code: 400 } -exports.COPY_QUIZ_ERROR = { - message: 'Une erreur s\'est produite lors de la copie du quiz.', +exports.COPY_QUESTIONNAIRE_ERROR = { + message: 'Une erreur s\'est produite lors de la copie du questionnaire.', code: 400 } diff --git a/server/controllers/questionnaires.js b/server/controllers/questionnaires.js new file mode 100644 index 0000000..3473f4e --- /dev/null +++ b/server/controllers/questionnaires.js @@ -0,0 +1,317 @@ +const emailer = require('../config/email.js'); + +const AppError = require('../middleware/AppError.js'); +const { MISSING_REQUIRED_PARAMETER, NOT_IMPLEMENTED, QUESTIONNAIRE_NOT_FOUND, FOLDER_NOT_FOUND, QUESTIONNAIRE_ALREADY_EXISTS, GETTING_QUESTIONNAIRE_ERROR, DELETE_QUESTIONNAIRE_ERROR, UPDATE_QUESTIONNAIRE_ERROR, MOVING_QUESTIONNAIRE_ERROR } = require('../constants/errorCodes.js'); + +class QuestionnaireController { + + constructor(questionnaireModel, foldersModel) { + this.questionnaires = questionnaireModel; + this.folders = foldersModel; + } + + create = async (req, res, next) => { + try { + const { title, content, folderId } = req.body; + + if (!title || !content || !folderId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + // Is this folder mine + const owner = await this.folders.getOwner(folderId); + + if (owner != req.user.userId) { + throw new AppError(FOLDER_NOT_FOUND); + } + + const result = await this.questionnaires.create(title, content, folderId, req.user.userId); + + if (!result) { + throw new AppError(QUESTIONNAIRE_ALREADY_EXISTS); + } + + return res.status(200).json({ + message: 'Questionnaire créé avec succès.' + }); + + } catch (error) { + return next(error); + } + }; + + get = async (req, res, next) => { + try { + const { questionnaireId: questionnaireId } = req.params; + + if (!questionnaireId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + const content = await this.questionnaires.getContent(questionnaireId); + + if (!content) { + throw new AppError(GETTING_QUESTIONNAIRE_ERROR); + } + + // Is this questionnaire mine + if (content.userId != req.user.userId) { + throw new AppError(QUESTIONNAIRE_NOT_FOUND); + } + + return res.status(200).json({ + data: content + }); + + } catch (error) { + return next(error); + } + }; + + delete = async (req, res, next) => { + try { + const { questionnaireId: questionnaireId } = req.params; + + if (!questionnaireId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + // Is this questionnaire mine + const owner = await this.questionnaires.getOwner(questionnaireId); + + if (owner != req.user.userId) { + throw new AppError(QUESTIONNAIRE_NOT_FOUND); + } + + const result = await this.questionnaires.delete(questionnaireId); + + if (!result) { + throw new AppError(DELETE_QUESTIONNAIRE_ERROR); + } + + return res.status(200).json({ + message: 'Questionnaire supprimé avec succès.' + }); + + } catch (error) { + return next(error); + } + }; + + update = async (req, res, next) => { + try { + const { questionnaireId: questionnaireId, newTitle, newContent } = req.body; + + if (!newTitle || !newContent || !questionnaireId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + // Is this questionnaire mine + const owner = await this.questionnaires.getOwner(questionnaireId); + + if (owner != req.user.userId) { + throw new AppError(QUESTIONNAIRE_NOT_FOUND); + } + + const result = await this.questionnaires.update(questionnaireId, newTitle, newContent); + + if (!result) { + throw new AppError(UPDATE_QUESTIONNAIRE_ERROR); + } + + return res.status(200).json({ + message: 'Questionnaire mis à jours avec succès.' + }); + + } catch (error) { + return next(error); + } + }; + + move = async (req, res, next) => { + try { + const { questionnaireId: questionnaireId, newFolderId } = req.body; + + if (!questionnaireId || !newFolderId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + // Is this questionnaire mine + const questionnaireOwner = await this.questionnaires.getOwner(questionnaireId); + + if (questionnaireOwner != req.user.userId) { + throw new AppError(QUESTIONNAIRE_NOT_FOUND); + } + + // Is this folder mine + const folderOwner = await this.folders.getOwner(newFolderId); + + if (folderOwner != req.user.userId) { + throw new AppError(FOLDER_NOT_FOUND); + } + + const result = await this.questionnaires.move(questionnaireId, newFolderId); + + if (!result) { + throw new AppError(MOVING_QUESTIONNAIRE_ERROR); + } + + return res.status(200).json({ + message: 'Utilisateur déplacé avec succès.' + }); + + } catch (error) { + return next(error); + } + }; + + copy = async (req, _res, _next) => { + const { questionnaireId, newTitle, folderId } = req.body; + + if (!questionnaireId || !newTitle || !folderId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + throw new AppError(NOT_IMPLEMENTED); + // const { questionnaireId } = req.params; + // const { newUserId } = req.body; + + // try { + // //Trouver le questionnaire a dupliquer + // const conn = db.getConnection(); + // const questionnaireToDuplicate = await conn.collection('questionnaire').findOne({ _id: ObjectId.createFromHexString(questionnaireId) }); + // if (!questionnaireToDuplicate) { + // throw new Error("Questionnaire non trouvé"); + // } + // console.log(questionnaireToDuplicate); + // //Suppression du id du questionnaire pour ne pas le répliquer + // delete questionnaireToDuplicate._id; + // //Ajout du duplicata + // await conn.collection('questionnaire').insertOne({ ...questionnaireToDuplicate, userId: ObjectId.createFromHexString(newUserId) }); + // res.json(Response.ok("Dossier dupliqué avec succès pour un autre utilisateur")); + + // } catch (error) { + // if (error.message.startsWith("Questionnaire non trouvé")) { + // return res.status(404).json(Response.badRequest(error.message)); + // } + // res.status(500).json(Response.serverError(error.message)); + // } + }; + + removeQuestionnairesByFolderId = async (req, res, next) => { + try { + const { folderId } = req.body; + + if (!folderId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + // Call the method from the Questionnaire model to delete questionnaires by folder ID + await this.questionnaires.deleteQuestionnairesByFolderId(folderId); + + return res.status(200).json({ + message: 'Questionnaires deleted successfully.' + }); + } catch (error) { + return next(error); + } + }; + + duplicate = async (req, res, next) => { + const { questionnaireId } = req.body; + + try { + const newQuestionnaireId = await this.questionnaires.duplicate(questionnaireId, req.user.userId); + res.status(200).json({ success: true, newQuestionnaireId }); + } catch (error) { + return next(error); + } + }; + + questionnaireExists = async (title, userId) => { + try { + const existingFile = await this.questionnaires.questionnaireExists(title, userId); + return existingFile !== null; + } catch (_error) { + throw new AppError(GETTING_QUESTIONNAIRE_ERROR); + } + }; + + share = async (req, res, next) => { + try { + const { questionnaireId, email } = req.body; + + if (!questionnaireId || !email) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + const link = `${process.env.FRONTEND_URL}/teacher/Share/${questionnaireId}`; + + emailer.questionnaireShare(email, link); + + return res.status(200).json({ + message: 'Questionnaire partagé avec succès.' + }); + + } catch (error) { + return next(error); + } + }; + + getShare = async (req, res, next) => { + try { + const { questionnaireId } = req.params; + + if (!questionnaireId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + const content = await this.questionnaires.getContent(questionnaireId); + + if (!content) { + throw new AppError(GETTING_QUESTIONNAIRE_ERROR); + } + + return res.status(200).json({ + data: content.title + }); + + } catch (error) { + return next(error); + } + }; + + receiveShare = async (req, res, next) => { + try { + const { questionnaireId, folderId } = req.body; + + if (!questionnaireId || !folderId) { + throw new AppError(MISSING_REQUIRED_PARAMETER); + } + + const folderOwner = await this.folders.getOwner(folderId); + if (folderOwner != req.user.userId) { + throw new AppError(FOLDER_NOT_FOUND); + } + + const content = await this.questionnaires.getContent(questionnaireId); + if (!content) { + throw new AppError(GETTING_QUESTIONNAIRE_ERROR); + } + + const result = await this.questionnaires.create(content.title, content.content, folderId, req.user.userId); + if (!result) { + throw new AppError(QUESTIONNAIRE_ALREADY_EXISTS); + } + + return res.status(200).json({ + message: 'Questionnaire partagé reçu.' + }); + } catch (error) { + return next(error); + } + }; + +} + +module.exports = QuestionnaireController; diff --git a/server/controllers/quiz.js b/server/controllers/quiz.js deleted file mode 100644 index 77f7953..0000000 --- a/server/controllers/quiz.js +++ /dev/null @@ -1,317 +0,0 @@ -const emailer = require('../config/email.js'); - -const AppError = require('../middleware/AppError.js'); -const { MISSING_REQUIRED_PARAMETER, NOT_IMPLEMENTED, QUIZ_NOT_FOUND, FOLDER_NOT_FOUND, QUIZ_ALREADY_EXISTS, GETTING_QUIZ_ERROR, DELETE_QUIZ_ERROR, UPDATE_QUIZ_ERROR, MOVING_QUIZ_ERROR } = require('../constants/errorCodes'); - -class QuizController { - - constructor(quizModel, foldersModel) { - this.quizzes = quizModel; - this.folders = foldersModel; - } - - create = async (req, res, next) => { - try { - const { title, content, folderId } = req.body; - - if (!title || !content || !folderId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - // Is this folder mine - const owner = await this.folders.getOwner(folderId); - - if (owner != req.user.userId) { - throw new AppError(FOLDER_NOT_FOUND); - } - - const result = await this.quizzes.create(title, content, folderId, req.user.userId); - - if (!result) { - throw new AppError(QUIZ_ALREADY_EXISTS); - } - - return res.status(200).json({ - message: 'Quiz créé avec succès.' - }); - - } catch (error) { - return next(error); - } - }; - - get = async (req, res, next) => { - try { - const { quizId } = req.params; - - if (!quizId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - const content = await this.quizzes.getContent(quizId); - - if (!content) { - throw new AppError(GETTING_QUIZ_ERROR); - } - - // Is this quiz mine - if (content.userId != req.user.userId) { - throw new AppError(QUIZ_NOT_FOUND); - } - - return res.status(200).json({ - data: content - }); - - } catch (error) { - return next(error); - } - }; - - delete = async (req, res, next) => { - try { - const { quizId } = req.params; - - if (!quizId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - // Is this quiz mine - const owner = await this.quizzes.getOwner(quizId); - - if (owner != req.user.userId) { - throw new AppError(QUIZ_NOT_FOUND); - } - - const result = await this.quizzes.delete(quizId); - - if (!result) { - throw new AppError(DELETE_QUIZ_ERROR); - } - - return res.status(200).json({ - message: 'Quiz supprimé avec succès.' - }); - - } catch (error) { - return next(error); - } - }; - - update = async (req, res, next) => { - try { - const { quizId, newTitle, newContent } = req.body; - - if (!newTitle || !newContent || !quizId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - // Is this quiz mine - const owner = await this.quizzes.getOwner(quizId); - - if (owner != req.user.userId) { - throw new AppError(QUIZ_NOT_FOUND); - } - - const result = await this.quizzes.update(quizId, newTitle, newContent); - - if (!result) { - throw new AppError(UPDATE_QUIZ_ERROR); - } - - return res.status(200).json({ - message: 'Quiz mis à jours avec succès.' - }); - - } catch (error) { - return next(error); - } - }; - - move = async (req, res, next) => { - try { - const { quizId, newFolderId } = req.body; - - if (!quizId || !newFolderId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - // Is this quiz mine - const quizOwner = await this.quizzes.getOwner(quizId); - - if (quizOwner != req.user.userId) { - throw new AppError(QUIZ_NOT_FOUND); - } - - // Is this folder mine - const folderOwner = await this.folders.getOwner(newFolderId); - - if (folderOwner != req.user.userId) { - throw new AppError(FOLDER_NOT_FOUND); - } - - const result = await this.quizzes.move(quizId, newFolderId); - - if (!result) { - throw new AppError(MOVING_QUIZ_ERROR); - } - - return res.status(200).json({ - message: 'Utilisateur déplacé avec succès.' - }); - - } catch (error) { - return next(error); - } - }; - - copy = async (req, _res, _next) => { - const { quizId, newTitle, folderId } = req.body; - - if (!quizId || !newTitle || !folderId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - throw new AppError(NOT_IMPLEMENTED); - // const { quizId } = req.params; - // const { newUserId } = req.body; - - // try { - // //Trouver le quiz a dupliquer - // const conn = db.getConnection(); - // const quiztoduplicate = await conn.collection('quiz').findOne({ _id: ObjectId.createFromHexString(quizId) }); - // if (!quiztoduplicate) { - // throw new Error("Quiz non trouvé"); - // } - // console.log(quiztoduplicate); - // //Suppression du id du quiz pour ne pas le répliquer - // delete quiztoduplicate._id; - // //Ajout du duplicata - // await conn.collection('quiz').insertOne({ ...quiztoduplicate, userId: ObjectId.createFromHexString(newUserId) }); - // res.json(Response.ok("Dossier dupliqué avec succès pour un autre utilisateur")); - - // } catch (error) { - // if (error.message.startsWith("Quiz non trouvé")) { - // return res.status(404).json(Response.badRequest(error.message)); - // } - // res.status(500).json(Response.serverError(error.message)); - // } - }; - - deleteQuizzesByFolderId = async (req, res, next) => { - try { - const { folderId } = req.body; - - if (!folderId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - // Call the method from the Quiz model to delete quizzes by folder ID - await this.quizzes.deleteQuizzesByFolderId(folderId); - - return res.status(200).json({ - message: 'Quizzes deleted successfully.' - }); - } catch (error) { - return next(error); - } - }; - - duplicate = async (req, res, next) => { - const { quizId } = req.body; - - try { - const newQuizId = await this.quizzes.duplicate(quizId, req.user.userId); - res.status(200).json({ success: true, newQuizId }); - } catch (error) { - return next(error); - } - }; - - quizExists = async (title, userId) => { - try { - const existingFile = await this.quizzes.quizExists(title, userId); - return existingFile !== null; - } catch (_error) { - throw new AppError(GETTING_QUIZ_ERROR); - } - }; - - share = async (req, res, next) => { - try { - const { quizId, email } = req.body; - - if (!quizId || !email) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - const link = `${process.env.FRONTEND_URL}/teacher/Share/${quizId}`; - - emailer.quizShare(email, link); - - return res.status(200).json({ - message: 'Quiz partagé avec succès.' - }); - - } catch (error) { - return next(error); - } - }; - - getShare = async (req, res, next) => { - try { - const { quizId } = req.params; - - if (!quizId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - const content = await this.quizzes.getContent(quizId); - - if (!content) { - throw new AppError(GETTING_QUIZ_ERROR); - } - - return res.status(200).json({ - data: content.title - }); - - } catch (error) { - return next(error); - } - }; - - receiveShare = async (req, res, next) => { - try { - const { quizId, folderId } = req.body; - - if (!quizId || !folderId) { - throw new AppError(MISSING_REQUIRED_PARAMETER); - } - - const folderOwner = await this.folders.getOwner(folderId); - if (folderOwner != req.user.userId) { - throw new AppError(FOLDER_NOT_FOUND); - } - - const content = await this.quizzes.getContent(quizId); - if (!content) { - throw new AppError(GETTING_QUIZ_ERROR); - } - - const result = await this.quizzes.create(content.title, content.content, folderId, req.user.userId); - if (!result) { - throw new AppError(QUIZ_ALREADY_EXISTS); - } - - return res.status(200).json({ - message: 'Quiz partagé reçu.' - }); - } catch (error) { - return next(error); - } - }; - -} - -module.exports = QuizController; diff --git a/server/models/folders.js b/server/models/folders.js index 7a5fb30..f64dfd7 100644 --- a/server/models/folders.js +++ b/server/models/folders.js @@ -3,9 +3,9 @@ const ObjectId = require('mongodb').ObjectId; const { generateUniqueTitle } = require('./utils'); class Folders { - constructor(db, quizModel) { + constructor(db, questionnaireModel) { this.db = db; - this.quizModel = quizModel; + this.questionnaireModel = questionnaireModel; } async create(title, userId) { @@ -58,7 +58,7 @@ class Folders { return folder.userId; } - // finds all quizzes in a folder + // finds all questionnaires in a folder async getContent(folderId) { await this.db.connect() const conn = this.db.getConnection(); @@ -79,7 +79,7 @@ class Folders { const folderResult = await foldersCollection.deleteOne({ _id: ObjectId.createFromHexString(folderId) }); if (folderResult.deletedCount != 1) return false; - await this.quizModel.deleteQuizzesByFolderId(folderId); + await this.questionnaireModel.deleteQuestionnairesByFolderId(folderId); return true; } @@ -124,14 +124,14 @@ class Folders { throw new Error('Failed to create duplicate folder'); } - // copy the quizzes from source folder to destination folder + // copy the questionnaires from source folder to destination folder const content = await this.getContent(folderId); // console.log("folders.duplicate: found content", content); - for (const quiz of content) { - // console.log("folders.duplicate: creating quiz (copy)", quiz); - const result = await this.quizModel.create(quiz.title, quiz.content, newFolderId.toString(), userId); + for (const questionnaire of content) { + // console.log("folders.duplicate: creating questionnaire (copy)", questionnaire); + const result = await this.questionnaireModel.create(questionnaire.title, questionnaire.content, newFolderId.toString(), userId); if (!result) { - throw new Error('Failed to create duplicate quiz'); + throw new Error('Failed to create duplicate questionnaire'); } } @@ -155,8 +155,8 @@ class Folders { if (!newFolderId) { throw new Error('Failed to create a new folder.'); } - for (const quiz of sourceFolder.content) { - await this.quizModel.create(quiz.title, quiz.content, newFolderId, userId); + for (const questionnaire of sourceFolder.content) { + await this.questionnaireModel.create(questionnaire.title, questionnaire.content, newFolderId, userId); } return newFolderId; diff --git a/server/models/questionnaires.js b/server/models/questionnaires.js new file mode 100644 index 0000000..eabfe68 --- /dev/null +++ b/server/models/questionnaires.js @@ -0,0 +1,155 @@ +const { ObjectId } = require('mongodb'); +const { generateUniqueTitle } = require('./utils'); + +class Questionnaire { + + constructor(db) { + // console.log("Questionnaire constructor: db", db) + this.db = db; + } + + async create(title, content, folderId, userId) { + // console.log(`questionnaires: create title: ${title}, folderId: ${folderId}, userId: ${userId}`); + await this.db.connect() + const conn = this.db.getConnection(); + + const questionnaireCollection = conn.collection('files'); + + const existingQuestionnaire = await questionnaireCollection.findOne({ title: title, folderId: folderId, userId: userId }) + + if (existingQuestionnaire) { + throw new Error(`Questionnaire already exists with title: ${title}, folderId: ${folderId}, userId: ${userId}`); + } + + const newQuestionnaire = { + folderId: folderId, + userId: userId, + title: title, + content: content, + created_at: new Date(), + updated_at: new Date() + } + + const result = await questionnaireCollection.insertOne(newQuestionnaire); + // console.log("questionnaires: create insertOne result", result); + + return result.insertedId; + } + + async getOwner(questionnaireId) { + await this.db.connect() + const conn = this.db.getConnection(); + + const questionnaireCollection = conn.collection('files'); + + const questionnaire = await questionnaireCollection.findOne({ _id: ObjectId.createFromHexString(questionnaireId) }); + + return questionnaire.userId; + } + + async getContent(questionnaireId) { + await this.db.connect() + const conn = this.db.getConnection(); + + const questionnaireCollection = conn.collection('files'); + + const questionnaire = await questionnaireCollection.findOne({ _id: ObjectId.createFromHexString(questionnaireId) }); + + return questionnaire; + } + + async delete(questionnaireId) { + await this.db.connect() + const conn = this.db.getConnection(); + + const questionnaireCollection = conn.collection('files'); + + const result = await questionnaireCollection.deleteOne({ _id: ObjectId.createFromHexString(questionnaireId) }); + + if (result.deletedCount != 1) return false; + + return true; + } + async deleteQuestionnairesByFolderId(folderId) { + await this.db.connect(); + const conn = this.db.getConnection(); + + const questionnairesCollection = conn.collection('files'); + + // Delete all questionnaires with the specified folderId + const result = await questionnairesCollection.deleteMany({ folderId: folderId }); + return result.deletedCount > 0; + } + + async update(questionnaireId, newTitle, newContent) { + await this.db.connect() + const conn = this.db.getConnection(); + + const questionnaireCollection = conn.collection('files'); + + const result = await questionnaireCollection.updateOne( + { _id: ObjectId.createFromHexString(questionnaireId) }, + { + $set: { + title: newTitle, + content: newContent, + updated_at: new Date() + } + } + ); + + return result.modifiedCount === 1; + } + + async move(questionnaireId, newFolderId) { + await this.db.connect() + const conn = this.db.getConnection(); + + const questionnaireCollection = conn.collection('files'); + + const result = await questionnaireCollection.updateOne( + { _id: ObjectId.createFromHexString(questionnaireId) }, + { $set: { folderId: newFolderId } } + ); + + if (result.modifiedCount != 1) return false; + + return true + } + + async duplicate(questionnaireId, userId) { + const conn = this.db.getConnection(); + const questionnaireCollection = conn.collection('files'); + + const sourceQuestionnaire = await questionnaireCollection.findOne({ _id: ObjectId.createFromHexString(questionnaireId), userId: userId }); + if (!sourceQuestionnaire) { + throw new Error('Questionnaire not found for questionnaireId: ' + questionnaireId); + } + + // Use the utility function to generate a unique title + const newQuestionnaireTitle = await generateUniqueTitle(sourceQuestionnaire.title, async (title) => { + return await questionnaireCollection.findOne({ title: title, folderId: sourceQuestionnaire.folderId, userId: userId }); + }); + + const newQuestionnaireId = await this.create(newQuestionnaireTitle, sourceQuestionnaire.content, sourceQuestionnaire.folderId, userId); + + if (!newQuestionnaireId) { + throw new Error('Failed to create duplicate questionnaire'); + } + + return newQuestionnaireId; + } + + async questionnaireExists(title, userId) { + await this.db.connect(); + const conn = this.db.getConnection(); + + const filesCollection = conn.collection('files'); + const existingFolder = await filesCollection.findOne({ title: title, userId: userId }); + + return existingFolder !== null; + } + +} + +module.exports = Questionnaire; diff --git a/server/models/quiz.js b/server/models/quiz.js deleted file mode 100644 index b388659..0000000 --- a/server/models/quiz.js +++ /dev/null @@ -1,155 +0,0 @@ -const { ObjectId } = require('mongodb'); -const { generateUniqueTitle } = require('./utils'); - -class Quiz { - - constructor(db) { - // console.log("Quiz constructor: db", db) - this.db = db; - } - - async create(title, content, folderId, userId) { - // console.log(`quizzes: create title: ${title}, folderId: ${folderId}, userId: ${userId}`); - await this.db.connect() - const conn = this.db.getConnection(); - - const quizCollection = conn.collection('files'); - - const existingQuiz = await quizCollection.findOne({ title: title, folderId: folderId, userId: userId }) - - if (existingQuiz) { - throw new Error(`Quiz already exists with title: ${title}, folderId: ${folderId}, userId: ${userId}`); - } - - const newQuiz = { - folderId: folderId, - userId: userId, - title: title, - content: content, - created_at: new Date(), - updated_at: new Date() - } - - const result = await quizCollection.insertOne(newQuiz); - // console.log("quizzes: create insertOne result", result); - - return result.insertedId; - } - - async getOwner(quizId) { - await this.db.connect() - const conn = this.db.getConnection(); - - const quizCollection = conn.collection('files'); - - const quiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId) }); - - return quiz.userId; - } - - async getContent(quizId) { - await this.db.connect() - const conn = this.db.getConnection(); - - const quizCollection = conn.collection('files'); - - const quiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId) }); - - return quiz; - } - - async delete(quizId) { - await this.db.connect() - const conn = this.db.getConnection(); - - const quizCollection = conn.collection('files'); - - const result = await quizCollection.deleteOne({ _id: ObjectId.createFromHexString(quizId) }); - - if (result.deletedCount != 1) return false; - - return true; - } - async deleteQuizzesByFolderId(folderId) { - await this.db.connect(); - const conn = this.db.getConnection(); - - const quizzesCollection = conn.collection('files'); - - // Delete all quizzes with the specified folderId - const result = await quizzesCollection.deleteMany({ folderId: folderId }); - return result.deletedCount > 0; - } - - async update(quizId, newTitle, newContent) { - await this.db.connect() - const conn = this.db.getConnection(); - - const quizCollection = conn.collection('files'); - - const result = await quizCollection.updateOne( - { _id: ObjectId.createFromHexString(quizId) }, - { - $set: { - title: newTitle, - content: newContent, - updated_at: new Date() - } - } - ); - - return result.modifiedCount === 1; - } - - async move(quizId, newFolderId) { - await this.db.connect() - const conn = this.db.getConnection(); - - const quizCollection = conn.collection('files'); - - const result = await quizCollection.updateOne( - { _id: ObjectId.createFromHexString(quizId) }, - { $set: { folderId: newFolderId } } - ); - - if (result.modifiedCount != 1) return false; - - return true - } - - async duplicate(quizId, userId) { - const conn = this.db.getConnection(); - const quizCollection = conn.collection('files'); - - const sourceQuiz = await quizCollection.findOne({ _id: ObjectId.createFromHexString(quizId), userId: userId }); - if (!sourceQuiz) { - throw new Error('Quiz not found for quizId: ' + quizId); - } - - // Use the utility function to generate a unique title - const newQuizTitle = await generateUniqueTitle(sourceQuiz.title, async (title) => { - return await quizCollection.findOne({ title: title, folderId: sourceQuiz.folderId, userId: userId }); - }); - - const newQuizId = await this.create(newQuizTitle, sourceQuiz.content, sourceQuiz.folderId, userId); - - if (!newQuizId) { - throw new Error('Failed to create duplicate quiz'); - } - - return newQuizId; - } - - async quizExists(title, userId) { - await this.db.connect(); - const conn = this.db.getConnection(); - - const filesCollection = conn.collection('files'); - const existingFolder = await filesCollection.findOne({ title: title, userId: userId }); - - return existingFolder !== null; - } - -} - -module.exports = Quiz; diff --git a/server/routers/questionnaires.js b/server/routers/questionnaires.js new file mode 100644 index 0000000..7cb617f --- /dev/null +++ b/server/routers/questionnaires.js @@ -0,0 +1,23 @@ +const express = require('express'); +const router = express.Router(); +const questionnaires = require('../app.js').questionnaires; +const jwt = require('../middleware/jwtToken.js'); +const asyncHandler = require('./routerUtils.js'); + +if (!questionnaires) { + console.error("questionnaires is not defined"); +} + +router.post("/create", jwt.authenticate, asyncHandler(questionnaires.create)); +router.get("/get/:questionnaireId", jwt.authenticate, asyncHandler(asyncHandler(questionnaires.get))); +router.delete("/delete/:questionnaireId", jwt.authenticate, asyncHandler(questionnaires.delete)); +router.put("/update", jwt.authenticate, asyncHandler(questionnaires.update)); +router.put("/move", jwt.authenticate, asyncHandler(questionnaires.move)); + +router.post("/duplicate", jwt.authenticate, asyncHandler(questionnaires.duplicate)); +router.post("/copy/:questionnaireId", jwt.authenticate, asyncHandler(questionnaires.copy)); +router.put("/Share", jwt.authenticate, asyncHandler(questionnaires.share)); +router.get("/getShare/:questionnaireId", jwt.authenticate, asyncHandler(questionnaires.getShare)); +router.post("/receiveShare", jwt.authenticate, asyncHandler(questionnaires.receiveShare)); + +module.exports = router; diff --git a/server/routers/quiz.js b/server/routers/quiz.js deleted file mode 100644 index 0139c7b..0000000 --- a/server/routers/quiz.js +++ /dev/null @@ -1,23 +0,0 @@ -const express = require('express'); -const router = express.Router(); -const quizzes = require('../app.js').quizzes; -const jwt = require('../middleware/jwtToken.js'); -const asyncHandler = require('./routerUtils.js'); - -if (!quizzes) { - console.error("quizzes is not defined"); -} - -router.post("/create", jwt.authenticate, asyncHandler(quizzes.create)); -router.get("/get/:quizId", jwt.authenticate, asyncHandler(asyncHandler(quizzes.get))); -router.delete("/delete/:quizId", jwt.authenticate, asyncHandler(quizzes.delete)); -router.put("/update", jwt.authenticate, asyncHandler(quizzes.update)); -router.put("/move", jwt.authenticate, asyncHandler(quizzes.move)); - -router.post("/duplicate", jwt.authenticate, asyncHandler(quizzes.duplicate)); -router.post("/copy/:quizId", jwt.authenticate, asyncHandler(quizzes.copy)); -router.put("/Share", jwt.authenticate, asyncHandler(quizzes.share)); -router.get("/getShare/:quizId", jwt.authenticate, asyncHandler(quizzes.getShare)); -router.post("/receiveShare", jwt.authenticate, asyncHandler(quizzes.receiveShare)); - -module.exports = router; diff --git a/server/socket/socket.js b/server/socket/socket.js index fc21632..5ff62b5 100644 --- a/server/socket/socket.js +++ b/server/socket/socket.js @@ -76,8 +76,8 @@ const setupWebsocket = (io) => { socket.to(roomName).emit("launch-student-mode", questions); }); - socket.on("end-quiz", ({ roomName }) => { - socket.to(roomName).emit("end-quiz"); + socket.on("end-questionnaire", ({ roomName }) => { + socket.to(roomName).emit("end-questionnaire"); }); socket.on("message", (data) => {