From 81285c8ebdbc9e5ba5e311dcb9d068e39497dc64 Mon Sep 17 00:00:00 2001 From: seoyeoneel02 Date: Wed, 11 Sep 2024 23:33:17 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EC=B2=B4=ED=98=95=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84=20#122?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/recommend/recommend.controller.js | 9 ++++++ src/domains/recommend/recommend.dao.js | 31 +++++++++++++++++++ src/domains/recommend/recommend.dto.js | 19 ++++++++++++ src/domains/recommend/recommend.provider.js | 6 ++++ src/domains/recommend/recommend.sql.js | 26 ++++++++++++++++ src/index.js | 2 ++ src/routes/recommend.js | 9 ++++++ 7 files changed, 102 insertions(+) create mode 100644 src/domains/recommend/recommend.controller.js create mode 100644 src/domains/recommend/recommend.dao.js create mode 100644 src/domains/recommend/recommend.dto.js create mode 100644 src/domains/recommend/recommend.provider.js create mode 100644 src/domains/recommend/recommend.sql.js create mode 100644 src/routes/recommend.js diff --git a/src/domains/recommend/recommend.controller.js b/src/domains/recommend/recommend.controller.js new file mode 100644 index 0000000..6a8c00d --- /dev/null +++ b/src/domains/recommend/recommend.controller.js @@ -0,0 +1,9 @@ +import { response } from "../../config/response.js"; +import { status } from "../../config/response.status.js"; +import { getBodyInfo } from "./recommend.provider.js"; + +export const bodyInfo = async (req, res, next) => { + console.log("비슷한 체형의 유저를 추천합니다"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await getBodyInfo(userId))); +} \ No newline at end of file diff --git a/src/domains/recommend/recommend.dao.js b/src/domains/recommend/recommend.dao.js new file mode 100644 index 0000000..f557df7 --- /dev/null +++ b/src/domains/recommend/recommend.dao.js @@ -0,0 +1,31 @@ +import { pool } from "../../config/db.config.js"; +import { BaseError } from "../../config/error.js"; +import { status } from "../../config/response.status.js"; +import { getUser, findUserToBody, getFitToUserId, getStyleToUserId } from "./recommend.sql.js"; + +export const getBodyInfoDAO = async (userId) => { + try { + const conn = await pool.getConnection(); + const result = []; + const user = await pool.query(getUser, userId); + const height = user[0][0].height; + const weight = user[0][0].weight; + const recommend = await pool.query(findUserToBody, [userId, height, height, weight, weight, height, weight]); + + if(recommend[0].length == 0){ + conn.release(); + return -1; + }else{ + for (let i = 0; i < recommend[0].length; i++) { + const user = await pool.query(getUser, recommend[0][i].uuid); + const fit = await pool.query(getFitToUserId, recommend[0][i].uuid); + const style = await pool.query(getStyleToUserId, recommend[0][i].uuid); + result.push({user, fit, style}); + } + } + conn.release(); + return result; + } catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } +} \ No newline at end of file diff --git a/src/domains/recommend/recommend.dto.js b/src/domains/recommend/recommend.dto.js new file mode 100644 index 0000000..4298bf2 --- /dev/null +++ b/src/domains/recommend/recommend.dto.js @@ -0,0 +1,19 @@ +export const getBodyInfoDTO = (data) => { + const user = []; + if(data == -1){ + user.push("해당 유저는 등록되어 있지 않아요."); + }else{ + for (let i = 0; i < data.length; i++) { + user.push({ + "user_id": data[i].user[0][0].uuid, + "nickname": data[i].user[0][0].nickname, + "user_image": data[i].user[0][0].img_url, + "height": data[i].user[0][0].height, + "weight": data[i].user[0][0].weight, + "prefer_fit": data[i].fit[0].map(fitItem => fitItem.pf_name), + "prefer_style": data[i].style[0].map(styleItem => styleItem.style_name) + }) + } + } + return {"userData": user}; +} \ No newline at end of file diff --git a/src/domains/recommend/recommend.provider.js b/src/domains/recommend/recommend.provider.js new file mode 100644 index 0000000..d772cce --- /dev/null +++ b/src/domains/recommend/recommend.provider.js @@ -0,0 +1,6 @@ +import { getBodyInfoDTO } from "./recommend.dto.js" +import { getBodyInfoDAO } from "./recommend.dao.js"; + +export const getBodyInfo = async (userId) => { + return getBodyInfoDTO(await getBodyInfoDAO(userId)); +} \ No newline at end of file diff --git a/src/domains/recommend/recommend.sql.js b/src/domains/recommend/recommend.sql.js new file mode 100644 index 0000000..7611674 --- /dev/null +++ b/src/domains/recommend/recommend.sql.js @@ -0,0 +1,26 @@ +export const getUser = +"SELECT m.uuid, m.nickname, m.img_url, b.height, b.weight " ++ "FROM body_info b JOIN member m on b.uuid = m.uuid " ++ "WHERE b.uuid = ? ;" + +export const findUserToBody = +"SELECT b.uuid " ++ "FROM body_info b " ++ "WHERE NOT uuid = ? and height BETWEEN ?-5 AND ?+5 " ++ "AND weight BETWEEN ?-5 AND ?+5 " ++ "ORDER BY ABS(height-?) + ABS(weight-?) ASC LIMIT 24;" + +export const getFitToUserId = +"SELECT uf.uuid, uf.pf_name " ++ "FROM user_fit uf " ++ "WHERE uf.uuid = ? ;" + +export const getStyleToUserId = +"SELECT us.uuid, us.style_name " ++ "FROM user_style us " ++ "WHERE us.uuid = ? ;" + +export const findUserToFit = +"SELECT uf.uuid, uf.style_name " ++ "FROM user_fit uf " ++ "WHERE uf.pf_name = ? ;" \ No newline at end of file diff --git a/src/index.js b/src/index.js index 32ba547..b65076a 100644 --- a/src/index.js +++ b/src/index.js @@ -22,6 +22,7 @@ import compareSizeRoutes from './routes/comparesize.routes.js'; import manualResultsRoutes from './routes/manualresults.routes.js'; import { profileRouter } from './routes/profile.js'; import { logoutRouter } from './routes/logout.js'; +import { recommendRouter } from './routes/recommend.js'; dotenv.config(); @@ -62,6 +63,7 @@ app.use('/temp-token', tempRouter); app.use('/FITple/comparesizes', compareSizeRoutes); app.use('/FITple/manualresults', manualResultsRoutes); app.use('/FITple/profile', profileRouter); +app.use('/FITple/recommend', recommendRouter); // error handling app.use((req, res, next) => { diff --git a/src/routes/recommend.js b/src/routes/recommend.js new file mode 100644 index 0000000..e450aff --- /dev/null +++ b/src/routes/recommend.js @@ -0,0 +1,9 @@ +import express from "express"; +import asyncHandler from 'express-async-handler'; +import { LoginCheck } from "../middlewares/logincheck.js"; +import { bodyInfo } from "../domains/recommend/recommend.controller.js"; + +export const recommendRouter = express.Router({mergeParams: true}); + +//체형 추천 +recommendRouter.get('/body_info', LoginCheck, asyncHandler(bodyInfo)); \ No newline at end of file From 79fd6be3c9b6defb3e13ea353d68d5d414dda7dd Mon Sep 17 00:00:00 2001 From: seoyeoneel02 Date: Wed, 11 Sep 2024 23:44:26 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EC=B2=B4=ED=98=95=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EB=AA=A8=EB=91=90=EB=B3=B4=EA=B8=B0=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84=20#122?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/recommend/recommend.controller.js | 8 ++++- src/domains/recommend/recommend.dao.js | 29 ++++++++++++++++++- src/domains/recommend/recommend.provider.js | 6 +++- src/domains/recommend/recommend.sql.js | 12 ++++++-- src/routes/recommend.js | 7 +++-- 5 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/domains/recommend/recommend.controller.js b/src/domains/recommend/recommend.controller.js index 6a8c00d..624da3e 100644 --- a/src/domains/recommend/recommend.controller.js +++ b/src/domains/recommend/recommend.controller.js @@ -1,9 +1,15 @@ import { response } from "../../config/response.js"; import { status } from "../../config/response.status.js"; -import { getBodyInfo } from "./recommend.provider.js"; +import { getBodyInfo, getBodyInfoAll } from "./recommend.provider.js"; export const bodyInfo = async (req, res, next) => { console.log("비슷한 체형의 유저를 추천합니다"); const userId = res.locals.uuid; res.send(response(status.SUCCESS, await getBodyInfo(userId))); +} + +export const bodyInfoAll = async (req, res, next) => { + console.log("비슷한 체형의 유저를 추천합니다"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await getBodyInfoAll(userId))); } \ No newline at end of file diff --git a/src/domains/recommend/recommend.dao.js b/src/domains/recommend/recommend.dao.js index f557df7..a687b38 100644 --- a/src/domains/recommend/recommend.dao.js +++ b/src/domains/recommend/recommend.dao.js @@ -1,7 +1,7 @@ import { pool } from "../../config/db.config.js"; import { BaseError } from "../../config/error.js"; import { status } from "../../config/response.status.js"; -import { getUser, findUserToBody, getFitToUserId, getStyleToUserId } from "./recommend.sql.js"; +import { getUser, findUserToBody, getFitToUserId, getStyleToUserId, findUserAllToBody } from "./recommend.sql.js"; export const getBodyInfoDAO = async (userId) => { try { @@ -12,6 +12,33 @@ export const getBodyInfoDAO = async (userId) => { const weight = user[0][0].weight; const recommend = await pool.query(findUserToBody, [userId, height, height, weight, weight, height, weight]); + if(recommend[0].length == 0){ + conn.release(); + return -1; + }else{ + for (let i = 0; i < recommend[0].length; i++) { + const user = await pool.query(getUser, recommend[0][i].uuid); + const fit = await pool.query(getFitToUserId, recommend[0][i].uuid); + const style = await pool.query(getStyleToUserId, recommend[0][i].uuid); + result.push({user, fit, style}); + } + } + conn.release(); + return result; + } catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } +} + +export const getBodyInfoAllDAO = async (userId) => { + try { + const conn = await pool.getConnection(); + const result = []; + const user = await pool.query(getUser, userId); + const height = user[0][0].height; + const weight = user[0][0].weight; + const recommend = await pool.query(findUserAllToBody, [userId, height, height, weight, weight, height, weight]); + if(recommend[0].length == 0){ conn.release(); return -1; diff --git a/src/domains/recommend/recommend.provider.js b/src/domains/recommend/recommend.provider.js index d772cce..c5be42e 100644 --- a/src/domains/recommend/recommend.provider.js +++ b/src/domains/recommend/recommend.provider.js @@ -1,6 +1,10 @@ import { getBodyInfoDTO } from "./recommend.dto.js" -import { getBodyInfoDAO } from "./recommend.dao.js"; +import { getBodyInfoDAO, getBodyInfoAllDAO } from "./recommend.dao.js"; export const getBodyInfo = async (userId) => { return getBodyInfoDTO(await getBodyInfoDAO(userId)); +} + +export const getBodyInfoAll = async (userId) => { + return getBodyInfoDTO(await getBodyInfoAllDAO(userId)); } \ No newline at end of file diff --git a/src/domains/recommend/recommend.sql.js b/src/domains/recommend/recommend.sql.js index 7611674..35dd131 100644 --- a/src/domains/recommend/recommend.sql.js +++ b/src/domains/recommend/recommend.sql.js @@ -8,7 +8,7 @@ export const findUserToBody = + "FROM body_info b " + "WHERE NOT uuid = ? and height BETWEEN ?-5 AND ?+5 " + "AND weight BETWEEN ?-5 AND ?+5 " -+ "ORDER BY ABS(height-?) + ABS(weight-?) ASC LIMIT 24;" ++ "ORDER BY ABS(height-?) + ABS(weight-?) ASC LIMIT 8;" export const getFitToUserId = "SELECT uf.uuid, uf.pf_name " @@ -23,4 +23,12 @@ export const getStyleToUserId = export const findUserToFit = "SELECT uf.uuid, uf.style_name " + "FROM user_fit uf " -+ "WHERE uf.pf_name = ? ;" \ No newline at end of file ++ "WHERE uf.pf_name = ? ;" + + +export const findUserAllToBody = +"SELECT b.uuid " ++ "FROM body_info b " ++ "WHERE NOT uuid = ? and height BETWEEN ?-5 AND ?+5 " ++ "AND weight BETWEEN ?-5 AND ?+5 " ++ "ORDER BY ABS(height-?) + ABS(weight-?) ASC LIMIT 24;" \ No newline at end of file diff --git a/src/routes/recommend.js b/src/routes/recommend.js index e450aff..38338e0 100644 --- a/src/routes/recommend.js +++ b/src/routes/recommend.js @@ -1,9 +1,12 @@ import express from "express"; import asyncHandler from 'express-async-handler'; import { LoginCheck } from "../middlewares/logincheck.js"; -import { bodyInfo } from "../domains/recommend/recommend.controller.js"; +import { bodyInfo, bodyInfoAll } from "../domains/recommend/recommend.controller.js"; export const recommendRouter = express.Router({mergeParams: true}); //체형 추천 -recommendRouter.get('/body_info', LoginCheck, asyncHandler(bodyInfo)); \ No newline at end of file +recommendRouter.get('/body_info', LoginCheck, asyncHandler(bodyInfo)); + +//체형 추천-모두 보기 +recommendRouter.get('/body_info/all', LoginCheck, asyncHandler(bodyInfoAll)); \ No newline at end of file From 9745ee1e1abd4688267313455f5513fd278eae45 Mon Sep 17 00:00:00 2001 From: seoyeoneel02 Date: Fri, 13 Sep 2024 14:25:35 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20swagger=20=EC=9E=91=EC=84=B1=20#122?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/recommend/recommend.controller.js | 2 +- src/swagger/recommend.swagger.yaml | 182 ++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/swagger/recommend.swagger.yaml diff --git a/src/domains/recommend/recommend.controller.js b/src/domains/recommend/recommend.controller.js index 624da3e..cc778b1 100644 --- a/src/domains/recommend/recommend.controller.js +++ b/src/domains/recommend/recommend.controller.js @@ -9,7 +9,7 @@ export const bodyInfo = async (req, res, next) => { } export const bodyInfoAll = async (req, res, next) => { - console.log("비슷한 체형의 유저를 추천합니다"); + console.log("비슷한 체형의 유저를 모두 추천합니다"); const userId = res.locals.uuid; res.send(response(status.SUCCESS, await getBodyInfoAll(userId))); } \ No newline at end of file diff --git a/src/swagger/recommend.swagger.yaml b/src/swagger/recommend.swagger.yaml new file mode 100644 index 0000000..082da07 --- /dev/null +++ b/src/swagger/recommend.swagger.yaml @@ -0,0 +1,182 @@ +paths: + /FITple/recommend/body_info: + get: + tags: + - Recommend + summary: 비슷한 체형의 유저 추천 + operationId: profile + security: + - bearerAuth: [] + responses: + '200': + description: 비슷한 체형의 유저 조회 성공 + schema: + type: object + properties: + status: + type: integer + example: 200 + isSuccess: + type: boolean + example: true + code: + type: integer + example: 200 + message: + type: string + example: "success!" + data: + type: array + example: { + "userData": [ + { + "user_id": 32, + "nickname": "선도하는요리사", + "user_image": "https://fitple-dev-bucket.s3.ap-northeast-2.amazonaws.com/image/1724175918950-fitple_logo.png", + "height": 165, + "weight": 56, + "prefer_fit": [ + "오버", + "슬림" + ], + "prefer_style": [ + "모던시크", + "유니크" + ] + }, + { + "user_id": 23, + "nickname": "지속가능한펭귄", + "user_image": "https://fitple-dev-bucket.s3.ap-northeast-2.amazonaws.com/image/1724175918950-fitple_logo.png", + "height": 166, + "weight": 59, + "prefer_fit": [ + "레귤러", + "슬림" + ], + "prefer_style": [ + "러블리", + "아메카지" + ] + } + ] + } + + '400': + description: 잘못된 요청 + schema: + type: object + properties: + status: + type: integer + isSuccess: + type: boolean + code: + type: integer + message: + type: string + + '500': + description: 서버 에러 + schema: + type: object + properties: + status: + type: integer + isSuccess: + type: boolean + code: + type: integer + message: + type: string + + /FITple/recommend/body_info/all: + get: + tags: + - Recommend + summary: 비슷한 체형의 유저 모두 추천 + operationId: profile + security: + - bearerAuth: [] + responses: + '200': + description: 비슷한 체형의 유저 모두 조회 성공 + schema: + type: object + properties: + status: + type: integer + example: 200 + isSuccess: + type: boolean + example: true + code: + type: integer + example: 200 + message: + type: string + example: "success!" + data: + type: array + example: { + "userData": [ + { + "user_id": 32, + "nickname": "선도하는요리사", + "user_image": "https://fitple-dev-bucket.s3.ap-northeast-2.amazonaws.com/image/1724175918950-fitple_logo.png", + "height": 165, + "weight": 56, + "prefer_fit": [ + "오버", + "슬림" + ], + "prefer_style": [ + "모던시크", + "유니크" + ] + }, + { + "user_id": 23, + "nickname": "지속가능한펭귄", + "user_image": "https://fitple-dev-bucket.s3.ap-northeast-2.amazonaws.com/image/1724175918950-fitple_logo.png", + "height": 166, + "weight": 59, + "prefer_fit": [ + "레귤러", + "슬림" + ], + "prefer_style": [ + "러블리", + "아메카지" + ] + } + ] + } + + '400': + description: 잘못된 요청 + schema: + type: object + properties: + status: + type: integer + isSuccess: + type: boolean + code: + type: integer + message: + type: string + + '500': + description: 서버 에러 + schema: + type: object + properties: + status: + type: integer + isSuccess: + type: boolean + code: + type: integer + message: + type: string