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
5e259cfd
Commit
5e259cfd
authored
Jul 08, 2022
by
Kim, MinGyu
Browse files
context를 사용하여 login 구성
parent
81cba2c9
Changes
14
Hide whitespace changes
Inline
Side-by-side
frontend/src/App.tsx
View file @
5e259cfd
...
...
@@ -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 @
5e259cfd
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 @
5e259cfd
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 @
5e259cfd
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 @
5e259cfd
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 @
5e259cfd
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 @
5e259cfd
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 @
5e259cfd
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 @
5e259cfd
...
...
@@ -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 @
5e259cfd
...
...
@@ -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 @
5e259cfd
...
...
@@ -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 @
5e259cfd
...
...
@@ -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 @
5e259cfd
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 @
5e259cfd
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