diff --git a/src/domains/search/search.controller.js b/src/domains/search/search.controller.js index 1bb60c8..87509ef 100644 --- a/src/domains/search/search.controller.js +++ b/src/domains/search/search.controller.js @@ -1,7 +1,7 @@ import { response } from "../../config/response.js"; import { status } from "../../config/response.status.js"; -import { getSearch, getCloth, getSearchResult, getSearchBrand, getMyCloth } from "./search.provider.js"; -import { addMyCloth } from "./search.service.js"; +import { getSearch, getCloth, getSearchResult, getSearchBrand, getMyCloth, getMyWish } from "./search.provider.js"; +import { addMyCloth, addMyWish, delMyWish } from "./search.service.js"; export const searchPreview = async (req, res, next) => { console.log("검색 메인화면을 조회합니다"); @@ -33,4 +33,22 @@ export const addCloth = async (req, res, next) => { console.log("옷 등록을 요청하였습니다!"); const userId = res.locals.uuid; res.send(response(status.SUCCESS, await addMyCloth(userId, req.body))); +} + +export const addWish = async (req, res, next) => { + console.log("관심 있는 옷 추가를 요청하였습니다!"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await addMyWish(userId, req.params.clothId))); +} + +export const delWish = async (req, res, next) => { + console.log("관심 있는 옷 삭제를 요청하였습니다!"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await delMyWish(userId, req.params.clothId))); +} + +export const getWish = async (req, res, next) => { + console.log("관심 있는 옷 조회를 요청하였습니다!"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await getMyWish(userId, req.params.clothId))); } \ No newline at end of file diff --git a/src/domains/search/search.dao.js b/src/domains/search/search.dao.js index 4365d6d..153d311 100644 --- a/src/domains/search/search.dao.js +++ b/src/domains/search/search.dao.js @@ -7,7 +7,8 @@ import { UserNicknameToClothId, UserCategoryToClothId, UserNicknameToClothName, UserCategoryToClothName, brandToBrandName, userIdToNickname, userToNickname, getBrandToBrandId, userToBrand, categoryToBrand, clothToBrand, clothCategoryToBrand, - insertCloth, insertRealSize, getCloth } from "./search.sql.js"; + insertCloth, insertRealSize, getCloth, + addWishSQL, delWishSQL, getWishSQL } from "./search.sql.js"; // nickname+cloth 반환 export const getNicknameToClothId = async (category) => { @@ -224,4 +225,48 @@ export const getAddCloth = async (clothId) => { } catch (err) { throw new BaseError(status.PARAMETER_IS_WRONG); } +} + +// Wish 추가 +export const addWishDAO = async (userId, clothId) => { + try{ + const conn = await pool.getConnection(); + const is_exist = await pool.query(getWishSQL, [clothId, userId]); + if(is_exist[0].length !== 0){ + throw new BaseError(status.PARAMETER_IS_WRONG); + } + const wish = await pool.query(addWishSQL, [clothId, userId]); + + conn.release(); + return wish[0].insertId; + }catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } +} + +// Wish 삭제 +export const delWishDAO = async (userId, clothId) => { + try{ + const conn = await pool.getConnection(); + await pool.query(delWishSQL, [clothId, userId]); + const wish = await pool.query(getWishSQL, [clothId, userId]); + + conn.release(); + return wish; + }catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } +} + +// Wish 조회 +export const getWishDAO = async (userId, clothId) => { + try{ + const conn = await pool.getConnection(); + const wish = await pool.query(getWishSQL, [clothId, userId]); + + conn.release(); + return wish; + }catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } } \ No newline at end of file diff --git a/src/domains/search/search.dto.js b/src/domains/search/search.dto.js index 84647e7..6ed6d28 100644 --- a/src/domains/search/search.dto.js +++ b/src/domains/search/search.dto.js @@ -170,4 +170,29 @@ export const addClothResponseDTO = (data) => { }) } return {"clothData": cloth}; +} + +export const addWishDTO = (wish) => { + return {"wish_id": wish}; +} + +export const delWishDTO = (wish) => { + let wish_id; + if(wish[0].length == 0){ + wish_id = 0; + } + + return {"wish_id": wish_id}; +} + +export const getWishDTO = (wish) => { + + let wish_id; + if(wish[0].length == 0){ + wish_id = 0; + } else if(wish[0].length == 1){ + wish_id = wish[0][0].id + } + + return {"wish_id": wish_id}; } \ No newline at end of file diff --git a/src/domains/search/search.provider.js b/src/domains/search/search.provider.js index c1c7538..5e80289 100644 --- a/src/domains/search/search.provider.js +++ b/src/domains/search/search.provider.js @@ -1,8 +1,7 @@ -import { previewSearchResponseDTO, previewClothResponseDTO, SearchResultResponseDTO, SearchBrandResponseDTO, previewMyClothResponseDTO } from "./search.dto.js" -import { getNicknameToClothId, - getPreviewCloth, getUserToClothId, - getNicknameToClothName, getPreviewBrand, getPreviewUser, - getBrand, getNicknameToBrand, getPreviewMyCloth } from "./search.dao.js"; +import { previewSearchResponseDTO, previewClothResponseDTO, SearchResultResponseDTO, SearchBrandResponseDTO, + previewMyClothResponseDTO, getWishDTO } from "./search.dto.js" +import { getNicknameToClothId, getPreviewCloth, getUserToClothId, getNicknameToClothName, getPreviewBrand, getPreviewUser, + getBrand, getNicknameToBrand, getPreviewMyCloth, getWishDAO } from "./search.dao.js"; export const getSearch = async (query) => { const { category } = query; @@ -30,4 +29,9 @@ export const getSearchBrand = async (brandId, query) => { export const getMyCloth = async (userId, clothId) => { return previewMyClothResponseDTO(await getPreviewMyCloth(userId, clothId)); +} + +export const getMyWish = async (userId, clothId) => { + + return getWishDTO(await getWishDAO(userId, clothId)); } \ No newline at end of file diff --git a/src/domains/search/search.service.js b/src/domains/search/search.service.js index 877edde..442c853 100644 --- a/src/domains/search/search.service.js +++ b/src/domains/search/search.service.js @@ -1,7 +1,7 @@ import { BaseError } from "../../config/error.js"; import { status } from "../../config/response.status.js"; -import { addClothResponseDTO } from "./search.dto.js"; -import { clothAdd, getAddCloth } from "./search.dao.js"; +import { addClothResponseDTO, addWishDTO, delWishDTO } from "./search.dto.js"; +import { clothAdd, getAddCloth, addWishDAO, delWishDAO } from "./search.dao.js"; export const addMyCloth = async (userId, body) => { const requiredFields = ['name', 'product_code', 'category', 'size', 'fit']; @@ -46,4 +46,12 @@ export const addMyCloth = async (userId, body) => { 'hem': body.hem }); return addClothResponseDTO(await getAddCloth(clothData)); +} + +export const addMyWish = async (userId, clothId) => { + return addWishDTO(await addWishDAO(userId, clothId)); +} + +export const delMyWish = async (userId, clothId) => { + return delWishDTO(await delWishDAO(userId, clothId)); } \ No newline at end of file diff --git a/src/domains/search/search.sql.js b/src/domains/search/search.sql.js index 524b020..ebe4685 100644 --- a/src/domains/search/search.sql.js +++ b/src/domains/search/search.sql.js @@ -105,4 +105,10 @@ export const insertCloth = export const insertRealSize = "INSERT INTO real_size (cloth_id, length, shoulder, chest, armhole, sleeve, sleeve_length, hem) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ;" -export const getCloth = "SELECT * FROM cloth WHERE id = ? ; " \ No newline at end of file +export const getCloth = "SELECT * FROM cloth WHERE id = ? ; " + +export const addWishSQL = "INSERT INTO wish (cloth_id, wisher_uuid) VALUES (?, ?) ;" + +export const delWishSQL = "DELETE FROM wish WHERE cloth_id = ? AND wisher_uuid = ? ;" + +export const getWishSQL = "SELECT id FROM wish WHERE cloth_id = ? AND wisher_uuid = ? ;" \ No newline at end of file diff --git a/src/routes/search.js b/src/routes/search.js index a1862a6..31c5508 100644 --- a/src/routes/search.js +++ b/src/routes/search.js @@ -1,7 +1,7 @@ import express from "express"; import asyncHandler from 'express-async-handler'; import { LoginCheck } from "../middlewares/logincheck.js"; -import { searchPreview, clothView, searchView, brandView, addClothPreview, addCloth } from "../domains/search/search.controller.js"; +import { searchPreview, clothView, searchView, brandView, addClothPreview, addCloth, addWish, delWish, getWish } from "../domains/search/search.controller.js"; export const searchRouter = express.Router({mergeParams: true}); @@ -21,4 +21,13 @@ searchRouter.get('/brand/:brandId', LoginCheck, asyncHandler(brandView)); searchRouter.get('/:clothId/add', LoginCheck, asyncHandler(addClothPreview)); //검색-옷장에 등록 -searchRouter.post('/:clothId/add', LoginCheck, asyncHandler(addCloth)); \ No newline at end of file +searchRouter.post('/:clothId/add', LoginCheck, asyncHandler(addCloth)); + +//검색-wish에 추가 +searchRouter.post('/:clothId/wish', LoginCheck, asyncHandler(addWish)); + +//검색-wish에서 삭제 +searchRouter.delete('/:clothId/wish', LoginCheck, asyncHandler(delWish)); + +//검색-wish +searchRouter.get('/:clothId/wish', LoginCheck, asyncHandler(getWish)); \ No newline at end of file diff --git a/src/swagger/search.swagger.yaml b/src/swagger/search.swagger.yaml index 96fb640..318a85b 100644 --- a/src/swagger/search.swagger.yaml +++ b/src/swagger/search.swagger.yaml @@ -3,7 +3,8 @@ paths: get: tags: - Search - summary: 전체 옷장 조회 로직 + summary: 검색 메인화면 조회 로직 + operationId: searchPreview parameters: - name: category in: query @@ -92,6 +93,7 @@ paths: tags: - Search summary: 옷 상세 조회 로직 + operationId: searchView parameters: - name: clothId in: path @@ -189,6 +191,7 @@ paths: tags: - Search summary: 통합 검색 조회 로직 + operationId: searchWord parameters: - name: name in: query @@ -290,6 +293,7 @@ paths: tags: - Search summary: 브랜드 상세 조회 로직 + operationId: searchBrand parameters: - name: brandId in: path @@ -388,6 +392,7 @@ paths: tags: - Search summary: 추가할 옷 상세 조회 로직 + operationId: viewAddCloth security: - bearerAuth: [] parameters: @@ -468,7 +473,7 @@ paths: tags: - Search summary: 옷 등록 로직 - operationId: search + operationId: addSearchCloth security: - bearerAuth: [] requestBody: @@ -595,6 +600,238 @@ paths: type: string example: 잘못된 요청입니다 + '500': + description: 서버 에러 + schema: + type: object + properties: + status: + type: integer + example: 500 + isSuccess: + type: boolean + example: false + code: + type: integer + example: COMMON000 + message: + type: string + example: 서버 에러, 관리자에게 문의 바랍니다. + + /FITple/search/{clothId}/wish: + post: + tags: + - Search + summary: wish 등록 로직 + operationId: addWish + security: + - bearerAuth: [] + parameters: + - name: clothId + in: path + required: true + schema: + type: integer + responses: + '200': + description: wish 등록 성공 + 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: { + "clothData": [ + { + "wish_id": 20 + } + ] + } + + '400': + description: 잘못된 요청 + schema: + type: object + properties: + status: + type: integer + example: 400 + isSuccess: + type: boolean + example: false + code: + type: integer + example: COMMON001 + message: + type: string + example: 잘못된 요청입니다 + + '500': + description: 서버 에러 + schema: + type: object + properties: + status: + type: integer + example: 500 + isSuccess: + type: boolean + example: false + code: + type: integer + example: COMMON000 + message: + type: string + example: 서버 에러, 관리자에게 문의 바랍니다. + + delete: + tags: + - Search + summary: wish 삭제 로직 + operationId: delWish + security: + - bearerAuth: [] + parameters: + - name: clothId + in: path + required: true + schema: + type: integer + responses: + '200': + description: wish 삭제 성공 + 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: { + "clothData": [ + { + "wish_id": 20 + } + ] + } + + '400': + description: 잘못된 요청 + schema: + type: object + properties: + status: + type: integer + example: 400 + isSuccess: + type: boolean + example: false + code: + type: integer + example: COMMON001 + message: + type: string + example: 잘못된 요청입니다 + + '500': + description: 서버 에러 + schema: + type: object + properties: + status: + type: integer + example: 500 + isSuccess: + type: boolean + example: false + code: + type: integer + example: COMMON000 + message: + type: string + example: 서버 에러, 관리자에게 문의 바랍니다. + + get: + tags: + - Search + summary: wish 조회 로직 + operationId: getWish + security: + - bearerAuth: [] + parameters: + - name: clothId + in: path + required: true + schema: + type: integer + responses: + '200': + description: wish 조회 성공 + 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: { + "clothData": [ + { + "wish_id": 20 + } + ] + } + + '400': + description: 잘못된 요청 + schema: + type: object + properties: + status: + type: integer + example: 400 + isSuccess: + type: boolean + example: false + code: + type: integer + example: COMMON001 + message: + type: string + example: 잘못된 요청입니다 + '500': description: 서버 에러 schema: