diff --git a/backend/src/config/const.ts b/backend/src/config/const.ts index a562318..fc4e6a9 100644 --- a/backend/src/config/const.ts +++ b/backend/src/config/const.ts @@ -37,5 +37,7 @@ export const MESSAGES = { ERROR_SUBMITTING_QUIZ_RESULT: "Failed to submit quiz result.", ACCESS_DENIED: "Access denied to this quiz.", ERROR_FETCHING_QUIZ_RESULTS: "Failed to retrieve quiz results.", + ERROR_DELETING_QUIZ: "Failed to delete quiz.", + QUIZ_DELETED: "Quiz deleted successfully.", }, }; diff --git a/backend/src/controllers/quiz.controller.ts b/backend/src/controllers/quiz.controller.ts index 4c19ca0..a67c3a2 100644 --- a/backend/src/controllers/quiz.controller.ts +++ b/backend/src/controllers/quiz.controller.ts @@ -7,7 +7,7 @@ import logger from "../config/logger"; // Import Winston logger export const createQuiz = async (req: Request, res: Response) => { const { title, questions, secretCode } = req.body; const clubId = Number(req.query.ClubID); - + if (!secretCode || typeof secretCode !== "string") { logger.warn("Invalid or missing secret code during quiz creation."); return res.status(400).json({ error: MESSAGES.QUIZ.INVALID_SECRET_CODE }); @@ -22,7 +22,7 @@ export const createQuiz = async (req: Request, res: Response) => { clubId: clubId, }, }); - + await Promise.all( questions.map((q: any) => prisma.question.create({ @@ -35,7 +35,7 @@ export const createQuiz = async (req: Request, res: Response) => { }) ) ); - + logger.info(`Quiz created successfully: ${title} for ClubID: ${clubId}`); res.status(201).json({ quizId: quiz.id }); } catch (error) { @@ -46,13 +46,13 @@ export const createQuiz = async (req: Request, res: Response) => { export const getClubQuizzes = async (req: Request, res: Response) => { const clubId = Number(req.query.ClubID); - + try { const quizzes = await prisma.quiz.findMany({ where: { clubId: clubId }, select: { id: true, title: true, createdAt: true }, }); - + logger.info(`Fetched quizzes for ClubID: ${clubId}`); res.json(quizzes); } catch (error) { @@ -71,14 +71,14 @@ export const getQuizById = async (req: Request, res: Response) => { where: { id: parseInt(id) }, include: { questions: true }, }); - + if (!quiz) { logger.warn(`Quiz not found for ID: ${id}`); return res.status(404).json({ error: MESSAGES.QUIZ.QUIZ_NOT_FOUND }); } const isSecretCodeValid = await bcrypt.compare(secretCode, quiz.secretCode); - + if (!isSecretCodeValid) { logger.warn(`Invalid secret code for quiz ID: ${id}`); return res.status(403).json({ error: MESSAGES.QUIZ.INVALID_SECRET_CODE }); @@ -101,7 +101,7 @@ export const createQuizUser = async (req: Request, res: Response) => { const user = await prisma.user.create({ data: { name, rollNo, year: parsedYear }, }); - + logger.info(`Created quiz user: ${name}`); res.status(201).json(user); } catch (error) { @@ -125,7 +125,9 @@ export const submitQuiz = async (req: Request, res: Response) => { }, }); - logger.info(`Quiz result submitted for quiz ID: ${id} by user ID: ${userId}`); + logger.info( + `Quiz result submitted for quiz ID: ${id} by user ID: ${userId}` + ); res.status(201).json(result); } catch (error) { logger.error(`${MESSAGES.QUIZ.ERROR_SUBMITTING_QUIZ_RESULT}: ${error}`); @@ -145,7 +147,9 @@ export const getQuizResults = async (req: Request, res: Response) => { }); if (!quiz || quiz.clubId !== clubId) { - logger.warn(`Unauthorized access to quiz results for quiz ID: ${id} by ClubID: ${clubId}`); + logger.warn( + `Unauthorized access to quiz results for quiz ID: ${id} by ClubID: ${clubId}` + ); return res.status(403).json({ error: MESSAGES.QUIZ.ACCESS_DENIED }); } @@ -161,3 +165,22 @@ export const getQuizResults = async (req: Request, res: Response) => { res.status(500).json({ error: MESSAGES.QUIZ.ERROR_FETCHING_QUIZ_RESULTS }); } }; + +// Delete quiz by ID +export const deleteQuiz = async (req: Request, res: Response) => { + try { + const { id } = req.params; + await prisma.result.deleteMany({ where: { quizId: parseInt(id) }, }); + await prisma.question.deleteMany({ where: { quizId: parseInt(id) }, }); + await prisma.quiz.delete({ where: { id: parseInt(id) }, }); + + //also delete the users who have taken the quiz + //not done yet + + logger.info(`Quiz deleted successfully for ID: ${id}`); + res.json({ message: MESSAGES.QUIZ.QUIZ_DELETED }); + } catch (error) { + logger.error(`${MESSAGES.QUIZ.ERROR_DELETING_QUIZ}: ${error}`); + res.status(500).json({ error: MESSAGES.QUIZ.ERROR_DELETING_QUIZ }); + } +}; diff --git a/backend/src/routes/quiz.routes.ts b/backend/src/routes/quiz.routes.ts index 9838343..b2e4be3 100644 --- a/backend/src/routes/quiz.routes.ts +++ b/backend/src/routes/quiz.routes.ts @@ -6,13 +6,14 @@ import { createQuizUser, submitQuiz, getQuizResults, + deleteQuiz } from "../controllers/quiz.controller"; const router = Router(); router.post("/createQuiz", createQuiz); -// Get quizzes for a club +// Get quizzes list for a club router.get("/getClubQuizzes", getClubQuizzes); // Get quiz by ID (only if secret code is correct) @@ -25,4 +26,6 @@ router.post("/:id/submit", submitQuiz); //get results for a quiz only for that club admin access router.get("/:id/results", getQuizResults); +router.delete("/:id",deleteQuiz); + export default router; diff --git a/frontend/src/appComponents/AdminResults.tsx b/frontend/src/appComponents/AdminResults.tsx index b8edac9..1f031d9 100644 --- a/frontend/src/appComponents/AdminResults.tsx +++ b/frontend/src/appComponents/AdminResults.tsx @@ -19,7 +19,7 @@ export default function AdminResults() { } }, [userData]); - const fetchResults = async (e:any) => { + const fetchResults = async (e: any) => { e.preventDefault(); setLoading(true); try { @@ -58,7 +58,7 @@ export default function AdminResults() { } }; - const handleIdChange = (event:any) => { + const handleIdChange = (event: any) => { setId(event.target.value); }; @@ -94,17 +94,34 @@ export default function AdminResults() { Quiz ID Quiz Name - Creation Time + Creation Time + Action - {quizzes.map((quiz:any) => ( + {quizzes.map((quiz: any) => ( {quiz.id} {quiz.title} {new Date(quiz.createdAt).toLocaleString()} + { + if (confirm("Are you sure you want to delete this quiz?")) { + console.log("id: ", quiz.id); + axios.delete(`/api/quizzes/${quiz.id}`).then((response) => { + if (response.status === 200) { + fetchQuizzes(); + } + }).catch((error) => { + console.error("Error deleting quiz", error); + }); + }else{ + console.log("Deletion"); + } + }}> + Delete + ))} diff --git a/frontend/src/appComponents/QuizPage.tsx b/frontend/src/appComponents/QuizPage.tsx index 1f87229..c3035aa 100644 --- a/frontend/src/appComponents/QuizPage.tsx +++ b/frontend/src/appComponents/QuizPage.tsx @@ -1,6 +1,6 @@ import axios from "./axiosInstance"; import { useState, useEffect } from "react"; -import { useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; interface Question { id: string; @@ -23,6 +23,7 @@ export default function QuizPage() { const [userId, setUserId] = useState(null); const { id } = useParams<{ id: string }>(); + const navigate = useNavigate(); useEffect(() => { if (userId && secretCode != "") { fetchQuiz(); @@ -51,7 +52,7 @@ export default function QuizPage() { } }; - const handleUserInfoSubmit = async (e:any) => { + const handleUserInfoSubmit = async (e: any) => { e.preventDefault(); axios .post("/api/quizzes/createUser", userInfo, { @@ -96,7 +97,10 @@ export default function QuizPage() { "Content-Type": "application/json", }, }, - ) + ).then(() => { + alert("Quiz submitted successfully"); + navigate("/"); + }) .catch((error) => { console.error("Error submitting quiz result", error); });