문제를 수정합니다. id: {problemId}
;
}
-export default EditProblem
+export default EditProblem;
diff --git a/src/client/src/quiz/NewQuiz.jsx b/src/client/src/quiz/NewQuiz.jsx
index e924138849264f276f63fb3de26dbae7889ea8d8..b4602bf0fa5e21caff7b4c455acce423b384b1aa 100644
--- a/src/client/src/quiz/NewQuiz.jsx
+++ b/src/client/src/quiz/NewQuiz.jsx
@@ -6,11 +6,18 @@ import NewProblem from "./NewProblem";
import Problem from "./Problem";
function NewQuiz() {
-
+ const [title, setTitle] = useState('')
const [problems, setProblems] = useState([])
const jwt = authHelpers.isAuthenticated();
+ const handleChange = (event) => {
+ const { name, value } = event.target
+ if (name === 'title') {
+ setTitle(value)
+ }
+ }
+
const addProblem = (problem) => {
console.log(problem)
setProblems([...problems, problem])
@@ -20,6 +27,7 @@ function NewQuiz() {
event.preventDefault();
const quizData = {
+ title,
problems
}
@@ -37,11 +45,13 @@ function NewQuiz() {
return (
- Quiz List
+ New Quiz
+
Title
+
{
problems.map((problem, index) => {
- return
+ return
})
}
diff --git a/src/client/src/quiz/Problem.jsx b/src/client/src/quiz/Problem.jsx
index 761106b70080d88cc97f4b7d8f570fef7e7db6a7..e064171cd7774fdc38799465c4f0a759beb25d15 100644
--- a/src/client/src/quiz/Problem.jsx
+++ b/src/client/src/quiz/Problem.jsx
@@ -1,20 +1,23 @@
import React from "react";
+import {Link} from 'react-router-dom';
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
-function Problem({ problem, number }) {
+function Problem({ problem, number, onUpdate, onRemove }) {
return (
- {number}번. {problem.question}
+ {number+1}번. {problem.question}
Answers
{problem.answers.map((answer, index) => {
return {answer} ;
})}
- 수정
- 삭제
+
+ onUpdate(number)}>수정
+
+ 삭제
);
diff --git a/src/client/src/quiz/Quiz.jsx b/src/client/src/quiz/Quiz.jsx
index be938346f8798ca86de270bd4c086813db00f643..81de645d4faff34bcd60b2087584bc97832b77c0 100644
--- a/src/client/src/quiz/Quiz.jsx
+++ b/src/client/src/quiz/Quiz.jsx
@@ -26,10 +26,20 @@ function Quiz() {
};
}, [quizId]);
+ const handleUpdate = (index) => {
+ console.log(`Quiz에서 handleUpdate ${index}번 실행`);
+ console.log(`Quiz에서 handleUpdate ${JSON.stringify(quiz.problems[index])}`);
+ }
+
+ const handleRemove = () => {
+ console.log('Quiz에서 handleRemove 실행');
+ }
+
return (
+
제목: {quiz.title}
{quiz.problems?.map((problem, i) => {
- return
;
+ return
;
})}
);
diff --git a/src/client/src/quiz/Quizzes.jsx b/src/client/src/quiz/Quizzes.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..e8b56b99c7601527718dba3dac0960b74687cd8f
--- /dev/null
+++ b/src/client/src/quiz/Quizzes.jsx
@@ -0,0 +1,50 @@
+import React, { useEffect, useState } from "react";
+import Card from "react-bootstrap/Card";
+import { Link, useParams } from "react-router-dom";
+import authHelpers from "../auth/auth-helpers";
+import { listByUserId } from "./api-quiz";
+
+function Quizzes() {
+ const { userId } = useParams();
+ const [quizzes, setQuizzes] = useState([]);
+
+ const jwt = authHelpers.isAuthenticated();
+
+ useEffect(() => {
+ const abortController = new AbortController();
+ const signal = abortController.signal;
+
+ listByUserId({ userId: userId }, { t: jwt.token }, signal).then((data) => {
+ if (data.error) {
+ console.log(data.error);
+ } else {
+ // console.log(data);
+ setQuizzes(data);
+ }
+ });
+
+ return () => {
+ abortController.abort();
+ };
+ }, [userId]);
+
+ return (
+
+ All Quizzes Here
+ {quizzes.map((quiz, i) => {
+ return (
+
+
+
+ 제목: {quiz.title}
+ 만든날: {quiz.created}
+
+
+
+ );
+ })}
+
+ );
+}
+
+export default Quizzes;
diff --git a/src/client/src/quiz/api-quiz.js b/src/client/src/quiz/api-quiz.js
index 1074aea411f32a80ae171d015578512b0d5ff31b..c379f9506c5ef2e6acec8bbcb3b79282c0bd7564 100644
--- a/src/client/src/quiz/api-quiz.js
+++ b/src/client/src/quiz/api-quiz.js
@@ -1,7 +1,7 @@
const create = async (params, credentials, quiz) => {
try {
- let response = await fetch('/api/quiz/' + params.userId, {
+ let response = await fetch('/api/quiz/by/' + params.userId, {
method: 'POST',
headers: {
'Accept': 'application/json',
@@ -33,7 +33,24 @@ const read = async (params, credentials, signal) => {
}
}
+const listByUserId = async (params, credentials, signal) => {
+ try {
+ let response = await fetch('/api/quiz/by/' + params.userId, {
+ method: 'GET',
+ signal: signal,
+ headers: {
+ 'Accept': 'application/json',
+ 'Authorization': 'Bearer ' + credentials.t,
+ },
+ })
+ return await response.json()
+ } catch (error) {
+ console.log(error)
+ }
+}
+
export {
create,
read,
+ listByUserId,
}
\ No newline at end of file
diff --git a/src/client/src/user/Signup.jsx b/src/client/src/user/Signup.jsx
index ecc951077db0ade7c5348a7e8831a2d84e7e4c6a..03de80693425325ef01767fa457ec0a63bea1bef 100644
--- a/src/client/src/user/Signup.jsx
+++ b/src/client/src/user/Signup.jsx
@@ -1,35 +1,85 @@
-import React, { useState } from 'react'
-import Button from 'react-bootstrap/Button'
-import Form from 'react-bootstrap/Form'
+import React, { useState } from "react";
+import Button from "react-bootstrap/Button";
+import Form from "react-bootstrap/Form";
+import Modal from 'react-bootstrap/Modal'
+import {Link} from 'react-router-dom'
+import { create } from "./api-user";
function Signup() {
const [values, setValues] = useState({
- name: '',
- password: '',
- email: '',
+ name: "",
+ password: "",
+ email: "",
open: false,
- error: '',
- })
+ error: "",
+ });
+
+ const handleChange = (name) => (event) => {
+ const { value } = event.target;
+ setValues({ ...values, [name]: value });
+ };
+
+ const handleSubmit = (event) => {
+ // console.log(values);
+ const user = {
+ name: values.name || undefined,
+ email: values.email || undefined,
+ password: values.password || undefined,
+ };
+ create(user).then((data) => {
+ if (data.error) {
+ console.log(data.error);
+ setValues({ ...values, error: data.error });
+ } else {
+ setValues({ ...values, error: "", open: true });
+ }
+ });
+ };
return (
Name
-
+
Password
-
+
Email
-
+
- 확인
+ 확인
+
+
+ New Account
+
+
+ New Account successfully created.
+
+
+
+ Sign in
+
+
+
- )
+ );
}
-export default Signup
+export default Signup;
diff --git a/src/server/helpers/dbErrorHandler.js b/src/server/helpers/dbErrorHandler.js
new file mode 100644
index 0000000000000000000000000000000000000000..554958515fc18028a74b8b546eb9b4dc17ce38ee
--- /dev/null
+++ b/src/server/helpers/dbErrorHandler.js
@@ -0,0 +1,32 @@
+const getErrorMessage = (err) => {
+ let message = ''
+ // console.log('error in getErrorMessage', err)
+ if (err.code) {
+ switch (err.code) {
+ case 11000:
+ case 11001:
+ message = getUniqueErrorMessage(err)
+ break
+ default:
+ message = 'Something went wrong'
+ }
+ } else if (err._message) {
+ message = err._message
+ }
+ return message
+}
+
+const getUniqueErrorMessage = (err) => {
+ let output
+ // console.log('error in getUniqueErrormessage', err)
+ try {
+ let fieldName = err.message.substring(err.message.lastIndexOf('.$') + 2,
+ err.message.lastIndexOf('_1'))
+ output = fieldName.charAt(0).toUpperCase() + fieldName.slice(1) + ' already exists'
+ } catch (error) {
+ output = 'Unique field already exists'
+ }
+ return output
+}
+
+export default { getErrorMessage }
\ No newline at end of file
diff --git a/src/server/quiz/problem.model.js b/src/server/quiz/problem.model.js
index b9b4ea517469585ff9dc8ac226c28c2a039cdb02..ce049e796bf69a6699dcec4b77f1ebb339632294 100644
--- a/src/server/quiz/problem.model.js
+++ b/src/server/quiz/problem.model.js
@@ -1,6 +1,10 @@
import mongoose from 'mongoose'
const ProblemSchema = new mongoose.Schema({
+ author: {
+ type: mongoose.SchemaTypes.ObjectId,
+ ref: 'User'
+ },
type: String, // 객관식, 주관식 single/multiple choice
created: {
type: Date,
diff --git a/src/server/quiz/quiz.controller.js b/src/server/quiz/quiz.controller.js
index 8603f3c23da388cd6bb97be0cd3272565378a538..cb105be908bccd4a423393cc625b2bed430f47d9 100644
--- a/src/server/quiz/quiz.controller.js
+++ b/src/server/quiz/quiz.controller.js
@@ -1,11 +1,12 @@
import formidable from 'formidable'
import fs from 'fs'
+import dbErrorHandler from '../helpers/dbErrorHandler.js'
import Problem from './problem.model.js'
import Quiz from './quiz.model.js'
const create = async (req, res) => {
try {
- const { problems } = req.body
+ const { title, problems } = req.body
const quiz = new Quiz()
// console.log('quiz in quiz.controller:', quiz);
@@ -14,10 +15,12 @@ const create = async (req, res) => {
// console.log('problem in quiz.controller:', problem);
const p = new Problem(problem)
// console.log('problem in quiz.controller:', p);
+ p.author = req.profile
await p.save()
quiz.problems.push(p._id)
}
+ quiz.title = title
quiz.author = req.profile
// console.log('quiz in quiz.controller:', quiz);
@@ -42,11 +45,39 @@ const isAuthor = (req, res, next) => {
next()
}
+const isProblemAuthor = (req, res, next) => {
+ const isProblemAuthor = req.auth && req.problem && req.auth._id == req.problem.author._id
+ if (!isProblemAuthor) {
+ return res.status(403).json({
+ error: 'User is not an author of the problem'
+ })
+ }
+ next()
+}
+
const read = async (req, res) => {
let quiz = req.quiz
res.json(quiz)
}
+const readProblem = async (req, res) => {
+ let problem = req.problem
+ res.json(problem)
+}
+
+const listByUserId = async (req, res) => {
+ try {
+ const authorId = req.profile._id
+ const quizzes = await Quiz.find({author: authorId}).exec()
+ // console.log('quizzes in listByUserId:', quizzes);
+ res.json(quizzes)
+ } catch (error) {
+ return res.status(400).json({
+ error: dbErrorHandler.getErrorMessage(error)
+ })
+ }
+}
+
const quizById = async (req, res, next, id) => {
try {
const quiz = await Quiz.findById(id)
@@ -67,9 +98,32 @@ const quizById = async (req, res, next, id) => {
}
}
+const problemById = async (req, res, next, id) => {
+ try {
+ const problem = await Problem.findById(id)
+ .populate('author', '_id name')
+ .exec()
+ if (!problem) {
+ return res.status(400).json({
+ error: 'Problem not found'
+ })
+ }
+ req.problem = problem
+ next()
+ } catch (error) {
+ return res.status(400).json({
+ error: dbErrorHandler.getErrorMessage(error)
+ })
+ }
+}
+
export default {
create,
read,
+ readProblem,
isAuthor,
+ isProblemAuthor,
+ listByUserId,
quizById,
+ problemById,
}
\ No newline at end of file
diff --git a/src/server/quiz/quiz.routes.js b/src/server/quiz/quiz.routes.js
index 8a6b1b820827af681a25703804a1678513de5988..5a805e24f33f3b55d832c644a969b090cfe40936 100644
--- a/src/server/quiz/quiz.routes.js
+++ b/src/server/quiz/quiz.routes.js
@@ -5,13 +5,18 @@ import quizCtrl from './quiz.controller.js'
const router = express.Router()
-router.route('/api/quiz/:userId')
+router.route('/api/quiz/by/:userId')
.post(authCtrl.requireSignin, authCtrl.hasAuthorization, userCtrl.isInstructor, quizCtrl.create)
-
+ .get(authCtrl.requireSignin, authCtrl.hasAuthorization, quizCtrl.listByUserId)
+
router.route('/api/quiz/:quizId')
.get(authCtrl.requireSignin, quizCtrl.isAuthor, quizCtrl.read)
+router.route('/api/quiz/problem/:problemId')
+ .get(authCtrl.requireSignin, quizCtrl.isProblemAuthor, quizCtrl.readProblem)
router.param('userId', userCtrl.userById)
router.param('quizId', quizCtrl.quizById)
+router.param('problemId', quizCtrl.problemById)
+
export default router
\ No newline at end of file
diff --git a/src/server/user/user.controller.js b/src/server/user/user.controller.js
index 4982f2123e0a8a34c4283737720c2ffae62f1928..cb82acbe6eda5f4860d27b313d720e5c67f91a9b 100644
--- a/src/server/user/user.controller.js
+++ b/src/server/user/user.controller.js
@@ -2,9 +2,11 @@ import User from './user.model.js'
import formidable from 'formidable'
import extend from 'lodash/extend.js'
import fs from 'fs'
+import dbErrorHandler from '../helpers/dbErrorHandler.js'
const create = async (req, res) => {
const user = new User(req.body)
+ // console.log('user in user.controll:', req.body);
try {
await user.save()
return res.json({
@@ -12,7 +14,7 @@ const create = async (req, res) => {
})
} catch (error) {
return res.status(400).json({
- error: 'User creation error'
+ error: dbErrorHandler.getErrorMessage(error)
})
}
}