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
85077051
Commit
85077051
authored
Jul 06, 2022
by
Lee Soobeom
Browse files
Merge remote-tracking branch 'origin/mk8' into develop0
parents
483dba83
fc01d0b3
Changes
16
Show whitespace changes
Inline
Side-by-side
frontend/src/Pages/posting.tsx
View file @
85077051
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 @
85077051
frontend/src/pages/board.tsx
View file @
85077051
...
...
@@ -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 @
85077051
...
...
@@ -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 @
85077051
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
...
...
src/app.ts
View file @
85077051
...
...
@@ -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
)
=>
{
console
.
log
(
"
익스프레스 에러:
"
,
err
);
...
...
src/controllers/auth.controller.ts
View file @
85077051
...
...
@@ -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 @
85077051
src/controllers/post.controller.ts
View file @
85077051
src/db/index.ts
View file @
85077051
export
*
as
userDb
from
"
./user.db
"
;
export
*
as
postDb
from
"
./post.db
"
;
src/db/post.db.ts
View file @
85077051
import
{
PostType
,
Post
}
from
"
../models
"
;
export
const
createPost
=
async
(
post
:
PostType
)
=>
{
const
newPost
=
await
Post
.
create
(
post
);
return
newPost
;
};
export
const
checkTitleNull
=
async
(
title
:
string
,
...
...
@@ -36,3 +44,4 @@ export const selectCity = async (
}
}
src/index.ts
View file @
85077051
...
...
@@ -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 @
85077051
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 @
85077051
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 @
85077051
...
...
@@ -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 @
85077051
...
...
@@ -9,4 +9,5 @@ router.use("/users", userRouter);
router
.
use
(
"
/auth
"
,
authRouter
);
router
.
use
(
"
/posts
"
,
postRouter
);
//router.route
export
default
router
;
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