diff --git a/src/main/java/io/oduck/api/domain/member/entity/Member.java b/src/main/java/io/oduck/api/domain/member/entity/Member.java index 14eb31b1..b8ff369e 100644 --- a/src/main/java/io/oduck/api/domain/member/entity/Member.java +++ b/src/main/java/io/oduck/api/domain/member/entity/Member.java @@ -67,7 +67,8 @@ public class Member extends BaseEntity { private List attractionPoints; @Builder - public Member(Long id, Role role, LoginType loginType, AuthSocial authSocial, AuthLocal authLocal, MemberProfile memberProfile) { + public Member(Long id, Role role, LoginType loginType, AuthSocial authSocial, AuthLocal authLocal, + MemberProfile memberProfile) { this.id = id; this.role = role; this.loginType = loginType; @@ -79,26 +80,37 @@ public Member(Long id, Role role, LoginType loginType, AuthSocial authSocial, A // TODO: set 말고 다른 이름으로 변경하기 public void relateAuthSocial(AuthSocial authSocial) { this.authSocial = authSocial; - if(authSocial != null) { + if (authSocial != null) { authSocial.relateMember(this); } } public void relateAuthLocal(AuthLocal authLocal) { this.authLocal = authLocal; - if(authLocal != null) { + if (authLocal != null) { authLocal.relateMember(this); } } public void relateMemberProfile(MemberProfile memberProfile) { this.memberProfile = memberProfile; - if(memberProfile != null) { + if (memberProfile != null) { memberProfile.relateMember(this); } } public void delete() { this.deletedAt = LocalDateTime.now(); + this.memberProfile.delete(); + + if (this.authLocal != null) { + this.authLocal.delete(); + } + + if (this.authSocial != null) { + this.authSocial.delete(); + } + + this.role = Role.WITHDRAWAL; } } diff --git a/src/main/java/io/oduck/api/domain/member/entity/MemberProfile.java b/src/main/java/io/oduck/api/domain/member/entity/MemberProfile.java index d2f775f3..b970c3db 100644 --- a/src/main/java/io/oduck/api/domain/member/entity/MemberProfile.java +++ b/src/main/java/io/oduck/api/domain/member/entity/MemberProfile.java @@ -3,14 +3,13 @@ import io.oduck.api.global.audit.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToOne; +import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -71,4 +70,8 @@ public void updateName(String name) { public void updateInfo(String info) { this.info = info; } + + public void delete() { + this.deletedAt = LocalDateTime.now(); + } } diff --git a/src/main/java/io/oduck/api/domain/member/entity/Role.java b/src/main/java/io/oduck/api/domain/member/entity/Role.java index 7945f8e3..ed23e4f3 100644 --- a/src/main/java/io/oduck/api/domain/member/entity/Role.java +++ b/src/main/java/io/oduck/api/domain/member/entity/Role.java @@ -1,5 +1,5 @@ package io.oduck.api.domain.member.entity; public enum Role { - ADMIN, MEMBER, GUEST + ADMIN, MEMBER, GUEST, WITHDRAWAL } diff --git a/src/main/java/io/oduck/api/domain/member/repository/MemberRepository.java b/src/main/java/io/oduck/api/domain/member/repository/MemberRepository.java index 63dd92a0..28e99a55 100644 --- a/src/main/java/io/oduck/api/domain/member/repository/MemberRepository.java +++ b/src/main/java/io/oduck/api/domain/member/repository/MemberRepository.java @@ -1,10 +1,11 @@ package io.oduck.api.domain.member.repository; import io.oduck.api.domain.member.entity.Member; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface MemberRepository extends JpaRepository, MemberRepositoryCustom{ - + Optional findByIdAndDeletedAtIsNull(Long id); } diff --git a/src/main/java/io/oduck/api/domain/member/repository/MemberRepositoryImpl.java b/src/main/java/io/oduck/api/domain/member/repository/MemberRepositoryImpl.java index 8263ca58..0b2eeaf7 100644 --- a/src/main/java/io/oduck/api/domain/member/repository/MemberRepositoryImpl.java +++ b/src/main/java/io/oduck/api/domain/member/repository/MemberRepositoryImpl.java @@ -37,6 +37,7 @@ public Optional selectProfileByName(String name) { ) .from(memberProfile) .where(memberProfile.name.eq(name)) + .where(memberProfile.deletedAt.isNull()) .fetchOne()); } diff --git a/src/main/java/io/oduck/api/domain/member/service/MemberServiceImpl.java b/src/main/java/io/oduck/api/domain/member/service/MemberServiceImpl.java index 7fd2e75f..a1ef5772 100644 --- a/src/main/java/io/oduck/api/domain/member/service/MemberServiceImpl.java +++ b/src/main/java/io/oduck/api/domain/member/service/MemberServiceImpl.java @@ -27,7 +27,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class MemberServiceImpl implements MemberService{ +public class MemberServiceImpl implements MemberService { private final PasswordEncoder passwordEncoder; private final AuthLocalRepository authLocalRepository; private final MemberRepository memberRepository; @@ -46,18 +46,12 @@ public void signUpByLocal(CreateReq createReq) { try { String encryptedPassword = passwordEncoder.encode(createReq.getPassword()); - AuthLocal authLocal = AuthLocal.builder() - .email(createReq.getEmail()) - .password(encryptedPassword) - .build(); + AuthLocal authLocal = AuthLocal.builder().email(createReq.getEmail()) + .password(encryptedPassword).build(); - MemberProfile memberProfile = MemberProfile.builder() - .name(generateNickname()) - .build(); + MemberProfile memberProfile = MemberProfile.builder().name(generateNickname()).build(); - Member member = Member.builder() - .loginType(LoginType.LOCAL) - .build(); + Member member = Member.builder().loginType(LoginType.LOCAL).build(); member.relateAuthLocal(authLocal); member.relateMemberProfile(memberProfile); @@ -77,26 +71,19 @@ public MemberProfileRes getProfileByName(String name, Long memberId) { throw new NotFoundException("Member"); } Long reviewsCount = memberRepository.countReviewsByMemberId(memberProfile.getMemberId()); - Long bookmarksCount = memberRepository.countBookmarksByMemberId(memberProfile.getMemberId()); + Long bookmarksCount = + memberRepository.countBookmarksByMemberId(memberProfile.getMemberId()); Long likesCount = memberRepository.countLikesByMemberId(memberProfile.getMemberId()); - Activity activity = Activity.builder() - .reviews(reviewsCount) - .bookmarks(bookmarksCount) - .likes(likesCount) - .point(memberProfile.getPoint()) - .build(); + Activity activity = Activity.builder().reviews(reviewsCount).bookmarks(bookmarksCount) + .likes(likesCount).point(memberProfile.getPoint()).build(); - MemberProfileRes memberProfileRes = MemberProfileRes. builder() - .isMine(memberProfile.getMemberId().equals(memberId)) - .memberId(memberProfile.getMemberId()) - .name (memberProfile.getName()) - .description(memberProfile.getDescription()) - .thumbnail(memberProfile.getThumbnail()) - .backgroundImage (memberProfile.getBackgroundImage()) - .activity(activity) - .build(); + MemberProfileRes memberProfileRes = MemberProfileRes.builder() + .isMine(memberProfile.getMemberId().equals(memberId)) + .memberId(memberProfile.getMemberId()).name(memberProfile.getName()) + .description(memberProfile.getDescription()).thumbnail(memberProfile.getThumbnail()) + .backgroundImage(memberProfile.getBackgroundImage()).activity(activity).build(); return memberProfileRes; } @@ -116,16 +103,13 @@ public void updateProfile(PatchReq body, Long memberId) { } // Null 체크 - Optional - .ofNullable(body.getDescription()) - .ifPresent( - memberProfile::updateInfo - ); - + Optional.ofNullable(body.getDescription()).ifPresent(memberProfile::updateInfo); + memberProfileRepository.save(memberProfile); } @Override + @Transactional public void withdrawMember(Long memberId) { Member member = getMemberById(memberId); member.delete(); @@ -133,24 +117,18 @@ public void withdrawMember(Long memberId) { } private Member getMemberById(Long memberId) { - return memberRepository.findById(memberId) - .orElseThrow( - () -> new NotFoundException("Member") - ); + return memberRepository.findByIdAndDeletedAtIsNull(memberId) + .orElseThrow(() -> new NotFoundException("Member")); } private MemberProfile getProfileByMemberId(Long memberId) { return memberProfileRepository.findByMemberId(memberId) - .orElseThrow( - () -> new NotFoundException("Member") - ); + .orElseThrow(() -> new NotFoundException("Member")); } private ProfileWithoutActivity getProfileWithoutActivity(String name) { return memberRepository.selectProfileByName(name) - .orElseThrow( - () -> new NotFoundException("Member") - ); + .orElseThrow(() -> new NotFoundException("Member")); } private void checkDuplicatedName(String name) { diff --git a/src/main/java/io/oduck/api/global/security/auth/entity/AuthLocal.java b/src/main/java/io/oduck/api/global/security/auth/entity/AuthLocal.java index c9472b66..cc7e5299 100644 --- a/src/main/java/io/oduck/api/global/security/auth/entity/AuthLocal.java +++ b/src/main/java/io/oduck/api/global/security/auth/entity/AuthLocal.java @@ -4,12 +4,12 @@ import io.oduck.api.global.audit.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToOne; +import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -43,4 +43,6 @@ public AuthLocal(Member member, String email, String password) { public void relateMember(Member member) { this.member = member; } + + public void delete() { this.deletedAt = LocalDateTime.now(); } } diff --git a/src/main/java/io/oduck/api/global/security/auth/entity/AuthSocial.java b/src/main/java/io/oduck/api/global/security/auth/entity/AuthSocial.java index 11ddd86a..4fa4d330 100644 --- a/src/main/java/io/oduck/api/global/security/auth/entity/AuthSocial.java +++ b/src/main/java/io/oduck/api/global/security/auth/entity/AuthSocial.java @@ -6,12 +6,12 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToOne; +import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -50,4 +50,6 @@ public AuthSocial(Long id, Member member, String email, String socialId, SocialT public void relateMember(Member member) { this.member = member; } + + public void delete() { this.deletedAt = LocalDateTime.now(); } } diff --git a/src/main/java/io/oduck/api/global/security/auth/service/AuthService.java b/src/main/java/io/oduck/api/global/security/auth/service/AuthService.java index ff818205..2b5da816 100644 --- a/src/main/java/io/oduck/api/global/security/auth/service/AuthService.java +++ b/src/main/java/io/oduck/api/global/security/auth/service/AuthService.java @@ -42,7 +42,7 @@ public Status getStatus(AuthUser user) { .point(memberProfile.getPoint()) .build(); - if (user.getRole().equals("ADMIN")) { + if (user.getRole().equals("ADMIN") || user.getRole().equals("WITHDRAWAL")) { status = AdminStatus.builder() .status(status) .role(user.getRole()) @@ -74,7 +74,7 @@ public void login(LocalAuthDto localAuthDto) { } private String extractPasswordIfAdmin(Role role, String password) { - if (role.equals(Role.MEMBER)) return password; + if (!role.equals(Role.ADMIN)) return password; LocalTime now = LocalTime.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HHmm"); diff --git a/src/test/java/io/oduck/api/unit/member/service/MemberServiceTest.java b/src/test/java/io/oduck/api/unit/member/service/MemberServiceTest.java index adba4eb5..cc4dbec6 100644 --- a/src/test/java/io/oduck/api/unit/member/service/MemberServiceTest.java +++ b/src/test/java/io/oduck/api/unit/member/service/MemberServiceTest.java @@ -54,19 +54,17 @@ class GetProfileByName { String name = memberProfile.getName(); ProfileWithoutActivity profileWithoutActivity = ProfileWithoutActivity.builder() - .memberId(1L) - .name(name) - .description(memberProfile.getInfo()) - .thumbnail(memberProfile.getThumbnail()) - .backgroundImage(memberProfile.getBackgroundImage()) - .point(memberProfile.getPoint()) - .build(); + .memberId(1L).name(name).description(memberProfile.getInfo()) + .thumbnail(memberProfile.getThumbnail()) + .backgroundImage(memberProfile.getBackgroundImage()).point(memberProfile.getPoint()) + .build(); @DisplayName("본인 프로필 조회 성공시 오류 없이 회원 프로필 반환") @Test void getMemberByNameIfMine() { // given - given(memberRepository.selectProfileByName(anyString())).willReturn(Optional.ofNullable(profileWithoutActivity)); + given(memberRepository.selectProfileByName(anyString())) + .willReturn(Optional.ofNullable(profileWithoutActivity)); given(memberRepository.countReviewsByMemberId(anyLong())).willReturn(1L); given(memberRepository.countLikesByMemberId(anyLong())).willReturn(1L); @@ -75,16 +73,17 @@ void getMemberByNameIfMine() { // then assertDoesNotThrow(() -> memberService.getProfileByName(name, 1L)); // 오류 없이 회원 프로필 반환 - assertEquals(res.getName(), name); // 회원 프로필의 이름이 요청한 이름과 같은지 확인 + assertEquals(res.getName(), name); // 회원 프로필의 이름이 요청한 이름과 같은지 확인 assertTrue(res.getIsMine()); - assertNotNull(res.getActivity()); // 회원 프로필의 활동 정보가 null이 아닌지 확인 + assertNotNull(res.getActivity()); // 회원 프로필의 활동 정보가 null이 아닌지 확인 } @DisplayName("타 회원 프로필 조회 성공시 오류 없이 회원 프로필 반환, isMine = false") @Test void getMemberByNameIfOthers() { // given - given(memberRepository.selectProfileByName(anyString())).willReturn(Optional.ofNullable(profileWithoutActivity)); + given(memberRepository.selectProfileByName(anyString())) + .willReturn(Optional.ofNullable(profileWithoutActivity)); given(memberRepository.countReviewsByMemberId(anyLong())).willReturn(1L); given(memberRepository.countLikesByMemberId(anyLong())).willReturn(1L); @@ -93,9 +92,9 @@ void getMemberByNameIfOthers() { // then assertDoesNotThrow(() -> memberService.getProfileByName(name, 1L)); // 오류 없이 회원 프로필 반환 - assertEquals(res.getName(), name); // 회원 프로필의 이름이 요청한 이름과 같은지 확인 + assertEquals(res.getName(), name); // 회원 프로필의 이름이 요청한 이름과 같은지 확인 assertFalse(res.getIsMine()); - assertNotNull(res.getActivity()); // 회원 프로필의 활동 정보가 null이 아닌지 확인 + assertNotNull(res.getActivity()); // 회원 프로필의 활동 정보가 null이 아닌지 확인 } @DisplayName("존재하지 않는 회원 프로필 조회시 NotFoundException 발생") @@ -108,8 +107,7 @@ void getMemberByNameIfNotFound() { // when // then assertThrows(NotFoundException.class, - () -> memberService.getProfileByName(notExistName, 1L) - ); + () -> memberService.getProfileByName(notExistName, 1L)); } } @@ -122,47 +120,38 @@ void updateProfileSuccess() { // given Member member = new MemberStub().getMember(); MemberProfile memberProfile = member.getMemberProfile(); - PatchReq patchReq = PatchReq.builder() - .name("newName") - .description("newDescription") - .build(); - MemberProfile updatedMemberProfile = MemberProfile.builder() - .member(member) - .name(patchReq.getName()) - .info(patchReq.getDescription()) - .build(); + PatchReq patchReq = + PatchReq.builder().name("newName").description("newDescription").build(); + MemberProfile updatedMemberProfile = MemberProfile.builder().member(member) + .name(patchReq.getName()).info(patchReq.getDescription()).build(); - given(memberProfileRepository.findByMemberId(anyLong())).willReturn(Optional.ofNullable(memberProfile)); + given(memberProfileRepository.findByMemberId(anyLong())) + .willReturn(Optional.ofNullable(memberProfile)); given(memberProfileRepository.existsByName(anyString())).willReturn(false); // when // then assertDoesNotThrow(() -> memberService.updateProfile(patchReq, 1L)); } + @DisplayName("회원 프로필 수정시 실패. 중복 이름 존재시") @Test void updateProfileFailureWhenSameNameAsAlreadyExist() { // given Member member = new MemberStub().getMember(); MemberProfile memberProfile = member.getMemberProfile(); - PatchReq patchReq = PatchReq.builder() - .name("newName") - .description("newDescription") - .build(); - MemberProfile updatedMemberProfile = MemberProfile.builder() - .member(member) - .name(patchReq.getName()) - .info(patchReq.getDescription()) - .build(); + PatchReq patchReq = + PatchReq.builder().name("newName").description("newDescription").build(); + MemberProfile updatedMemberProfile = MemberProfile.builder().member(member) + .name(patchReq.getName()).info(patchReq.getDescription()).build(); - given(memberProfileRepository.findByMemberId(anyLong())).willReturn(Optional.ofNullable(memberProfile)); + given(memberProfileRepository.findByMemberId(anyLong())) + .willReturn(Optional.ofNullable(memberProfile)); given(memberProfileRepository.existsByName(anyString())).willReturn(true); // when // then - assertThrows(ConflictException.class, - () -> memberService.updateProfile(patchReq, 1L) - ); + assertThrows(ConflictException.class, () -> memberService.updateProfile(patchReq, 1L)); } } @@ -177,7 +166,8 @@ class DeleteMember { void deleteMemberSuccess() { // given Member member = new MemberStub().getMember(); - given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(member)); + given(memberRepository.findByIdAndDeletedAtIsNull(anyLong())) + .willReturn(Optional.ofNullable(member)); // when // then @@ -188,13 +178,12 @@ void deleteMemberSuccess() { @Test void deleteMemberFailureWhenNotExist() { // given - given(memberRepository.findById(anyLong())).willReturn(Optional.empty()); + given(memberRepository.findByIdAndDeletedAtIsNull(anyLong())) + .willReturn(Optional.empty()); // when // then - assertThrows(NotFoundException.class, - () -> memberService.withdrawMember(1L) - ); + assertThrows(NotFoundException.class, () -> memberService.withdrawMember(1L)); } } }