From e3595639b57c2b791012ceef1625205a6da591ea Mon Sep 17 00:00:00 2001 From: blaxsior Date: Fri, 27 Oct 2023 12:12:07 +0900 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20docker=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EB=82=B4=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /home/app을 WORKDIR로 하면 로컬에서는 동작하는데, amazon linux의 docker 환경에서는 동작하지 않음 - nodejs 공식 문서에 나온 /usr/src/app으로 변경함 --- backend/server/Dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/server/Dockerfile b/backend/server/Dockerfile index 18ee485..4735a97 100644 --- a/backend/server/Dockerfile +++ b/backend/server/Dockerfile @@ -1,7 +1,12 @@ FROM node:alpine as base +# 이유는 정확히 알 수 없으나, ec2 docker 환경에서 /home/app/package.json을 찾지 못하는 문제가 발생함. +# nodejs가 추천하는 기준 대로 변경함 +# WORKDIR /home/app + # 작업 폴더 지정 -WORKDIR /home/app +# https://nodejs.org/en/docs/guides/nodejs-docker-webapp +WORKDIR /usr/src/app # 설정 파일들 복사 COPY package*.json . From 5217701da7b5f7149ab86de8530d4704bfc0b9b3 Mon Sep 17 00:00:00 2001 From: blaxsior Date: Sun, 29 Oct 2023 22:05:14 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EC=9D=B8=EA=B8=B0=20=ED=82=A4?= =?UTF-8?q?=EC=9B=8C=EB=93=9C=20=EB=AA=A9=EB=A1=9D=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=B4=20scheduler=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/README.md | 3 +- backend/docker-compose.dev.yml | 9 ++---- backend/docker-compose.yml | 7 ++--- backend/server/Dockerfile.dev | 10 +++--- backend/server/src/app.module.ts | 2 ++ backend/server/src/batch/batch.module.ts | 10 ++++++ .../server/src/batch/batch.service.spec.ts | 18 +++++++++++ backend/server/src/batch/batch.service.ts | 20 ++++++++++++ .../src/search/dtos/common/out-keyword.dto.ts | 15 +++++++++ .../dtos/keyword-with-top-comments.dto.ts | 14 ++------- .../src/search/dtos/popular-keyword.dto.ts | 5 ++- .../server/src/search/search.controller.ts | 31 +++++++++++++------ backend/server/src/search/search.module.ts | 1 + backend/server/src/search/search.service.ts | 10 +++++- 14 files changed, 114 insertions(+), 41 deletions(-) create mode 100644 backend/server/src/batch/batch.module.ts create mode 100644 backend/server/src/batch/batch.service.spec.ts create mode 100644 backend/server/src/batch/batch.service.ts create mode 100644 backend/server/src/search/dtos/common/out-keyword.dto.ts diff --git a/backend/README.md b/backend/README.md index ea367cc..c980ab8 100644 --- a/backend/README.md +++ b/backend/README.md @@ -180,8 +180,7 @@ NewsSource는 뉴스를 수집할 언론사를 의미합니다. 뉴스 스크래 | 기능 | 설명 | 경로 | Guard | |-|-|-|-| |이슈 키워드 목록|최근 이슈 키워드 목록을 가져옵니다.|``GET /search/popular-keywords``|| -|키워드 및 대표 댓글 목록|특정 키워드에 대해 기간 내 감정 별로 최대 공감 수를 받은 댓글들을 가져옵니다.| ``GET /search/top-comments?keyword=~``|| - +|키워드 및 대표 댓글 목록|특정 키워드에 대해 기간 내 감정 별로 최대 공감 수를 받은 댓글들을 가져옵니다.| ``GET /search/keyword?keyword=~``|| # API 경로 현재 프로젝트는 [@nestjs/swagger](https://www.npmjs.com/package/@nestjs/swagger)을 이용하여 API를 문서화합니다. 서버를 가동한 후 다음 주소를 통해 swagger 문서를 볼 수 있습니다. diff --git a/backend/docker-compose.dev.yml b/backend/docker-compose.dev.yml index ab39465..0137809 100644 --- a/backend/docker-compose.dev.yml +++ b/backend/docker-compose.dev.yml @@ -11,12 +11,7 @@ services: env_file: - "./server/.env" volumes: - - /home/app/node_modules - - ./server:/home/app - deploy: - restart_policy: - condition: on-failure - delay: 3s - max_attempts: 3 + - /usr/src/app/node_modules + - ./server:/usr/src/app my-redis: image: redis:alpine \ No newline at end of file diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index cced02d..a9d8091 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -6,12 +6,11 @@ services: - ./.env ports: - 8080:8080 - volumes: - - /home/app/node_modules - - ./server:/home/app deploy: restart_policy: condition: on-failure delay: 3s # 실패 시 대기시간 max_attempts: 3 # 최대 재실행 횟수 - window: 120s # "성공" 기준이 되는 실행 시간 \ No newline at end of file + window: 120s # "성공" 기준이 되는 실행 시간 + my-redis: + image: redis:alpine \ No newline at end of file diff --git a/backend/server/Dockerfile.dev b/backend/server/Dockerfile.dev index dbaf8fb..ea346c8 100644 --- a/backend/server/Dockerfile.dev +++ b/backend/server/Dockerfile.dev @@ -1,12 +1,7 @@ FROM node:alpine # 작업 폴더 생성 -RUN mkdir /home/app -# 작업 폴더 지정 -WORKDIR /home/app - -# port 8080으로 외부 데이터 들을 수 있음 -EXPOSE 8080 +WORKDIR /usr/src/app # 설정 파일들 복사 COPY package*.json . @@ -15,6 +10,9 @@ COPY package*.json . RUN npm ci # 나머지 파일들 복사 COPY . . +# 파일 빌드 +# port 8080으로 외부 데이터 들을 수 있음 +EXPOSE 8080 # 실행 시 보여줄 명령 CMD ["npm", "run", "start:dev"] diff --git a/backend/server/src/app.module.ts b/backend/server/src/app.module.ts index 04f53da..7e71e71 100644 --- a/backend/server/src/app.module.ts +++ b/backend/server/src/app.module.ts @@ -13,6 +13,7 @@ import { AuthModule } from './auth/auth.module'; import { TokenModule } from './token/token.module'; import { RedisModule } from './redis/redis.module'; import { SearchModule } from './search/search.module'; +import { BatchModule } from './batch/batch.module'; @Module({ imports: [ @@ -25,6 +26,7 @@ import { SearchModule } from './search/search.module'; TokenModule, RedisModule, SearchModule, + BatchModule, ], }) export class AppModule {} diff --git a/backend/server/src/batch/batch.module.ts b/backend/server/src/batch/batch.module.ts new file mode 100644 index 0000000..f11588b --- /dev/null +++ b/backend/server/src/batch/batch.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { BatchService } from './batch.service'; +import { ScheduleModule } from '@nestjs/schedule'; +import { SearchModule } from 'src/search/search.module'; + +@Module({ + imports: [ScheduleModule.forRoot(), SearchModule], + providers: [BatchService], +}) +export class BatchModule {} diff --git a/backend/server/src/batch/batch.service.spec.ts b/backend/server/src/batch/batch.service.spec.ts new file mode 100644 index 0000000..92ff216 --- /dev/null +++ b/backend/server/src/batch/batch.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { BatchService } from './batch.service'; + +describe('BatchService', () => { + let service: BatchService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [BatchService], + }).compile(); + + service = module.get(BatchService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/backend/server/src/batch/batch.service.ts b/backend/server/src/batch/batch.service.ts new file mode 100644 index 0000000..d680d65 --- /dev/null +++ b/backend/server/src/batch/batch.service.ts @@ -0,0 +1,20 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Cron } from '@nestjs/schedule'; + +import { SearchService } from 'src/search/search.service'; + +@Injectable() +export class BatchService { + private readonly logger = new Logger(BatchService.name); + constructor(private searchService: SearchService) {} + + @Cron('0 0 0 * * *') + async runSchedule() { + try { + const result = await this.searchService.clearPopularKeywords(); + this.logger.log(`clear popular keyword list. delete count: ${result}`); + } catch (e) { + this.logger.error('wrong with clearPopKeywords', e); + } + } +} diff --git a/backend/server/src/search/dtos/common/out-keyword.dto.ts b/backend/server/src/search/dtos/common/out-keyword.dto.ts new file mode 100644 index 0000000..d838896 --- /dev/null +++ b/backend/server/src/search/dtos/common/out-keyword.dto.ts @@ -0,0 +1,15 @@ +import { Expose } from 'class-transformer'; +import { Keyword } from '../../../keyword/keyword.entity'; + +export class OutKeywordDto + implements Pick +{ + @Expose() + id: number; + + @Expose() + name: string; + + @Expose() + description: string; +} diff --git a/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts b/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts index c428111..2ce6c66 100644 --- a/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts +++ b/backend/server/src/search/dtos/keyword-with-top-comments.dto.ts @@ -1,7 +1,7 @@ import { Expose } from 'class-transformer'; import { IsOptional, IsString } from 'class-validator'; import { AnalysisComment } from '../../analysis-comment/entity/analysis-comment.entity'; -import { Keyword } from '../../keyword/keyword.entity'; +import { OutKeywordDto } from './common/out-keyword.dto'; export class KeywordWithTopCommentsReqQueryDto { /** @@ -17,7 +17,7 @@ export class KeywordWithTopCommentsReqQueryDto { */ @IsString() @IsOptional() - from: string; + from?: string; /** * 검색 끝일 @@ -25,15 +25,7 @@ export class KeywordWithTopCommentsReqQueryDto { */ @IsString() @IsOptional() - to: string; -} - -export class OutKeywordDto implements Pick { - @Expose() - id: number; - - @Expose() - name: string; + to?: string; } export class OutCommentDto diff --git a/backend/server/src/search/dtos/popular-keyword.dto.ts b/backend/server/src/search/dtos/popular-keyword.dto.ts index 00ca099..d3da9c2 100644 --- a/backend/server/src/search/dtos/popular-keyword.dto.ts +++ b/backend/server/src/search/dtos/popular-keyword.dto.ts @@ -1,6 +1,7 @@ import { IsInt, IsOptional, IsPositive } from 'class-validator'; +import { OutKeywordDto } from './common/out-keyword.dto'; -export class ReqPopularKeywordQueryDto { +export class PopularKeywordsReqQueryDto { /** * 한번에 가져올 키워드 개수 * @example 3 @@ -10,3 +11,5 @@ export class ReqPopularKeywordQueryDto { @IsOptional() count?: number = 10; } + +export class PopularKeywordsResDto extends OutKeywordDto {} diff --git a/backend/server/src/search/search.controller.ts b/backend/server/src/search/search.controller.ts index 30b15a0..1affd5c 100644 --- a/backend/server/src/search/search.controller.ts +++ b/backend/server/src/search/search.controller.ts @@ -1,13 +1,17 @@ import { Controller, Get, Query } from '@nestjs/common'; import { ApiResponse, ApiTags } from '@nestjs/swagger'; -import { Keyword } from 'src/keyword/keyword.entity'; -import { ReqPopularKeywordQueryDto } from './dtos/popular-keyword.dto'; + import { SearchService } from './search.service'; +import { Serialize } from '../interceptors/serialize.interceptor'; + +import { + PopularKeywordsReqQueryDto, + PopularKeywordsResDto, +} from './dtos/popular-keyword.dto'; import { KeywordWithTopCommentsReqQueryDto, KeywordWithTopCommentsResDto, } from './dtos/keyword-with-top-comments.dto'; -import { Serialize } from 'src/interceptors/serialize.interceptor'; @ApiTags('Search') @Controller('search') @@ -19,13 +23,20 @@ export class SearchController { @ApiResponse({ status: 200, description: '중요한 키워드 목록을 반환한다.', - type: () => Keyword, + type: () => PopularKeywordsResDto, }) - @Get('popular-keyword') + // @Serialize(PopularKeywordsResDto) + @Get('popular-keywords') async getPopularKeywords( - @Query() dto: ReqPopularKeywordQueryDto, - ): Promise { - return await this.service.findManyPopularKeyword(dto.count!); + @Query() dto: PopularKeywordsReqQueryDto, + ): Promise { + const keywords = await this.service.findManyPopularKeywords(dto.count!); + const results = keywords.map((keyword) => { + const { id, description, name } = keyword; + return { id, description, name }; + }); + + return results; } /** @@ -37,7 +48,9 @@ export class SearchController { }) @Serialize(KeywordWithTopCommentsResDto) @Get('keyword') - async getTopComments(@Query() dto: KeywordWithTopCommentsReqQueryDto) { + async getKeywordWithTopComments( + @Query() dto: KeywordWithTopCommentsReqQueryDto, + ) { const { name, from, to } = dto; return await this.service.getKeywordWithTopCommentsForEmotion( name, diff --git a/backend/server/src/search/search.module.ts b/backend/server/src/search/search.module.ts index be8ab05..a0b5424 100644 --- a/backend/server/src/search/search.module.ts +++ b/backend/server/src/search/search.module.ts @@ -9,5 +9,6 @@ import { SearchController } from './search.controller'; imports: [KeywordModule, AnalysisCommentModule], providers: [redisProvider, SearchService], controllers: [SearchController], + exports: [SearchService], }) export class SearchModule {} diff --git a/backend/server/src/search/search.service.ts b/backend/server/src/search/search.service.ts index b914e89..774db11 100644 --- a/backend/server/src/search/search.service.ts +++ b/backend/server/src/search/search.service.ts @@ -18,7 +18,7 @@ export class SearchService { /** * 인기 있는 키워드 목록을 반환한다. 메인 화면에서 사용됨. */ - async findManyPopularKeyword(count: number): Promise { + async findManyPopularKeywords(count: number): Promise { const key = this.config.get('POPULAR_KEYWORDS_KEY'); const keyword_ids = (await this.redisStore.zrevrange(key, 0, count)).map( (it) => parseInt(it), @@ -56,4 +56,12 @@ export class SearchService { comments, }; } + + /** + * 최근 인기 키워드 목록을 초기화 + */ + async clearPopularKeywords() { + const key = this.config.get('POPULAR_KEYWORDS_KEY'); + return await this.redisStore.del(key); + } } From 2ec5bcff0adb4b7a8ed89d505f86b5167524d3c9 Mon Sep 17 00:00:00 2001 From: blaxsior Date: Wed, 1 Nov 2023 10:09:32 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B8=A1=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - search 관련 기능 구현. 키워드 목록, 키워드 + 기사 문장 등 기능 구현함 --- backend/docker-compose.dev.yml | 2 +- .../analysis-comment.controller.spec.ts | 9 +-- .../analysis-comment.controller.ts | 11 ++-- .../analysis-comment.service.ts | 56 ++++++++++++++++++- backend/server/src/app.controller.spec.ts | 18 ++++++ backend/server/src/app.controller.ts | 23 ++++++++ backend/server/src/app.module.ts | 2 + .../server/src/search/search.controller.ts | 17 +++++- backend/server/src/search/search.service.ts | 25 ++++++++- 9 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 backend/server/src/app.controller.spec.ts create mode 100644 backend/server/src/app.controller.ts diff --git a/backend/docker-compose.dev.yml b/backend/docker-compose.dev.yml index 0137809..36f0356 100644 --- a/backend/docker-compose.dev.yml +++ b/backend/docker-compose.dev.yml @@ -2,7 +2,7 @@ version: '3' services: backend: ports: - - 8080:8080 + - 3030:8080 depends_on: - my-redis # redis 동작해야 의미 O build: diff --git a/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts b/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts index 1a6b749..d5f7480 100644 --- a/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts +++ b/backend/server/src/analysis-comment/analysis-comment.controller.spec.ts @@ -2,7 +2,6 @@ import { Test, TestingModule } from '@nestjs/testing'; import { AnalysisCommentController } from './analysis-comment.controller'; import { AnalysisCommentService } from './analysis-comment.service'; import { CreateCommentDto } from './dtos/create-comment.dto'; -import { GetCommentsQueriesDto } from './dtos/get-comments-query.dto'; import { AuthGuard } from '../auth/auth.guard'; jest.mock('./analysis-comment.service'); @@ -51,13 +50,11 @@ describe('AnalysisCommentController', () => { describe('getComments()', () => { it('call commentService.getComments', async () => { // dummy data - const dummyDto: GetCommentsQueriesDto = { - search: '', - }; + const comment_id = 1; // action - await controller.getComments(dummyDto); + await controller.getComment(comment_id); // assert - expect(service.findMany).toBeCalled(); + expect(service.findManyWithQuery).toBeCalled(); }); }); }); diff --git a/backend/server/src/analysis-comment/analysis-comment.controller.ts b/backend/server/src/analysis-comment/analysis-comment.controller.ts index d3607ed..537fbc7 100644 --- a/backend/server/src/analysis-comment/analysis-comment.controller.ts +++ b/backend/server/src/analysis-comment/analysis-comment.controller.ts @@ -1,8 +1,7 @@ -import { Controller, Post, Get, Body, Query, UseGuards } from '@nestjs/common'; +import { Controller, Post, Get, Body, UseGuards, Param } from '@nestjs/common'; import { ApiBearerAuth, ApiResponse, ApiTags } from '@nestjs/swagger'; import { CreateCommentDto } from './dtos/create-comment.dto'; -import { GetCommentsQueriesDto } from './dtos/get-comments-query.dto'; import { AnalysisCommentService } from './analysis-comment.service'; import { AuthGuard } from '../auth/auth.guard'; @@ -33,9 +32,9 @@ export class AnalysisCommentController { description: '가져온 댓글 목록', status: 200, }) - @Get() - async getComments(@Query() queries: GetCommentsQueriesDto) { - const comments = await this.commentService.findMany(queries); - return comments; + @Get(':id') + async getComment(@Param('id') id: number) { + const comment = await this.commentService.findOneById(id); + return comment; } } diff --git a/backend/server/src/analysis-comment/analysis-comment.service.ts b/backend/server/src/analysis-comment/analysis-comment.service.ts index 43ef074..496cc85 100644 --- a/backend/server/src/analysis-comment/analysis-comment.service.ts +++ b/backend/server/src/analysis-comment/analysis-comment.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { DataSource, Repository } from 'typeorm'; +import { Between, DataSource, FindOperator, Repository } from 'typeorm'; import { AnalysisComment } from './entity/analysis-comment.entity'; import { CreateCommentDto } from './dtos/create-comment.dto'; import { ArticleContent } from './entity/article-content.entity'; import { GetCommentsQueriesDto } from './dtos/get-comments-query.dto'; + @Injectable() export class AnalysisCommentService { constructor( @@ -40,7 +41,58 @@ export class AnalysisCommentService { return comment; } - async findMany({ search, psize, head_id, from, to }: GetCommentsQueriesDto) { + /** + * id 기반으로 댓글을 검색한다. 연관 기사 문장과 함께 가져올지 지정할 수 있다. + */ + async findOneById(id: number, isWithSentences = true) { + return await this.comment_repo.findOne({ + where: { + id: id, + }, + relations: { + news_sentences: isWithSentences, + }, + }); + } + + /** + * commment 정보를 이용하여 연관된 키워드 목록을 가져온다 + */ + async findManyByInfo(info: { + keyword_id: number; + emotion: string; + count: number; + from?: string; + to?: string; + }) { + const { keyword_id, emotion, count, from, to } = info; + let between: FindOperator | undefined; + if (from && to) { + between = Between(new Date(from), new Date(to)); + } + + await this.comment_repo.find({ + where: { + keyword_id: keyword_id, + emotion: emotion, + createdAt: between, + }, + order: { + sympathy: { + direction: 'DESC', + }, + }, + take: count, + }); + } + + async findManyWithQuery({ + search, + psize, + head_id, + from, + to, + }: GetCommentsQueriesDto) { if (!search) return []; const qb = this.comment_repo.createQueryBuilder(); diff --git a/backend/server/src/app.controller.spec.ts b/backend/server/src/app.controller.spec.ts new file mode 100644 index 0000000..aec925a --- /dev/null +++ b/backend/server/src/app.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AppController } from './app.controller'; + +describe('AppController', () => { + let controller: AppController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [AppController], + }).compile(); + + controller = module.get(AppController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/backend/server/src/app.controller.ts b/backend/server/src/app.controller.ts new file mode 100644 index 0000000..84a6b47 --- /dev/null +++ b/backend/server/src/app.controller.ts @@ -0,0 +1,23 @@ +import { Controller, Get } from '@nestjs/common'; + +@Controller() +export class AppController { + /** + * 접근 가능한 메인 주소 + */ + @Get() + sayHello() { + return ` + + + + keyword-on + + + +

Keyword-on에 어서 오세요

+

키워드 온 메인 페이지입니다!

+ +`; + } +} diff --git a/backend/server/src/app.module.ts b/backend/server/src/app.module.ts index 7e71e71..f90f108 100644 --- a/backend/server/src/app.module.ts +++ b/backend/server/src/app.module.ts @@ -14,6 +14,7 @@ import { TokenModule } from './token/token.module'; import { RedisModule } from './redis/redis.module'; import { SearchModule } from './search/search.module'; import { BatchModule } from './batch/batch.module'; +import { AppController } from './app.controller'; @Module({ imports: [ @@ -28,5 +29,6 @@ import { BatchModule } from './batch/batch.module'; SearchModule, BatchModule, ], + controllers: [AppController], }) export class AppModule {} diff --git a/backend/server/src/search/search.controller.ts b/backend/server/src/search/search.controller.ts index 1affd5c..f5758e4 100644 --- a/backend/server/src/search/search.controller.ts +++ b/backend/server/src/search/search.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Query } from '@nestjs/common'; +import { Controller, Get, Query, Param } from '@nestjs/common'; import { ApiResponse, ApiTags } from '@nestjs/swagger'; import { SearchService } from './search.service'; @@ -30,7 +30,7 @@ export class SearchController { async getPopularKeywords( @Query() dto: PopularKeywordsReqQueryDto, ): Promise { - const keywords = await this.service.findManyPopularKeywords(dto.count!); + const keywords = await this.service.getManyPopularKeywords(dto.count!); const results = keywords.map((keyword) => { const { id, description, name } = keyword; return { id, description, name }; @@ -47,7 +47,7 @@ export class SearchController { type: () => KeywordWithTopCommentsResDto, }) @Serialize(KeywordWithTopCommentsResDto) - @Get('keyword') + @Get('keyword-search-result') async getKeywordWithTopComments( @Query() dto: KeywordWithTopCommentsReqQueryDto, ) { @@ -58,4 +58,15 @@ export class SearchController { to, ); } + + /** + * 선택한 댓글의 정보를 연관 문장과 함께 가져온다 + */ + @ApiResponse({ + status: 200, + }) + @Get('detail/comment/:id') + async getCommentWithSentences(@Param('id') id: number) { + return await this.service.getCommentWithSentences(id); + } } diff --git a/backend/server/src/search/search.service.ts b/backend/server/src/search/search.service.ts index 774db11..6eeb4d9 100644 --- a/backend/server/src/search/search.service.ts +++ b/backend/server/src/search/search.service.ts @@ -18,7 +18,7 @@ export class SearchService { /** * 인기 있는 키워드 목록을 반환한다. 메인 화면에서 사용됨. */ - async findManyPopularKeywords(count: number): Promise { + async getManyPopularKeywords(count: number): Promise { const key = this.config.get('POPULAR_KEYWORDS_KEY'); const keyword_ids = (await this.redisStore.zrevrange(key, 0, count)).map( (it) => parseInt(it), @@ -64,4 +64,27 @@ export class SearchService { const key = this.config.get('POPULAR_KEYWORDS_KEY'); return await this.redisStore.del(key); } + + /** + * 댓글을 관련된 문장과 함께 가져오기 + */ + async getCommentWithSentences(id: number) { + const commentWithSentences = await this.commentService.findOneById( + id, + true, + ); + if (!commentWithSentences) + throw new NotFoundException(`there is no comment id: ${id}`); + return commentWithSentences; + } + + async getRelatedKeywordList(info: { + keyword_id: number; + emotion: string; + count: number; + from?: string; + to?: string; + }) { + return await this.commentService.findManyByInfo(info); + } }