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
travel
Commits
fc01d0b3
Commit
fc01d0b3
authored
Jul 06, 2022
by
Kim, MinGyu
Browse files
db 생성
parent
58a76189
Changes
19
Show whitespace changes
Inline
Side-by-side
frontend/package.json
View file @
fc01d0b3
...
...
@@ -29,6 +29,7 @@
"webpack-dev-server"
:
"^4.9.2"
},
"dependencies"
:
{
"axios"
:
"^0.27.2"
,
"react"
:
"^18.2.0"
,
"react-dom"
:
"^18.2.0"
,
"react-router-dom"
:
"^6.3.0"
...
...
frontend/src/Pages/posting.tsx
View file @
fc01d0b3
import
React
from
"
react
"
;
import
React
,
{
useState
}
from
"
react
"
;
import
Theme
from
"
./theme
"
;
import
{
PostType
}
from
"
./typesrc
"
;
import
axios
from
"
axios
"
;
function
Title
()
{
const
[
title
,
setTitle
]
=
useState
<
string
>
(
"
질문종류
"
);
function
TitleChange
(
e
:
{
target
:
{
value
:
React
.
SetStateAction
<
string
>
}
})
{
setTitle
(
e
.
target
.
value
);
}
}
function
Body
()
{
const
[
body
,
setBody
]
=
useState
<
string
>
(
"
질문종류
"
);
function
BodyChange
(
e
:
{
target
:
{
value
:
React
.
SetStateAction
<
string
>
}
})
{
setBody
(
e
.
target
.
value
);
}
}
function
SelectCity
()
{
const
[
selectCity
,
setSelectCity
]
=
useState
<
string
>
(
"
질문종류
"
);
function
CityChange
(
e
:
{
target
:
{
value
:
React
.
SetStateAction
<
string
>
}
})
{
setSelectCity
(
e
.
target
.
value
);
}
return
(
<
select
id
=
"Questions"
className
=
"border border-3 border-black w-1/12"
onChange
=
{
CityChange
}
defaultValue
=
"질문종류"
>
<
option
value
=
"질문종류"
>
도시
</
option
>
<
option
value
=
"Seoul"
>
서울
</
option
>
<
option
value
=
"Busan"
>
부산
</
option
>
<
option
value
=
"Incheon"
>
인천
</
option
>
<
option
value
=
"Daegoo"
>
대구
</
option
>
<
option
value
=
"Kwangjoo"
>
광주
</
option
>
<
option
value
=
"Daejeon"
>
대전
</
option
>
<
option
value
=
"Woolsan"
>
울산
</
option
>
<
option
value
=
"Sejong"
>
세종
</
option
>
<
option
value
=
"Dokdo"
>
독도
</
option
>
<
option
value
=
"Jeju"
>
제주
</
option
>
</
select
>
);
}
function
SelectTheme
()
{
const
[
selectTheme
,
setSelectTheme
]
=
useState
<
string
>
(
"
질문종류
"
);
function
ThemeChange
(
e
:
{
target
:
{
value
:
React
.
SetStateAction
<
string
>
}
})
{
setSelectTheme
(
e
.
target
.
value
);
}
return
(
<
select
id
=
"Questions"
className
=
"border border-3 border-black w-1/12"
onChange
=
{
ThemeChange
}
defaultValue
=
"질문종류"
>
<
option
value
=
"질문종류"
>
테마
</
option
>
<
option
value
=
"cycling"
>
사이클링
</
option
>
<
option
value
=
"surfing"
>
서핑
</
option
>
<
option
value
=
"activity"
>
액티비티
</
option
>
<
option
value
=
"camping"
>
캠핑
</
option
>
<
option
value
=
"sking"
>
스키
</
option
>
<
option
value
=
"boat"
>
보트
</
option
>
<
option
value
=
"desert"
>
사막
</
option
>
<
option
value
=
"golf"
>
골프
</
option
>
<
option
value
=
"cave"
>
동굴
</
option
>
<
option
value
=
"history"
>
문화재
</
option
>
<
option
value
=
"zoo"
>
동물원
</
option
>
<
option
value
=
"cycling"
>
사이클링
</
option
>
<
option
value
=
"cycling"
>
{
selectTheme
}
</
option
>
</
select
>
);
}
// 눌렀다는 데이터가 어딘가에 있어야 한다. Map 객체를 이용해서 기타등등
// function postup() {
// axios.post("localhost:3000/api/post/up", {
// id: "a",
// title: title,
// body: body,
// date: `${() => new Date()}`,
// theme: selectTheme,
// city: selectCity,
// });
// }
export
default
function
Posting
()
{
return
(
return
(
<
div
className
=
"flex flex-col border-3"
>
<
form
className
=
"w-full items-center"
>
<
form
className
=
"w-full items-center"
>
<
div
className
=
"flex flex-row relative"
>
<
p
className
=
"basis-
4
/12
place-self-center
"
>
Id
</
p
>
<
p
className
=
"basis-
1
/12
gap-x-8
"
>
Id
</
p
>
<
p
className
=
"basis-8/12 invisible"
>
empty
</
p
>
<
SelectCity
/>
<
SelectTheme
/>
<
button
data
-
dropdown
-
toggle
=
"dropdownId"
className
=
"basis-1/12"
>
Theme
</
button
>
<
p
className
=
"basis-1/12"
>
city
</
p
>
<
button
className
=
"basis-1/12 "
>
글쓰기
</
button
>
<
button
type
=
"submit"
className
=
"border border-black basis-1/12 gap-x-8"
>
글쓰기
</
button
>
</
div
>
<
div
className
=
"flex border-4"
>
<
textarea
placeholder
=
"title"
className
=
"w-full h-8"
></
textarea
>
<
textarea
onChange
=
{
Title
}
placeholder
=
"title"
className
=
"w-full h-8"
></
textarea
>
</
div
>
<
div
className
=
"flex border-2"
>
<
div
onChange
=
{
Body
}
className
=
"flex border-2"
>
<
textarea
placeholder
=
"body"
className
=
"w-full h-96"
></
textarea
>
</
div
>
</
form
>
...
...
frontend/src/Pages/typesrc.tsx
View file @
fc01d0b3
...
...
@@ -3,4 +3,6 @@ export interface PostType {
title
:
string
;
date
:
string
;
counts
:
number
;
theme
:
string
;
city
:
string
;
}
frontend/src/pages/board.tsx
View file @
fc01d0b3
...
...
@@ -4,7 +4,7 @@ import { PostType } from "./typesrc";
import
Post
from
"
./post
"
;
function
range
(
start
:
number
,
end
:
number
)
{
return
(
new
Array
(
end
-
start
+
1
)
)
.
fill
(
undefined
).
map
((
_
,
i
)
=>
i
+
start
);
return
new
Array
(
end
-
start
+
1
).
fill
(
undefined
).
map
((
_
,
i
)
=>
i
+
start
);
}
interface
Posts
{
...
...
@@ -12,46 +12,94 @@ interface Posts {
}
export
const
fakes
=
[
{
id
:
"
a
"
,
title
:
'
여행가고싶다...
'
,
date
:
'
2022-06-30
'
,
counts
:
0
},
{
id
:
"
b
"
,
title
:
'
바다!바다!바다!
'
,
date
:
'
2022-08-01
'
,
counts
:
0
},
{
id
:
"
c
"
,
title
:
'
Jeju-island
'
,
date
:
'
2022-9-10
'
,
counts
:
0
},
{
id
:
"
d
"
,
title
:
'
마! 부싼 가봤나!
'
,
date
:
'
2022-9-22
'
,
counts
:
0
},
{
id
:
"
e
"
,
title
:
'
Daegu
'
,
date
:
'
2022-10-1
'
,
counts
:
0
},
{
id
:
"
f
"
,
title
:
'
강원도 감자는 맛있다.
'
,
date
:
'
2022-12-12
'
,
counts
:
0
},
{
id
:
"
g
"
,
title
:
'
부산남자의 서울여행
'
,
date
:
'
2022-12-25
'
,
counts
:
0
}
{
id
:
"
a
"
,
title
:
"
여행가고싶다...
"
,
date
:
"
2022-06-30
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
{
id
:
"
b
"
,
title
:
"
바다!바다!바다!
"
,
date
:
"
2022-08-01
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
{
id
:
"
c
"
,
title
:
"
Jeju-island
"
,
date
:
"
2022-9-10
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
{
id
:
"
d
"
,
title
:
"
마! 부싼 가봤나!
"
,
date
:
"
2022-9-22
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
{
id
:
"
e
"
,
title
:
"
Daegu
"
,
date
:
"
2022-10-1
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
{
id
:
"
f
"
,
title
:
"
강원도 감자는 맛있다.
"
,
date
:
"
2022-12-12
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
{
id
:
"
g
"
,
title
:
"
부산남자의 서울여행
"
,
date
:
"
2022-12-25
"
,
counts
:
0
,
theme
:
"
surfing
"
,
city
:
"
seoul
"
,
},
];
export
default
function
BoardPage
()
{
const
[
posts
,
setPosts
]
=
useState
<
PostType
[]
>
(
fakes
);
const
titleHandleClick
=
(
event
:
MouseEvent
<
HTMLButtonElement
>
)
=>
{
const
postId
=
event
.
currentTarget
.
id
const
newposts
=
[...
posts
]
newposts
.
forEach
(
post
=>
{
const
postId
=
event
.
currentTarget
.
id
;
const
newposts
=
[...
posts
]
;
newposts
.
forEach
(
(
post
)
=>
{
if
(
post
.
id
===
postId
)
{
post
.
counts
=
post
.
counts
+
1
return
}
})
setPosts
(
newposts
)
post
.
counts
=
post
.
counts
+
1
;
return
;
}
});
setPosts
(
newposts
);
};
return
(
<
div
className
=
"flex flex-col items-center"
>
<
div
className
=
"flex flex-col items-center mt-6"
>
<
div
>
`Travel Report's Board`
</
div
>
<
div
>
`여행지 후기를 남겨주세요!`
</
div
>
<
div
>
`Travel Report's Board`
</
div
>
<
div
>
`여행지 후기를 남겨주세요!`
</
div
>
</
div
>
<
div
className
=
"flex flex-col w-10/12 mt-16"
>
<
div
className
=
"flex justify-end"
>
<
div
className
=
"border-2 mb-2"
><
Link
to
=
"/posting"
><
button
>
글쓰기+
</
button
></
Link
></
div
>
{
/* Link */
}
<
div
className
=
"border-2 mb-2"
>
<
Link
to
=
"/posting"
>
<
button
>
글쓰기+
</
button
>
</
Link
>
</
div
>
{
"
"
}
{
/* Link */
}
</
div
>
<
div
className
=
"sm:overflow-y-scroll"
>
<
div
className
=
"flex flex-row divide-x-2 border-2 border-solid bg-gray-500 border-y-2 h-10 "
>
...
...
frontend/src/pages/header.tsx
View file @
fc01d0b3
...
...
@@ -14,6 +14,7 @@ export default function Header() {
<
div
className
=
"flex flex-row-reverse"
>
<
button
className
=
"px-5 py-2 bg-teal-400 rounded"
>
<
Link
to
=
"/login"
className
=
"hover:bg-teal-100 focus:text-purple-500 "
>
Login
</
Link
>
</
button
>
<
button
className
=
"px-5 py-2 bg-purple-400 rounded"
>
<
Link
to
=
"/board"
className
=
"hover:bg-purple-300 focus:text-purple-500 "
>
Board
</
Link
>
...
...
frontend/src/pages/login.tsx
View file @
fc01d0b3
import
{
Link
,
}
from
"
react-router-dom
"
;
import
React
,
{
useState
}
from
"
react
"
;
import
{
Link
}
from
"
react-router-dom
"
;
import
React
,
{
useState
,
FormEventHandler
}
from
"
react
"
;
interface
login
{
id
:
string
;
password
:
string
;
id
:
string
;
password
:
string
;
}
const
fake
=
{
id
:
"
asdf
"
,
password
:
"
qwer
"
}
//
const fake = {
id: "asdf", password: "qwer"
};
function
Logindata
(
fake
:
login
){
function
Logindata
()
{
const
[
id
,
setId
]
=
useState
(
""
);
const
[
password
,
setPassword
]
=
useState
(
""
);
return
(
<
div
className
=
"flex flex-col md:w-2/3 md:gap-2"
>
<
input
className
=
"
placeholder
:
text
-
slate
-
300
function
login
()
{
fetch
(
`http://localhost:3000/api/auth/login`
,
{
method
:
"
POST
"
,
body
:
JSON
.
stringify
({
email
:
`
${
id
}
`
,
password
:
`
${
password
}
`
,
}),
}).
then
((
response
)
=>
{
console
.
log
(
response
.
json
());
});
}
return
(
<
div
className
=
"flex flex-col md:w-2/3 md:gap-2"
>
<
input
className
=
"
placeholder
:
text
-
slate
-
300
bg
-
white
border
border
-
slate
-
500
rounded
-
2xl
py
-
2
pl
-
9
pr
-
3
focus
:
border
-
black
" placeholder="
Id
" type="
text
" name="
Id
"
onChange
=
{
(
e
)
=>
setId
(
e
.
target
.
value
)
}
/>
<
input
className
=
"
placeholder
:
italic
placeholder
:
text
-
slate
-
300
"
placeholder
=
"Id"
type
=
"text"
name
=
"Id"
onChange
=
{
(
e
)
=>
setId
(
e
.
target
.
value
)
}
/>
<
input
className
=
"
placeholder
:
italic
placeholder
:
text
-
slate
-
300
bg
-
white
border
border
-
slate
-
500
rounded
-
2xl
py
-
2
pl
-
9
pr
-
3
focus
:
border
-
black
" placeholder="
Password
" type="
text
" name="
Password
"
onChange
=
{
(
e
)
=>
setPassword
(
e
.
target
.
value
)
}
/>
"
placeholder
=
"Password"
type
=
"password"
name
=
"Password"
onChange
=
{
(
e
)
=>
setPassword
(
e
.
target
.
value
)
}
/>
<
button
type
=
"submit"
className
=
"md:w-1/3 bg-sky-600 hover:bg-sky-700 rounded-xl"
onClick
=
{
login
}
>
<
Link
to
=
{
"
/
"
}
>
login
</
Link
>
</
button
>
</
div
>
)
);
}
export
default
function
Login
()
{
return
(
<
div
>
{
/* <form onSubmit={loginsubmit}> */
}
<
div
className
=
"flex flex-row grid grid-rows-2"
>
<
div
className
=
" p-12 w-1/2 h-1/2 md:w-40 md:h-40 bg-red-400 place-self-center rounded-2xl"
>
<
Link
to
=
"/"
>
Travel Report
</
Link
>
</
div
>
<
div
className
=
" flex-row w-auto h-60 md:w-1/2 bg-white border-2 border-black grid place-items-center rounded-xl place-self-center"
>
<
div
className
=
"flex flex-col w-full md:flex-row md:p-20 md:gap-10"
>
<
Logindata
id
=
{
""
}
password
=
{
""
}
/>
<
button
type
=
"submit"
className
=
"md:w-1/3 bg-sky-600 hover:bg-sky-700 rounded-xl"
>
login
</
button
>
<
Logindata
/>
</
div
>
<
div
className
=
"flex-row grid grid-cols-3"
>
<
button
className
=
"bg-white bottom-0 right-0"
>
...
...
@@ -65,8 +83,6 @@ export default function Login() {
</
button
>
</
div
>
</
div
>
</
div
>
{
/* </form> */
}
</
div
>
// Login Page
...
...
frontend/webpack.dev.js
View file @
fc01d0b3
...
...
@@ -6,5 +6,13 @@ const common = require("./webpack.common.js");
module
.
exports
=
merge
(
common
,
{
mode
:
"
development
"
,
devtool
:
"
inline-source-map
"
,
devServer
:
{
historyApiFallback
:
true
},
devServer
:
{
proxy
:
[
{
context
:
[
"
/api
"
],
target
:
"
http://localhost:3000
"
,
changeOrigin
:
true
,
}
],
historyApiFallback
:
true
},
});
src/app.ts
View file @
fc01d0b3
...
...
@@ -8,6 +8,8 @@ app.use(express.json());
app
.
use
(
express
.
urlencoded
({
extended
:
true
}));
app
.
use
(
cookieParser
());
app
.
get
(
'
/
'
,
(
req
,
res
)
=>
res
.
send
(
'
Hello World! 안녕하세요
'
))
app
.
use
(
"
/api
"
,
router
);
app
.
use
((
err
:
any
,
req
:
Request
,
res
:
Response
,
next
:
NextFunction
)
=>
{
...
...
src/controllers/auth.controller.ts
View file @
fc01d0b3
...
...
@@ -25,15 +25,15 @@ export const login = asyncWrap(async (req, res) => {
return
res
.
status
(
401
).
send
(
"
잘못된 비밀번호를 입력하셨습니다
"
);
}
// 3) 비밀번호가 맞으면 토큰 생성
const
token
=
jwt
.
sign
({
userId
:
user
.
id
},
jwtCofig
.
secret
,
{
const
token
=
jwt
.
sign
({
userId
:
user
.
id
},
jwtCofig
.
secret
,
{
//userId를 토큰에다 넣는 중.
expiresIn
:
jwtCofig
.
expires
,
});
// 4) 토큰을 쿠키에 저장
res
.
cookie
(
cookieConfig
.
name
,
token
,
{
maxAge
:
cookieConfig
.
maxAge
,
path
:
"
/
"
,
httpOnly
:
envConfig
.
mode
===
"
production
"
,
secure
:
envConfig
.
mode
===
"
production
"
,
res
.
cookie
(
cookieConfig
.
name
,
token
,
{
//token은 쿠키에 무엇을 실렸는가 이다. 항상 갖고 있다가 홈페이지 들어가면 서버로 접속
maxAge
:
cookieConfig
.
maxAge
,
// 이 기간 한에서만 유효
path
:
"
/
"
,
//어떠한 경로에 관해서만 쓴다. 지금은 전부에 쓴다.
httpOnly
:
envConfig
.
mode
===
"
production
"
,
//false 면 브라우저에서 쿠키를 조작, true면 조작할 수 있다.
secure
:
envConfig
.
mode
===
"
production
"
,
//true 면 https 를 통해서만 쿠키 전달, false면
});
// 5) 사용자 반환
res
.
json
({
...
...
@@ -51,15 +51,15 @@ export const requireLogin = asyncWrap(async (reqExp, res, next) => {
const
req
=
reqExp
as
TypedRequestAuth
<
string
|
JwtPayload
>
;
try
{
// 1) 쿠키 토큰 존재 여부 확인
const
token
=
req
.
cookies
[
cookieConfig
.
name
];
const
token
=
req
.
cookies
[
cookieConfig
.
name
];
//클라이언트 쪽에서 보낸 토큰을 받는중
if
(
!
token
)
{
throw
new
Error
(
"
토큰이 존재하지 않습니다
"
);
}
// 2) 쿠키 유효성 검사
const
decodedUser
=
jwt
.
verify
(
token
,
jwtCofig
.
secret
);
const
decodedUser
=
jwt
.
verify
(
token
,
jwtCofig
.
secret
);
// 아까보낸 토근을 디코딩중.
// 3) 요청 객체에 토큰 사용자 객체 추가
req
.
auth
=
decodedUser
;
next
();
next
();
// 에러가 안나오면 next 사용, 나오면 catch쪽으로.
}
catch
(
error
)
{
res
.
clearCookie
(
cookieConfig
.
name
);
console
.
log
(
"
error in requreLogin===
\n
"
,
error
);
...
...
src/controllers/index.ts
View file @
fc01d0b3
export
*
as
userCtrl
from
"
./user.controller
"
;
export
*
as
authCtrl
from
"
./auth.controller
"
;
export
*
as
postCtrl
from
"
./post.controller
"
;
src/controllers/post.controller.ts
0 → 100644
View file @
fc01d0b3
import
{
postDb
}
from
"
../db
"
;
import
{
asyncWrap
}
from
"
../helpers/asyncWrap
"
;
export
const
postup
=
asyncWrap
(
async
(
req
,
res
)
=>
{
const
{
id
,
title
,
date
,
body
,
theme
,
city
}
=
req
.
body
;
if
(
theme
==
"
테마
"
)
{
return
res
.
status
(
422
).
send
(
"
테마를 선택해주십시요.
"
);
}
else
if
(
city
==
"
도시
"
){
return
res
.
status
(
422
).
send
(
"
도시를 선택해주십시요.
"
);
}
const
newPost
=
await
postDb
.
createPost
({
id
,
title
,
date
,
body
,
theme
,
city
});
res
.
json
(
newPost
);
})
\ No newline at end of file
src/db/index.ts
View file @
fc01d0b3
export
*
as
userDb
from
"
./user.db
"
;
export
*
as
postDb
from
"
./post.db
"
;
\ No newline at end of file
src/db/post.db.ts
0 → 100644
View file @
fc01d0b3
import
{
PostType
,
Post
}
from
"
../models
"
;
export
const
createPost
=
async
(
post
:
PostType
)
=>
{
const
newPost
=
await
Post
.
create
(
post
);
return
newPost
;
};
\ No newline at end of file
src/index.ts
View file @
fc01d0b3
...
...
@@ -5,6 +5,7 @@ import { mongoUri } from "./config";
connect
(
mongoUri
)
.
then
((
mgs
)
=>
{
console
.
log
(
`Mongoose is connected with version:
${
mgs
.
version
}
`
);
app
.
listen
(
3000
,
()
=>
{
console
.
log
(
`server is running on port
${
3000
}
`
);
});
...
...
src/models/index.ts
View file @
fc01d0b3
export
{
default
as
User
,
IUser
}
from
"
./user.model
"
;
export
{
default
as
Post
,
PostType
}
from
"
./post.model
"
;
src/models/post.model.ts
0 → 100644
View file @
fc01d0b3
import
{
model
,
Schema
}
from
"
mongoose
"
;
export
interface
PostType
{
id
:
string
;
title
:
string
;
date
:
Date
;
body
:
string
;
counts
?:
number
;
theme
:
string
;
city
:
string
;
}
const
schema
=
new
Schema
<
PostType
>
({
id
:
{
type
:
String
},
title
:
{
type
:
String
},
date
:
{
type
:
Date
},
body
:
{
type
:
String
},
counts
:
{
type
:
Number
},
theme
:
{
type
:
String
},
city
:
{
type
:
String
},
});
export
default
model
<
PostType
>
(
"
Post
"
,
schema
);
src/models/user.model.ts
View file @
fc01d0b3
...
...
@@ -14,7 +14,7 @@ const validateEmail = (email: string) => {
const
schema
=
new
Schema
<
IUser
>
({
email
:
{
type
:
String
,
type
:
String
,
//mongoose type 인 String 으로 일반적인 string 과는 겉으로는 대문자 차이
rquired
:
true
,
unique
:
true
,
validate
:
[
validateEmail
,
"
이메일을 입력해주세요
"
],
...
...
src/routes/index.ts
View file @
fc01d0b3
import
express
from
"
express
"
;
import
userRouter
from
"
./user.route
"
;
import
authRouter
from
"
./auth.route
"
;
import
postRouter
from
"
./post.route
"
;
const
router
=
express
.
Router
();
router
.
use
(
"
/users
"
,
userRouter
);
router
.
use
(
"
/auth
"
,
authRouter
);
export
default
router
;
src/routes/post.route.ts
0 → 100644
View file @
fc01d0b3
import
express
from
"
express
"
;
import
{
postCtrl
}
from
"
../controllers
"
;
const
router
=
express
.
Router
();
router
.
route
(
"
/
"
).
post
(
postCtrl
.
postup
)
export
default
router
\ No newline at end of file
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