From 1836a2d864d2039077329bb7eff414e0d1726868 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:31:32 +0900 Subject: [PATCH] =?UTF-8?q?[BSVR-136]=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20presigned=20url=20API=20&=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EC=88=98=EC=A0=95=20API=20(#46)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 이미지 업로드 presigned url 컴포넌트 개선 * fix: 테스트 수정 * feat: 멤버 프로필 업데이트 시그니처 추가 * feat: member 프로필 업데이트 API * feat: ddl-auto 설정 변경 * Delete infrastructure/jpa/src/main/resources/application-kakao.yml * Delete application/src/main/resources/application-jwt.yml * feat: 프로필 update 쿼리 구현 --- .../application/media/MediaController.java | 19 +++++++- .../request/CreatePresignedUrlRequest.java | 4 +- .../controller/UpdateMemberController.java | 40 +++++++++++++++++ .../dto/request/UpdateProfileRequest.java | 14 ++++++ .../dto/response/MemberProfileResponse.java | 10 +++++ .../spot/domain/media/MediaProperty.java | 1 + .../depromeet/spot/domain/member/Member.java | 45 ++++++++----------- .../repository/MemberJpaRepository.java | 16 +++++++ .../repository/MemberRepositoryImpl.java | 15 +++++++ .../src/main/resources/application-jpa.yaml | 4 +- .../ncp/objectstorage/FileNameGenerator.java | 25 ++--------- .../objectstorage/PresignedUrlGenerator.java | 15 ++----- .../objectstorage/FileNameGeneratorTest.java | 23 ++-------- .../PresignedUrlGeneratorTest.java | 20 ++------- .../port/in/member/ReadMemberUsecase.java | 8 ++++ .../port/in/member/UpdateMemberUsecase.java | 13 ++++++ .../out/media/CreatePresignedUrlPort.java | 3 +- .../port/out/member/MemberRepository.java | 4 ++ .../service/member/ReadMemberService.java | 20 +++++++++ .../service/member/UpdateMemberService.java | 32 +++++++++++++ 20 files changed, 228 insertions(+), 103 deletions(-) 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/ReadMemberUsecase.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/ReadMemberService.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/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/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/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/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/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 ccbeab7f..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 @@ -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; @@ -21,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); @@ -30,4 +38,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/infrastructure/jpa/src/main/resources/application-jpa.yaml b/infrastructure/jpa/src/main/resources/application-jpa.yaml index 9fd702ee..4650ce11 100644 --- a/infrastructure/jpa/src/main/resources/application-jpa.yaml +++ b/infrastructure/jpa/src/main/resources/application-jpa.yaml @@ -1,8 +1,8 @@ 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: 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..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,7 +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; @@ -34,26 +33,15 @@ void init() { } @Test - void 리뷰_속성이_아니라면_리뷰_미디어를_생성할_수_없다() { + void 이미지_확장자가_아니라면_이미지_미디어를_생성할_수_없다() { // given Long userId = 1L; - PresignedUrlRequest request = new PresignedUrlRequest("jpg", MediaProperty.STADIUM); + MediaProperty property = MediaProperty.PROFILE_IMAGE; + PresignedUrlRequest request = new PresignedUrlRequest("mp4", property); // when // then - assertThatThrownBy(() -> presignedUrlGenerator.forReview(userId, request)) - .isInstanceOf(InvalidReviewMediaException.class); - } - - @Test - void 리뷰_미디어_확장자가_아니라면_리뷰_미디어를_생성할_수_없다() { - // given - Long userId = 1L; - PresignedUrlRequest request = new PresignedUrlRequest("mp4", MediaProperty.REVIEW); - - // when - // then - assertThatThrownBy(() -> presignedUrlGenerator.forReview(userId, request)) + assertThatThrownBy(() -> presignedUrlGenerator.forImage(userId, request)) .isInstanceOf(InvalidExtensionException.class); } } 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/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/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 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..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,7 +8,11 @@ public interface MemberRepository { Member save(Member member); + Member update(Member member); + 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 new file mode 100644 index 00000000..c8c22ec6 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/UpdateMemberService.java @@ -0,0 +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.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) { + Member member = readMemberUsecase.findById(memberId); + readBaseballTeamUsecase.areAllTeamIdsExist(Set.of(command.teamId())); + Member updateMember = + member.updateProfile(command.profileImage(), command.nickname(), command.teamId()); + return memberRepository.update(updateMember); + } +}