Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
students
quiz-competition
Commits
75cdec2c
Commit
75cdec2c
authored
Sep 30, 2020
by
Yoon, Daeki
😅
Browse files
quiz 문제 수정, 삭제까지
parent
8a0556fb
Changes
10
Show whitespace changes
Inline
Side-by-side
src/client/src/MainRouter.jsx
View file @
75cdec2c
...
...
@@ -8,6 +8,7 @@ import Quiz from "./quiz/Quiz";
import
Signup
from
"
./user/Signup
"
;
import
Quizzes
from
"
./quiz/Quizzes
"
;
import
EditProblem
from
"
./quiz/EditProblem
"
;
import
NewProblem
from
"
./quiz/NewProblem
"
;
function
MainRouter
()
{
return
(
...
...
@@ -29,6 +30,9 @@ function MainRouter() {
<
Route
path
=
"/quiz/by/:userId"
>
<
Quizzes
/>
</
Route
>
{
/* <Route path="/quiz/problem/new/:quizId">
<NewProblem />
</Route> */
}
<
Route
path
=
"/quiz/problem/edit/:problemId"
>
<
EditProblem
/>
</
Route
>
...
...
src/client/src/quiz/EditProblem.jsx
View file @
75cdec2c
import
React
,
{
useState
,
useEffect
}
from
"
react
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
import
{
Link
,
useParams
}
from
"
react-router-dom
"
;
import
Form
from
"
react-bootstrap/Form
"
;
import
Col
from
"
react-bootstrap/Col
"
;
import
Button
from
"
react-bootstrap/Button
"
;
import
Modal
from
'
react-bootstrap/Modal
'
import
authHelpers
from
"
../auth/auth-helpers
"
;
import
{
readProblem
,
updateProblem
}
from
"
./api-quiz
"
;
function
EditProblem
()
{
const
{
problemId
}
=
useParams
();
const
[
problem
,
setProblem
]
=
useState
({});
const
[
problem
,
setProblem
]
=
useState
({
show
:
false
});
const
jwt
=
authHelpers
.
isAuthenticated
();
useEffect
(()
=>
{
return
()
=>
{};
const
abortController
=
new
AbortController
();
const
signal
=
abortController
.
signal
;
readProblem
({
problemId
},
{
t
:
jwt
.
token
},
signal
).
then
((
data
)
=>
{
if
(
data
.
error
)
{
console
.
log
(
data
.
error
);
}
else
{
console
.
log
(
data
);
setProblem
(
data
);
}
});
return
()
=>
{
abortController
.
abort
();
};
},
[
problemId
]);
return
<
div
>
문제를 수정합니다. id:
{
problemId
}
</
div
>;
const
addAnswer
=
()
=>
{
setProblem
({...
problem
,
answers
:
[...
problem
.
answers
,
''
]})
};
const
removeAnswer
=
(
index
)
=>
{
const
list
=
[...
problem
.
answers
];
list
.
splice
(
index
,
1
);
setProblem
({...
problem
,
answers
:
list
})
};
const
handleAnswer
=
(
event
,
index
)
=>
{
const
{
value
}
=
event
.
target
;
const
list
=
[...
problem
.
answers
];
list
[
index
]
=
value
;
setProblem
({...
problem
,
answers
:
list
})
};
const
handleQuestion
=
(
event
)
=>
{
const
{
value
}
=
event
.
target
setProblem
({...
problem
,
question
:
value
})
};
const
handleSave
=
(
event
)
=>
{
event
.
preventDefault
();
console
.
log
(
problem
);
updateProblem
({
problemId
},
{
t
:
jwt
.
token
},
problem
).
then
(
data
=>
{
if
(
data
.
error
)
{
console
.
log
(
data
.
error
);
}
else
{
console
.
log
(
data
);
setProblem
({...
data
,
show
:
true
})
}
})
};
return
(
<
div
>
문제를 수정합니다. id:
{
problemId
}
<
Form
>
<
Form
.
Group
controlId
=
"question"
>
<
Form
.
Label
>
Question
</
Form
.
Label
>
<
Form
.
Control
name
=
"question"
as
=
"textarea"
value
=
{
problem
.
question
}
rows
=
{
5
}
onChange
=
{
handleQuestion
}
/>
</
Form
.
Group
>
<
Form
.
Label
>
Answers
</
Form
.
Label
>
{
problem
.
answers
?.
map
((
answer
,
index
)
=>
{
return
(
<
Form
.
Row
key
=
{
index
}
>
<
Col
>
<
Form
.
Control
type
=
"text"
value
=
{
answer
}
onChange
=
{
(
event
)
=>
handleAnswer
(
event
,
index
)
}
/>
</
Col
>
<
Col
>
{
problem
.
answers
.
length
!==
1
&&
(
<
Button
onClick
=
{
()
=>
removeAnswer
(
index
)
}
>
Remove
</
Button
>
)
}
{
problem
.
answers
.
length
-
1
===
index
&&
(
<
Button
onClick
=
{
addAnswer
}
>
Add
</
Button
>
)
}
</
Col
>
</
Form
.
Row
>
);
})
}
<
Button
onClick
=
{
handleSave
}
>
저장
</
Button
>
</
Form
>
<
Modal
show
=
{
problem
.
show
}
>
<
Modal
.
Header
>
<
Modal
.
Title
>
Edit Problem
</
Modal
.
Title
>
</
Modal
.
Header
>
<
Modal
.
Body
>
Problem successfully modified.
</
Modal
.
Body
>
<
Modal
.
Footer
>
<
Link
to
=
{
`/quiz/
${
problem
.
quiz
}
`
}
>
<
Button
>
Go to quiz
</
Button
>
</
Link
>
</
Modal
.
Footer
>
</
Modal
>
</
div
>
);
}
export
default
EditProblem
;
src/client/src/quiz/NewProblem.jsx
View file @
75cdec2c
...
...
@@ -2,8 +2,10 @@ import React, { useState } from "react";
import
Button
from
"
react-bootstrap/Button
"
;
import
Form
from
"
react-bootstrap/Form
"
;
import
Col
from
"
react-bootstrap/Col
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
function
NewProblem
({
addProblem
})
{
const
{
quizId
}
=
useParams
();
const
[
answers
,
setAnswers
]
=
useState
([
""
]);
const
[
question
,
setQuestion
]
=
useState
(
""
);
...
...
@@ -58,7 +60,7 @@ function NewProblem({ addProblem }) {
</
Col
>
<
Col
>
{
answers
.
length
!==
1
&&
(
<
Button
onClick
=
{
removeAnswer
}
>
Remove
</
Button
>
<
Button
onClick
=
{
()
=>
removeAnswer
(
index
)
}
>
Remove
</
Button
>
)
}
{
answers
.
length
-
1
===
index
&&
(
<
Button
onClick
=
{
addAnswer
}
>
Add
</
Button
>
...
...
@@ -67,7 +69,7 @@ function NewProblem({ addProblem }) {
</
Form
.
Row
>
);
})
}
<
Button
onClick
=
{
clickAdd
}
>
Add
</
Button
>
<
Button
onClick
=
{
clickAdd
}
>
문제 추가
</
Button
>
</
Form
>
</
div
>
);
...
...
src/client/src/quiz/NewQuiz.jsx
View file @
75cdec2c
import
React
,
{
useState
}
from
"
react
"
;
import
Button
from
"
react-bootstrap/Button
"
;
import
Form
from
"
react-bootstrap/Form
"
;
import
Col
from
"
react-bootstrap/Col
"
;
import
authHelpers
from
"
../auth/auth-helpers
"
;
import
{
create
}
from
"
./api-quiz
"
;
import
NewProblem
from
"
./NewProblem
"
;
//
import NewProblem from "./NewProblem";
import
Problem
from
"
./Problem
"
;
function
NewQuiz
()
{
...
...
@@ -51,13 +53,84 @@ function NewQuiz() {
<
input
id
=
'title'
name
=
'title'
onChange
=
{
handleChange
}
placeholder
=
'Title'
/>
{
problems
.
map
((
problem
,
index
)
=>
{
return
<
Problem
key
=
{
index
}
problem
=
{
problem
}
number
=
{
index
+
1
}
/>
return
<
Problem
key
=
{
index
}
problem
=
{
problem
}
number
=
{
index
}
/>
})
}
<
NewProblem
addProblem
=
{
addProblem
}
/>
<
New
Quiz
Problem
addProblem
=
{
addProblem
}
/>
<
Button
onClick
=
{
clickSubmit
}
>
퀴즈 저장
</
Button
>
</
div
>
);
}
export
default
NewQuiz
;
function
NewQuizProblem
({
addProblem
})
{
// const { quizId } = useParams();
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
(
index
)
}
>
Remove
</
Button
>
)
}
{
answers
.
length
-
1
===
index
&&
(
<
Button
onClick
=
{
addAnswer
}
>
Add
</
Button
>
)
}
</
Col
>
</
Form
.
Row
>
);
})
}
<
Button
onClick
=
{
clickAdd
}
>
문제 추가
</
Button
>
</
Form
>
</
div
>
);
}
src/client/src/quiz/Problem.jsx
View file @
75cdec2c
...
...
@@ -17,7 +17,7 @@ function Problem({ problem, number, onUpdate, onRemove }) {
<
Link
to
=
{
`/quiz/problem/edit/
${
problem
.
_id
}
`
}
>
<
Button
onClick
=
{
(
event
)
=>
onUpdate
(
number
)
}
>
수정
</
Button
>
</
Link
>
<
Button
onClick
=
{
onRemove
}
>
삭제
</
Button
>
<
Button
onClick
=
{
()
=>
onRemove
(
number
)
}
>
삭제
</
Button
>
</
Card
.
Body
>
</
Card
>
);
...
...
src/client/src/quiz/Quiz.jsx
View file @
75cdec2c
import
React
,
{
useState
,
useEffect
}
from
"
react
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
import
{
read
}
from
"
./api-quiz
"
;
import
{
Link
,
useParams
}
from
"
react-router-dom
"
;
import
{
read
,
removeProblem
}
from
"
./api-quiz
"
;
import
auth
from
"
../auth/auth-helpers
"
;
import
Problem
from
'
./Problem
'
import
Button
from
"
react-bootstrap/Button
"
;
function
Quiz
()
{
const
{
quizId
}
=
useParams
();
...
...
@@ -31,8 +32,20 @@ function Quiz() {
console
.
log
(
`Quiz에서 handleUpdate
${
JSON
.
stringify
(
quiz
.
problems
[
index
])}
`
);
}
const
handleRemove
=
()
=>
{
const
handleRemove
=
(
index
)
=>
{
console
.
log
(
'
Quiz에서 handleRemove 실행
'
);
const
problem
=
quiz
.
problems
[
index
]
console
.
log
(
problem
);
removeProblem
({
problemId
:
problem
.
_id
},
{
t
:
jwt
.
token
}).
then
(
data
=>
{
if
(
data
.
error
)
{
console
.
log
(
data
.
error
);
}
else
{
console
.
log
(
'
deleted Problem:
'
,
data
);
const
list
=
[...
quiz
.
problems
]
list
.
splice
(
index
,
1
)
setQuiz
({...
quiz
,
problems
:
list
})
}
})
}
return
(
...
...
@@ -41,6 +54,9 @@ function Quiz() {
{
quiz
.
problems
?.
map
((
problem
,
i
)
=>
{
return
<
Problem
key
=
{
i
}
problem
=
{
problem
}
number
=
{
i
}
onUpdate
=
{
handleUpdate
}
onRemove
=
{
handleRemove
}
/>;
})
}
<
Link
to
=
{
`/quiz/problem/new/
${
quizId
}
`
}
>
<
Button
>
문제 추가
</
Button
>
</
Link
>
</
div
>
);
}
...
...
src/client/src/quiz/api-quiz.js
View file @
75cdec2c
...
...
@@ -33,6 +33,56 @@ const read = async (params, credentials, signal) => {
}
}
const
readProblem
=
async
(
params
,
credentials
,
signal
)
=>
{
try
{
let
response
=
await
fetch
(
'
/api/quiz/problem/
'
+
params
.
problemId
,
{
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
)
}
}
const
updateProblem
=
async
(
params
,
credentials
,
problem
)
=>
{
try
{
let
response
=
await
fetch
(
'
/api/quiz/problem/
'
+
params
.
problemId
,
{
method
:
'
PUT
'
,
headers
:
{
'
Accept
'
:
'
application/json
'
,
'
Content-Type
'
:
'
application/json
'
,
'
Authorization
'
:
'
Bearer
'
+
credentials
.
t
,
},
body
:
JSON
.
stringify
(
problem
)
})
return
await
response
.
json
()
}
catch
(
error
)
{
console
.
log
(
error
)
}
}
const
removeProblem
=
async
(
params
,
credentials
)
=>
{
try
{
let
response
=
await
fetch
(
'
/api/quiz/problem/
'
+
params
.
problemId
,
{
method
:
'
DELETE
'
,
headers
:
{
'
Accept
'
:
'
application/json
'
,
'
Authorization
'
:
'
Bearer
'
+
credentials
.
t
,
}
})
return
await
response
.
json
()
}
catch
(
error
)
{
console
.
log
(
error
)
}
}
const
listByUserId
=
async
(
params
,
credentials
,
signal
)
=>
{
try
{
let
response
=
await
fetch
(
'
/api/quiz/by/
'
+
params
.
userId
,
{
...
...
@@ -52,5 +102,8 @@ const listByUserId = async (params, credentials, signal) => {
export
{
create
,
read
,
readProblem
,
updateProblem
,
removeProblem
,
listByUserId
,
}
\ No newline at end of file
src/server/quiz/problem.model.js
View file @
75cdec2c
...
...
@@ -5,6 +5,10 @@ const ProblemSchema = new mongoose.Schema({
type
:
mongoose
.
SchemaTypes
.
ObjectId
,
ref
:
'
User
'
},
quiz
:
{
type
:
mongoose
.
SchemaTypes
.
ObjectId
,
ref
:
'
Quiz
'
},
type
:
String
,
// 객관식, 주관식 single/multiple choice
created
:
{
type
:
Date
,
...
...
src/server/quiz/quiz.controller.js
View file @
75cdec2c
...
...
@@ -16,6 +16,7 @@ const create = async (req, res) => {
const
p
=
new
Problem
(
problem
)
// console.log('problem in quiz.controller:', p);
p
.
author
=
req
.
profile
p
.
quiz
=
quiz
.
_id
await
p
.
save
()
quiz
.
problems
.
push
(
p
.
_id
)
}
...
...
@@ -65,6 +66,38 @@ const readProblem = async (req, res) => {
res
.
json
(
problem
)
}
const
updateProblem
=
async
(
req
,
res
)
=>
{
try
{
const
problem
=
req
.
problem
console
.
log
(
'
req.body in updateProblem in quiz.controller
'
,
req
.
body
);
problem
.
question
=
req
.
body
.
question
problem
.
answers
=
req
.
body
.
answers
problem
.
updated
=
new
Date
()
console
.
log
(
'
updated problem in updateProblem in quiz.controller
'
,
problem
);
await
problem
.
save
()
res
.
json
(
problem
)
}
catch
(
error
)
{
return
res
.
status
(
400
).
json
({
error
:
dbErrorHandler
.
getErrorMessage
(
error
)
})
}
}
const
removeProblem
=
async
(
req
,
res
)
=>
{
try
{
const
problem
=
req
.
problem
await
Quiz
.
findByIdAndUpdate
(
problem
.
quiz
,
{
$pull
:
{
problems
:
problem
.
_id
}
})
const
deletedProblem
=
await
problem
.
remove
()
res
.
json
(
deletedProblem
)
}
catch
(
error
)
{
return
res
.
status
(
400
).
json
({
error
:
dbErrorHandler
.
getErrorMessage
(
error
)
})
}
}
const
listByUserId
=
async
(
req
,
res
)
=>
{
try
{
const
authorId
=
req
.
profile
.
_id
...
...
@@ -121,6 +154,8 @@ export default {
create
,
read
,
readProblem
,
updateProblem
,
removeProblem
,
isAuthor
,
isProblemAuthor
,
listByUserId
,
...
...
src/server/quiz/quiz.routes.js
View file @
75cdec2c
...
...
@@ -14,6 +14,8 @@ router.route('/api/quiz/:quizId')
router
.
route
(
'
/api/quiz/problem/:problemId
'
)
.
get
(
authCtrl
.
requireSignin
,
quizCtrl
.
isProblemAuthor
,
quizCtrl
.
readProblem
)
.
put
(
authCtrl
.
requireSignin
,
quizCtrl
.
isProblemAuthor
,
quizCtrl
.
updateProblem
)
.
delete
(
authCtrl
.
requireSignin
,
quizCtrl
.
isProblemAuthor
,
quizCtrl
.
removeProblem
)
router
.
param
(
'
userId
'
,
userCtrl
.
userById
)
router
.
param
(
'
quizId
'
,
quizCtrl
.
quizById
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment