From 1820323b417511eddb991ce20e13044b15e1e5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Tue, 10 Feb 2026 17:31:08 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat(#355):=20=ED=94=84=EC=82=AC=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/application/service/UserService.java | 25 +++++++++++++++++++ .../controller/UserController.java | 10 ++++++++ .../MyProfileCardUpdateRequestDto.java | 13 ++++++++++ .../presentation/swagger/UserSwagger.java | 8 ++++++ 4 files changed, 56 insertions(+) create mode 100644 src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java diff --git a/src/main/java/com/example/RealMatch/user/application/service/UserService.java b/src/main/java/com/example/RealMatch/user/application/service/UserService.java index 495d8d17..b634c32b 100644 --- a/src/main/java/com/example/RealMatch/user/application/service/UserService.java +++ b/src/main/java/com/example/RealMatch/user/application/service/UserService.java @@ -20,6 +20,7 @@ import com.example.RealMatch.user.infrastructure.ScrapMockDataProvider; import com.example.RealMatch.user.presentation.code.UserErrorCode; import com.example.RealMatch.user.presentation.dto.request.MyEditInfoRequestDto; +import com.example.RealMatch.user.presentation.dto.request.MyProfileCardUpdateRequestDto; import com.example.RealMatch.user.presentation.dto.response.MyEditInfoResponseDto; import com.example.RealMatch.user.presentation.dto.response.MyLoginResponseDto; import com.example.RealMatch.user.presentation.dto.response.MyPageResponseDto; @@ -146,6 +147,30 @@ public MyLoginResponseDto getSocialLoginInfo(Long userId) { return MyLoginResponseDto.from(linkedProviders); } + @Transactional + public MyProfileCardResponseDto updateMyProfileImage( + Long userId, + MyProfileCardUpdateRequestDto request + ) { + // 유저 조회 + User user = userRepository.findById(userId) + .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); + + // 매칭 검사 진행 여부 예외 처리 - 매칭 검사를 안하면 프로필 카드가 없음 + UserMatchingDetail detail = userMatchingDetailRepository + .findByUserIdAndIsDeprecatedFalse(userId) + .orElseThrow(() -> new CustomException(UserErrorCode.PROFILE_CARD_NOT_FOUND)); + + // 이미지 URL만 교체 + user.updateProfileImage(request.getProfileImageUrl()); + + // 변경된 프로필 이미지로 프로필 카드 DTO 재생성 + List categories = + userContentCategoryRepository.findByUserId(userId); + + return MyProfileCardResponseDto.from(user, detail, categories); + } + @Transactional(readOnly = true) public boolean isNicknameAvailable(String nickname) { return nicknameValidator.isAvailable(nickname); diff --git a/src/main/java/com/example/RealMatch/user/presentation/controller/UserController.java b/src/main/java/com/example/RealMatch/user/presentation/controller/UserController.java index d6e0bd34..55affa0f 100644 --- a/src/main/java/com/example/RealMatch/user/presentation/controller/UserController.java +++ b/src/main/java/com/example/RealMatch/user/presentation/controller/UserController.java @@ -20,6 +20,7 @@ import com.example.RealMatch.user.application.service.UserService; import com.example.RealMatch.user.application.service.UserWithdrawService; import com.example.RealMatch.user.presentation.dto.request.MyEditInfoRequestDto; +import com.example.RealMatch.user.presentation.dto.request.MyProfileCardUpdateRequestDto; import com.example.RealMatch.user.presentation.dto.response.FavoriteBrandListResponseDto; import com.example.RealMatch.user.presentation.dto.response.FavoriteCampaignListResponseDto; import com.example.RealMatch.user.presentation.dto.response.MyEditInfoResponseDto; @@ -166,4 +167,13 @@ public CustomResponse getMyFavoriteCampaigns( ) ); } + @PatchMapping("/me/profile-image") + public CustomResponse updateMyProfileImage( + @AuthenticationPrincipal CustomUserDetails userDetails, + @RequestBody @Valid MyProfileCardUpdateRequestDto request + ) { + return CustomResponse.ok( + userService.updateMyProfileImage(userDetails.getUserId(), request) + ); + } } diff --git a/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java b/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java new file mode 100644 index 00000000..1c7ab3aa --- /dev/null +++ b/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java @@ -0,0 +1,13 @@ +package com.example.RealMatch.user.presentation.dto.request; + +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class MyProfileCardUpdateRequestDto { + + @Size(max = 255) + private String profileImageUrl; +} diff --git a/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java b/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java index c6e8cfe5..93a1a06a 100644 --- a/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java +++ b/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java @@ -11,6 +11,7 @@ import com.example.RealMatch.match.domain.entity.enums.CampaignSortType; import com.example.RealMatch.match.presentation.dto.request.MatchRequestDto; import com.example.RealMatch.user.presentation.dto.request.MyEditInfoRequestDto; +import com.example.RealMatch.user.presentation.dto.request.MyProfileCardUpdateRequestDto; import com.example.RealMatch.user.presentation.dto.response.FavoriteBrandListResponseDto; import com.example.RealMatch.user.presentation.dto.response.FavoriteCampaignListResponseDto; import com.example.RealMatch.user.presentation.dto.response.MyEditInfoResponseDto; @@ -207,4 +208,11 @@ CustomResponse getMyFavoriteCampaigns( @RequestParam(required = false) CampaignSortType sort ); + + @Operation(summary = "프로필 이미지 수정", + description = "Attachment API로 업로드된 이미지 URL을 받아 프로필 이미지를 변경합니다") + CustomResponse updateMyProfileImage( + @Parameter(hidden = true) CustomUserDetails userDetails, + @RequestBody MyProfileCardUpdateRequestDto request + ); } From 0d21f2d783df6cf975cb40c2e8f0689e61c66080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Tue, 10 Feb 2026 17:32:34 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat(#355):=20=EC=8A=A4=EC=9B=A8=EA=B1=B0?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RealMatch/user/presentation/swagger/UserSwagger.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java b/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java index 93a1a06a..413a5fd1 100644 --- a/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java +++ b/src/main/java/com/example/RealMatch/user/presentation/swagger/UserSwagger.java @@ -149,7 +149,7 @@ CustomResponse checkNicknameAvailable( @RequestParam String nickname ); - @Operation(summary = "회원 탈퇴", description = "회원 탈퇴(Soft Delete) 처리 후 role을 WITHDRAWN으로 변경합니다.") + @Operation(summary = "회원 탈퇴 API By 고경수 ", description = "회원 탈퇴(Soft Delete) 처리 후 role을 WITHDRAWN으로 변경합니다.") CustomResponse withdraw( @Parameter(hidden = true) @AuthenticationPrincipal CustomUserDetails userDetails ); @@ -209,7 +209,7 @@ CustomResponse getMyFavoriteCampaigns( CampaignSortType sort ); - @Operation(summary = "프로필 이미지 수정", + @Operation(summary = "프로필 이미지 수정 API By 고경수", description = "Attachment API로 업로드된 이미지 URL을 받아 프로필 이미지를 변경합니다") CustomResponse updateMyProfileImage( @Parameter(hidden = true) CustomUserDetails userDetails, From 7bd281300c97513ccbb11b9160215a3e42fa6e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=A0=EA=B2=BD=EC=88=98?= Date: Tue, 10 Feb 2026 17:39:56 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat(#355):=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/dto/request/MyProfileCardUpdateRequestDto.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java b/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java index 1c7ab3aa..17f8394e 100644 --- a/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java +++ b/src/main/java/com/example/RealMatch/user/presentation/dto/request/MyProfileCardUpdateRequestDto.java @@ -8,6 +8,7 @@ @NoArgsConstructor public class MyProfileCardUpdateRequestDto { + @jakarta.validation.constraints.NotBlank @Size(max = 255) private String profileImageUrl; }