From 124129d4d4ee86024db42a99cc6ce6fb6f4d1028 Mon Sep 17 00:00:00 2001 From: EunjiShin Date: Thu, 18 Jul 2024 21:35:14 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20presigned=20url=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/media/MediaController.java | 19 ++++++++++++-- .../request/CreatePresignedUrlRequest.java | 4 +-- .../src/main/resources/application-jwt.yml | 3 +++ .../spot/domain/media/MediaProperty.java | 1 + .../src/main/resources/application-kakao.yml | 4 +++ .../ncp/objectstorage/FileNameGenerator.java | 25 +++---------------- .../objectstorage/PresignedUrlGenerator.java | 15 +++-------- .../objectstorage/FileNameGeneratorTest.java | 23 +++-------------- .../PresignedUrlGeneratorTest.java | 18 ++----------- .../out/media/CreatePresignedUrlPort.java | 3 +-- 10 files changed, 41 insertions(+), 74 deletions(-) create mode 100644 application/src/main/resources/application-jwt.yml create mode 100644 infrastructure/jpa/src/main/resources/application-kakao.yml diff --git a/application/src/main/java/org/depromeet/spot/application/media/MediaController.java b/application/src/main/java/org/depromeet/spot/application/media/MediaController.java index 9e6538b5..96850d02 100644 --- a/application/src/main/java/org/depromeet/spot/application/media/MediaController.java +++ b/application/src/main/java/org/depromeet/spot/application/media/MediaController.java @@ -1,9 +1,12 @@ package org.depromeet.spot.application.media; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; import org.depromeet.spot.application.media.dto.request.CreatePresignedUrlRequest; import org.depromeet.spot.application.media.dto.response.MediaUrlResponse; +import org.depromeet.spot.domain.media.MediaProperty; import org.depromeet.spot.usecase.port.out.media.CreatePresignedUrlPort; import org.depromeet.spot.usecase.port.out.media.CreatePresignedUrlPort.PresignedUrlRequest; import org.springframework.http.HttpStatus; @@ -32,8 +35,20 @@ public class MediaController { public MediaUrlResponse createReviewImageUploadUrl( @PathVariable Long memberId, @RequestBody @Valid CreatePresignedUrlRequest request) { PresignedUrlRequest command = - new PresignedUrlRequest(request.fileExtension(), request.property()); - String presignedUrl = createPresignedUrlPort.forReview(memberId, command); + new PresignedUrlRequest(request.fileExtension(), MediaProperty.REVIEW); + String presignedUrl = createPresignedUrlPort.forImage(memberId, command); + return new MediaUrlResponse(presignedUrl); + } + + @ResponseStatus(HttpStatus.CREATED) + @PostMapping(value = "/members/{memberId}/profile/images") + @Operation(summary = "유저의 프로필 이미지 업로드 url을 생성합니다.") + public MediaUrlResponse createProfileImageUploadUrl( + @PathVariable @Positive @NotNull Long memberId, + @RequestBody @Valid CreatePresignedUrlRequest request) { + PresignedUrlRequest command = + new PresignedUrlRequest(request.fileExtension(), MediaProperty.PROFILE_IMAGE); + String presignedUrl = createPresignedUrlPort.forImage(memberId, command); return new MediaUrlResponse(presignedUrl); } } diff --git a/application/src/main/java/org/depromeet/spot/application/media/dto/request/CreatePresignedUrlRequest.java b/application/src/main/java/org/depromeet/spot/application/media/dto/request/CreatePresignedUrlRequest.java index 3645442b..a8eaeb0c 100644 --- a/application/src/main/java/org/depromeet/spot/application/media/dto/request/CreatePresignedUrlRequest.java +++ b/application/src/main/java/org/depromeet/spot/application/media/dto/request/CreatePresignedUrlRequest.java @@ -1,5 +1,3 @@ package org.depromeet.spot.application.media.dto.request; -import org.depromeet.spot.domain.media.MediaProperty; - -public record CreatePresignedUrlRequest(String fileExtension, MediaProperty property) {} +public record CreatePresignedUrlRequest(String fileExtension) {} diff --git a/application/src/main/resources/application-jwt.yml b/application/src/main/resources/application-jwt.yml new file mode 100644 index 00000000..fba63b90 --- /dev/null +++ b/application/src/main/resources/application-jwt.yml @@ -0,0 +1,3 @@ +spring: + jwt: + secret: c3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4t \ No newline at end of file diff --git a/domain/src/main/java/org/depromeet/spot/domain/media/MediaProperty.java b/domain/src/main/java/org/depromeet/spot/domain/media/MediaProperty.java index 81e2f544..9f534f0b 100644 --- a/domain/src/main/java/org/depromeet/spot/domain/media/MediaProperty.java +++ b/domain/src/main/java/org/depromeet/spot/domain/media/MediaProperty.java @@ -9,6 +9,7 @@ public enum MediaProperty { STADIUM_SEAT("stadium-seat-charts"), STADIUM_SEAT_LABEL("stadium-seat-label-charts"), TEAM_LOGO("team-logos"), + PROFILE_IMAGE("profile-images"), ; private final String folderName; diff --git a/infrastructure/jpa/src/main/resources/application-kakao.yml b/infrastructure/jpa/src/main/resources/application-kakao.yml new file mode 100644 index 00000000..2454b087 --- /dev/null +++ b/infrastructure/jpa/src/main/resources/application-kakao.yml @@ -0,0 +1,4 @@ +oauth: + clientId: 1f043adfbb8f5438907686f472d3b164 + kauthTokenUrlHost: https://kauth.kakao.com + kauthUserUrlHost: https://kapi.kakao.com diff --git a/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/FileNameGenerator.java b/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/FileNameGenerator.java index 55c4b4eb..1c3d6a37 100644 --- a/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/FileNameGenerator.java +++ b/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/FileNameGenerator.java @@ -1,8 +1,6 @@ package org.depromeet.spot.ncp.objectstorage; -import org.depromeet.spot.domain.media.MediaProperty; import org.depromeet.spot.domain.media.extension.ImageExtension; -import org.depromeet.spot.domain.media.extension.StadiumSeatMediaExtension; import org.depromeet.spot.usecase.port.in.util.TimeUsecase; import org.springframework.stereotype.Service; @@ -16,29 +14,14 @@ public class FileNameGenerator { private final TimeUsecase timeUsecase; - public String createReviewFileName( - final Long userId, final ImageExtension fileExtension, final String folderName) { + public String createFileName( + final Long memberId, final ImageExtension fileExtension, final String folderName) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder .append(folderName) .append("/") - .append(MediaProperty.REVIEW) - .append("_user_") - .append(userId) - .append("_") - .append(timeUsecase.getNow()) - .append(".") - .append(fileExtension.getValue()); - return stringBuilder.toString(); - } - - public String createStadiumFileName( - final StadiumSeatMediaExtension fileExtension, final String folderName) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder - .append(folderName) - .append("/") - .append(MediaProperty.STADIUM) + .append("user_") + .append(memberId) .append("_") .append(timeUsecase.getNow()) .append(".") diff --git a/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGenerator.java b/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGenerator.java index 617490a4..8ac7a1f9 100644 --- a/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGenerator.java +++ b/infrastructure/ncp/src/main/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGenerator.java @@ -4,8 +4,6 @@ import java.util.Date; import org.depromeet.spot.common.exception.media.MediaException.InvalidExtensionException; -import org.depromeet.spot.common.exception.media.MediaException.InvalidReviewMediaException; -import org.depromeet.spot.domain.media.MediaProperty; import org.depromeet.spot.domain.media.extension.ImageExtension; import org.depromeet.spot.ncp.config.ObjectStorageConfig; import org.depromeet.spot.usecase.port.out.media.CreatePresignedUrlPort; @@ -33,24 +31,19 @@ public class PresignedUrlGenerator implements CreatePresignedUrlPort { private static final long EXPIRE_MS = 1000 * 60 * 5L; @Override - public String forReview(final Long userId, PresignedUrlRequest request) { - isValidReviewMedia(request.getProperty(), request.getFileExtension()); + public String forImage(final Long memberId, PresignedUrlRequest request) { + isValidImageExtension(request.getFileExtension()); final ImageExtension fileExtension = ImageExtension.from(request.getFileExtension()); final String folderName = request.getProperty().getFolderName(); final String fileName = - fileNameGenerator.createReviewFileName(userId, fileExtension, folderName); + fileNameGenerator.createFileName(memberId, fileExtension, folderName); final URL url = createPresignedUrl(fileName); return url.toString(); } - // 1차 MVP에서 사진만 허용 - private void isValidReviewMedia(final MediaProperty property, final String fileExtension) { - if (property != MediaProperty.REVIEW) { - throw new InvalidReviewMediaException(); - } - + private void isValidImageExtension(final String fileExtension) { if (!ImageExtension.isValid(fileExtension)) { throw new InvalidExtensionException(fileExtension); } diff --git a/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/FileNameGeneratorTest.java b/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/FileNameGeneratorTest.java index 8ceb1e46..9ef39b38 100644 --- a/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/FileNameGeneratorTest.java +++ b/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/FileNameGeneratorTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import org.depromeet.spot.domain.media.extension.ImageExtension; -import org.depromeet.spot.domain.media.extension.StadiumSeatMediaExtension; import org.depromeet.spot.ncp.mock.FakeTimeUsecase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -19,30 +18,16 @@ void init() { } @Test - void 리뷰_첨부파일_이름을_생성할_수_있다() { + void 첨부_파일_이름을_생성할_수_있다() { // given Long userId = 1L; ImageExtension extension = ImageExtension.JPG; // when - final String folderName = "review-images"; - final String fileName = - fileNameGenerator.createReviewFileName(userId, extension, folderName); + final String folderName = "folder-names"; + final String fileName = fileNameGenerator.createFileName(userId, extension, folderName); // then - assertThat(fileName).isEqualTo("review-images/REVIEW_user_1_2024-07-09T21:00.jpg"); - } - - @Test - void 경기장_첨부파일_이름을_생성할_수_있다() { - // given - StadiumSeatMediaExtension extension = StadiumSeatMediaExtension.SVG; - - // when - final String folderName = "stadium-images"; - final String fileName = fileNameGenerator.createStadiumFileName(extension, folderName); - - // then - assertThat(fileName).isEqualTo("stadium-images/STADIUM_2024-07-09T21:00.svg"); + assertThat(fileName).isEqualTo("folder-names/user_1_2024-07-09T21:00.jpg"); } } diff --git a/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java b/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java index c8a8fbc2..8fd12b54 100644 --- a/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java +++ b/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import org.depromeet.spot.common.exception.media.MediaException.InvalidExtensionException; -import org.depromeet.spot.common.exception.media.MediaException.InvalidReviewMediaException; -import org.depromeet.spot.domain.media.MediaProperty; import org.depromeet.spot.ncp.mock.FakeAmazonS3Config; import org.depromeet.spot.ncp.mock.FakeTimeUsecase; import org.depromeet.spot.ncp.property.ObjectStorageProperties; @@ -34,22 +32,10 @@ void init() { } @Test - void 리뷰_속성이_아니라면_리뷰_미디어를_생성할_수_없다() { + void 이미지_확장자가_아니라면_리뷰_미디어를_생성할_수_없다() { // given Long userId = 1L; - PresignedUrlRequest request = new PresignedUrlRequest("jpg", MediaProperty.STADIUM); - - // when - // then - assertThatThrownBy(() -> presignedUrlGenerator.forReview(userId, request)) - .isInstanceOf(InvalidReviewMediaException.class); - } - - @Test - void 리뷰_미디어_확장자가_아니라면_리뷰_미디어를_생성할_수_없다() { - // given - Long userId = 1L; - PresignedUrlRequest request = new PresignedUrlRequest("mp4", MediaProperty.REVIEW); + PresignedUrlRequest request = new PresignedUrlRequest("mp4"); // when // then diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/media/CreatePresignedUrlPort.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/media/CreatePresignedUrlPort.java index 2c7350f5..b5bca996 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/media/CreatePresignedUrlPort.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/media/CreatePresignedUrlPort.java @@ -7,8 +7,7 @@ public interface CreatePresignedUrlPort { - // FIXME: 유저 도메인 생성 후 userId -> Member 등으로 교체 - String forReview(Long userId, PresignedUrlRequest request); + String forImage(Long userId, PresignedUrlRequest request); @Getter @AllArgsConstructor From d1b94e77edacebff7eb295ea5c9e93bae4c3b852 Mon Sep 17 00:00:00 2001 From: EunjiShin Date: Thu, 18 Jul 2024 21:43:55 +0900 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jpa/src/main/resources/application-jpa.yaml | 2 +- .../spot/ncp/objectstorage/PresignedUrlGeneratorTest.java | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/infrastructure/jpa/src/main/resources/application-jpa.yaml b/infrastructure/jpa/src/main/resources/application-jpa.yaml index a4939dbd..34963243 100644 --- a/infrastructure/jpa/src/main/resources/application-jpa.yaml +++ b/infrastructure/jpa/src/main/resources/application-jpa.yaml @@ -9,7 +9,7 @@ spring: database: mysql database-platform: org.hibernate.dialect.MySQL8Dialect hibernate: - ddl-auto: update # 주의: 프로덕션 환경에서는 'validate' 사용 권장 + ddl-auto: none # 주의: 프로덕션 환경에서는 'validate' 사용 권장 properties: hibernate: use_sql_comments: true diff --git a/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java b/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java index 8fd12b54..42ea28a9 100644 --- a/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java +++ b/infrastructure/ncp/src/test/java/org/depromeet/spot/ncp/objectstorage/PresignedUrlGeneratorTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import org.depromeet.spot.common.exception.media.MediaException.InvalidExtensionException; +import org.depromeet.spot.domain.media.MediaProperty; import org.depromeet.spot.ncp.mock.FakeAmazonS3Config; import org.depromeet.spot.ncp.mock.FakeTimeUsecase; import org.depromeet.spot.ncp.property.ObjectStorageProperties; @@ -32,14 +33,15 @@ void init() { } @Test - void 이미지_확장자가_아니라면_리뷰_미디어를_생성할_수_없다() { + void 이미지_확장자가_아니라면_이미지_미디어를_생성할_수_없다() { // given Long userId = 1L; - PresignedUrlRequest request = new PresignedUrlRequest("mp4"); + MediaProperty property = MediaProperty.PROFILE_IMAGE; + PresignedUrlRequest request = new PresignedUrlRequest("mp4", property); // when // then - assertThatThrownBy(() -> presignedUrlGenerator.forReview(userId, request)) + assertThatThrownBy(() -> presignedUrlGenerator.forImage(userId, request)) .isInstanceOf(InvalidExtensionException.class); } } From ad943004fc1c0b06eb8921ecf490adf80efbd791 Mon Sep 17 00:00:00 2001 From: EunjiShin Date: Thu, 18 Jul 2024 21:57:19 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=EB=A9=A4=EB=B2=84=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/UpdateMemberController.java | 40 +++++++++++++++++++ .../dto/request/UpdateProfileRequest.java | 14 +++++++ .../dto/response/MemberProfileResponse.java | 10 +++++ .../port/in/member/UpdateMemberUsecase.java | 13 ++++++ .../service/member/UpdateMemberService.java | 24 +++++++++++ 5 files changed, 101 insertions(+) create mode 100644 application/src/main/java/org/depromeet/spot/application/member/controller/UpdateMemberController.java create mode 100644 application/src/main/java/org/depromeet/spot/application/member/dto/request/UpdateProfileRequest.java create mode 100644 application/src/main/java/org/depromeet/spot/application/member/dto/response/MemberProfileResponse.java create mode 100644 usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/UpdateMemberUsecase.java create mode 100644 usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java diff --git a/application/src/main/java/org/depromeet/spot/application/member/controller/UpdateMemberController.java b/application/src/main/java/org/depromeet/spot/application/member/controller/UpdateMemberController.java new file mode 100644 index 00000000..31c1b2bd --- /dev/null +++ b/application/src/main/java/org/depromeet/spot/application/member/controller/UpdateMemberController.java @@ -0,0 +1,40 @@ +package org.depromeet.spot.application.member.controller; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +import org.depromeet.spot.application.member.dto.request.UpdateProfileRequest; +import org.depromeet.spot.application.member.dto.response.MemberProfileResponse; +import org.depromeet.spot.domain.member.Member; +import org.depromeet.spot.usecase.port.in.member.UpdateMemberUsecase; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; + +@RestController +@Tag(name = "멤버") +@RequiredArgsConstructor +@RequestMapping("/api/v1/members") +public class UpdateMemberController { + + private final UpdateMemberUsecase updateMemberUsecase; + + @PutMapping("/{memberId}") + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "Member 프로필 수정 API") + public MemberProfileResponse updateProfile( + @PathVariable @NotNull @Positive final Long memberId, + @RequestBody @Valid @NotNull UpdateProfileRequest request) { + Member member = updateMemberUsecase.updateProfile(memberId, request.toCommand()); + return MemberProfileResponse.from(member); + } +} diff --git a/application/src/main/java/org/depromeet/spot/application/member/dto/request/UpdateProfileRequest.java b/application/src/main/java/org/depromeet/spot/application/member/dto/request/UpdateProfileRequest.java new file mode 100644 index 00000000..6fb04be5 --- /dev/null +++ b/application/src/main/java/org/depromeet/spot/application/member/dto/request/UpdateProfileRequest.java @@ -0,0 +1,14 @@ +package org.depromeet.spot.application.member.dto.request; + +import org.depromeet.spot.usecase.port.in.member.UpdateMemberUsecase.UpdateProfileCommand; + +public record UpdateProfileRequest(String profileImage, String nickname, Long teamId) { + + public UpdateProfileCommand toCommand() { + return UpdateProfileCommand.builder() + .nickname(nickname) + .profileImage(profileImage) + .teamId(teamId) + .build(); + } +} diff --git a/application/src/main/java/org/depromeet/spot/application/member/dto/response/MemberProfileResponse.java b/application/src/main/java/org/depromeet/spot/application/member/dto/response/MemberProfileResponse.java new file mode 100644 index 00000000..ded286bf --- /dev/null +++ b/application/src/main/java/org/depromeet/spot/application/member/dto/response/MemberProfileResponse.java @@ -0,0 +1,10 @@ +package org.depromeet.spot.application.member.dto.response; + +import org.depromeet.spot.domain.member.Member; + +public record MemberProfileResponse(Long id, String nickname, Long teamId) { + + public static MemberProfileResponse from(Member member) { + return new MemberProfileResponse(member.getId(), member.getNickname(), member.getTeamId()); + } +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/UpdateMemberUsecase.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/UpdateMemberUsecase.java new file mode 100644 index 00000000..4f3b8309 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/UpdateMemberUsecase.java @@ -0,0 +1,13 @@ +package org.depromeet.spot.usecase.port.in.member; + +import org.depromeet.spot.domain.member.Member; + +import lombok.Builder; + +public interface UpdateMemberUsecase { + + Member updateProfile(Long memberId, UpdateProfileCommand command); + + @Builder + record UpdateProfileCommand(String profileImage, String nickname, Long teamId) {} +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java new file mode 100644 index 00000000..cb65d6b2 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java @@ -0,0 +1,24 @@ +package org.depromeet.spot.usecase.service.member; + +import org.depromeet.spot.domain.member.Member; +import org.depromeet.spot.usecase.port.in.member.UpdateMemberUsecase; +import org.depromeet.spot.usecase.port.out.MemberRepository; +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class UpdateMemberService implements UpdateMemberUsecase { + + private final MemberRepository memberRepository; + + @Override + public Member updateProfile(final Long memberId, UpdateProfileCommand command) { + return null; + } + + // FIXME: member 패키지 동시 작업 중이라, 충돌 방지를 위해 findById를 여기에 생성했어요 + // FIXME: 작업 병합 후 ReadUsecase로 이관 필요 + private Member findById(final Long memberId) {} +} From ea4949f4501a82a1d6837e2a698d62ee3f17dda5 Mon Sep 17 00:00:00 2001 From: EunjiShin Date: Thu, 18 Jul 2024 22:09:17 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20member=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../depromeet/spot/domain/member/Member.java | 45 ++++++++----------- .../repository/MemberRepositoryImpl.java | 8 ++++ .../port/in/member/ReadMemberUsecase.java | 8 ++++ .../port/out/member/MemberRepository.java | 2 + .../service/member/ReadMemberService.java | 20 +++++++++ .../service/member/UpdateMemberService.java | 20 ++++++--- 6 files changed, 70 insertions(+), 33 deletions(-) create mode 100644 usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/ReadMemberUsecase.java create mode 100644 usecase/src/main/java/org/depromeet/spot/usecase/service/member/ReadMemberService.java diff --git a/domain/src/main/java/org/depromeet/spot/domain/member/Member.java b/domain/src/main/java/org/depromeet/spot/domain/member/Member.java index d7a83b43..52e5e8ef 100644 --- a/domain/src/main/java/org/depromeet/spot/domain/member/Member.java +++ b/domain/src/main/java/org/depromeet/spot/domain/member/Member.java @@ -5,11 +5,13 @@ import org.depromeet.spot.domain.member.enums.MemberRole; import org.depromeet.spot.domain.member.enums.SnsProvider; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @Getter @Builder +@AllArgsConstructor public class Member { private final Long id; @@ -26,32 +28,21 @@ public class Member { private final LocalDateTime createdAt; private final LocalDateTime deletedAt; - public Member( - Long id, - String email, - String name, - String nickname, - String phoneNumber, - Integer level, - String profileImage, - SnsProvider snsProvider, - String idToken, - Long teamId, - MemberRole role, - LocalDateTime createdAt, - LocalDateTime deletedAt) { - this.id = id; - this.email = email; - this.name = name; - this.nickname = nickname; - this.phoneNumber = phoneNumber; - this.level = level; - this.profileImage = profileImage; - this.snsProvider = snsProvider; - this.idToken = idToken; - this.teamId = teamId; - this.role = role; - this.createdAt = createdAt; - this.deletedAt = deletedAt; + public Member updateProfile(String newProfileImage, String newNickname, Long newTeamId) { + return Member.builder() + .id(id) + .email(email) + .name(name) + .nickname(newNickname) + .phoneNumber(phoneNumber) + .level(level) + .profileImage(newProfileImage) + .snsProvider(snsProvider) + .idToken(idToken) + .teamId(newTeamId) + .role(role) + .createdAt(createdAt) + .deletedAt(deletedAt) + .build(); } } diff --git a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java index ccbeab7f..36237978 100644 --- a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java +++ b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java @@ -2,6 +2,7 @@ import java.util.Optional; +import org.depromeet.spot.common.exception.member.MemberException.MemberNotFoundException; import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.jpa.member.entity.MemberEntity; import org.depromeet.spot.usecase.port.out.member.MemberRepository; @@ -30,4 +31,11 @@ public Optional findByIdToken(String idToken) { public Boolean existsByNickname(String nickname) { return memberJpaRepository.existsByNickname(nickname); } + + @Override + public Member findById(Long memberId) { + MemberEntity entity = + memberJpaRepository.findById(memberId).orElseThrow(MemberNotFoundException::new); + return entity.toDomain(); + } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/ReadMemberUsecase.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/ReadMemberUsecase.java new file mode 100644 index 00000000..a6efa1ad --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/ReadMemberUsecase.java @@ -0,0 +1,8 @@ +package org.depromeet.spot.usecase.port.in.member; + +import org.depromeet.spot.domain.member.Member; + +public interface ReadMemberUsecase { + + Member findById(Long memberId); +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java index 3ea7f85d..78437fb8 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java @@ -11,4 +11,6 @@ public interface MemberRepository { Optional findByIdToken(String idToken); Boolean existsByNickname(String nickname); + + Member findById(Long memberId); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/ReadMemberService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/ReadMemberService.java new file mode 100644 index 00000000..b8e47a0d --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/ReadMemberService.java @@ -0,0 +1,20 @@ +package org.depromeet.spot.usecase.service.member; + +import org.depromeet.spot.domain.member.Member; +import org.depromeet.spot.usecase.port.in.member.ReadMemberUsecase; +import org.depromeet.spot.usecase.port.out.member.MemberRepository; +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class ReadMemberService implements ReadMemberUsecase { + + private final MemberRepository memberRepository; + + @Override + public Member findById(Long memberId) { + return memberRepository.findById(memberId); + } +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java index cb65d6b2..0e1d967f 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java @@ -1,24 +1,32 @@ package org.depromeet.spot.usecase.service.member; +import java.util.Set; + import org.depromeet.spot.domain.member.Member; +import org.depromeet.spot.usecase.port.in.member.ReadMemberUsecase; import org.depromeet.spot.usecase.port.in.member.UpdateMemberUsecase; -import org.depromeet.spot.usecase.port.out.MemberRepository; +import org.depromeet.spot.usecase.port.in.team.ReadBaseballTeamUsecase; +import org.depromeet.spot.usecase.port.out.member.MemberRepository; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; @Service +@Transactional @RequiredArgsConstructor public class UpdateMemberService implements UpdateMemberUsecase { private final MemberRepository memberRepository; + private final ReadMemberUsecase readMemberUsecase; + private final ReadBaseballTeamUsecase readBaseballTeamUsecase; @Override public Member updateProfile(final Long memberId, UpdateProfileCommand command) { - return null; + Member member = readMemberUsecase.findById(memberId); + readBaseballTeamUsecase.areAllTeamIdsExist(Set.of(command.teamId())); + Member updateMember = + member.updateProfile(command.profileImage(), command.nickname(), command.teamId()); + return memberRepository.save(updateMember); } - - // FIXME: member 패키지 동시 작업 중이라, 충돌 방지를 위해 findById를 여기에 생성했어요 - // FIXME: 작업 병합 후 ReadUsecase로 이관 필요 - private Member findById(final Long memberId) {} } From 896c4190552c630de0a9fe4e2601cdd44e8b6b63 Mon Sep 17 00:00:00 2001 From: EunjiShin Date: Thu, 18 Jul 2024 22:10:18 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20ddl-auto=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infrastructure/jpa/src/main/resources/application-jpa.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/infrastructure/jpa/src/main/resources/application-jpa.yaml b/infrastructure/jpa/src/main/resources/application-jpa.yaml index 13bb895a..4650ce11 100644 --- a/infrastructure/jpa/src/main/resources/application-jpa.yaml +++ b/infrastructure/jpa/src/main/resources/application-jpa.yaml @@ -1,15 +1,15 @@ spring: datasource: - url: jdbc:mysql://localhost:3306/spot + url: jdbc:mysql://mysql:3306/spot username: test1234 - password: DPM15thspot! + password: test1234 driver-class-name: com.mysql.cj.jdbc.Driver jpa: database: mysql database-platform: org.hibernate.dialect.MySQL8Dialect hibernate: - ddl-auto: none # 주의: 프로덕션 환경에서는 'validate' 사용 권장 + ddl-auto: update # 주의: 프로덕션 환경에서는 'validate' 사용 권장 properties: hibernate: use_sql_comments: true From ac59a40a9c575e562c1e56b643366bce55a2f3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9A=B0=EB=94=94?= <38103085+EunjiShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 22:13:45 +0900 Subject: [PATCH 6/8] Delete infrastructure/jpa/src/main/resources/application-kakao.yml --- infrastructure/jpa/src/main/resources/application-kakao.yml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 infrastructure/jpa/src/main/resources/application-kakao.yml diff --git a/infrastructure/jpa/src/main/resources/application-kakao.yml b/infrastructure/jpa/src/main/resources/application-kakao.yml deleted file mode 100644 index 2454b087..00000000 --- a/infrastructure/jpa/src/main/resources/application-kakao.yml +++ /dev/null @@ -1,4 +0,0 @@ -oauth: - clientId: 1f043adfbb8f5438907686f472d3b164 - kauthTokenUrlHost: https://kauth.kakao.com - kauthUserUrlHost: https://kapi.kakao.com From 9b9a9ec78dbe3bd768127d1432a0c915a4d9b739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9A=B0=EB=94=94?= <38103085+EunjiShin@users.noreply.github.com> Date: Thu, 18 Jul 2024 22:13:58 +0900 Subject: [PATCH 7/8] Delete application/src/main/resources/application-jwt.yml --- application/src/main/resources/application-jwt.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 application/src/main/resources/application-jwt.yml diff --git a/application/src/main/resources/application-jwt.yml b/application/src/main/resources/application-jwt.yml deleted file mode 100644 index fba63b90..00000000 --- a/application/src/main/resources/application-jwt.yml +++ /dev/null @@ -1,3 +0,0 @@ -spring: - jwt: - secret: c3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4tc3BvdC1qd3QtdG9rZW4t \ No newline at end of file From 586acb3f696ca65f8eb18930aefb50357adced8e Mon Sep 17 00:00:00 2001 From: EunjiShin Date: Thu, 18 Jul 2024 22:27:20 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20updat?= =?UTF-8?q?e=20=EC=BF=BC=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/repository/MemberJpaRepository.java | 16 ++++++++++++++++ .../member/repository/MemberRepositoryImpl.java | 7 +++++++ .../port/out/member/MemberRepository.java | 2 ++ .../service/member/UpdateMemberService.java | 2 +- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberJpaRepository.java b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberJpaRepository.java index 48a2b393..2333d318 100644 --- a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberJpaRepository.java +++ b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberJpaRepository.java @@ -4,9 +4,25 @@ import org.depromeet.spot.jpa.member.entity.MemberEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface MemberJpaRepository extends JpaRepository { Optional findByIdToken(String idToken); Boolean existsByNickname(String nickname); + + @Modifying + @Query( + "update MemberEntity m set " + + "m.nickname = :nickname, " + + "m.profileImage = :profileImage, " + + "m.teamId = :teamId " + + "where m.id = :memberId") + void updateProfile( + @Param("memberId") Long memberId, + @Param("profileImage") String profileImage, + @Param("teamId") Long teamId, + @Param("nickname") String nickname); } diff --git a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java index 36237978..c70e82bd 100644 --- a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java +++ b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/MemberRepositoryImpl.java @@ -22,6 +22,13 @@ public Member save(Member member) { return memberEntity.toDomain(); } + @Override + public Member update(Member member) { + memberJpaRepository.updateProfile( + member.getId(), member.getProfileImage(), member.getTeamId(), member.getNickname()); + return member; + } + @Override public Optional findByIdToken(String idToken) { return memberJpaRepository.findByIdToken(idToken).map(MemberEntity::toDomain); diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java index 78437fb8..496f0300 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java @@ -8,6 +8,8 @@ public interface MemberRepository { Member save(Member member); + Member update(Member member); + Optional findByIdToken(String idToken); Boolean existsByNickname(String nickname); diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java index 0e1d967f..c8c22ec6 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java @@ -27,6 +27,6 @@ public Member updateProfile(final Long memberId, UpdateProfileCommand command) { readBaseballTeamUsecase.areAllTeamIdsExist(Set.of(command.teamId())); Member updateMember = member.updateProfile(command.profileImage(), command.nickname(), command.teamId()); - return memberRepository.save(updateMember); + return memberRepository.update(updateMember); } }