diff --git a/src/DTO/authDTO.ts b/src/DTO/authDTO.ts index 39a677a..d9fdfb5 100644 --- a/src/DTO/authDTO.ts +++ b/src/DTO/authDTO.ts @@ -28,6 +28,24 @@ namespace authDTO { email: string; password: string; } + + export interface emailReqDTO { + email: string; + } + + export interface codeReqDTO { + email: string; + emailCode: string; + } + + export interface codeResDTO { + isOkay: boolean; + } + + export interface passwordReqDTO { + email: string; + password: string; + } } export default authDTO; diff --git a/src/controller/auth.ts b/src/controller/auth.ts index 8c18463..16ea9a4 100644 --- a/src/controller/auth.ts +++ b/src/controller/auth.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express"; -import { check, validationResult } from "express-validator"; +import { validationResult } from "express-validator"; // libraries import { response, returnCode } from "../library"; // services @@ -14,9 +14,14 @@ import { authDTO } from "../DTO"; */ const signupController = async (req: Request, res: Response) => { + // 이메일 형식이 잘못된 경우 const errors = validationResult(req); if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); + return response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); } try { @@ -57,9 +62,14 @@ const signupController = async (req: Request, res: Response) => { */ const signinController = async (req: Request, res: Response) => { + // 이메일 형식이 잘못된 경우 const errors = validationResult(req); if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); + return response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); } try { @@ -107,113 +117,167 @@ const signinController = async (req: Request, res: Response) => { } }; -// /** -// * @이메일_인증번호_전송 -// * @route Post auth/email -// * @access Public -// */ - -// router.post( -// "/email", -// [check("email", "Please include a valid email").isEmail()], -// async (req: Request, res: Response) => { -// const errors = validationResult(req); -// if (!errors.isEmpty()) { -// return res.status(400).json({ errors: errors.array() }); -// } - -// try { -// const data = await postEmail(req.body); - -// // 요청 바디가 부족할 경우 -// if (data == -1) { -// response(res, returnCode.BAD_REQUEST, "요청 값이 올바르지 않습니다"); -// } -// // email이 DB에 없을 경우 -// if (data == -2) { -// response(res, returnCode.BAD_REQUEST, "아이디가 존재하지 않습니다"); -// } -// // 성공 -// response(res, returnCode.OK, "인증번호 전송 성공"); -// } catch (err) { -// console.error(err.message); -// response(res, returnCode.INTERNAL_SERVER_ERROR, "서버 오류"); -// } -// } -// ); - -// /** -// * @인증번호_확인 -// * @route Post auth/code -// * @access Public -// */ - -// router.post("/code", async (req: Request, res: Response) => { -// try { -// const data = await postCode(req.body); - -// // 요청 바디가 부족할 경우 -// if (data === -1) { -// response(res, returnCode.BAD_REQUEST, "요청 값이 올바르지 않습니다"); -// } -// // email이 DB에 없을 경우 -// if (data === -2) { -// response(res, returnCode.BAD_REQUEST, "아이디가 존재하지 않습니다"); -// } -// // 인증번호가 올바르지 않은 경우 -// if (data === -3) { -// dataResponse(res, returnCode.OK, "인증번호 인증 실패", { isOkay: false }); -// } -// // 인증번호 인증 성공 -// dataResponse(res, returnCode.OK, "인증번호 인증 성공", { isOkay: true }); -// } catch (err) { -// console.error(err.message); -// response(res, returnCode.INTERNAL_SERVER_ERROR, "서버 오류"); -// } -// }); - -// /** -// * @비밀번호_변경 -// * @route Patch auth/pw -// * @desc Authenticate user & get token -// * @access Public -// */ - -// router.patch( -// "/pw", -// [ -// check("email", "Please include a valid email").isEmail(), -// check( -// "password", -// "Please enter a password with 6 or more characters" -// ).isLength({ min: 6 }), -// ], -// async (req: Request, res: Response) => { -// const errors = validationResult(req); -// if (!errors.isEmpty()) { -// return res.status(400).json({ errors: errors.array() }); -// } - -// try { -// const reqData: pwReqDTO = req.body; -// const data = await patchPassword(reqData); - -// // 요청 바디가 부족할 경우 -// if (data === -1) { -// response(res, returnCode.BAD_REQUEST, "요청 값이 올바르지 않습니다"); -// } -// // email이 DB에 없을 경우 -// if (data === -2) { -// response(res, returnCode.BAD_REQUEST, "아이디가 존재하지 않습니다"); -// } -// // 성공 -// response(res, returnCode.OK, "비밀번호 변경 성공"); -// } catch (err) { -// console.error(err.message); -// response(res, returnCode.INTERNAL_SERVER_ERROR, "서버 오류"); -// } -// } -// ); +/** + * @이메일_인증번호_전송 + * @route Post auth/email + * @desc post email code for certification + * @access Public + */ + +const postEmailController = async (req: Request, res: Response) => { + // 이메일 형식이 잘못된 경우 + const errors = validationResult(req); + if (!errors.isEmpty()) { + return response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); + } + + try { + const reqData: authDTO.emailReqDTO = req.body; + const resData: undefined | -1 | -2 | -3 = await authService.postEmail( + reqData + ); + + // 요청 바디가 부족할 경우 + if (resData === -1) { + response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); + } + // email이 DB에 없을 경우 + else if (resData === -2) { + response.basicResponse( + res, + returnCode.BAD_REQUEST, + "아이디가 존재하지 않습니다" + ); + } + // 이메일 전송이 실패한 경우 + else if (resData === -3) { + response.basicResponse( + res, + returnCode.SERVICE_UNAVAILABLE, + "이메일 전송이 실패하였습니다" + ); + } + // 성공 + else { + response.basicResponse(res, returnCode.NO_CONTENT, "인증번호 전송 성공"); + } + } catch (err) { + console.error(err.message); + response.basicResponse(res, returnCode.INTERNAL_SERVER_ERROR, "서버 오류"); + } +}; + +/** + * @인증번호_확인 + * @route Post auth/code + * @desc check the certification code + * @access Public + */ + +const postCodeController = async (req: Request, res: Response) => { + // 이메일 형식이 잘못된 경우 + const errors = validationResult(req); + if (!errors.isEmpty()) { + return response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); + } + + try { + const reqData: authDTO.codeReqDTO = req.body; + const resData: undefined | -1 | -2 | -3 = await authService.postCode( + reqData + ); + + // 요청 바디가 부족할 경우 + if (resData === -1) { + response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); + } + // email이 DB에 없을 경우 + if (resData === -2) { + response.basicResponse( + res, + returnCode.BAD_REQUEST, + "아이디가 존재하지 않습니다" + ); + } + // 인증번호가 올바르지 않은 경우 + if (resData === -3) { + response.dataResponse(res, returnCode.OK, "인증번호 인증 실패", { + isOkay: false, + }); + } + // 인증번호 인증 성공 + response.dataResponse(res, returnCode.OK, "인증번호 인증 성공", { + isOkay: true, + }); + } catch (err) { + console.error(err.message); + response.basicResponse(res, returnCode.INTERNAL_SERVER_ERROR, "서버 오류"); + } +}; + +/** + * @비밀번호_변경 + * @route Patch auth/pw + * @desc change password + * @access Public + */ + +const patchPasswordController = async (req: Request, res: Response) => { + // 이메일 형식 또는 비밀번호 형식이 잘못된 경우 + const errors = validationResult(req); + if (!errors.isEmpty()) { + return response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); + } + + try { + const reqData: authDTO.passwordReqDTO = req.body; + const data: undefined | -1 | -2 = await authService.patchPassword(reqData); + + // 요청 바디가 부족할 경우 + if (data === -1) { + response.basicResponse( + res, + returnCode.BAD_REQUEST, + "요청 값이 올바르지 않습니다" + ); + } + // email이 DB에 없을 경우 + else if (data === -2) { + response.basicResponse( + res, + returnCode.BAD_REQUEST, + "아이디가 존재하지 않습니다" + ); + } + // 성공 + else { + response.basicResponse(res, returnCode.NO_CONTENT, "비밀번호 변경 성공"); + } + } catch (err) { + console.error(err.message); + response.basicResponse(res, returnCode.INTERNAL_SERVER_ERROR, "서버 오류"); + } +}; /** * @햄버거바 @@ -238,6 +302,9 @@ const authController = { signinController, signupController, hamburgerController, + postEmailController, + postCodeController, + patchPasswordController, }; export default authController; diff --git a/src/library/emailTemplete.ejs b/src/library/emailTemplete.ejs index ed4ad1c..003994b 100644 --- a/src/library/emailTemplete.ejs +++ b/src/library/emailTemplete.ejs @@ -26,7 +26,7 @@
-

비밀번호 찾기를 위한 인증번호 입니다.

+

💡 비밀번호 찾기를 위한 인증번호 입니다.

비밀번호를 꼭 변경해주세요!

<%= authCode %> diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index 75f5bdc..d22a4fd 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -1,9 +1,10 @@ // libararies +import { Request, Response } from "express"; import jwt from "jsonwebtoken"; import config from "../config"; import { response, returnCode } from "../library"; -export default (req, res, next) => { +export default (req: Request, res: Response, next) => { // 토큰 검사 if (req.headers.authorization == null) { response.basicResponse( @@ -17,7 +18,7 @@ export default (req, res, next) => { // Verify token try { const decoded = jwt.verify(token, config.jwtSecret); - + req.body.userID = decoded.user; next(); } catch (err) { diff --git a/src/middleware/index.ts b/src/middleware/index.ts index c5d688b..af11905 100644 --- a/src/middleware/index.ts +++ b/src/middleware/index.ts @@ -1,2 +1,3 @@ export { default as authMiddleware } from "./auth"; export { default as publicAuthMiddleware } from "./publicAuth"; +export { default as typeCheckMiddleware } from "./typeCheck"; diff --git a/src/middleware/publicAuth.ts b/src/middleware/publicAuth.ts index e32058f..6ee4bbd 100644 --- a/src/middleware/publicAuth.ts +++ b/src/middleware/publicAuth.ts @@ -1,9 +1,10 @@ // libararies +import { Request, Response } from "express"; import jwt from "jsonwebtoken"; import config from "../config"; import { response, returnCode } from "../library"; -export default (req, res, next) => { +export default (req: Request, res: Response, next) => { // 토큰 검사 if (req.headers.authorization == null) { req.body.userID = null; diff --git a/src/middleware/typeCheck.ts b/src/middleware/typeCheck.ts new file mode 100644 index 0000000..a8530c9 --- /dev/null +++ b/src/middleware/typeCheck.ts @@ -0,0 +1,9 @@ +import { check } from "express-validator"; + +export default [ + check("email", "Please include a valid email").isEmail(), + check( + "password", + "Please enter a password with 6 or more characters" + ).isLength({ min: 6 }), +]; diff --git a/src/router/auth.ts b/src/router/auth.ts index 1d59328..0345eed 100644 --- a/src/router/auth.ts +++ b/src/router/auth.ts @@ -1,10 +1,18 @@ import express from "express"; import { authController } from "../controller"; +import { typeCheckMiddleware } from "../middleware"; const router = express.Router(); -router.post("/signup", authController.signupController); -router.post("/signin", authController.signinController); +router.post("/signup", typeCheckMiddleware, authController.signupController); +router.post("/signin", typeCheckMiddleware, authController.signinController); +router.post("/email", typeCheckMiddleware, authController.postEmailController); +router.post("/code", typeCheckMiddleware, authController.postCodeController); router.get("/hamburger", authController.hamburgerController); +router.patch( + "/pw", + typeCheckMiddleware, + authController.patchPasswordController +); export default router; diff --git a/src/service/authService.ts b/src/service/authService.ts index 664d36e..0036bc4 100644 --- a/src/service/authService.ts +++ b/src/service/authService.ts @@ -51,17 +51,10 @@ const postSignup = async (data: authDTO.signupReqDTO) => { password: hashPassword, nickname, isMarketing, + interest: interest.join(), }); - // UserInterest 생성 const userID = (await user).id; - const interests = await interest.map((interestOne) => { - UserInterest.create({ - userID: userID, - interest: interestOne, - }); - return interestOne; - }); // Badge 생성 const badge = await Badge.create({ @@ -240,137 +233,138 @@ const getHamburger = async () => { return resData; }; -// /** -// * @이메일_인증번호_전송 -// * @route Post auth/email -// * @body email -// * @error -// * 1. 요청 바디 부족 -// * 2. 아이디가 존재하지 않음 -// */ -// export async function postEmail(body) { -// const { email } = body; - -// // 1. 요청 바디 부족 -// if (!email) { -// return -1; -// } - -// // 2. email이 DB에 존재하지 않음 -// let user = await User.findOne({ email }); -// if (!user) { -// return -2; -// } - -// // 인증번호를 user에 저장 -> 제한 시간 설정하기! -// const authNum = Math.random().toString().substr(2, 6); -// user.emailCode = authNum; -// await user.save(); - -// let emailTemplate; -// ejs.renderFile( -// "src/library/emailTemplete.ejs", -// { authCode: authNum }, -// (err, data) => { -// if (err) { -// console.log(err); -// } -// emailTemplate = data; -// } -// ); - -// const mailOptions = { -// front: "hyunjin5697@gmail.com", -// to: email, -// subject: "메일 제목", -// text: "메일 내용", -// html: emailTemplate, -// }; - -// await emailSender.sendMail(mailOptions, (error, info) => { -// if (error) { -// // res.json({ msg: "err" }); -// console.log(error); -// } else { -// // res.json({ msg: "sucess" }); -// console.log("success"); -// } -// emailSender.close(); -// }); - -// return 0; -// } - -// /** -// * @인증번호_인증 -// * @route Post auth/code -// * @body email -// * @error -// * 1. 요청 바디 부족 -// * 2. 유저가 존재하지 않음 -// */ -// export async function postCode(body) { -// // 저장해놓은 authNum이랑 body로 온 인증번호랑 비교 -// const { email, emailCode } = body; - -// // 1. 요청 바디 부족 -// if (!email || !emailCode) { -// return -1; -// } - -// // 2. 유저가 존재하지 않음 -// // isDeleted = false 인 유저를 찾아야함 -// // 회원 탈퇴했다가 다시 가입한 경우 생각하기 -// let user = await User.findOne({ email: email }); -// if (!user) { -// return -2; -// } - -// if (emailCode !== user.emailCode) { -// // 인증번호가 일치하지 않음 -// return -3; -// } else { -// // 인증번호 일치 -// return 0; -// } - -// return; -// } - -// /** -// * @비밀번호_재설정 -// * @route Patch auth/pw -// * @body email -// * @error -// * 1. 요청 바디 부족 -// * 2. 아이디가 존재하지 않음 -// */ -// export async function patchPassword(reqData: pwReqDTO) { -// const { email, password } = reqData; - -// // 1. 요청 바디 부족 -// if (!email || !password) { -// return -1; -// } - -// // 2. email이 DB에 존재하지 않음 -// let user = await User.findOne({ email }); -// if (!user) { -// return -2; -// } - -// // 비밀번호 변경 로직 -// // Encrpyt password -// const salt = await bcrypt.genSalt(10); -// user.password = await bcrypt.hash(password, salt); -// await user.save(); -// return; -// } +/** + * @이메일_인증번호_전송 + * @route Post auth/email + * @body email + * @error + * 1. 요청 바디 부족 + * 2. 이매일이 DB에 존재하지 않음 + * 3. 이메일 전송 실패 + */ +const postEmail = async (body: authDTO.emailReqDTO) => { + const { email } = body; + + // 1. 요청 바디 부족 + if (!email) { + return -1; + } + + // 2. email이 DB에 존재하지 않음 + const user = await User.findOne({ where: { email } }); + if (!user) { + return -2; + } + + // 인증번호를 user에 저장 -> 제한 시간 설정하기! + const authNum = Math.random().toString().substr(2, 6); + user.emailCode = authNum; + await user.save(); + + let emailTemplate: string; + ejs.renderFile( + "src/library/emailTemplete.ejs", + { authCode: authNum }, + (err, data) => { + if (err) { + console.log(err); + } + emailTemplate = data; + } + ); + + const mailOptions = { + front: process.env.EMAIL_ADDRESS, + to: email, + subject: "O2 이메일 인증번호입니다.", + text: "O2 이메일 인증번호 입니다.", + html: emailTemplate, + }; + + emailSender.sendMail(mailOptions, (error, info) => { + if (error) { + console.log(error); + return -3; + } else { + console.log("success"); + } + emailSender.close(); + }); + + return undefined; +}; + +/** + * @인증번호_인증 + * @route Post auth/code + * @body email, emailCode + * @error + * 1. 요청 바디 부족 + * 2. 유저가 존재하지 않음 + * 3. 인증번호 인증 실패 + */ +export async function postCode(body: authDTO.codeReqDTO) { + const { email, emailCode } = body; + + // 1. 요청 바디 부족 + if (!email || !emailCode) { + return -1; + } + + // 2. 유저가 존재하지 않음 + // isDeleted = false 인 유저를 찾아야함 + // 회원 탈퇴했다가 다시 가입한 경우 생각하기 + const user = await User.findOne({ where: { email } }); + if (!user) { + return -2; + } + + if (emailCode !== user.emailCode) { + // 인증번호가 일치하지 않음 + return -3; + } + + // 인증번호 일치 + return undefined; +} + +/** + * @비밀번호_재설정 + * @route Patch auth/pw + * @body email, password + * @error + * 1. 요청 바디 부족 + * 2. 아이디가 존재하지 않음 + */ +export async function patchPassword(reqData: authDTO.passwordReqDTO) { + const { email, password } = reqData; + + // 1. 요청 바디 부족 + if (!email || !password) { + return -1; + } + + // 2. email이 DB에 존재하지 않음 + const user = await User.findOne({ where: { email } }); + if (!user) { + return -2; + } + + // 비밀번호 변경 로직 + // Encrpyt password + const salt = await bcrypt.genSalt(10); + user.password = await bcrypt.hash(password, salt); + await user.save(); + return; +} const authService = { postSignup, postSignin, getHamburger, + postEmail, + postCode, + patchPassword, }; export default authService;