diff --git a/src/common/constants/error-message.js b/src/common/constants/error-message.js index a6594f9..5b0cbcb 100644 --- a/src/common/constants/error-message.js +++ b/src/common/constants/error-message.js @@ -31,6 +31,7 @@ const ErrorMessage = Object.freeze({ DELETE_RECENT_WORD_ERROR: '최근 검색어 삭제중 오류가 발생하였습니다.', SEARCH_WORDS_ERROR: '검색 결과 조회 중 오류가 발생하였습니다.', RANK_WORDS_ERROR: '인기 검색어 조회 중 오류가 발생하였습니다.', + RELATED_WORDS_ERROR: '연관 검색어 조회 중 오류가 발생하였습니다.', }); module.exports = ErrorMessage; diff --git a/src/common/constants/success-message.js b/src/common/constants/success-message.js index 12160a0..f4a4ea2 100644 --- a/src/common/constants/success-message.js +++ b/src/common/constants/success-message.js @@ -20,6 +20,7 @@ const SucesssMessage = Object.freeze({ SEARCH_WORDS_SUCCESS: '검색어 조회 성공', SEARCH_WORDS_NONE: '검색 결과가 없습니다.', RANK_WORDS_SUCCESS: '인기 검색어 조회 성공', + RELATED_WORDS_SUCCESS: '연관 검색어 조회 성공', }); module.exports = SucesssMessage; diff --git a/src/common/utils/response-handler.js b/src/common/utils/response-handler.js index 7c8e89b..f9bf3ef 100644 --- a/src/common/utils/response-handler.js +++ b/src/common/utils/response-handler.js @@ -70,8 +70,7 @@ const sendResponse = { // logging Error const errInfo = { - uid: req.userInfo ? req.userInfo.userId : undefined, - creatorId: req.userInfo ? req.userInfo.creatorId : undefined, + user_id: req.user ? req.user._id : undefined, where: 'apiServer', from: req.baseUrl || 'unknown', params: { diff --git a/src/routes/user/user.controller.js b/src/routes/user/user.controller.js index 4318de6..509a8d1 100755 --- a/src/routes/user/user.controller.js +++ b/src/routes/user/user.controller.js @@ -5,7 +5,7 @@ const config = require('../../common/config'); const userService = require('./user.service'); const sendResponse = require('../../common/utils/response-handler'); const ErrorMessage = require('../../common/constants/error-message'); -const SucesssMessage = require('../../common/constants/success-message'); +const SuccessMessage = require('../../common/constants/success-message'); const { validateRequest } = require('../../common/utils/request.validator'); const { nicknameCheckReqQuerySchema, @@ -23,7 +23,7 @@ exports.register = async (req, res) => { const data = { user_id: newUser._id }; sendResponse.created(res, { - message: SucesssMessage.REGISTER_SUCCESSS, + message: SuccessMessage.REGISTER_SUCCESSS, data, }); } catch (err) { @@ -49,7 +49,7 @@ exports.isNicknameExist = async (req, res) => { } return sendResponse.ok(res, { - message: SucesssMessage.AVAILABLE_NICKNAME, + message: SuccessMessage.AVAILABLE_NICKNAME, data, }); } catch (err) { @@ -74,7 +74,7 @@ exports.isEmailExist = async (req, res) => { }); } return sendResponse.ok(res, { - message: SucesssMessage.AVAILABLE_EMAIL, + message: SuccessMessage.AVAILABLE_EMAIL, data, }); } catch (err) { @@ -103,7 +103,7 @@ exports.localLogin = async (req, res, next) => { res.cookie('refreshToken', refreshToken, config.cookieInRefreshTokenOptions); return sendResponse.ok(res, { - message: SucesssMessage.LOGIN_SUCCESSS, + message: SuccessMessage.LOGIN_SUCCESSS, data: { accessToken: accessToken, }, @@ -135,7 +135,7 @@ exports.kakaoLogin = async (req, res) => { res.cookie('refreshToken', refreshToken, config.cookieInRefreshTokenOptions); sendResponse.ok(res, { - message: SucesssMessage.LOGIN_SUCCESSS, + message: SuccessMessage.LOGIN_SUCCESSS, data: { accessToken: accessToken, }, @@ -167,7 +167,7 @@ exports.refreshToken = async (req, res) => { res.cookie('refreshToken', newRefreshToken, config.cookieInRefreshTokenOptions); sendResponse.ok(res, { - message: SucesssMessage.REFRESH_TOKEN, + message: SuccessMessage.REFRESH_TOKEN, data: { accessToken: newAccessToken, }, @@ -179,7 +179,7 @@ exports.getProfile = (req, res) => { const { _id, nickname, email } = req.user; const data = { _id, nickname, email }; sendResponse.ok(res, { - message: SucesssMessage.GET_PROFILE_SUCCESS, + message: SuccessMessage.GET_PROFILE_SUCCESS, data, }); }; @@ -187,7 +187,7 @@ exports.getProfile = (req, res) => { exports.logout = (_, res) => { res.clearCookie('refreshToken'); return sendResponse.ok(res, { - message: SucesssMessage.LOGOUT_SUCCESS, + message: SuccessMessage.LOGOUT_SUCCESS, }); }; @@ -196,7 +196,7 @@ exports.recentSearches = async (req, res) => { const { _id } = req.user; const recentSearches = await userService.getRecentSearches(_id); sendResponse.ok(res, { - message: SucesssMessage.RECENT_WORDS_SUCCESS, + message: SuccessMessage.RECENT_WORDS_SUCCESS, data: { recentSearches }, }); } catch (err) { @@ -211,7 +211,7 @@ exports.delRecentSearch = async (req, res) => { const { searchTerm } = req.params; await userService.delRecentSearch(_id, searchTerm); sendResponse.ok(res, { - message: SucesssMessage.DELETE_RECENT_WORD_SUCCESS, + message: SuccessMessage.DELETE_RECENT_WORD_SUCCESS, }); } catch (err) { console.log(err); diff --git a/src/routes/user/user.model.js b/src/routes/user/user.model.js index 3d6a7bd..b39fcde 100644 --- a/src/routes/user/user.model.js +++ b/src/routes/user/user.model.js @@ -15,7 +15,7 @@ const requestSchema = new mongoose.Schema( ], info: { type: String }, type: { type: String, enum: ['add', 'mod'], required: true }, - status: { type: String, enum: ['ped', 'rej', 'app'], default: 'pend' }, + status: { type: String, enum: ['pend', 'rej', 'app'], default: 'pend' }, deletedAt: { type: Date, default: null }, }, { timestamps: true } diff --git a/src/routes/word/word.controller.js b/src/routes/word/word.controller.js index e12d5dd..ec6d8e1 100644 --- a/src/routes/word/word.controller.js +++ b/src/routes/word/word.controller.js @@ -4,31 +4,18 @@ const sendResponse = require('../../common/utils/response-handler'); const ErrorMessage = require('../../common/constants/error-message'); const SucesssMessage = require('../../common/constants/success-message'); const { validateRequest } = require('../../common/utils/request.validator'); -const { rankWordsSchema, searchTermSchema } = require('./word.schema'); - -exports.getRankWords = async (req, res) => { - try { - const data = await wordService.getRankWords(); - sendResponse.ok(res, { - message: SucesssMessage.RANK_WORDS_SUCCESS, - data, - }); - } catch (error) { - sendResponse.fail(req, res, ErrorMessage.RANK_WORDS_ERROR); - } -}; +const { searchTermSchema, relatedTermSchema } = require('./word.schema'); +// 검색어 조회 exports.getSearchWords = async (req, res) => { try { const _id = req?.user ? req.user._id : null; - // 검색어 검증 const validData = validateRequest(searchTermSchema, req.params); // 요청 파라미터에서 검색어 추출 const searchTerm = validData.searchTerm; // 검색어 조회 const data = await wordService.getSearchWords(searchTerm); - if (_id) { await userService.updateRecentSearch(_id, searchTerm); } @@ -45,3 +32,31 @@ exports.getSearchWords = async (req, res) => { sendResponse.fail(req, res, ErrorMessage.SEARCH_WORDS_ERROR); } }; + +// 인기 검색어 조회 +exports.getRankWords = async (req, res) => { + try { + const data = await wordService.getRankWords(); + sendResponse.ok(res, { + message: SucesssMessage.RANK_WORDS_SUCCESS, + data, + }); + } catch (error) { + sendResponse.fail(req, res, ErrorMessage.RANK_WORDS_ERROR); + } +}; + +// 연관검색어 : 쿼리스트링으로 전달받은 검색어 searchTerm을 포함하는 단어 조회 +exports.getRelatedWords = async (req, res) => { + try { + let { searchTerm, limit } = req.query; + searchTerm = validateRequest(relatedTermSchema, searchTerm); + const data = await wordService.getRelatedWords(searchTerm, limit); + sendResponse.ok(res, { + message: SucesssMessage.RELATED_WORDS_SUCCESS, + data, + }); + } catch (error) { + sendResponse.fail(req, res, ErrorMessage.RELATED_WORDS_ERROR); + } +}; diff --git a/src/routes/word/word.repository.js b/src/routes/word/word.repository.js index 66bff83..59bacdc 100644 --- a/src/routes/word/word.repository.js +++ b/src/routes/word/word.repository.js @@ -26,3 +26,16 @@ exports.getRankWords = async () => { return null; } }; + +exports.getRelatedWords = async (searchTerm, limit) => { + try { + const relatedWords = await Word.find({ word: new RegExp(searchTerm, 'i') }) + .sort({ freq: -1 }) + .limit(parseInt(limit)); + const wordNames = relatedWords.map((word) => word.word); + return wordNames; + } catch (error) { + console.log('Error while getting related words:', error); + return null; + } +}; diff --git a/src/routes/word/word.route.js b/src/routes/word/word.route.js index a906b57..7474b7b 100644 --- a/src/routes/word/word.route.js +++ b/src/routes/word/word.route.js @@ -1,13 +1,13 @@ const express = require('express'); const wordRouter = express.Router(); - +const { isUser } = require('../../common/utils/auth'); const { getRankWords, getSearchWords, getRelatedWords } = require('./word.controller'); -const { isLoggedIn, isUser } = require('../../common/utils/auth'); - -// 메인 검색 -wordRouter.get('/rank', getRankWords); // 인기 검색어 조회 -// wordRouter.get('/:searchTerm', getRelatedWords); // params로 전달받은 검색어 searchTerm을 포함하는 단어 조회 +// 인기 검색어 조회 +wordRouter.get('/rank', getRankWords); +// 연관검색어 : 쿼리스트링으로 전달받은 검색어 searchTerm을 포함하는 단어 조회 +wordRouter.get('/search/related', getRelatedWords); +// 검색어 조회 wordRouter.post('/search/:searchTerm', isUser, getSearchWords); module.exports = wordRouter; diff --git a/src/routes/word/word.schema.js b/src/routes/word/word.schema.js index bf21d26..2a164ce 100644 --- a/src/routes/word/word.schema.js +++ b/src/routes/word/word.schema.js @@ -1,3 +1,15 @@ +const relatedTermSchema = { + type: 'string', + properties: { + searchTerm: { + type: 'string', + maxLength: 50, + }, + }, + required: ['searchTerm'], + additionalProperties: false, +}; + const searchTermSchema = { type: 'object', properties: { @@ -10,4 +22,4 @@ const searchTermSchema = { additionalProperties: false, }; -module.exports = { searchTermSchema }; +module.exports = { searchTermSchema, relatedTermSchema }; diff --git a/src/routes/word/word.service.js b/src/routes/word/word.service.js index c0c1717..ad8f43b 100644 --- a/src/routes/word/word.service.js +++ b/src/routes/word/word.service.js @@ -11,3 +11,9 @@ exports.getRankWords = async () => { const rankWords = await wordRepository.getRankWords(); return rankWords; }; + +// 연관검색어 조회 +exports.getRelatedWords = async (searchTerm, limit) => { + const relatedWords = await wordRepository.getRelatedWords(searchTerm, limit); + return relatedWords; +};