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
6ffbcae1
Commit
6ffbcae1
authored
Jul 08, 2022
by
Lee Soobeom
Browse files
Merge remote-tracking branch 'origin/mk10' into develop
parents
7c259f47
5e259cfd
Changes
14
Hide whitespace changes
Inline
Side-by-side
frontend/src/App.tsx
View file @
6ffbcae1
...
...
@@ -5,12 +5,22 @@ import { Login, Signup } from "./auth";
import
{
Board
}
from
"
./board
"
;
import
{
Header
,
Body
}
from
"
./home
"
;
import
Posting
from
"
./post/posting
"
;
import
{
AuthProvider
}
from
"
./auth/auth.context
"
;
import
Layout
from
"
./commons/layout
"
;
export
const
App
=
()
=>
{
return
(
<
BrowserRouter
>
<
Routes
>
<
Route
path
=
"login"
element
=
{
<
Login
/>
}
/>
{
/* <Route element={<Layout children={} />}> */
}
<
Route
path
=
"login"
element
=
{
<
AuthProvider
>
<
Login
/>
</
AuthProvider
>
}
/>
<
Route
path
=
"signup"
element
=
{
<
Signup
/>
}
/>
<
Route
path
=
"/"
element
=
{
<
Header
/>
}
>
...
...
@@ -18,6 +28,7 @@ export const App = () => {
<
Route
path
=
"board"
element
=
{
<
Board
/>
}
/>
<
Route
path
=
"posting"
element
=
{
<
Posting
/>
}
/>
</
Route
>
{
/* </Route> */
}
</
Routes
>
</
BrowserRouter
>
);
...
...
frontend/src/auth/RequireAuth.tsx
0 → 100644
View file @
6ffbcae1
import
React
,
{
FC
}
from
"
react
"
;
import
{
Navigate
,
useLocation
}
from
"
react-router-dom
"
;
import
{
useAuth
}
from
"
./auth.context
"
;
export
const
RequireAuth
:
FC
<
{
children
:
JSX
.
Element
}
>
=
({
children
})
=>
{
const
{
user
}
=
useAuth
();
const
location
=
useLocation
();
if
(
!
user
.
isLoggedIn
)
{
return
(
<
Navigate
to
=
{
"
/login
"
}
state
=
{
{
from
:
location
.
pathname
}
}
replace
/>
);
}
return
children
;
};
frontend/src/auth/auth.context.tsx
0 → 100644
View file @
6ffbcae1
import
React
,
{
createContext
,
FC
,
ReactNode
,
useContext
,
useState
,
}
from
"
react
"
;
import
{
IUser
}
from
"
../types
"
;
import
{
getLocalUser
,
handleLogin
,
handleLogout
}
from
"
./auth.helper
"
;
interface
IAuthContext
{
login
:
(
email
:
string
,
password
:
string
,
cb
?:
VoidFunction
)
=>
Promise
<
void
>
;
logout
:
(
cb
?:
VoidFunction
)
=>
Promise
<
void
>
;
user
:
IUser
;
}
const
AuthContext
=
createContext
<
IAuthContext
>
({
login
:
async
()
=>
{},
logout
:
async
()
=>
{},
user
:
{
isLoggedIn
:
false
},
});
export
const
AuthProvider
:
FC
<
{
children
:
ReactNode
}
>
=
({
children
})
=>
{
const
[
user
,
setUser
]
=
useState
(
getLocalUser
());
const
login
=
async
(
email
:
string
,
password
:
string
,
cb
:
VoidFunction
=
()
=>
{}
)
=>
{
const
user
=
await
handleLogin
(
email
,
password
);
setUser
(
user
);
cb
();
};
const
logout
=
async
(
cb
:
VoidFunction
=
()
=>
{})
=>
{
await
handleLogout
();
setUser
({
...
user
,
isLoggedIn
:
false
});
cb
();
};
return
(
<
AuthContext
.
Provider
value
=
{
{
login
,
logout
,
user
}
}
>
{
children
}
</
AuthContext
.
Provider
>
);
};
export
const
useAuth
=
()
=>
useContext
(
AuthContext
);
frontend/src/auth/auth.helper.tsx
0 → 100644
View file @
6ffbcae1
import
{
authApi
}
from
"
../apis
"
;
import
{
IUser
}
from
"
../types
"
;
const
LOCAL_USER_INFO
=
"
survey-user-info
"
;
/**
* 1. 백엔드 로그인을 호출하여 로그인 정보를 얻습니다.
* 2. 로컬 저장소에 저장합니다.
* 3. 사용자 정보를 반환합니다.
* @param email 이메일
* @param password 비밀번호
* @returns 사용자 정보
*/
export
const
handleLogin
=
async
(
email
:
string
,
password
:
string
)
=>
{
const
user
:
IUser
=
await
authApi
.
login
(
email
,
password
);
// 로컬 저장소에는 로그인 여부만 저장
localStorage
.
setItem
(
LOCAL_USER_INFO
,
JSON
.
stringify
({
isLoggedIn
:
user
.
isLoggedIn
,
})
);
return
user
;
};
/**
* 로컬 저장소의 정보를 삭제합니다.
* 백엔드 로그아웃을 호출하여 쿠키를 제거합니다.
*/
export
const
handleLogout
=
async
()
=>
{
console
.
log
(
"
handle logout called
"
);
localStorage
.
removeItem
(
LOCAL_USER_INFO
);
try
{
await
authApi
.
logout
();
}
catch
(
error
)
{
console
.
log
(
"
logout 중에 에러 발생:
"
,
error
);
}
};
/**
* 1. 로컬 저장소에 저장된 사용자 로그인 정보를 반환합니다.
* 2. 로컬 저장소에 정보가 없으면 { isLoggedIn: false }를 반환합니다.
* @returns 로컬 저장소에 저장된 사용자 정보
*/
export
const
getLocalUser
=
()
=>
{
console
.
log
(
"
get local user called
"
);
const
userInfo
=
localStorage
.
getItem
(
LOCAL_USER_INFO
);
const
user
:
IUser
=
{
isLoggedIn
:
false
};
if
(
!
userInfo
)
{
return
user
;
}
const
userData
=
JSON
.
parse
(
userInfo
);
if
(
userData
.
isLoggedIn
)
{
user
.
isLoggedIn
=
true
;
}
else
{
user
.
isLoggedIn
=
false
;
}
return
user
;
};
frontend/src/auth/login.tsx
View file @
6ffbcae1
import
{
Link
}
from
"
react-router-dom
"
;
import
React
,
{
useState
,
FormEventHandler
}
from
"
react
"
;
import
{
Link
,
useNavigate
}
from
"
react-router-dom
"
;
import
React
,
{
useState
,
useEffect
,
FormEvent
}
from
"
react
"
;
import
{
LoginUser
}
from
"
../types
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
useAuth
}
from
"
./auth.context
"
;
interface
login
{
id
:
string
;
password
:
string
;
}
export
default
function
Login
()
{
const
[
user
,
setUser
]
=
useState
<
LoginUser
>
({
email
:
""
,
password
:
""
,
});
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
error
,
setError
]
=
useState
(
""
);
const
[
disabled
,
setDisabled
]
=
useState
(
false
);
const
[
success
,
setSuccess
]
=
useState
(
false
);
const
navigate
=
useNavigate
();
const
{
login
}
=
useAuth
();
// const fake = { id: "asdf", password: "qwer" };
useEffect
(()
=>
{
setDisabled
(
!
(
user
.
email
&&
user
.
password
));
},
[
user
]);
function
Logindata
()
{
const
[
id
,
setId
]
=
useState
(
""
);
const
[
password
,
setPassword
]
=
useState
(
""
);
function
handleChange
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
{
const
{
name
,
value
}
=
event
.
currentTarget
;
setUser
({
...
user
,
[
name
]:
value
});
}
function
login
()
{
fetch
(
`http://localhost:3000/api/auth/login`
,
{
method
:
"
POST
"
,
async
function
handleSubmit
(
event
:
FormEvent
)
{
event
.
preventDefault
();
try
{
setError
(
""
);
console
.
log
(
"
user data
"
,
user
);
body
:
JSON
.
stringify
({
email
:
`
${
id
}
`
,
password
:
`
${
password
}
`
,
}),
}).
then
((
response
)
=>
{
console
.
log
(
response
.
json
());
});
// setLoading(true);
await
login
(
user
.
email
,
user
.
password
,
()
=>
{
navigate
(
"
/
"
,
{
replace
:
true
});
});
// console.log("서버연결됬나요", res);
// console.log("로그인");
// setSuccess(true);
// setError("");
}
catch
(
error
)
{
console
.
log
(
"
에러발생
"
);
// setError("이메일 혹은 비밀번호를 다시 입력해주세요.");
catchErrors
(
error
,
setError
);
}
finally
{
setLoading
(
false
);
}
}
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
<
div
className
=
"flex flex-col items-center my-10"
>
<
div
className
=
"bg-white w-1/2 md:w-1/3 my-8 text-center text-2xl"
>
<
Link
to
=
"/"
>
Travel Report
</
Link
>
</
div
>
<
div
className
=
"flex flex-col w-full md:w-1/2 p-8 md:p-4 md:p-0"
>
<
form
onSubmit
=
{
handleSubmit
}
>
<
div
className
=
"flex flex-col md:flex-row border-2 border-black rounded-xl p-8 md:p-12 gap-y-4 md:gap-x-6"
>
<
div
className
=
"flex flex-col md:w-2/3 md:gap-2 "
>
<
input
className
=
"
placeholder
:
text
-
slate
-
300
bg
-
white
border
border
-
slate
-
500
md
:
rounded
-
2xl
py
-
3
md
:
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
bg
-
white
border
border
-
slate
-
500
rounded
-
2xl
py
-
2
pl
-
9
pr
-
3
placeholder
=
"이메일"
type
=
"email"
name
=
"email"
onChange
=
{
handleChange
}
/>
<
input
className
=
"
placeholder
:
italic
placeholder
:
text
-
slate
-
300
bg
-
white
border
border
-
slate
-
500
md
:
rounded
-
2xl
py
-
3
md
:
py
-
2
pl
-
9
pr
-
3
focus
:
border
-
black
"
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-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
/>
</
div
>
<
div
className
=
"flex-row grid grid-cols-3"
>
<
button
className
=
"bg-white bottom-0 right-0"
>
<
Link
to
=
"/signup"
>
회원가입
</
Link
>
placeholder
=
"Password"
type
=
"password"
name
=
"password"
onChange
=
{
handleChange
}
/>
</
div
>
<
button
disabled
=
{
disabled
}
type
=
"submit"
className
=
"my-4 md:my-0 md:w-1/3 bg-sky-600 hover:bg-sky-700 rounded-xl text-xl py-4"
>
login
</
button
>
</
div
>
</
form
>
<
div
className
=
"flex justify-around m-4"
>
<
button
className
=
"bg-white "
>
<
Link
to
=
"/signup"
>
회원가입
</
Link
>
</
button
>
<
div
className
=
"grid grid-cols-2 divide-x-2"
>
<
div
></
div
>
<
div
></
div
>
<
button
className
=
"bg-white inset-x-0"
>
<
Link
to
=
"/forgot"
>
비밀번호 찾기
</
Link
>
</
button
>
</
div
>
<
button
className
=
"bg-white"
>
<
Link
to
=
"/forgot"
>
비밀번호 찾기
</
Link
>
</
button
>
</
div
>
</
div
>
{
/* </form> */
}
</
div
>
// Login Page
</
div
>
);
}
frontend/src/auth/signup.tsx
View file @
6ffbcae1
import
React
,
{
FormEvent
,
useEffect
,
useState
}
from
"
react
"
;
import
{
Link
,
use
Navigate
}
from
"
react-router-dom
"
;
import
{
Link
,
Navigate
}
from
"
react-router-dom
"
;
import
{
authApi
}
from
"
../apis
"
;
import
{
catchErrors
}
from
"
../helpers
"
;
import
{
SpinnerIcon
}
from
"
../icons
"
;
...
...
@@ -17,7 +17,6 @@ export default function Signup() {
const
[
error
,
setError
]
=
useState
(
""
);
const
[
disabled
,
setDisabled
]
=
useState
(
false
);
const
[
success
,
setSuccess
]
=
useState
(
false
);
const
navigate
=
useNavigate
();
useEffect
(()
=>
{
setDisabled
(
!
(
user
.
name
&&
user
.
email
&&
user
.
password
&&
user
.
password2
));
...
...
@@ -65,7 +64,7 @@ export default function Signup() {
if
(
success
)
{
alert
(
"
회원가입 되었습니다
"
);
n
avigate
(
"
/login
"
,
{
replace
:
true
})
;
return
<
N
avigate
to
=
{
"
/login
"
}
replace
/>
;
}
return
(
...
...
frontend/src/commons/layout.tsx
0 → 100644
View file @
6ffbcae1
import
React
,
{
ReactNode
}
from
"
react
"
;
import
{
AuthProvider
}
from
"
../auth/auth.context
"
;
export
default
function
Layout
({
children
}:
{
children
:
ReactNode
})
{
return
<
AuthProvider
>
{
children
}
</
AuthProvider
>;
}
frontend/src/home/header.tsx
View file @
6ffbcae1
import
React
from
"
react
"
;
import
{
Link
,
Outlet
}
from
"
react-router-dom
"
;
import
React
,
{
useState
}
from
"
react
"
;
import
{
Link
,
Outlet
}
from
"
react-router-dom
"
;
import
{
useAuth
}
from
"
../auth/auth.context
"
;
import
"
tailwindcss/tailwind.css
"
;
export
default
function
Header
()
{
return
(
<
div
className
=
"flex flex-col "
>
<
div
className
=
"flex flex-row px-5 py-20 md:place-content-between"
>
<
button
className
=
"px-5 py-2"
>
<
Link
to
=
"/"
className
=
"hover:bg-gray-200 focus:text-purple-500"
>
Travel Report
</
Link
>
</
button
>
<
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
>
const
{
logout
}
=
useAuth
();
return
(
<
div
className
=
"flex flex-col "
>
<
div
className
=
"flex flex-row px-5 py-20 md:place-content-between"
>
<
button
className
=
"px-5 py-2"
>
<
Link
to
=
"/"
className
=
"hover:bg-gray-200 focus:text-purple-500"
>
Travel Report
</
Link
>
</
button
>
<
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
onClick
=
{
()
=>
{
logout
();
}
}
>
Logout
</
button
>
<
div
>
<
label
>
{
/* <span className="sr-only">Search</span> */
}
<
span
className
=
"absolute inset-y-0 left-0 flex items-center pl-2"
>
<
svg
className
=
"h-5 w-5 fill-slate-300"
viewBox
=
"0 0 20 20"
></
svg
>
</
span
>
<
input
className
=
"placeholder:italic placeholder:text-slate-400 block bg-white w-full border border-slate-300 rounded-md py-2 pl-9 pr-3 shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm"
placeholder
=
"Search for anything..."
type
=
"text"
name
=
"search"
/>
</
label
>
</
div
>
</
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
>
</
button
>
<
div
>
<
label
>
{
/* <span className="sr-only">Search</span> */
}
<
span
className
=
"absolute inset-y-0 left-0 flex items-center pl-2"
>
<
svg
className
=
"h-5 w-5 fill-slate-300"
viewBox
=
"0 0 20 20"
></
svg
>
</
span
>
<
input
className
=
"placeholder:italic placeholder:text-slate-400 block bg-white w-full border border-slate-300 rounded-md py-2 pl-9 pr-3 shadow-sm focus:outline-none focus:border-sky-500 focus:ring-sky-500 focus:ring-1 sm:text-sm"
placeholder
=
"Search for anything..."
type
=
"text"
name
=
"search"
/>
</
label
>
</
div
>
</
div
>
<
Outlet
/>
</
div
>
);
}
\ No newline at end of file
<
Outlet
/>
</
div
>
);
}
frontend/src/post/posting.tsx
View file @
6ffbcae1
...
...
@@ -70,7 +70,7 @@ function SelectTheme() {
<
option
value
=
"history"
>
문화재
</
option
>
<
option
value
=
"zoo"
>
동물원
</
option
>
<
option
value
=
"cycling"
>
사이클링
</
option
>
<
option
value
=
"cycling"
>
{
selectTheme
}
</
option
>
{
/*
<option value="cycling">{selectTheme}</option>
*/
}
</
select
>
);
}
...
...
frontend/src/types/index.tsx
View file @
6ffbcae1
...
...
@@ -13,3 +13,14 @@ export interface SignupUser {
name
:
string
;
password
:
string
;
}
export
interface
LoginUser
{
email
:
string
;
password
:
string
;
}
export
interface
IUser
{
email
?:
string
;
isLoggedIn
:
boolean
;
_id
?:
string
;
}
src/controllers/auth.controller.ts
View file @
6ffbcae1
...
...
@@ -25,15 +25,18 @@ export const login = asyncWrap(async (req, res) => {
return
res
.
status
(
401
).
send
(
"
잘못된 비밀번호를 입력하셨습니다
"
);
}
// 3) 비밀번호가 맞으면 토큰 생성
const
token
=
jwt
.
sign
({
userId
:
user
.
id
},
jwtCofig
.
secret
,
{
//userId를 토큰에다 넣는 중.
const
token
=
jwt
.
sign
({
userId
:
user
.
id
},
jwtCofig
.
secret
,
{
//userId를 토큰에다 넣는 중.
expiresIn
:
jwtCofig
.
expires
,
});
// 4) 토큰을 쿠키에 저장
res
.
cookie
(
cookieConfig
.
name
,
token
,
{
//token은 쿠키에 무엇을 실렸는가 이다. 항상 갖고 있다가 홈페이지 들어가면 서버로 접속
maxAge
:
cookieConfig
.
maxAge
,
// 이 기간 한에서만 유효
path
:
"
/
"
,
//어떠한 경로에 관해서만 쓴다. 지금은 전부에 쓴다.
httpOnly
:
envConfig
.
mode
===
"
production
"
,
//false 면 브라우저에서 쿠키를 조작, true면 조작할 수 있다.
secure
:
envConfig
.
mode
===
"
production
"
,
//true 면 https 를 통해서만 쿠키 전달, false면
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
({
...
...
@@ -59,7 +62,7 @@ export const requireLogin = asyncWrap(async (reqExp, res, next) => {
const
decodedUser
=
jwt
.
verify
(
token
,
jwtCofig
.
secret
);
// 아까보낸 토근을 디코딩중.
// 3) 요청 객체에 토큰 사용자 객체 추가
req
.
auth
=
decodedUser
;
next
();
// 에러가 안나오면 next 사용, 나오면 catch쪽으로.
next
();
// 에러가 안나오면 next 사용, 나오면 catch쪽으로.
}
catch
(
error
)
{
res
.
clearCookie
(
cookieConfig
.
name
);
console
.
log
(
"
error in requreLogin===
\n
"
,
error
);
...
...
@@ -84,13 +87,13 @@ export const signup = asyncWrap(async (req, res) => {
if
(
userExist
)
{
return
res
.
status
(
422
).
send
(
`
${
email
}
사용자가 이미 존재합니다`
);
}
// 3) 비밀번호 암호화
// 3) 비밀번호 암호화
는 useDb.createUser에서 처리
const
hash
=
await
bcrypt
.
hash
(
password
,
10
);
// 4) 새로운 사용자 만들기
const
newUser
=
await
userDb
.
createUser
({
email
,
password
:
hash
,
password
,
});
// 5) 사용자 반환
// 5) 사용자 반환
(내부적으로 몽구스가 toJSON() 호출)
res
.
json
(
newUser
);
});
src/controllers/user.controller.ts
View file @
6ffbcae1
...
...
@@ -10,5 +10,5 @@ export const createUser = asyncWrap(async (req, res) => {
const
user
=
req
.
body
;
console
.
log
(
"
user body
"
,
user
);
const
newUser
=
await
userDb
.
createUser
(
user
);
return
res
.
json
(
u
ser
);
return
res
.
json
(
newU
ser
);
});
src/db/user.db.ts
View file @
6ffbcae1
import
bcrypt
from
"
bcryptjs
"
;
import
{
IUser
,
User
}
from
"
../models
"
;
export
const
createUser
=
async
(
user
:
IUser
)
=>
{
const
newUser
=
await
User
.
create
(
user
);
// 비밀번호 암호화
const
hash
=
await
bcrypt
.
hash
(
user
.
password
,
10
);
const
newUser
=
await
User
.
create
({
email
:
user
.
email
,
password
:
hash
});
return
newUser
;
};
...
...
src/models/user.model.ts
View file @
6ffbcae1
import
{
model
,
Schema
,
Types
}
from
"
mongoose
"
;
import
{
model
,
Schema
,
Types
,
version
}
from
"
mongoose
"
;
export
interface
IUser
{
email
:
string
;
...
...
@@ -12,16 +12,27 @@ const validateEmail = (email: string) => {
return
re
.
test
(
email
);
};
const
schema
=
new
Schema
<
IUser
>
({
email
:
{
type
:
String
,
//mongoose type 인 String 으로 일반적인 string 과는 겉으로는 대문자 차이
rquired
:
true
,
unique
:
true
,
validate
:
[
validateEmail
,
"
이메일을 입력해주세요
"
],
const
schema
=
new
Schema
<
IUser
>
(
{
email
:
{
type
:
String
,
//mongoose type인 String으로 일반적인 string과는 겉으로는 대문자 차이
rquired
:
true
,
unique
:
true
,
validate
:
[
validateEmail
,
"
이메일을 입력해주세요
"
],
},
name
:
{
type
:
String
},
password
:
{
type
:
String
,
required
:
true
,
select
:
false
},
role
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Role
"
},
},
name
:
{
type
:
String
},
password
:
{
type
:
String
,
required
:
true
,
select
:
false
},
role
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
"
Role
"
},
});
{
toJSON
:
{
versionKey
:
false
,
transform
(
doc
,
ret
,
options
)
{
delete
ret
.
password
;
},
},
}
);
export
default
model
<
IUser
>
(
"
User
"
,
schema
);
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