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
abd187d8
Commit
abd187d8
authored
Sep 29, 2020
by
Yoon, Daeki
😅
Browse files
edit problem중
parent
08ce2115
Changes
16
Show whitespace changes
Inline
Side-by-side
nodemon.json
0 → 100644
View file @
abd187d8
{
"watch"
:
[
"src/server"
],
"env"
:
{
"NODE_ENV"
:
"development"
}
}
\ No newline at end of file
src/client/src/MainRouter.jsx
View file @
abd187d8
...
@@ -3,6 +3,8 @@ import { Route, Switch } from "react-router-dom";
...
@@ -3,6 +3,8 @@ 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
Quiz
from
'
./quiz/Quiz
'
function
MainRouter
()
{
function
MainRouter
()
{
return
(
return
(
...
@@ -16,6 +18,12 @@ function MainRouter() {
...
@@ -16,6 +18,12 @@ function MainRouter() {
<
Route
path
=
"/signin"
>
<
Route
path
=
"/signin"
>
<
Signin
/>
<
Signin
/>
</
Route
>
</
Route
>
<
Route
path
=
'/quiz/new'
>
<
NewQuiz
/>
</
Route
>
<
Route
path
=
"/quiz/:quizId"
>
<
Quiz
/>
</
Route
>
</
Switch
>
</
Switch
>
</
div
>
</
div
>
// <BrowserRouter>
// <BrowserRouter>
...
...
src/client/src/core/Menu.jsx
View file @
abd187d8
...
@@ -14,13 +14,13 @@ function Menu() {
...
@@ -14,13 +14,13 @@ function Menu() {
return
(
return
(
<
Navbar
sticky
=
"top"
bg
=
"dark"
variant
=
"dark"
expand
=
"sm"
>
<
Navbar
sticky
=
"top"
bg
=
"dark"
variant
=
"dark"
expand
=
"sm"
>
<
Navbar
.
Brand
href
=
"/"
>
<
Navbar
.
Brand
href
=
"/"
>
<
i
className
=
"fas fa-
child
fa-2x"
></
i
>
<
i
className
=
"fas fa-
diagnoses
fa-2x"
></
i
>
</
Navbar
.
Brand
>
</
Navbar
.
Brand
>
<
Navbar
.
Toggle
aria
-
controls
=
"basic-navbar-nav"
/>
<
Navbar
.
Toggle
aria
-
controls
=
"basic-navbar-nav"
/>
<
Navbar
.
Collapse
id
=
"basic-navbar-nav"
>
<
Navbar
.
Collapse
id
=
"basic-navbar-nav"
>
<
Nav
className
=
"mr-auto"
>
<
Nav
className
=
"mr-auto"
>
<
Nav
.
Link
href
=
"
#home
"
>
Home
</
Nav
.
Link
>
<
Nav
.
Link
href
=
"
/
"
>
Home
</
Nav
.
Link
>
<
Nav
.
Link
href
=
"
#link"
>
Link
</
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
>
<
NavDropdown
.
Item
href
=
"#action/3.2"
>
<
NavDropdown
.
Item
href
=
"#action/3.2"
>
...
...
src/client/src/quiz/EditProblem.jsx
0 → 100644
View file @
abd187d8
import
React
from
'
react
'
function
EditProblem
()
{
return
(
<
div
>
</
div
>
)
}
export
default
EditProblem
src/client/src/quiz/NewProblem.jsx
0 → 100644
View file @
abd187d8
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
;
src/client/src/quiz/NewQuiz.jsx
0 → 100644
View file @
abd187d8
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
;
src/client/src/quiz/Problem.jsx
0 → 100644
View file @
abd187d8
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
;
src/client/src/quiz/Problems.jsx
0 → 100644
View file @
abd187d8
import
React
from
'
react
'
function
Problems
()
{
return
(
<
div
>
</
div
>
)
}
export
default
Problems
src/client/src/quiz/Quiz.jsx
0 → 100644
View file @
abd187d8
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
;
src/client/src/quiz/api-quiz.js
0 → 100644
View file @
abd187d8
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
src/server/quiz/answer.model.js
View file @
abd187d8
import
mongoose
from
'
mongoose
'
import
mongoose
from
'
mongoose
'
const
AnswerSchema
=
new
mongoose
.
Schema
({
const
AnswerSchema
=
new
mongoose
.
Schema
({
question
Id
:
{
problem
Id
:
{
type
:
mongoose
.
Schema
.
Types
.
ObjectId
,
type
:
mongoose
.
Schema
.
Types
.
ObjectId
,
ref
:
'
Question
'
,
ref
:
'
Problem
'
,
},
},
type
:
String
,
// single/multiple choice?
type
:
String
,
// single/multiple choice?
score
:
Number
,
// 맞힌 점수
score
:
Number
,
// 맞힌 점수
points
:
Number
,
//
Question
.score와 자동 연결 필요
points
:
Number
,
//
Problem
.score와 자동 연결 필요
content
:
String
,
// 기록한 답
content
:
String
,
// 기록한 답
})
})
...
...
src/server/quiz/
question
.model.js
→
src/server/quiz/
problem
.model.js
View file @
abd187d8
import
mongoose
from
'
mongoose
'
import
mongoose
from
'
mongoose
'
const
Question
Schema
=
new
mongoose
.
Schema
({
const
Problem
Schema
=
new
mongoose
.
Schema
({
type
:
String
,
// 객관식, 주관식 single/multiple choice
type
:
String
,
// 객관식, 주관식 single/multiple choice
created
:
{
created
:
{
type
:
Date
,
type
:
Date
,
...
@@ -10,12 +10,12 @@ const QuestionSchema = new mongoose.Schema({
...
@@ -10,12 +10,12 @@ const QuestionSchema = new mongoose.Schema({
level
:
String
,
level
:
String
,
category
:
[
String
],
category
:
[
String
],
score
:
Number
,
//문제당 할당 점수
score
:
Number
,
//문제당 할당 점수
content
:
String
,
//질문
question
:
String
,
//질문
choice
s
:
[
String
],
// 선택형 항목
answer
s
:
[
String
],
// 선택형 항목
correct
:
{
correct
:
{
type
:
mongoose
.
Schema
.
Types
.
ObjectId
,
type
:
mongoose
.
Schema
.
Types
.
ObjectId
,
ref
:
'
Answer
'
ref
:
'
Answer
'
},
// 정답; Answer Model 객체
},
// 정답; Answer Model 객체
})
})
export
default
mongoose
.
model
(
'
Question
'
,
QuestionSchema
)
export
default
mongoose
.
model
(
'
Problem
'
,
ProblemSchema
)
\ No newline at end of file
\ No newline at end of file
src/server/quiz/quiz.controller.js
View file @
abd187d8
import
formidable
from
'
formidable
'
import
formidable
from
'
formidable
'
import
fs
from
'
fs
'
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
create
=
async
(
req
,
res
)
=>
{
const
form
=
new
formidable
.
IncomingForm
()
try
{
form
.
keepExtensions
=
true
const
{
problems
}
=
req
.
body
form
.
parse
(
req
,
async
(
err
,
fields
,
files
)
=>
{
if
(
err
)
{
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
({
return
res
.
status
(
400
).
json
({
error
:
'
Image could not be uploaded
'
error
:
'
Quiz save DB error
'
+
error
})
})
}
}
}
const
quiz
=
new
quizModel
(
fields
)
const
isAuthor
=
(
req
,
res
,
next
)
=>
{
quiz
.
author
=
req
.
profile
const
isAuthor
=
req
.
auth
&&
req
.
quiz
&&
req
.
auth
.
_id
==
req
.
quiz
.
author
.
_id
if
(
files
.
image
)
{
if
(
!
isAuthor
)
{
quiz
.
image
.
data
=
fs
.
readFileSync
(
files
.
image
.
path
)
return
res
.
status
(
403
).
json
({
quiz
.
image
.
contentType
=
files
.
image
.
type
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
{
try
{
const
result
=
await
quiz
.
save
()
const
quiz
=
await
Quiz
.
findById
(
id
)
res
.
json
(
result
)
.
populate
(
'
author
'
,
'
_id name
'
)
}
catch
(
error
)
{
.
populate
(
'
problems
'
)
.
exec
()
if
(
!
quiz
)
{
return
res
.
status
(
400
).
json
({
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
{
export
default
{
create
,
create
,
read
,
isAuthor
,
quizById
,
}
}
\ No newline at end of file
src/server/quiz/quiz.model.js
View file @
abd187d8
...
@@ -16,7 +16,10 @@ const QuizSchema = new mongoose.Schema({
...
@@ -16,7 +16,10 @@ const QuizSchema = new mongoose.Schema({
publishedAt
:
Date
,
publishedAt
:
Date
,
startAt
:
Date
,
startAt
:
Date
,
endAt
:
Date
,
endAt
:
Date
,
questions
:
[],
// Question Schemas
problems
:
[{
type
:
mongoose
.
SchemaTypes
.
ObjectId
,
ref
:
'
Problem
'
}],
// Problem Schemas
image
:
{
image
:
{
type
:
Buffer
,
type
:
Buffer
,
contentType
:
String
,
contentType
:
String
,
...
...
src/server/quiz/quiz.routes.js
View file @
abd187d8
...
@@ -8,6 +8,10 @@ const router = express.Router()
...
@@ -8,6 +8,10 @@ const router = express.Router()
router
.
route
(
'
/api/quiz/:userId
'
)
router
.
route
(
'
/api/quiz/:userId
'
)
.
post
(
authCtrl
.
requireSignin
,
authCtrl
.
hasAuthorization
,
userCtrl
.
isInstructor
,
quizCtrl
.
create
)
.
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
(
'
userId
'
,
userCtrl
.
userById
)
router
.
param
(
'
quizId
'
,
quizCtrl
.
quizById
)
export
default
router
export
default
router
\ No newline at end of file
src/server/user/user.controller.js
View file @
abd187d8
...
@@ -89,6 +89,7 @@ const isInstructor = (req, res, next) => {
...
@@ -89,6 +89,7 @@ const isInstructor = (req, res, next) => {
}
}
const
userById
=
async
(
req
,
res
,
next
,
id
)
=>
{
const
userById
=
async
(
req
,
res
,
next
,
id
)
=>
{
// console.log('req.body in userById', req.body);
try
{
try
{
let
user
=
await
User
.
findById
(
id
)
let
user
=
await
User
.
findById
(
id
)
.
exec
()
.
exec
()
...
...
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