diff --git a/src/domains/search/search.controller.js b/src/domains/search/search.controller.js index 87509ef..c425c25 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, getMyWish } from "./search.provider.js"; -import { addMyCloth, addMyWish, delMyWish } from "./search.service.js"; +import { getSearch, getCloth, getSearchResult, getSearchBrand, getMyCloth, getMyWish, getMyFollow } from "./search.provider.js"; +import { addMyCloth, addMyWish, delMyWish, addMyFollow, delMyFollow } from "./search.service.js"; export const searchPreview = async (req, res, next) => { console.log("검색 메인화면을 조회합니다"); @@ -51,4 +51,22 @@ 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))); +} + +export const addFollow = async (req, res, next) => { + console.log("팔로우를 요청하였습니다!"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await addMyFollow(userId, req.params.clothId))); +} + +export const delFollow = async (req, res, next) => { + console.log("팔로우 취소를 요청하였습니다!"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await delMyFollow(userId, req.params.clothId))); +} + +export const getFollow = async (req, res, next) => { + console.log("팔로우 조회를 요청하였습니다!"); + const userId = res.locals.uuid; + res.send(response(status.SUCCESS, await getMyFollow(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 153d311..91a08a6 100644 --- a/src/domains/search/search.dao.js +++ b/src/domains/search/search.dao.js @@ -8,7 +8,7 @@ import { UserNicknameToClothId, UserCategoryToClothId, brandToBrandName, userIdToNickname, userToNickname, getBrandToBrandId, userToBrand, categoryToBrand, clothToBrand, clothCategoryToBrand, insertCloth, insertRealSize, getCloth, - addWishSQL, delWishSQL, getWishSQL } from "./search.sql.js"; + addWishSQL, delWishSQL, getWishSQL, getFollowSQL, addFollowSQL, delFollowSQL } from "./search.sql.js"; // nickname+cloth 반환 export const getNicknameToClothId = async (category) => { @@ -269,4 +269,56 @@ export const getWishDAO = async (userId, clothId) => { }catch (err) { throw new BaseError(status.PARAMETER_IS_WRONG); } +} + +// Follow 추가 +export const addFollowDAO = async (userId, clothId) => { + try{ + const conn = await pool.getConnection(); + const to_user = await pool.query(getUserIdToClothId, clothId); + if(userId == to_user[0][0].uuid){ + throw new BaseError(status.PARAMETER_IS_WRONG); + } + const is_exist = await pool.query(getFollowSQL, [userId, to_user[0][0].uuid]); + if(is_exist[0].length !== 0){ + throw new BaseError(status.PARAMETER_IS_WRONG); + } + const follow = await pool.query(addFollowSQL, [userId, to_user[0][0].uuid]); + conn.release(); + return follow[0].insertId; + }catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } +} + +// Follow 취소 +export const delFollowDAO = async (userId, clothId) => { + try{ + const conn = await pool.getConnection(); + const to_user = await pool.query(getUserIdToClothId, clothId); + const is_exist = await pool.query(getFollowSQL, [userId, to_user[0][0].uuid]); + if(is_exist[0].length == 0){ + throw new BaseError(status.PARAMETER_IS_WRONG); + } + await pool.query(delFollowSQL, [userId, to_user[0][0].uuid]); + const follow = await pool.query(getFollowSQL, [userId, to_user[0][0].uuid]); + conn.release(); + return follow; + }catch (err) { + throw new BaseError(status.PARAMETER_IS_WRONG); + } +} + +// Follow 조회 +export const getFollowDAO = async (userId, clothId) => { + try{ + const conn = await pool.getConnection(); + const to_user = await pool.query(getUserIdToClothId, clothId); + const follow = await pool.query(getFollowSQL, [userId, to_user[0][0].uuid]); + + conn.release(); + return follow; + }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 6ed6d28..74bc4e0 100644 --- a/src/domains/search/search.dto.js +++ b/src/domains/search/search.dto.js @@ -195,4 +195,29 @@ export const getWishDTO = (wish) => { } return {"wish_id": wish_id}; +} + +export const addFollowDTO = (follow) => { + return {"follow_id": follow}; +} + +export const delFollowDTO = (follow) => { + let follow_id; + if(follow[0].length == 0){ + follow_id = 0; + } + + return {"follow_id": follow_id}; +} + +export const getFollowDTO = (follow) => { + + let follow_id; + if(follow[0].length == 0){ + follow_id = 0; + } else if(follow[0].length == 1){ + follow_id = follow[0][0].id + } + + return {"follow_id": follow_id}; } \ No newline at end of file diff --git a/src/domains/search/search.provider.js b/src/domains/search/search.provider.js index 5e80289..88f294c 100644 --- a/src/domains/search/search.provider.js +++ b/src/domains/search/search.provider.js @@ -1,7 +1,7 @@ import { previewSearchResponseDTO, previewClothResponseDTO, SearchResultResponseDTO, SearchBrandResponseDTO, - previewMyClothResponseDTO, getWishDTO } from "./search.dto.js" + previewMyClothResponseDTO, getWishDTO, getFollowDTO } from "./search.dto.js" import { getNicknameToClothId, getPreviewCloth, getUserToClothId, getNicknameToClothName, getPreviewBrand, getPreviewUser, - getBrand, getNicknameToBrand, getPreviewMyCloth, getWishDAO } from "./search.dao.js"; + getBrand, getNicknameToBrand, getPreviewMyCloth, getWishDAO, getFollowDAO } from "./search.dao.js"; export const getSearch = async (query) => { const { category } = query; @@ -34,4 +34,9 @@ export const getMyCloth = async (userId, clothId) => { export const getMyWish = async (userId, clothId) => { return getWishDTO(await getWishDAO(userId, clothId)); +} + +export const getMyFollow = async (userId, clothId) => { + + return getFollowDTO(await getFollowDAO(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 442c853..17813ec 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, addWishDTO, delWishDTO } from "./search.dto.js"; -import { clothAdd, getAddCloth, addWishDAO, delWishDAO } from "./search.dao.js"; +import { addClothResponseDTO, addWishDTO, delWishDTO, addFollowDTO, delFollowDTO } from "./search.dto.js"; +import { clothAdd, getAddCloth, addWishDAO, delWishDAO, addFollowDAO, delFollowDAO } from "./search.dao.js"; export const addMyCloth = async (userId, body) => { const requiredFields = ['name', 'product_code', 'category', 'size', 'fit']; @@ -54,4 +54,12 @@ export const addMyWish = async (userId, clothId) => { export const delMyWish = async (userId, clothId) => { return delWishDTO(await delWishDAO(userId, clothId)); +} + +export const addMyFollow = async (userId, clothId) => { + return addFollowDTO(await addFollowDAO(userId, clothId)); +} + +export const delMyFollow = async (userId, clothId) => { + return delFollowDTO(await delFollowDAO(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 ebe4685..be3a4e6 100644 --- a/src/domains/search/search.sql.js +++ b/src/domains/search/search.sql.js @@ -111,4 +111,10 @@ 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 +export const getWishSQL = "SELECT id FROM wish WHERE cloth_id = ? AND wisher_uuid = ? ;" + +export const getFollowSQL = "SELECT id FROM follow WHERE from_uuid = ? AND to_uuid = ? ;" + +export const addFollowSQL = "INSERT INTO follow (from_uuid, to_uuid) VALUES (?, ?) ;" + +export const delFollowSQL = "DELETE FROM follow WHERE from_uuid = ? AND to_uuid = ? ;" \ No newline at end of file diff --git a/src/routes/search.js b/src/routes/search.js index 31c5508..bb6ce5e 100644 --- a/src/routes/search.js +++ b/src/routes/search.js @@ -1,7 +1,8 @@ import express from "express"; import asyncHandler from 'express-async-handler'; import { LoginCheck } from "../middlewares/logincheck.js"; -import { searchPreview, clothView, searchView, brandView, addClothPreview, addCloth, addWish, delWish, getWish } from "../domains/search/search.controller.js"; +import { searchPreview, clothView, searchView, brandView, addClothPreview, addCloth, + addWish, delWish, getWish, addFollow, delFollow, getFollow } from "../domains/search/search.controller.js"; export const searchRouter = express.Router({mergeParams: true}); @@ -29,5 +30,14 @@ 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 +//검색-wish 조회 +searchRouter.get('/:clothId/wish', LoginCheck, asyncHandler(getWish)); + +//검색-follow에 추가 +searchRouter.post('/:clothId/follow', LoginCheck, asyncHandler(addFollow)); + +//검색-follow에서 삭제 +searchRouter.delete('/:clothId/follow', LoginCheck, asyncHandler(delFollow)); + +//검색-follow 조회 +searchRouter.get('/:clothId/follow', LoginCheck, asyncHandler(getFollow)); \ No newline at end of file diff --git a/src/swagger/search.swagger.yaml b/src/swagger/search.swagger.yaml index 318a85b..b9e7224 100644 --- a/src/swagger/search.swagger.yaml +++ b/src/swagger/search.swagger.yaml @@ -653,11 +653,7 @@ paths: data: type: array example: { - "clothData": [ - { - "wish_id": 20 - } - ] + "wish_id": 20 } '400': @@ -730,11 +726,7 @@ paths: data: type: array example: { - "clothData": [ - { - "wish_id": 20 - } - ] + "wish_id": 20 } '400': @@ -807,11 +799,227 @@ paths: data: type: array example: { - "clothData": [ - { - "wish_id": 20 - } - ] + "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: 서버 에러, 관리자에게 문의 바랍니다. + + /FITple/search/{clothId}/follow: + post: + tags: + - Search + summary: follow 등록 로직 + operationId: addFollow + security: + - bearerAuth: [] + parameters: + - name: clothId + in: path + required: true + schema: + type: integer + responses: + '200': + description: follow 등록 성공 + 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: { + "follow_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: follow 취소 로직 + operationId: delFollow + security: + - bearerAuth: [] + parameters: + - name: clothId + in: path + required: true + schema: + type: integer + responses: + '200': + description: follow 취소 성공 + 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: { + "follow_id": 0 + } + + '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: follow 조회 로직 + operationId: getFollow + security: + - bearerAuth: [] + parameters: + - name: clothId + in: path + required: true + schema: + type: integer + responses: + '200': + description: follow 조회 성공 + 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: { + "follow_id": 20 } '400':