Skip to content

Commit

Permalink
Merge pull request #94 from modern-agile-team/feature/board-images
Browse files Browse the repository at this point in the history
Refactor(2swo/Board-Image) 보드 이미지 수정 예외처리/코드 리펙토링
  • Loading branch information
2swo authored Nov 6, 2023
2 parents 79fc296 + 0cfe097 commit b22dfab
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 29 deletions.
4 changes: 3 additions & 1 deletion src/boards/controllers/Boards.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ApiGetOneBoard } from '../swagger-decorators/get-one-board-decorators';
import { ApiUpdateBoard } from '../swagger-decorators/patch-board-decorators';
import { ApiTags } from '@nestjs/swagger';
import { ApiDeleteBoard } from '../swagger-decorators/delete-board-decorators';
import { ApiUpdateBoardImage } from '../swagger-decorators/patch-board-images-decorators';

@Controller('boards')
@ApiTags('board API')
Expand Down Expand Up @@ -93,11 +94,12 @@ export class BoardsController {
}

@Patch('/images')
@ApiUpdateBoardImage()
@UseInterceptors(FilesInterceptor('files', 3))
async editBoardImages(
@Headers('access_token') accessToken: string,
@Query('boardId') boardId: number,
@Query('deleteImageUrl') deleteImageUrl: string,
@Query('deleteImageUrl') deleteImageUrl: string[],
@UploadedFiles() files: Express.Multer.File[],
) {
const userId = await this.tokenService.decodeToken(accessToken);
Expand Down
64 changes: 38 additions & 26 deletions src/boards/services/BoardImage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { BoardImageRepository } from '../repository/boardImage.repository';
import { S3Service } from '../../common/s3/s3.service';
import { CreateBoardImageDto } from '../dto/create.board-image.dto';
import { BoardImage } from '../entities/board-image.entity';

@Injectable()
export class BoardImagesService {
Expand All @@ -20,7 +21,7 @@ export class BoardImagesService {
const uploadedImage = await this.s3Service.uploadImage(
file,
userId,
'BoadImages/',
'BoadImages',
);
const boardImage = new CreateBoardImageDto();
boardImage.boardId = boardId;
Expand All @@ -34,42 +35,53 @@ export class BoardImagesService {

async updateBoardImages(
boardId: number,
files: Express.Multer.File[],
files: Express.Multer.File[] | undefined,
userId: number,
deleteImageUrl: string,
deleteImageUrl: string[],
): Promise<any> {
const existingImages =
const existingImages = // boardId에 해당하는 이미지url을 DB에서 불러옵니다.
await this.boardImageRepository.getBoardImages(boardId);

const imagesToDelete = existingImages.filter(
(image) => image.imageUrl === deleteImageUrl,
(image) => deleteImageUrl.includes(image.imageUrl), // 불러온 이미지들과 param값 비교
);
const s3ToDelete = imagesToDelete.map((image) => {
const parts = image.imageUrl.split('/');
const fileName = parts[parts.length - 1];
return 'BoardImages/' + fileName;
});

await this.boardImageRepository.deleteImages(imagesToDelete);
await this.s3Service.deleteImage(s3ToDelete.join(','));
await this.deleteImages(imagesToDelete); //이미지 삭제처리

// 여기서부터 새로운 이미지 추가
const newImagesArray: CreateBoardImageDto[] = [];
for (const file of files) {
const uploadedImage = await this.s3Service.uploadImage(
file,
userId,
'BoardImages/',
);
const boardImage = new CreateBoardImageDto();
boardImage.boardId = boardId;
boardImage.imageUrl = uploadedImage.url;
const savedImage =
await this.boardImageRepository.saveBoardImage(boardImage);
newImagesArray.push(savedImage);
// 예외처리 files이 없으면 실행되지 않음.
if (files && files.length > 0) {
for (const file of files) {
const uploadedImage = await this.s3Service.uploadImage(
file,
userId,
'BoardImages',
);
const boardImage = new CreateBoardImageDto();
boardImage.boardId = boardId;
boardImage.imageUrl = uploadedImage.url;
const savedImage =
await this.boardImageRepository.saveBoardImage(boardImage);
newImagesArray.push(savedImage);
}
}
return {
message: '이미지 업데이트 및 삭제가 성공적으로 처리되었습니다.',
newImagesArray,
};
}
// 이미지 삭제 수행
private async deleteImages(imagesToDelete: BoardImage[]) {
const s3ToDelete = imagesToDelete.map((image) => {
const parts = image.imageUrl.split('/');
const fileName = parts[parts.length - 1]; // S3에서 삭제할 이미지 파일명을 추출합니다.
console.log(fileName);
return 'BoardImages/' + fileName;
});

// 예외처리 (빈 배열이 아닐때만 삭제요청 하기)
if (s3ToDelete.length > 0) {
await this.boardImageRepository.deleteImages(imagesToDelete); // 이미지 삭제 (db)
await this.s3Service.deleteImage(s3ToDelete.join(',')); // 이미지 삭제 (s3)
}
}
}
4 changes: 2 additions & 2 deletions src/boards/swagger-decorators/patch-board-decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { ApiHeaders, ApiOperation, ApiResponse } from '@nestjs/swagger';
export function ApiUpdateBoard() {
return applyDecorators(
ApiOperation({
summary: '보드를 수정 API',
description: '보드 수정 API',
summary: '보드를 수정하는 API',
description: '보드 수정하는 API',
}),
ApiResponse({
status: 200,
Expand Down
85 changes: 85 additions & 0 deletions src/boards/swagger-decorators/patch-board-images-decorators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { applyDecorators } from '@nestjs/common';
import { ApiHeaders, ApiOperation, ApiResponse } from '@nestjs/swagger';

export function ApiUpdateBoardImage() {
return applyDecorators(
ApiOperation({
summary: '보드의 이미지를 수정하는 API',
description: '보드의 이미지를 수정하는 API',
}),
ApiResponse({
status: 200,
description: '보드의 내용을 성공적으로 수정한 경우',
content: {
JSON: {
example: {
message: '이미지 업데이트 및 삭제가 성공적으로 처리되었습니다.',
newImagesArray: [
{
boardId: '업데이트된 보드 아이디',
imageUrl: '새롭게 넣은 이미지 url',
id: '새롭게 넣은 이미지 id',
},
],
},
},
},
}),
ApiResponse({
status: 401,
description: '우리 서비스의 액세스 토큰이 아닌 경우',
content: {
JSON: {
example: { statusCode: 401, message: '유효하지 않은 토큰입니다.' },
},
},
}),
ApiResponse({
status: 403,
description: '만료된 액세스 토큰인 경우',
content: {
JSON: {
example: { statusCode: 403, message: '만료된 토큰입니다.' },
},
},
}),
ApiResponse({
status: 404,
description: 'DB에서 사용자를 찾을 수 없는 경우',
content: {
JSON: {
example: { statusCode: 404, message: '사용자를 찾을 수 없습니다.' },
},
},
}),
ApiResponse({
status: 411,
description: '액세스 토큰이 제공되지 않은 경우',
content: {
JSON: {
example: { statusCode: 411, message: '토큰이 제공되지 않았습니다.' },
},
},
}),
ApiResponse({
status: 500,
description: '보드 수정중 오류가 발생했습니다',
content: {
JSON: {
example: {
statusCode: 500,
message: '보드 수정 중 오류가 발생했습니다.',
},
},
},
}),
ApiHeaders([
{
name: 'access_token',
description: '액세스 토큰',
required: true,
example: '여기에 액세스 토큰',
},
]),
);
}

0 comments on commit b22dfab

Please sign in to comment.