Commit 8a0556fb authored by Yoon, Daeki's avatar Yoon, Daeki 😅
Browse files

Problem Edit 수정중

parent f21119fa
...@@ -3,9 +3,11 @@ import { Route, Switch } from "react-router-dom"; ...@@ -3,9 +3,11 @@ import { Route, Switch } from "react-router-dom";
import Signin from "./auth/Signin"; import Signin from "./auth/Signin";
import Home from "./core/Home"; import Home from "./core/Home";
import Menu from "./core/Menu"; import Menu from "./core/Menu";
import NewQuiz from './quiz/NewQuiz' import NewQuiz from "./quiz/NewQuiz";
import Quiz from './quiz/Quiz' import Quiz from "./quiz/Quiz";
import Signup from "./user/Signup" import Signup from "./user/Signup";
import Quizzes from "./quiz/Quizzes";
import EditProblem from "./quiz/EditProblem";
function MainRouter() { function MainRouter() {
return ( return (
...@@ -13,7 +15,6 @@ function MainRouter() { ...@@ -13,7 +15,6 @@ function MainRouter() {
<Menu /> <Menu />
<Switch> <Switch>
<Route exact path="/"> <Route exact path="/">
{/* {console.log('Home 안에서 ...')} */}
<Home /> <Home />
</Route> </Route>
<Route path="/signin"> <Route path="/signin">
...@@ -22,17 +23,21 @@ function MainRouter() { ...@@ -22,17 +23,21 @@ function MainRouter() {
<Route path="/signup"> <Route path="/signup">
<Signup /> <Signup />
</Route> </Route>
<Route path='/quiz/new'> <Route path="/quiz/new">
<NewQuiz /> <NewQuiz />
</Route> </Route>
<Route path="/quiz/:quizId"> <Route path="/quiz/by/:userId">
<Quizzes />
</Route>
<Route path="/quiz/problem/edit/:problemId">
<EditProblem />
</Route>
{/* 아래 "/quiz/:quizId" 는 "/quiz/by/:userId"와 순서 바뀌면 안된다. */}
<Route path="/quiz/:quizId">
<Quiz /> <Quiz />
</Route> </Route>
</Switch> </Switch>
</div> </div>
// <BrowserRouter>
// {console.log('BrowserRoter 안에서 ...')}
// </BrowserRouter>
); );
} }
......
...@@ -20,6 +20,7 @@ function Menu() { ...@@ -20,6 +20,7 @@ function Menu() {
<Navbar.Collapse id="basic-navbar-nav"> <Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto"> <Nav className="mr-auto">
<Nav.Link href="/">Home</Nav.Link> <Nav.Link href="/">Home</Nav.Link>
{authUser && <Nav.Link as={Link} to={`/quiz/by/${authUser.user._id}`}>Quizzes</Nav.Link>}
<Nav.Link href="/quiz/new">New Quiz</Nav.Link> <Nav.Link href="/quiz/new">New Quiz</Nav.Link>
<NavDropdown title="Dropdown" id="basic-nav-dropdown"> <NavDropdown title="Dropdown" id="basic-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item> <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
......
import React from 'react' import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
function EditProblem() { function EditProblem() {
return ( const { problemId } = useParams();
<div> const [problem, setProblem] = useState({});
</div> useEffect(() => {
) return () => {};
}, [problemId]);
return <div>문제를 수정합니다. id: {problemId}</div>;
} }
export default EditProblem export default EditProblem;
...@@ -6,11 +6,18 @@ import NewProblem from "./NewProblem"; ...@@ -6,11 +6,18 @@ import NewProblem from "./NewProblem";
import Problem from "./Problem"; import Problem from "./Problem";
function NewQuiz() { function NewQuiz() {
const [title, setTitle] = useState('')
const [problems, setProblems] = useState([]) const [problems, setProblems] = useState([])
const jwt = authHelpers.isAuthenticated(); const jwt = authHelpers.isAuthenticated();
const handleChange = (event) => {
const { name, value } = event.target
if (name === 'title') {
setTitle(value)
}
}
const addProblem = (problem) => { const addProblem = (problem) => {
console.log(problem) console.log(problem)
setProblems([...problems, problem]) setProblems([...problems, problem])
...@@ -20,6 +27,7 @@ function NewQuiz() { ...@@ -20,6 +27,7 @@ function NewQuiz() {
event.preventDefault(); event.preventDefault();
const quizData = { const quizData = {
title,
problems problems
} }
...@@ -37,11 +45,13 @@ function NewQuiz() { ...@@ -37,11 +45,13 @@ function NewQuiz() {
return ( return (
<div> <div>
<h1 className="text-center"> <h1 className="text-center">
Quiz List New Quiz
</h1> </h1>
<label htmlFor='title'>Title</label>
<input id='title' name='title' onChange={handleChange} placeholder='Title' />
{ {
problems.map((problem, index) => { problems.map((problem, index) => {
return <Problem key={index} problem={problem} /> return <Problem key={index} problem={problem} number={index+1} />
}) })
} }
<NewProblem addProblem={addProblem} /> <NewProblem addProblem={addProblem} />
......
import React from "react"; import React from "react";
import {Link} from 'react-router-dom';
import Card from "react-bootstrap/Card"; import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button"; import Button from "react-bootstrap/Button";
function Problem({ problem, number }) { function Problem({ problem, number, onUpdate, onRemove }) {
return ( return (
<Card> <Card>
<Card.Body> <Card.Body>
<Card.Title> <Card.Title>
{number}번. {problem.question} {number+1}번. {problem.question}
</Card.Title> </Card.Title>
Answers Answers
{problem.answers.map((answer, index) => { {problem.answers.map((answer, index) => {
return <Card.Text key={index}>{answer}</Card.Text>; return <Card.Text key={index}>{answer}</Card.Text>;
})} })}
<Button>수정</Button> <Link to={`/quiz/problem/edit/${problem._id}`}>
<Button>삭제</Button> <Button onClick={(event) => onUpdate(number)}>수정</Button>
</Link>
<Button onClick={onRemove}>삭제</Button>
</Card.Body> </Card.Body>
</Card> </Card>
); );
......
...@@ -26,10 +26,20 @@ function Quiz() { ...@@ -26,10 +26,20 @@ function Quiz() {
}; };
}, [quizId]); }, [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 ( return (
<div> <div>
<h2>제목: {quiz.title}</h2>
{quiz.problems?.map((problem, i) => { {quiz.problems?.map((problem, i) => {
return <Problem key={i} problem={problem} number={i+1} />; return <Problem key={i} problem={problem} number={i} onUpdate={handleUpdate} onRemove={handleRemove} />;
})} })}
</div> </div>
); );
......
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 (
<div>
All Quizzes Here
{quizzes.map((quiz, i) => {
return (
<Link key={i} to={`/quiz/${quiz._id}`}>
<Card>
<Card.Body>
<Card.Title>제목: {quiz.title}</Card.Title>
<Card.Text>만든날: {quiz.created}</Card.Text>
</Card.Body>
</Card>
</Link>
);
})}
</div>
);
}
export default Quizzes;
const create = async (params, credentials, quiz) => { const create = async (params, credentials, quiz) => {
try { try {
let response = await fetch('/api/quiz/' + params.userId, { let response = await fetch('/api/quiz/by/' + params.userId, {
method: 'POST', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
...@@ -33,7 +33,24 @@ const read = async (params, credentials, signal) => { ...@@ -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 { export {
create, create,
read, read,
listByUserId,
} }
\ No newline at end of file
import React, { useState } from 'react' import React, { useState } from "react";
import Button from 'react-bootstrap/Button' import Button from "react-bootstrap/Button";
import Form from 'react-bootstrap/Form' 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() { function Signup() {
const [values, setValues] = useState({ const [values, setValues] = useState({
name: '', name: "",
password: '', password: "",
email: '', email: "",
open: false, 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 ( return (
<div> <div>
<Form> <Form>
<Form.Group> <Form.Group>
<Form.Label>Name</Form.Label> <Form.Label>Name</Form.Label>
<Form.Control type='text' placeholder='Name' /> <Form.Control
type="text"
placeholder="Name"
onChange={handleChange('name')}
/>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Label>Password</Form.Label> <Form.Label>Password</Form.Label>
<Form.Control type='password' placeholder='Password' /> <Form.Control
type="password"
placeholder="Password"
onChange={handleChange('password')}
/>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Label>Email</Form.Label> <Form.Label>Email</Form.Label>
<Form.Control type='email' placeholder='Email' /> <Form.Control
type="email"
placeholder="Email"
onChange={handleChange('email')}
/>
</Form.Group> </Form.Group>
<Button>확인</Button> <Button onClick={handleSubmit}>확인</Button>
</Form> </Form>
<Modal show={values.open}>
<Modal.Header>
<Modal.Title>New Account</Modal.Title>
</Modal.Header>
<Modal.Body>
New Account successfully created.
</Modal.Body>
<Modal.Footer>
<Link to='/signin'>
<Button>Sign in</Button>
</Link>
</Modal.Footer>
</Modal>
</div> </div>
) );
} }
export default Signup export default Signup;
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
import mongoose from 'mongoose' import mongoose from 'mongoose'
const ProblemSchema = new mongoose.Schema({ const ProblemSchema = new mongoose.Schema({
author: {
type: mongoose.SchemaTypes.ObjectId,
ref: 'User'
},
type: String, // 객관식, 주관식 single/multiple choice type: String, // 객관식, 주관식 single/multiple choice
created: { created: {
type: Date, type: Date,
......
import formidable from 'formidable' import formidable from 'formidable'
import fs from 'fs' import fs from 'fs'
import dbErrorHandler from '../helpers/dbErrorHandler.js'
import Problem from './problem.model.js' import Problem from './problem.model.js'
import Quiz from './quiz.model.js' import Quiz from './quiz.model.js'
const create = async (req, res) => { const create = async (req, res) => {
try { try {
const { problems } = req.body const { title, problems } = req.body
const quiz = new Quiz() const quiz = new Quiz()
// console.log('quiz in quiz.controller:', quiz); // console.log('quiz in quiz.controller:', quiz);
...@@ -14,10 +15,12 @@ const create = async (req, res) => { ...@@ -14,10 +15,12 @@ const create = async (req, res) => {
// console.log('problem in quiz.controller:', problem); // console.log('problem in quiz.controller:', problem);
const p = new Problem(problem) const p = new Problem(problem)
// console.log('problem in quiz.controller:', p); // console.log('problem in quiz.controller:', p);
p.author = req.profile
await p.save() await p.save()
quiz.problems.push(p._id) quiz.problems.push(p._id)
} }
quiz.title = title
quiz.author = req.profile quiz.author = req.profile
// console.log('quiz in quiz.controller:', quiz); // console.log('quiz in quiz.controller:', quiz);
...@@ -42,11 +45,39 @@ const isAuthor = (req, res, next) => { ...@@ -42,11 +45,39 @@ const isAuthor = (req, res, next) => {
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) => { const read = async (req, res) => {
let quiz = req.quiz let quiz = req.quiz
res.json(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) => { const quizById = async (req, res, next, id) => {
try { try {
const quiz = await Quiz.findById(id) const quiz = await Quiz.findById(id)
...@@ -67,9 +98,32 @@ const quizById = async (req, res, next, 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 { export default {
create, create,
read, read,
readProblem,
isAuthor, isAuthor,
isProblemAuthor,
listByUserId,
quizById, quizById,
problemById,
} }
\ No newline at end of file
...@@ -5,13 +5,18 @@ import quizCtrl from './quiz.controller.js' ...@@ -5,13 +5,18 @@ import quizCtrl from './quiz.controller.js'
const router = express.Router() const router = express.Router()
router.route('/api/quiz/:userId') router.route('/api/quiz/by/:userId')
.post(authCtrl.requireSignin, authCtrl.hasAuthorization, userCtrl.isInstructor, quizCtrl.create) .post(authCtrl.requireSignin, authCtrl.hasAuthorization, userCtrl.isInstructor, quizCtrl.create)
.get(authCtrl.requireSignin, authCtrl.hasAuthorization, quizCtrl.listByUserId)
router.route('/api/quiz/:quizId') router.route('/api/quiz/:quizId')
.get(authCtrl.requireSignin, quizCtrl.isAuthor, quizCtrl.read) .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('userId', userCtrl.userById)
router.param('quizId', quizCtrl.quizById) router.param('quizId', quizCtrl.quizById)
router.param('problemId', quizCtrl.problemById)
export default router export default router
\ No newline at end of file
...@@ -2,9 +2,11 @@ import User from './user.model.js' ...@@ -2,9 +2,11 @@ import User from './user.model.js'
import formidable from 'formidable' import formidable from 'formidable'
import extend from 'lodash/extend.js' import extend from 'lodash/extend.js'
import fs from 'fs' import fs from 'fs'
import dbErrorHandler from '../helpers/dbErrorHandler.js'
const create = async (req, res) => { const create = async (req, res) => {
const user = new User(req.body) const user = new User(req.body)
// console.log('user in user.controll:', req.body);
try { try {
await user.save() await user.save()
return res.json({ return res.json({
...@@ -12,7 +14,7 @@ const create = async (req, res) => { ...@@ -12,7 +14,7 @@ const create = async (req, res) => {
}) })
} catch (error) { } catch (error) {
return res.status(400).json({ return res.status(400).json({
error: 'User creation error' error: dbErrorHandler.getErrorMessage(error)
}) })
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment