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
8a0556fb
Commit
8a0556fb
authored
Sep 30, 2020
by
Yoon, Daeki
😅
Browse files
Problem Edit 수정중
parent
f21119fa
Changes
14
Hide whitespace changes
Inline
Side-by-side
src/client/src/MainRouter.jsx
View file @
8a0556fb
...
...
@@ -3,9 +3,11 @@ 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
'
import
Signup
from
"
./user/Signup
"
import
NewQuiz
from
"
./quiz/NewQuiz
"
;
import
Quiz
from
"
./quiz/Quiz
"
;
import
Signup
from
"
./user/Signup
"
;
import
Quizzes
from
"
./quiz/Quizzes
"
;
import
EditProblem
from
"
./quiz/EditProblem
"
;
function
MainRouter
()
{
return
(
...
...
@@ -13,7 +15,6 @@ function MainRouter() {
<
Menu
/>
<
Switch
>
<
Route
exact
path
=
"/"
>
{
/* {console.log('Home 안에서 ...')} */
}
<
Home
/>
</
Route
>
<
Route
path
=
"/signin"
>
...
...
@@ -22,17 +23,21 @@ function MainRouter() {
<
Route
path
=
"/signup"
>
<
Signup
/>
</
Route
>
<
Route
path
=
'
/quiz/new
'
>
<
Route
path
=
"
/quiz/new
"
>
<
NewQuiz
/>
</
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
/>
</
Route
>
</
Switch
>
</
div
>
// <BrowserRouter>
// {console.log('BrowserRoter 안에서 ...')}
// </BrowserRouter>
);
}
...
...
src/client/src/core/Menu.jsx
View file @
8a0556fb
...
...
@@ -20,6 +20,7 @@ function Menu() {
<
Navbar
.
Collapse
id
=
"basic-navbar-nav"
>
<
Nav
className
=
"mr-auto"
>
<
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
>
<
NavDropdown
title
=
"Dropdown"
id
=
"basic-nav-dropdown"
>
<
NavDropdown
.
Item
href
=
"#action/3.1"
>
Action
</
NavDropdown
.
Item
>
...
...
src/client/src/quiz/EditProblem.jsx
View file @
8a0556fb
import
React
from
'
react
'
import
React
,
{
useState
,
useEffect
}
from
"
react
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
function
EditProblem
()
{
return
(
<
div
>
</
div
>
)
const
{
problemId
}
=
useParams
();
const
[
problem
,
setProblem
]
=
useState
({});
useEffect
(()
=>
{
return
()
=>
{};
},
[
problemId
]);
return
<
div
>
문제를 수정합니다. id:
{
problemId
}
</
div
>;
}
export
default
EditProblem
export
default
EditProblem
;
src/client/src/quiz/NewQuiz.jsx
View file @
8a0556fb
...
...
@@ -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
(
<
div
>
<
h1
className
=
"text-center"
>
Quiz
List
New
Quiz
</
h1
>
<
label
htmlFor
=
'title'
>
Title
</
label
>
<
input
id
=
'title'
name
=
'title'
onChange
=
{
handleChange
}
placeholder
=
'Title'
/>
{
problems
.
map
((
problem
,
index
)
=>
{
return
<
Problem
key
=
{
index
}
problem
=
{
problem
}
/>
return
<
Problem
key
=
{
index
}
problem
=
{
problem
}
number
=
{
index
+
1
}
/>
})
}
<
NewProblem
addProblem
=
{
addProblem
}
/>
...
...
src/client/src/quiz/Problem.jsx
View file @
8a0556fb
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
(
<
Card
>
<
Card
.
Body
>
<
Card
.
Title
>
{
number
}
번.
{
problem
.
question
}
{
number
+
1
}
번.
{
problem
.
question
}
</
Card
.
Title
>
Answers
{
problem
.
answers
.
map
((
answer
,
index
)
=>
{
return
<
Card
.
Text
key
=
{
index
}
>
{
answer
}
</
Card
.
Text
>;
})
}
<
Button
>
수정
</
Button
>
<
Button
>
삭제
</
Button
>
<
Link
to
=
{
`/quiz/problem/edit/
${
problem
.
_id
}
`
}
>
<
Button
onClick
=
{
(
event
)
=>
onUpdate
(
number
)
}
>
수정
</
Button
>
</
Link
>
<
Button
onClick
=
{
onRemove
}
>
삭제
</
Button
>
</
Card
.
Body
>
</
Card
>
);
...
...
src/client/src/quiz/Quiz.jsx
View file @
8a0556fb
...
...
@@ -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
(
<
div
>
<
h2
>
제목:
{
quiz
.
title
}
</
h2
>
{
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
>
);
...
...
src/client/src/quiz/Quizzes.jsx
0 → 100644
View file @
8a0556fb
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
;
src/client/src/quiz/api-quiz.js
View file @
8a0556fb
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
src/client/src/user/Signup.jsx
View file @
8a0556fb
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
(
<
div
>
<
Form
>
<
Form
.
Group
>
<
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
.
Label
>
Password
</
Form
.
Label
>
<
Form
.
Control
type
=
'password'
placeholder
=
'Password'
/>
<
Form
.
Control
type
=
"password"
placeholder
=
"Password"
onChange
=
{
handleChange
(
'
password
'
)
}
/>
</
Form
.
Group
>
<
Form
.
Group
>
<
Form
.
Label
>
Email
</
Form
.
Label
>
<
Form
.
Control
type
=
'email'
placeholder
=
'Email'
/>
<
Form
.
Control
type
=
"email"
placeholder
=
"Email"
onChange
=
{
handleChange
(
'
email
'
)
}
/>
</
Form
.
Group
>
<
Button
>
확인
</
Button
>
<
Button
onClick
=
{
handleSubmit
}
>
확인
</
Button
>
</
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
>
)
)
;
}
export
default
Signup
export
default
Signup
;
src/server/helpers/dbErrorHandler.js
0 → 100644
View file @
8a0556fb
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
src/server/quiz/problem.model.js
View file @
8a0556fb
import
mongoose
from
'
mongoose
'
const
ProblemSchema
=
new
mongoose
.
Schema
({
author
:
{
type
:
mongoose
.
SchemaTypes
.
ObjectId
,
ref
:
'
User
'
},
type
:
String
,
// 객관식, 주관식 single/multiple choice
created
:
{
type
:
Date
,
...
...
src/server/quiz/quiz.controller.js
View file @
8a0556fb
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
src/server/quiz/quiz.routes.js
View file @
8a0556fb
...
...
@@ -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
src/server/user/user.controller.js
View file @
8a0556fb
...
...
@@ -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
)
})
}
}
...
...
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