11import multer from 'multer' ;
22import path from 'path' ;
3- import fs from 'fs ' ;
3+ import { uploadToS3 , deleteFromS3 } from '../../s3.upload.js ' ;
44import { CommissionRepository } from "../repository/commission.repository.js" ;
55import { RequestRepository } from "../../request/repository/request.repository.js" ;
66import {
@@ -17,38 +17,14 @@ import {
1717} from "../../common/errors/commission.errors.js" ;
1818
1919export const CommissionService = {
20- // 업로드 디렉토리 설정
21- uploadDir : path . join ( process . cwd ( ) , 'uploads' , 'request-images' ) ,
2220
2321 /**
24- * 업로드 디렉토리 생성
22+ * S3 업로드를 위한 multer 설정
2523 */
26- ensureUploadDir ( ) {
27- if ( ! fs . existsSync ( this . uploadDir ) ) {
28- fs . mkdirSync ( this . uploadDir , { recursive : true } ) ;
29- console . log ( `업로드 디렉토리 생성: ${ this . uploadDir } ` ) ;
30- }
31- } ,
32-
33- /**
34- * multer 저장소 설정
35- */
36- storage : multer . diskStorage ( {
37- destination : function ( req , file , cb ) {
38- const uploadDir = path . join ( process . cwd ( ) , 'uploads' , 'request-images' ) ;
39- cb ( null , uploadDir ) ;
40- } ,
41- filename : function ( req , file , cb ) {
42- // 파일명: request_현재시간_랜덤값.확장자
43- const timestamp = Date . now ( ) ;
44- const random = Math . round ( Math . random ( ) * 1E9 ) ;
45- const ext = path . extname ( file . originalname ) ;
46- cb ( null , `request_${ timestamp } _${ random } ${ ext } ` ) ;
47- }
48- } ) ,
24+ storage : multer . memoryStorage ( ) ,
4925
5026 /**
51- * 파일 필터 (이미지만 허용)
27+ * 파일 필터
5228 */
5329 fileFilter ( req , file , cb ) {
5430 const allowedTypes = [ 'image/jpeg' , 'image/jpg' , 'image/png' ] ;
@@ -67,72 +43,64 @@ export const CommissionService = {
6743 * multer 인스턴스 생성
6844 */
6945 getUploadMiddleware ( ) {
70- // 업로드 디렉토리 확인
71- this . ensureUploadDir ( ) ;
72-
7346 return multer ( {
7447 storage : this . storage ,
7548 fileFilter : this . fileFilter ,
7649 limits : {
77- fileSize : 5 * 1024 * 1024 // 5MB 제한
50+ fileSize : 10 * 1024 * 1024
7851 }
7952 } ) . single ( 'image' ) ;
8053 } ,
8154
8255 /**
83- * 이미지 업로드 처리
56+ * S3 이미지 업로드 처리
8457 */
8558 async uploadRequestImage ( file ) {
8659 try {
8760 // 1. 파일 존재 여부 확인
8861 if ( ! file ) {
89- throw new ImageUploadFailedError ( '파일이 업로드되지 않았습니다' ) ;
62+ throw new ImageUploadFailedError ( { reason : '파일이 업로드되지 않았습니다' } ) ;
9063 }
9164
92- // 2. 파일 크기 추가 검증
93- if ( file . size > 5 * 1024 * 1024 ) {
94- this . deleteFile ( file . path ) ;
95- throw new FileSizeExceededError ( {
96- maxSize : '5MB' ,
97- receivedSize : `${ Math . round ( file . size / 1024 / 1024 * 100 ) / 100 } MB`
98- } ) ;
65+ // 2. 파일 크기 검증
66+ if ( file . size > 10 * 1024 * 1024 ) {
67+ throw new FileSizeExceededError ( { fileSize : file . size } ) ;
68+ }
69+
70+ // 3. 파일 확장자 검증
71+ const ext = path . extname ( file . originalname ) . toLowerCase ( ) . replace ( '.' , '' ) ;
72+ if ( ! [ 'jpeg' , 'jpg' , 'png' ] . includes ( ext ) ) {
73+ throw new UnsupportedImageFormatError ( { fileType : file . mimetype } ) ;
9974 }
10075
101- // 3. 파일 URL 생성
102- const baseUrl = process . env . BASE_URL || 'http://localhost:3000' ;
103- const imageUrl = `${ baseUrl } /uploads/request-images/${ file . filename } ` ;
76+ // 4. S3 업로드 (requests 폴더에 저장)
77+ const imageUrl = await uploadToS3 ( file . buffer , 'requests' , ext ) ;
10478
105- // 4. 성공 응답 반환
10679 return {
10780 image_url : imageUrl ,
10881 file_size : file . size ,
10982 file_type : file . mimetype
11083 } ;
11184
11285 } catch ( error ) {
113- // 오류 발생 시 업로드된 파일 삭제
114- if ( file && file . path ) {
115- this . deleteFile ( file . path ) ;
116- }
11786 throw error ;
11887 }
11988 } ,
12089
12190 /**
122- * 파일 삭제 헬퍼 메서드
91+ * S3 이미지 삭제
12392 */
124- deleteFile ( filePath ) {
93+ async deleteS3Image ( imageUrl ) {
12594 try {
126- if ( fs . existsSync ( filePath ) ) {
127- fs . unlinkSync ( filePath ) ;
128- console . log ( `파일 삭제 : ${ filePath } ` ) ;
95+ if ( imageUrl && imageUrl . includes ( 'amazonaws.com' ) ) {
96+ await deleteFromS3 ( imageUrl ) ;
97+ console . log ( `S3 이미지 삭제 완료 : ${ imageUrl } ` ) ;
12998 }
13099 } catch ( error ) {
131- console . error ( '파일 삭제 실패:' , error ) ;
100+ console . error ( 'S3 이미지 삭제 실패:' , error ) ;
132101 }
133102 } ,
134103
135-
136104 /**
137105 * 커미션 게시글 상세글 조회
138106 */
@@ -627,39 +595,39 @@ export const CommissionService = {
627595 // 캐릭터 데이터
628596 CHARACTER_DATA : [
629597 {
630- image : " https://example. com/character1 .png" ,
598+ image : ` https://${ process . env . AWS_S3_BUCKET_NAME } .s3.dualstack. ${ process . env . AWS_REGION } .amazonaws. com/reports/reportType1 .png` ,
631599 quote : {
632600 title : "커미션계의 VIP" ,
633601 description : "\"커미션계의 큰 손 등장!\" 덕분에 작가님들의 창작 활동이 풍요로워졌어요."
634602 } ,
635603 condition : "월 사용 포인트 15만포인트 이상"
636604 } ,
637605 {
638- image : " https://example. com/character2 .png" ,
606+ image : ` https://${ process . env . AWS_S3_BUCKET_NAME } .s3.dualstack. ${ process . env . AWS_REGION } .amazonaws. com/reports/reportType2 .png` ,
639607 quote : {
640608 title : "작가 덕후 신청자" ,
641609 description : "\"이 작가님만큼은 믿고 맡긴다!\" 단골의 미덕을 지닌 당신, 작가님도 감동했을 거예요."
642610 } ,
643611 condition : "같은 작가에게 3회 이상 신청"
644612 } ,
645613 {
646- image : " https://example. com/character3 .png" ,
614+ image : ` https://${ process . env . AWS_S3_BUCKET_NAME } .s3.dualstack. ${ process . env . AWS_REGION } .amazonaws. com/reports/reportType3 .png` ,
647615 quote : {
648616 title : "호기심 대장 신청자" ,
649617 description : "호기심이 가득해서, 언제나 새로운 작가를 탐색해요."
650618 } ,
651619 condition : "서로 다른 작가 5명 이상에게 커미션을 신청"
652620 } ,
653621 {
654- image : " https://example. com/character4 .png" ,
622+ image : ` https://${ process . env . AWS_S3_BUCKET_NAME } .s3.dualstack. ${ process . env . AWS_REGION } .amazonaws. com/reports/reportType4 .png` ,
655623 quote : {
656624 title : "숨겨진 보석 발굴가" ,
657625 description : "\"빛나는 원석을 내가 발견했다!\" 성장하는 작가님들의 첫걸음을 함께한 당신, 멋져요."
658626 } ,
659627 condition : "팔로워 수가 0명인 작가에게 신청 2회 이상"
660628 } ,
661629 {
662- image : " https://example. com/character5 .png" ,
630+ image : ` https://${ process . env . AWS_S3_BUCKET_NAME } .s3.dualstack. ${ process . env . AWS_REGION } .amazonaws. com/reports/reportType5 .png` ,
663631 quote : {
664632 title : "빠른 피드백러" ,
665633 description : "\"작가님, 이번 커미션 최고였어요!\" 정성 가득한 피드백으로 건강한 커미션 문화를 만들어가요."
0 commit comments