From 8433d34f7d7e8c2457f05885767ae3ff296a09bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=98=81=EC=9A=B0?= Date: Sun, 7 Sep 2025 16:59:25 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=ED=8F=AC=EC=8A=A4=ED=8C=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ixfp/gitmon/config/web/WebMvcConfig.kt | 1 + .../gitmon/controller/IPostingController.kt | 77 +++++++++++++++++++ .../gitmon/controller/PostingController.kt | 12 +++ .../gitmon/domain/posting/PostingService.kt | 2 +- 4 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/ixfp/gitmon/config/web/WebMvcConfig.kt b/src/main/kotlin/com/ixfp/gitmon/config/web/WebMvcConfig.kt index b0e2787..47c8f92 100644 --- a/src/main/kotlin/com/ixfp/gitmon/config/web/WebMvcConfig.kt +++ b/src/main/kotlin/com/ixfp/gitmon/config/web/WebMvcConfig.kt @@ -14,6 +14,7 @@ class WebMvcConfig( .addPathPatterns("/api/v1/member/repo/**") // 인증이 필요한 경로 .addPathPatterns("/api/v1/member", "/api/v1/member/") .addPathPatterns("/api/v1/posting", "/api/v1/posting/") + .addPathPatterns("/api/v1/posting/images", "/api/v1/posting/images/") } override fun addCorsMappings(registry: CorsRegistry) { diff --git a/src/main/kotlin/com/ixfp/gitmon/controller/IPostingController.kt b/src/main/kotlin/com/ixfp/gitmon/controller/IPostingController.kt index 68a3d6f..4fe1c44 100644 --- a/src/main/kotlin/com/ixfp/gitmon/controller/IPostingController.kt +++ b/src/main/kotlin/com/ixfp/gitmon/controller/IPostingController.kt @@ -110,4 +110,81 @@ interface IPostingController { content: MultipartFile, member: Member, ): ResponseEntity> + + @Operation( + summary = "이미지 업로드", + description = "포스팅에 사용할 이미지를 업로드합니다.", + security = [SecurityRequirement(name = ACCESS_TOKEN)], + ) + @ApiResponses( + value = [ + ApiResponse( + responseCode = "201", + description = "이미지 업로드 성공", + content = [ + Content( + mediaType = "application/json", + schema = + Schema( + example = """ + { + "status": "CREATED", + "data": "https://raw.githubusercontent.com/user/repo/main/images/uuid.jpg" + } + """, + ), + ), + ], + ), + ApiResponse( + responseCode = "400", + description = "허용되지 않은 이미지 확장자", + content = [ + Content( + mediaType = "application/json", + schema = + Schema( + example = """ + { + "status": "BAD_REQUEST", + "errorMessage": "invalid image extension" + } + """, + ), + ), + ], + ), + ApiResponse( + responseCode = "409", + description = "사용자의 레포지토리가 아직 설정되지 않음", + content = [ + Content( + mediaType = "application/json", + schema = + Schema( + example = """ + { + "status": "CONFLICT", + "errorMessage": "repository not configured" + } + """, + ), + ), + ], + ), + ], + ) + @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "업로드할 이미지 파일", + required = true, + content = [ + Content( + mediaType = MediaType.MULTIPART_FORM_DATA_VALUE, + ), + ], + ) + fun uploadImage( + image: MultipartFile, + member: Member, + ): ResponseEntity> } diff --git a/src/main/kotlin/com/ixfp/gitmon/controller/PostingController.kt b/src/main/kotlin/com/ixfp/gitmon/controller/PostingController.kt index 98d76c7..08a1923 100644 --- a/src/main/kotlin/com/ixfp/gitmon/controller/PostingController.kt +++ b/src/main/kotlin/com/ixfp/gitmon/controller/PostingController.kt @@ -77,6 +77,18 @@ class PostingController( return ApiResponseHelper.success(posting) } + @PostMapping( + "/images", + consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], + ) + override fun uploadImage( + @RequestPart image: MultipartFile, + @RequestAttribute(AUTHENTICATED_MEMBER) member: Member, + ): ResponseEntity> { + val imageUrl = postingService.uploadImage(member, image) + return ApiResponseHelper.created(imageUrl) + } + companion object { private val log = logger {} } diff --git a/src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingService.kt b/src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingService.kt index 88523da..7db461c 100644 --- a/src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingService.kt +++ b/src/main/kotlin/com/ixfp/gitmon/domain/posting/PostingService.kt @@ -140,7 +140,7 @@ class PostingService( return updatedPostingId } - private fun uploadImage( + fun uploadImage( member: Member, content: MultipartFile, ): String { From c6f8f84c22e195e5f82523d5abf24e0fbd8ae857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=98=81=EC=9A=B0?= Date: Sun, 7 Sep 2025 16:59:37 +0900 Subject: [PATCH 2/3] =?UTF-8?q?chore:=20dev=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/resources/application-dev.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..746eaf3 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,5 @@ +oauth2: + client: + github: + id: ${GITHUB_OAUTH2_CLIENT_ID_DEV} + secret: ${GITHUB_OAUTH2_CLIENT_SECRET_DEV} From a30d13994f3e878a5c6bf641bf646d47f26f2d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=98=81=EC=9A=B0?= Date: Sun, 7 Sep 2025 18:39:40 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chore:=20=EB=A9=80=ED=8B=B0=ED=8C=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=A6=88=2010MB=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기본: 1MB --- src/main/resources/application.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 51edf67..f02373a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,10 @@ spring: application: name: gitmon + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB datasource: url: ${DATABASE_URL} username: ${DATABASE_USERNAME}