From 4f94f70a9b048369ae5f4cab8d250fde4c2620bf Mon Sep 17 00:00:00 2001 From: AndrewTrieu Date: Thu, 9 Mar 2023 17:10:23 +0200 Subject: [PATCH] Update controllers --- .../routes/controllers/answerController.js | 56 ++++++- .../routes/controllers/mainController.js | 15 +- .../routes/controllers/questionController.js | 140 +++++++++++++----- .../routes/controllers/topicController.js | 4 +- drill-and-practice/services/answerService.js | 17 ++- 5 files changed, 188 insertions(+), 44 deletions(-) diff --git a/drill-and-practice/routes/controllers/answerController.js b/drill-and-practice/routes/controllers/answerController.js index 8c4bc00..665d94f 100644 --- a/drill-and-practice/routes/controllers/answerController.js +++ b/drill-and-practice/routes/controllers/answerController.js @@ -1 +1,55 @@ -import * as \ No newline at end of file +import * as questionService from "../../services/questionService.js"; +import * as answerService from "../../services/answerService.js"; +import { validasaur } from "../../deps.js"; + +const validationRules = { + option: [validasaur.required, validasaur.minLength(1)], +}; + +const addAnswer = async ({ request, response, params, state, render }) => { + const topicId = params.tId; + const questionId = params.qId; + const userId = (await state.session.get("user")).id; + const body = request.body({ type: "form-data" }); + const formData = await body.value; + const answerData = { + option: formData.get("option"), + correct: formData.get("correct"), + }; + const [passes, errors] = await validasaur.validate( + answerData, + validationRules + ); + const questionData = await questionService.getQuestionByQuestionId( + questionId + ); + if (userId !== questionData.user_id) { + response.status = 403; + response.body = "You are not the owner of this question!"; + return; + } + if (!passes) { + response.status = 422; + questionData.errors = errors; + questionData.option = answerData.option; + questionData.details = await answerService.getAnswersByQuestionId( + questionId + ); + questionData.topicId = topicId; + render("question.eta", questionData); + } else { + const correct = answerData.correct === "on" ? true : false; + await answerService.addAnswer(questionId, answerData.option, correct); + response.redirect(`/topics/${topicId}/questions/${questionId}`); + } +}; + +const deleteAnswer = async ({ params, response }) => { + const topicId = params.tId; + const questionId = params.qId; + const optionId = params.oId; + await answerService.deleteAnswer(questionId, optionId); + response.redirect(`/topics/${topicId}/questions/${questionId}`); +}; + +export { addAnswer, deleteAnswer }; diff --git a/drill-and-practice/routes/controllers/mainController.js b/drill-and-practice/routes/controllers/mainController.js index 3927f09..c5e67f5 100644 --- a/drill-and-practice/routes/controllers/mainController.js +++ b/drill-and-practice/routes/controllers/mainController.js @@ -1,5 +1,18 @@ +import { countTopics } from "../../services/topicService.js"; +import { countQuestions } from "../../services/questionService.js"; +import { countAnswers } from "../../services/answerService.js"; + const showMain = ({ render }) => { - render("main.eta"); + const statistics = { + totalTopics: 0, + totalQuestions: 0, + totalAnswers: 0, + }; + statistics.totalTopics = countTopics(); + statistics.totalQuestions = countQuestions(); + statistics.totalAnswers = countAnswers(); + + render("main.eta", statistics); }; export { showMain }; diff --git a/drill-and-practice/routes/controllers/questionController.js b/drill-and-practice/routes/controllers/questionController.js index b822a74..1257d5b 100644 --- a/drill-and-practice/routes/controllers/questionController.js +++ b/drill-and-practice/routes/controllers/questionController.js @@ -8,47 +8,121 @@ const validationRules = { }; const addQuestion = async ({ request, response, params, state, render }) => { - const topicId = params.id; - const userId (await state.session.get("user")).id; - const body = request.body({ type: "form-data" }); - const formData = await body.value; - const questionData = { - topicId: topicId, - question: formData.get("question_text"), - }; - const [passes, errors] = await validasaur.validate(questionData, validationRules); + const topicId = params.tId; + const userId = (await state.session.get("user")).id; + const body = request.body({ type: "form-data" }); + const formData = await body.value; + const questionData = { + topicId: topicId, + question: formData.get("question_text"), + }; + const [passes, errors] = await validasaur.validate( + questionData, + validationRules + ); - if (!passes) { - response.status = 422; - questionData.errors = errors; - questionData.currentQuestionsByTopicId = await questionService.getQuestionsByTopicId(topicId); - render("questions.eta", questionData); - } else { - await questionService.addQuestion(userId, topicId, questionData.question); - response.redirect(`/topics/${topicId}`); - } + if (!passes) { + response.status = 422; + questionData.errors = errors; + questionData.currentQuestions = await questionService.getQuestionsByTopicId( + topicId + ); + render("questions.eta", questionData); + } else { + await questionService.addQuestion(userId, topicId, questionData.question); + response.redirect(`/topics/${topicId}`); + } }; -const listQuestions = async ({ params, render, state }) => { - const topicId = params.id; - render("questions.eta", { - topicId: topicId, - currentQuestions = await questionService.getQuestionsByTopicId(topicId), - }); +const listQuestions = async ({ params, render }) => { + const topicId = params.tId; + render("questions.eta", { + topicId: topicId, + currentQuestions: await questionService.getQuestionsByTopicId(topicId), + }); }; const showQuestion = async ({ params, render }) => { - const questionId = params.qId; - const questionData = await questionService.getQuestionById(questionId); - questionData.answers = await answerService.getAnswersByQuestionId(questionId); - questionData.topicId = params.id - render("question.eta", questionData); + const questionId = params.qId; + const questionData = await questionService.getQuestionById(questionId); + questionData.answers = await answerService.getAnswersByQuestionId(questionId); + questionData.topicId = params.id; + render("question.eta", questionData); }; const deleteQuestion = async ({ params, response }) => { - const topicId = params.tId; - const questionId = params.qId; - await questionService.deleteQuestion(questionId); - response.redirect(`/topics/${topicId}`); + const topicId = params.tId; + const questionId = params.qId; + await questionService.deleteQuestion(questionId); + response.redirect(`/topics/${topicId}`); }; +const listQuiz = async ({ params, render }) => { + const topicId = params.tId; + const questionId = params.qId; + const questionData = await questionService.getQuestionById(questionId); + const quizData = { + topicId: topicId, + questionId: questionId, + question: questionData.question_text, + answers: await answerService.getAnswersByQuestionId(questionId), + }; + render("quiz.eta", quizData); +}; + +const getRandQuestion = async ({ params, response }) => { + const topicId = params.tId; + const randQuestion = await questionService.getRandQuestion(topicId); + if (randQuestion === null) { + response.body = "No questions in this topic!"; + } else { + response.redirect(`/topics/${topicId}/questions/${randQuestion.id}/quiz`); + } +}; + +const listQuizTopic = async ({ render }) => { + render("quizTopic.eta", { + allTopics: await topicService.getAllTopics(), + }); +}; + +const storeAnswer = async ({ response, params, state }) => { + const topicId = params.tId; + const questionId = params.qId; + const optionId = params.oId; + const userId = (await state.session.get("user")).id; + const correctOptionIds = await answerService.getCorrectOptionIds(questionId); + const correct = correctOptionIds.includes(Number(optionId)); + await answerService.storeAnswer(userId, questionId, optionId); + if (correct) { + response.redirect(`/quiz/${topicId}/questions/${questionId}/correct`); + } else { + response.redirect(`/quiz/${topicId}/questions/${questionId}/incorrect`); + } +}; + +const showCorrect = async ({ params, render }) => { + render("correct.eta", { tId: params.tId }); +}; + +const showIncorrect = async ({ params, render }) => { + const questionId = params.qId; + const correctOptions = { + data: [await answerService.getCorrectOptions(questionId)], + tId: params.tId, + }; + render("incorrect.eta", correctOptions); +}; + +export { + addQuestion, + listQuestions, + showQuestion, + deleteQuestion, + listQuiz, + getRandQuestion, + listQuizTopic, + storeAnswer, + showCorrect, + showIncorrect, +}; diff --git a/drill-and-practice/routes/controllers/topicController.js b/drill-and-practice/routes/controllers/topicController.js index 444ef4f..1d09d63 100644 --- a/drill-and-practice/routes/controllers/topicController.js +++ b/drill-and-practice/routes/controllers/topicController.js @@ -34,10 +34,10 @@ const addTopic = async ({ request, response, render, state }) => { }; const deleteTopic = async ({ params, response, state }) => { - const id = params.id; + const topicId = params.tId; const admin = (await state.session.get("user")).admin; if (admin) { - await topicService.deleteTopic(id); + await topicService.deleteTopic(topicId); } response.redirect("/topics"); }; diff --git a/drill-and-practice/services/answerService.js b/drill-and-practice/services/answerService.js index 897b9eb..f617fda 100644 --- a/drill-and-practice/services/answerService.js +++ b/drill-and-practice/services/answerService.js @@ -17,15 +17,18 @@ const addAnswer = async (questionId, optionText, isCorrect) => { const deleteAnswer = async (questionId, optionId) => { await sql`DELETE FROM question_answer_options WHERE question_id = ${questionId} AND id = ${optionId}`; -}; - -const deleteAnswerByOptionId = async (optionId) => { await sql`DELETE FROM question_answer_options WHERE id = ${optionId}`; }; -const getCorrectOption = async (questionId) => { +const getCorrectOptionIds = async (questionId) => { const result = - await sql`SELECT * FROM question_answer_options WHERE question_id = ${questionId} AND is_correct = true`; + await sql`SELECT id FROM question_answer_options WHERE question_id = ${questionId} AND is_correct = true`; + return result.rows; +}; + +const getCorrectOptions = async (questionId) => { + const result = + await sql`SELECT option_text FROM question_answer_options WHERE question_id = ${questionId} AND is_correct = true`; return result.rows; }; @@ -38,7 +41,7 @@ export { getAnswersByQuestionId, addAnswer, deleteAnswer, - deleteAnswerByOptionId, - getCorrectOption, + getCorrectOptionIds, + getCorrectOptions, storeAnswer, };