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
survey
Commits
374b9208
Commit
374b9208
authored
Jul 20, 2022
by
Jiwon Yoon
Browse files
file을 포함한 설문조사 답변 서버로 보내기
parent
667e4ac8
Changes
15
Show whitespace changes
Inline
Side-by-side
frontend/src/apis/answer.api.ts
0 → 100644
View file @
374b9208
import
axios
from
"
axios
"
;
import
{
AnswerType
}
from
"
../types
"
;
import
baseUrl
from
"
./baseUrl
"
;
export
const
saveAnswers
=
async
(
answer
:
FormData
)
=>
{
const
{
data
}
=
await
axios
.
post
(
`
${
baseUrl
}
/answers`
,
answer
);
return
data
;
};
frontend/src/apis/index.ts
View file @
374b9208
export
*
as
authApi
from
"
./auth.api
"
;
export
*
as
authApi
from
"
./auth.api
"
;
export
*
as
questionApi
from
"
./question.api
"
;
export
*
as
questionApi
from
"
./question.api
"
;
export
*
as
surveyApi
from
"
./survey.api
"
;
export
*
as
surveyApi
from
"
./survey.api
"
;
export
*
as
answerApi
from
"
./answer.api
"
;
export
{
baseImageUrl
}
from
"
./baseUrl
"
;
export
{
baseImageUrl
}
from
"
./baseUrl
"
;
frontend/src/commons/AFileForm.tsx
0 → 100644
View file @
374b9208
import
React
,
{
useState
}
from
"
react
"
;
import
{
FileType
,
AnswerType
}
from
"
../types
"
;
type
Props
=
{
element
:
FileType
;
response
:
AnswerType
;
handleAnswer
:
()
=>
void
;
addFiles
:
(
oneFile
:
{
questionId
:
string
;
file
:
File
})
=>
void
;
};
export
const
AFileForm
=
({
element
,
response
,
handleAnswer
,
addFiles
,
}:
Props
)
=>
{
const
handleChange
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
if
(
event
.
currentTarget
.
files
)
{
const
uploadFile
=
event
.
currentTarget
.
files
[
0
];
addFiles
({
questionId
:
element
.
_id
,
file
:
uploadFile
});
response
.
answers
.
map
((
a
)
=>
{
if
(
a
.
questionId
===
element
.
_id
)
{
a
.
answer
=
uploadFile
.
name
;
}
});
handleAnswer
();
}
};
return
(
<
div
id
=
"content"
className
=
"flex mt-4 w-full justify-center"
>
<
input
type
=
"file"
name
=
"file"
className
=
" w-11/12 h-16"
onChange
=
{
handleChange
}
></
input
>
</
div
>
);
};
frontend/src/commons/AQuestion.tsx
View file @
374b9208
...
@@ -5,13 +5,20 @@ import { ACheckboxForm } from "./ACheckbox";
...
@@ -5,13 +5,20 @@ import { ACheckboxForm } from "./ACheckbox";
import
{
ADropdownForm
}
from
"
./ADropdown
"
;
import
{
ADropdownForm
}
from
"
./ADropdown
"
;
import
{
AEssayForm
}
from
"
./AEssayForm
"
;
import
{
AEssayForm
}
from
"
./AEssayForm
"
;
import
{
ARadioForm
}
from
"
./ARadioForm
"
;
import
{
ARadioForm
}
from
"
./ARadioForm
"
;
import
{
AFileForm
}
from
"
./AFileForm
"
;
type
Props
=
{
type
Props
=
{
question
:
BasicQuestionType
;
question
:
BasicQuestionType
;
response
:
AnswerType
;
response
:
AnswerType
;
handleAnswer
:
()
=>
void
;
handleAnswer
:
()
=>
void
;
addFiles
:
(
oneFile
:
{
questionId
:
string
;
file
:
File
})
=>
void
;
};
};
export
const
AQuestion
=
({
question
,
handleAnswer
,
response
}:
Props
)
=>
{
export
const
AQuestion
=
({
question
,
handleAnswer
,
response
,
addFiles
,
}:
Props
)
=>
{
function
getContent
(
question
:
BasicQuestionType
)
{
function
getContent
(
question
:
BasicQuestionType
)
{
switch
(
question
.
type
)
{
switch
(
question
.
type
)
{
case
"
essay
"
:
case
"
essay
"
:
...
@@ -46,8 +53,15 @@ export const AQuestion = ({ question, handleAnswer, response }: Props) => {
...
@@ -46,8 +53,15 @@ export const AQuestion = ({ question, handleAnswer, response }: Props) => {
handleAnswer
=
{
handleAnswer
}
handleAnswer
=
{
handleAnswer
}
/>
/>
);
);
// case "file":
case
"
file
"
:
// return <AFileForm element={element} currentId={currentId} />;
return
(
<
AFileForm
element
=
{
question
}
response
=
{
response
}
handleAnswer
=
{
handleAnswer
}
addFiles
=
{
addFiles
}
/>
);
// case "rating":
// case "rating":
// return (
// return (
// <ARatingForm
// <ARatingForm
...
...
frontend/src/commons/SurveyForm.tsx
View file @
374b9208
import
React
,
{
FormEvent
,
useEffect
,
useState
}
from
"
react
"
;
import
React
,
{
FormEvent
,
useEffect
,
useState
}
from
"
react
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
import
{
surveyApi
}
from
"
../apis
"
;
import
{
surveyApi
,
answerApi
}
from
"
../apis
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
AnswerType
,
SurveyType
}
from
"
../types
"
;
import
{
AnswerType
,
SurveyType
}
from
"
../types
"
;
import
{
AQuestion
}
from
"
./AQuestion
"
;
import
{
AQuestion
}
from
"
./AQuestion
"
;
import
{
ARadioForm
}
from
"
./ARadioForm
"
;
export
const
SurveyForm
=
()
=>
{
export
const
SurveyForm
=
()
=>
{
let
{
surveyId
}
=
useParams
<
{
surveyId
:
string
}
>
();
let
{
surveyId
}
=
useParams
<
{
surveyId
:
string
}
>
();
const
[
files
,
setFiles
]
=
useState
<
{
questionId
:
string
;
file
:
File
}[]
>
([]);
const
[
error
,
setError
]
=
useState
(
""
);
const
[
error
,
setError
]
=
useState
(
""
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
success
,
setSuccess
]
=
useState
(
false
);
const
[
success
,
setSuccess
]
=
useState
(
false
);
...
@@ -18,8 +18,8 @@ export const SurveyForm = () => {
...
@@ -18,8 +18,8 @@ export const SurveyForm = () => {
comment
:
""
,
comment
:
""
,
questions
:
[],
questions
:
[],
});
});
const
[
response
,
setResponse
]
=
useState
<
AnswerType
>
({
const
[
answer
,
setResponse
]
=
useState
<
AnswerType
>
({
surveyId
:
surveyId
,
surveyId
:
"
surveyId
"
,
guestId
:
""
,
guestId
:
""
,
answers
:
[{
questionId
:
""
,
answer
:
""
}],
answers
:
[{
questionId
:
""
,
answer
:
""
}],
});
});
...
@@ -28,23 +28,30 @@ export const SurveyForm = () => {
...
@@ -28,23 +28,30 @@ export const SurveyForm = () => {
ansSurvey
();
ansSurvey
();
},
[
surveyId
]);
},
[
surveyId
]);
const
addFiles
=
(
oneFile
:
{
questionId
:
string
;
file
:
File
})
=>
{
if
(
!
files
.
find
((
a
)
=>
a
.
questionId
===
oneFile
.
questionId
))
{
setFiles
([...
files
,
oneFile
]);
}
};
async
function
ansSurvey
()
{
async
function
ansSurvey
()
{
try
{
try
{
if
(
surveyId
)
{
if
(
surveyId
)
{
const
answersurvey
:
SurveyType
=
await
surveyApi
.
ansSurvey
(
surveyId
);
const
answersurvey
:
any
=
await
surveyApi
.
ansSurvey
(
surveyId
);
console
.
log
(
answersurvey
);
console
.
log
(
answersurvey
);
const
questionIds
=
answersurvey
.
questions
.
map
((
el
)
=>
{
const
questionIds
=
answersurvey
.
questions
.
map
((
el
:
any
)
=>
{
return
{
questionId
:
el
.
_id
,
answer
:
""
};
return
{
questionId
:
el
.
_id
,
answer
:
""
};
});
});
console
.
log
(
questionIds
);
console
.
log
(
questionIds
);
if
(
answersurvey
)
{
setResponse
({
setResponse
({
...
response
,
...
answer
,
surveyId
:
answersurvey
.
_id
,
surveyId
:
answersurvey
.
_id
,
answers
:
questionIds
,
answers
:
questionIds
,
});
});
setSurvey
(
answersurvey
);
setSurvey
(
answersurvey
);
setSuccess
(
true
);
setSuccess
(
true
);
setError
(
""
);
setError
(
""
);
}
}
else
{
}
else
{
setLoading
(
true
);
setLoading
(
true
);
}
}
...
@@ -55,18 +62,35 @@ export const SurveyForm = () => {
...
@@ -55,18 +62,35 @@ export const SurveyForm = () => {
}
}
}
}
function
handleSubmit
(
event
:
FormEvent
)
{
async
function
handleSubmit
(
event
:
FormEvent
)
{
event
.
preventDefault
();
event
.
preventDefault
();
try
{
const
formData
=
new
FormData
();
formData
.
append
(
"
surveyId
"
,
answer
.
surveyId
);
formData
.
append
(
"
guestId
"
,
""
);
formData
.
append
(
"
answers
"
,
JSON
.
stringify
(
answer
.
answers
));
files
.
map
((
f
)
=>
{
formData
.
append
(
"
files
"
,
f
.
file
);
});
const
newAnswer
:
AnswerType
=
await
answerApi
.
saveAnswers
(
formData
);
// console.log(newAnswer);
setSuccess
(
true
);
setError
(
""
);
}
catch
(
error
)
{
catchErrors
(
error
,
setError
);
}
finally
{
setLoading
(
false
);
}
}
}
const
handleAnswer
=
()
=>
{
const
handleAnswer
=
()
=>
{
const
newList
=
[...
response
.
answers
];
const
newList
=
[...
answer
.
answers
];
setResponse
({
...
response
,
answers
:
newList
});
setResponse
({
...
answer
,
answers
:
newList
});
};
};
return
(
return
(
<>
<>
{
console
.
log
(
response
)
}
{
console
.
log
(
answer
)
}
<
form
onSubmit
=
{
handleSubmit
}
>
<
form
onSubmit
=
{
handleSubmit
}
>
<
div
className
=
"flex flex-col place-items-center"
>
<
div
className
=
"flex flex-col place-items-center"
>
<
div
className
=
"flex flex-col container place-items-center mt-4"
>
<
div
className
=
"flex flex-col container place-items-center mt-4"
>
...
@@ -78,7 +102,8 @@ export const SurveyForm = () => {
...
@@ -78,7 +102,8 @@ export const SurveyForm = () => {
return
(
return
(
<
AQuestion
<
AQuestion
question
=
{
question
}
question
=
{
question
}
response
=
{
response
}
response
=
{
answer
}
addFiles
=
{
addFiles
}
handleAnswer
=
{
handleAnswer
}
handleAnswer
=
{
handleAnswer
}
></
AQuestion
>
></
AQuestion
>
);
);
...
...
frontend/src/types/index.ts
View file @
374b9208
...
@@ -82,7 +82,7 @@ export interface RatingType extends BasicQuestionType {
...
@@ -82,7 +82,7 @@ export interface RatingType extends BasicQuestionType {
}
}
export
interface
AnswerType
{
export
interface
AnswerType
{
surveyId
?
:
string
;
surveyId
:
string
;
guestId
:
string
;
guestId
:
string
;
answers
:
{
questionId
:
string
;
answer
:
any
}[];
answers
:
{
questionId
:
string
;
answer
:
any
}[];
}
}
src/controllers/answer.controller.ts
0 → 100644
View file @
374b9208
import
{
asyncWrap
}
from
"
../helpers
"
;
import
{
TypedRequest
}
from
"
../types
"
;
import
formidable
from
"
formidable
"
;
import
{
FileInfo
}
from
"
../models
"
;
import
{
fileDb
,
userDb
}
from
"
../db
"
;
import
fs
from
"
fs/promises
"
;
export
const
createAnswers
=
asyncWrap
(
async
(
reqExp
,
res
)
=>
{
const
req
=
reqExp
as
TypedRequest
;
const
answer
=
req
.
body
;
const
answers
=
JSON
.
parse
(
answer
.
answers
);
answer
.
answers
=
answers
;
console
.
log
(
answers
);
const
file
=
req
.
files
.
img
as
formidable
.
File
;
let
img
;
try
{
// 1) 파일을 DB에 저장
if
(
file
)
{
// img = new FileInfo({
// name: file.originalFilename,
// url: file.newFilename,
// isNew: true,
// });
// await fileDb.createFile(file);
// 2) answer에 img 항목 추가
answer
.
img
=
img
;
}
// 3) Answer 만들기(map을 돌려서 하나씩 추가시켜야 함)
console
.
log
(
answer
);
// const newAnswer = await answerDb.createAnswer(answer);
// 주의: ref는 반드시 save를 해야 디비에 생성이 됩니다.
return
res
.
json
();
}
catch
(
error
:
any
)
{
console
.
log
(
"
error in create user:
"
,
error
);
// 오류 발생시 저장된 파일 제거
if
(
file
)
{
// img && (await fileDb.deleteFileById(img._id.toString()));
await
fs
.
unlink
(
file
.
filepath
);
}
res
.
status
(
422
).
send
(
error
.
message
||
"
사용자 생성 오류
"
);
}
});
src/controllers/file.controller.ts
View file @
374b9208
...
@@ -2,7 +2,7 @@ import formidable from "formidable";
...
@@ -2,7 +2,7 @@ import formidable from "formidable";
import
{
asyncWrap
}
from
"
../helpers/asyncWrap
"
;
import
{
asyncWrap
}
from
"
../helpers/asyncWrap
"
;
import
{
TypedRequest
}
from
"
../types
"
;
import
{
TypedRequest
}
from
"
../types
"
;
export
const
upload
Avatar
=
asyncWrap
(
async
(
reqExp
,
res
,
next
)
=>
{
export
const
upload
File
=
asyncWrap
(
async
(
reqExp
,
res
,
next
)
=>
{
const
req
=
reqExp
as
TypedRequest
;
const
req
=
reqExp
as
TypedRequest
;
const
form
=
formidable
({
multiples
:
false
,
uploadDir
:
"
uploads
"
});
const
form
=
formidable
({
multiples
:
false
,
uploadDir
:
"
uploads
"
});
...
@@ -12,12 +12,10 @@ export const uploadAvatar = asyncWrap(async (reqExp, res, next) => {
...
@@ -12,12 +12,10 @@ export const uploadAvatar = asyncWrap(async (reqExp, res, next) => {
reject
(
err
);
reject
(
err
);
return
;
return
;
}
}
console
.
log
(
"
fields
"
,
fields
);
// console.log("fields", fields);
console
.
log
(
"
files
"
,
files
);
// console.log("files", files);
req
.
body
=
fields
;
req
.
body
=
fields
;
req
.
files
=
files
;
req
.
files
=
files
;
resolve
(
files
);
resolve
(
files
);
});
});
});
});
...
...
src/controllers/index.ts
View file @
374b9208
...
@@ -4,3 +4,4 @@ export * as questionCtrl from "./question.controller";
...
@@ -4,3 +4,4 @@ export * as questionCtrl from "./question.controller";
export
*
as
surveyCtrl
from
"
./survey.controller
"
;
export
*
as
surveyCtrl
from
"
./survey.controller
"
;
export
*
as
roleCtrl
from
"
./role.controller
"
;
export
*
as
roleCtrl
from
"
./role.controller
"
;
export
*
as
userCtrl
from
"
./user.controller
"
;
export
*
as
userCtrl
from
"
./user.controller
"
;
export
*
as
answerCtrl
from
"
./answer.controller
"
;
src/
routes/response.route
.ts
→
src/
db/answer.db
.ts
View file @
374b9208
File moved
src/models/
response
.model.ts
→
src/models/
answer
.model.ts
View file @
374b9208
import
{
model
,
Schema
,
Types
}
from
"
mongoose
"
;
import
{
model
,
Schema
,
Types
}
from
"
mongoose
"
;
export
interface
I
Response
{
export
interface
I
Answer
{
_id
?:
Types
.
ObjectId
;
_id
?:
Types
.
ObjectId
;
surveyId
?:
Types
.
ObjectId
;
surveyId
?:
Types
.
ObjectId
;
questionId
?:
Types
.
ObjectId
;
questionId
?:
Types
.
ObjectId
;
respondent
?:
string
;
guestId
?:
string
;
answer
?:
any
;
answer
?:
any
;
}
}
const
schema
=
new
Schema
<
I
Response
>
(
const
schema
=
new
Schema
<
I
Answer
>
(
{
{
surveyId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Survey
"
},
surveyId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Survey
"
},
questionId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Question
"
},
questionId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Question
"
},
respondent
:
{
type
:
String
},
guestId
:
{
type
:
String
},
answer
:
{
type
:
Object
},
answer
:
{
type
:
Object
},
},
},
{
timestamps
:
true
}
{
timestamps
:
true
}
);
);
export
default
model
<
I
Response
>
(
"
Response
"
,
schema
);
export
default
model
<
I
Answer
>
(
"
Answer
"
,
schema
);
src/models/index.ts
View file @
374b9208
...
@@ -3,3 +3,4 @@ export { default as Question, IQuestion } from "./question.model";
...
@@ -3,3 +3,4 @@ export { default as Question, IQuestion } from "./question.model";
export
{
default
as
Role
}
from
"
./role.model
"
;
export
{
default
as
Role
}
from
"
./role.model
"
;
export
{
default
as
Survey
,
ISurvey
}
from
"
./survey.model
"
;
export
{
default
as
Survey
,
ISurvey
}
from
"
./survey.model
"
;
export
{
default
as
User
,
IUser
}
from
"
./user.model
"
;
export
{
default
as
User
,
IUser
}
from
"
./user.model
"
;
export
{
default
as
Answer
,
IAnswer
}
from
"
./answer.model
"
;
src/routes/answer.route.ts
0 → 100644
View file @
374b9208
import
express
from
"
express
"
;
import
{
answerCtrl
,
fileCtrl
}
from
"
../controllers
"
;
const
router
=
express
.
Router
();
router
.
route
(
"
/
"
).
post
(
fileCtrl
.
uploadFile
,
answerCtrl
.
createAnswers
);
export
default
router
;
src/routes/index.ts
View file @
374b9208
...
@@ -4,6 +4,7 @@ import questionRouter from "./question.route";
...
@@ -4,6 +4,7 @@ import questionRouter from "./question.route";
import
surveyRouter
from
"
./survey.route
"
;
import
surveyRouter
from
"
./survey.route
"
;
import
roleRouter
from
"
./role.route
"
;
import
roleRouter
from
"
./role.route
"
;
import
userRouter
from
"
./user.route
"
;
import
userRouter
from
"
./user.route
"
;
import
answerRouter
from
"
./answer.route
"
;
const
router
=
express
.
Router
();
const
router
=
express
.
Router
();
...
@@ -12,5 +13,6 @@ router.use("/questions", questionRouter);
...
@@ -12,5 +13,6 @@ router.use("/questions", questionRouter);
router
.
use
(
"
/surveys
"
,
surveyRouter
);
router
.
use
(
"
/surveys
"
,
surveyRouter
);
router
.
use
(
"
/roles
"
,
roleRouter
);
router
.
use
(
"
/roles
"
,
roleRouter
);
router
.
use
(
"
/users
"
,
userRouter
);
router
.
use
(
"
/users
"
,
userRouter
);
router
.
use
(
"
/answers
"
,
answerRouter
);
export
default
router
;
export
default
router
;
src/routes/user.route.ts
View file @
374b9208
...
@@ -9,7 +9,7 @@ router
...
@@ -9,7 +9,7 @@ router
.
post
(
.
post
(
authCtrl
.
requireLogin
,
authCtrl
.
requireLogin
,
authCtrl
.
hasRole
(
"
admin
"
),
authCtrl
.
hasRole
(
"
admin
"
),
fileCtrl
.
upload
Avatar
,
fileCtrl
.
upload
File
,
userCtrl
.
createUser
userCtrl
.
createUser
);
);
...
...
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