Skip to content

Commit

Permalink
deploy: 서버측 변경 사항 반영
Browse files Browse the repository at this point in the history
  • Loading branch information
blaxsior committed Nov 1, 2023
2 parents b96d4e3 + 2ec5bcf commit 8024024
Show file tree
Hide file tree
Showing 19 changed files with 256 additions and 58 deletions.
3 changes: 1 addition & 2 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 문서를 볼 수 있습니다.
Expand Down
11 changes: 3 additions & 8 deletions backend/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3'
services:
backend:
ports:
- 8080:8080
- 3030:8080
depends_on:
- my-redis # redis 동작해야 의미 O
build:
Expand All @@ -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
7 changes: 3 additions & 4 deletions backend/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 # "성공" 기준이 되는 실행 시간
window: 120s # "성공" 기준이 되는 실행 시간
my-redis:
image: redis:alpine
10 changes: 4 additions & 6 deletions backend/server/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -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 .
Expand All @@ -15,6 +10,9 @@ COPY package*.json .
RUN npm ci
# 나머지 파일들 복사
COPY . .
# 파일 빌드
# port 8080으로 외부 데이터 들을 수 있음
EXPOSE 8080

# 실행 시 보여줄 명령
CMD ["npm", "run", "start:dev"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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();
});
});
});
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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;
}
}
56 changes: 54 additions & 2 deletions backend/server/src/analysis-comment/analysis-comment.service.ts
Original file line number Diff line number Diff line change
@@ -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(
Expand Down Expand Up @@ -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<Date> | 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();
Expand Down
18 changes: 18 additions & 0 deletions backend/server/src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -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>(AppController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
23 changes: 23 additions & 0 deletions backend/server/src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Controller, Get } from '@nestjs/common';

@Controller()
export class AppController {
/**
* 접근 가능한 메인 주소
*/
@Get()
sayHello() {
return `
<!DOCTYPE html>
<html>
<head>
<title>keyword-on</title>
<meta charset='utf8'>
</head>
<body>
<h1>Keyword-on에 어서 오세요</h1>
<p>키워드 온 메인 페이지입니다!</p>
</body>
</html>`;
}
}
4 changes: 4 additions & 0 deletions backend/server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ 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';
import { AppController } from './app.controller';

@Module({
imports: [
Expand All @@ -25,6 +27,8 @@ import { SearchModule } from './search/search.module';
TokenModule,
RedisModule,
SearchModule,
BatchModule,
],
controllers: [AppController],
})
export class AppModule {}
10 changes: 10 additions & 0 deletions backend/server/src/batch/batch.module.ts
Original file line number Diff line number Diff line change
@@ -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 {}
18 changes: 18 additions & 0 deletions backend/server/src/batch/batch.service.spec.ts
Original file line number Diff line number Diff line change
@@ -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>(BatchService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
20 changes: 20 additions & 0 deletions backend/server/src/batch/batch.service.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
15 changes: 15 additions & 0 deletions backend/server/src/search/dtos/common/out-keyword.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Expose } from 'class-transformer';
import { Keyword } from '../../../keyword/keyword.entity';

export class OutKeywordDto
implements Pick<Keyword, 'id' | 'name' | 'description'>
{
@Expose()
id: number;

@Expose()
name: string;

@Expose()
description: string;
}
14 changes: 3 additions & 11 deletions backend/server/src/search/dtos/keyword-with-top-comments.dto.ts
Original file line number Diff line number Diff line change
@@ -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 {
/**
Expand All @@ -17,23 +17,15 @@ export class KeywordWithTopCommentsReqQueryDto {
*/
@IsString()
@IsOptional()
from: string;
from?: string;

/**
* 검색 끝일
* @example 2099-01-01
*/
@IsString()
@IsOptional()
to: string;
}

export class OutKeywordDto implements Pick<Keyword, 'id' | 'name'> {
@Expose()
id: number;

@Expose()
name: string;
to?: string;
}

export class OutCommentDto
Expand Down
5 changes: 4 additions & 1 deletion backend/server/src/search/dtos/popular-keyword.dto.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,3 +11,5 @@ export class ReqPopularKeywordQueryDto {
@IsOptional()
count?: number = 10;
}

export class PopularKeywordsResDto extends OutKeywordDto {}
Loading

0 comments on commit 8024024

Please sign in to comment.