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

edit problem중

parent 08ce2115
{
"watch": ["src/server"],
"env": {
"NODE_ENV": "development"
}
}
\ No newline at end of file
......@@ -3,6 +3,8 @@ import { Route, Switch } from "react-router-dom";
import Signin from "./auth/Signin";
import Home from "./core/Home";
import Menu from "./core/Menu";
import NewQuiz from './quiz/NewQuiz'
import Quiz from './quiz/Quiz'
function MainRouter() {
return (
......@@ -16,6 +18,12 @@ function MainRouter() {
<Route path="/signin">
<Signin />
</Route>
<Route path='/quiz/new'>
<NewQuiz />
</Route>
<Route path="/quiz/:quizId">
<Quiz />
</Route>
</Switch>
</div>
// <BrowserRouter>
......
......@@ -14,13 +14,13 @@ function Menu() {
return (
<Navbar sticky="top" bg="dark" variant="dark" expand="sm">
<Navbar.Brand href="/">
<i className="fas fa-child fa-2x"></i>
<i className="fas fa-diagnoses fa-2x"></i>
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#link">Link</Nav.Link>
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link href="/quiz/new">New Quiz</Nav.Link>
<NavDropdown title="Dropdown" id="basic-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">
......
import React from 'react'
function EditProblem() {
return (
<div>
</div>
)
}
export default EditProblem
import React, { useState } from "react";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import Col from "react-bootstrap/Col";
function NewProblem({ addProblem }) {
const [answers, setAnswers] = useState([""]);
const [question, setQuestion] = useState("");
const addAnswer = () => {
setAnswers([...answers, ""]);
};
const removeAnswer = (index) => {
const list = [...answers];
list.splice(index, 1);
setAnswers(list);
};
const handleAnswer = (event, index) => {
const { value } = event.target;
const list = [...answers];
list[index] = value;
setAnswers(list);
};
const handleQuestion = (event) => {
setQuestion(event.target.value);
};
const clickAdd = (event) => {
event.preventDefault();
addProblem({ question, answers });
};
return (
<div>
<Form>
<Form.Group controlId="question">
<Form.Label>Question</Form.Label>
<Form.Control
name="question"
as="textarea"
rows={5}
onChange={handleQuestion}
/>
</Form.Group>
<Form.Label>Answers</Form.Label>
{answers.map((answer, index) => {
return (
<Form.Row key={index}>
<Col>
<Form.Control
type="text"
value={answer}
onChange={(event) => handleAnswer(event, index)}
/>
</Col>
<Col>
{answers.length !== 1 && (
<Button onClick={removeAnswer}>Remove</Button>
)}
{answers.length - 1 === index && (
<Button onClick={addAnswer}>Add</Button>
)}
</Col>
</Form.Row>
);
})}
<Button onClick={clickAdd}>Add</Button>
</Form>
</div>
);
}
export default NewProblem;
import React, { useState } from "react";
import Button from "react-bootstrap/Button";
import authHelpers from "../auth/auth-helpers";
import { create } from "./api-quiz";
import NewProblem from "./NewProblem";
import Problem from "./Problem";
function NewQuiz() {
const [problems, setProblems] = useState([])
const jwt = authHelpers.isAuthenticated();
const addProblem = (problem) => {
console.log(problem)
setProblems([...problems, problem])
}
const clickSubmit = (event) => {
event.preventDefault();
const quizData = {
problems
}
create({ userId: jwt.user._id }, { t: jwt.token }, quizData).then(
(data) => {
if (data.error) {
console.log(data.error);
} else {
console.log(data);
}
}
);
};
return (
<div>
<h1 className="text-center">
Quiz List
</h1>
{
problems.map((problem, index) => {
return <Problem key={index} problem={problem} />
})
}
<NewProblem addProblem={addProblem} />
<Button onClick={clickSubmit}>퀴즈 저장</Button>
</div>
);
}
export default NewQuiz;
import React from "react";
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
function Problem({ problem, number }) {
return (
<Card>
<Card.Body>
<Card.Title>
{number}번. {problem.question}
</Card.Title>
Answers
{problem.answers.map((answer, index) => {
return <Card.Text key={index}>{answer}</Card.Text>;
})}
<Button>수정</Button>
<Button>삭제</Button>
</Card.Body>
</Card>
);
}
export default Problem;
import React from 'react'
function Problems() {
return (
<div>
</div>
)
}
export default Problems
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { read } from "./api-quiz";
import auth from "../auth/auth-helpers";
import Problem from './Problem'
function Quiz() {
const { quizId } = useParams();
const [quiz, setQuiz] = useState({});
const jwt = auth.isAuthenticated();
useEffect(() => {
const abortController = new AbortController();
const signal = abortController.signal;
read({ quizId: quizId }, { t: jwt.token }, signal).then((data) => {
if (data.error) {
console.log(data.error);
} else {
setQuiz(data);
}
});
return () => {
abortController.abort();
};
}, [quizId]);
return (
<div>
{quiz.problems?.map((problem, i) => {
return <Problem key={i} problem={problem} number={i+1} />;
})}
</div>
);
}
export default Quiz;
const create = async (params, credentials, quiz) => {
try {
let response = await fetch('/api/quiz/' + params.userId, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + credentials.t,
},
body: JSON.stringify(quiz),
})
return await response.json()
} catch (error) {
console.log(error)
}
}
const read = async (params, credentials, signal) => {
try {
let response = await fetch('/api/quiz/' + params.quizId, {
method: 'GET',
signal: signal,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + credentials.t,
},
})
return await response.json()
} catch (error) {
console.log(error)
}
}
export {
create,
read,
}
\ No newline at end of file
import mongoose from 'mongoose'
const AnswerSchema = new mongoose.Schema({
questionId: {
problemId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Question',
ref: 'Problem',
},
type: String, // single/multiple choice?
score: Number, // 맞힌 점수
points: Number, // Question.score와 자동 연결 필요
points: Number, // Problem.score와 자동 연결 필요
content: String, // 기록한 답
})
......
import mongoose from 'mongoose'
const QuestionSchema = new mongoose.Schema({
const ProblemSchema = new mongoose.Schema({
type: String, // 객관식, 주관식 single/multiple choice
created: {
type: Date,
......@@ -10,12 +10,12 @@ const QuestionSchema = new mongoose.Schema({
level: String,
category: [String],
score: Number, //문제당 할당 점수
content: String, //질문
choices: [String], // 선택형 항목
question: String, //질문
answers: [String], // 선택형 항목
correct: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Answer'
}, // 정답; Answer Model 객체
})
export default mongoose.model('Question', QuestionSchema)
\ No newline at end of file
export default mongoose.model('Problem', ProblemSchema)
\ No newline at end of file
import formidable from 'formidable'
import fs from 'fs'
import quizModel from './quiz.model.js'
import Problem from './problem.model.js'
import Quiz from './quiz.model.js'
const create = async (req, res) => {
const form = new formidable.IncomingForm()
form.keepExtensions = true
form.parse(req, async (err, fields, files) => {
if (err) {
try {
const { problems } = req.body
const quiz = new Quiz()
// console.log('quiz in quiz.controller:', quiz);
for await (let problem of problems) {
// console.log('problem in quiz.controller:', problem);
const p = new Problem(problem)
// console.log('problem in quiz.controller:', p);
await p.save()
quiz.problems.push(p._id)
}
quiz.author = req.profile
// console.log('quiz in quiz.controller:', quiz);
await quiz.save()
quiz.author.hashedPassword = undefined
quiz.author.salt = undefined
res.json(quiz)
} catch (error) {
return res.status(400).json({
error: 'Image could not be uploaded'
error: 'Quiz save DB error' + error
})
}
}
const quiz = new quizModel(fields)
quiz.author = req.profile
if (files.image) {
quiz.image.data = fs.readFileSync(files.image.path)
quiz.image.contentType = files.image.type
const isAuthor = (req, res, next) => {
const isAuthor = req.auth && req.quiz && req.auth._id == req.quiz.author._id
if (!isAuthor) {
return res.status(403).json({
error: 'User is not an author'
})
}
next()
}
const read = async (req, res) => {
let quiz = req.quiz
res.json(quiz)
}
const quizById = async (req, res, next, id) => {
try {
const result = await quiz.save()
res.json(result)
} catch (error) {
const quiz = await Quiz.findById(id)
.populate('author', '_id name')
.populate('problems')
.exec()
if (!quiz) {
return res.status(400).json({
error: 'Quiz save db error'
error: 'Quiz not found'
})
}
req.quiz = quiz
next()
} catch (error) {
return res.status(400).json({
error: 'Quiz by id query db error: ' + error
})
}
}
export default {
create,
read,
isAuthor,
quizById,
}
\ No newline at end of file
......@@ -16,7 +16,10 @@ const QuizSchema = new mongoose.Schema({
publishedAt: Date,
startAt: Date,
endAt: Date,
questions: [], // Question Schemas
problems: [{
type: mongoose.SchemaTypes.ObjectId,
ref: 'Problem'
}], // Problem Schemas
image: {
type: Buffer,
contentType: String,
......
......@@ -8,6 +8,10 @@ const router = express.Router()
router.route('/api/quiz/:userId')
.post(authCtrl.requireSignin, authCtrl.hasAuthorization, userCtrl.isInstructor, quizCtrl.create)
router.route('/api/quiz/:quizId')
.get(authCtrl.requireSignin, quizCtrl.isAuthor, quizCtrl.read)
router.param('userId', userCtrl.userById)
router.param('quizId', quizCtrl.quizById)
export default router
\ No newline at end of file
......@@ -89,6 +89,7 @@ const isInstructor = (req, res, next) => {
}
const userById = async (req, res, next, id) => {
// console.log('req.body in userById', req.body);
try {
let user = await User.findById(id)
.exec()
......
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