diff --git a/src/main/java/com/umc/naoman/domain/member/controller/MemberController.java b/src/main/java/com/umc/naoman/domain/member/controller/MemberController.java index 4dbf64b..9edf3c0 100644 --- a/src/main/java/com/umc/naoman/domain/member/controller/MemberController.java +++ b/src/main/java/com/umc/naoman/domain/member/controller/MemberController.java @@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.DeleteMapping; import static com.umc.naoman.global.result.code.MemberResultCode.*; @@ -77,4 +78,18 @@ public ResultResponse getMarketingAgreed(@PathVa public ResultResponse hasSamplePhoto(@LoginMember Member member) { return ResultResponse.of(CHECK_HAS_SAMPLE_PHOTO, memberService.hasSamplePhoto(member)); } + + @DeleteMapping + @Operation(summary = "회원 탈퇴 API", description = "[request]\n" + + "[response]\n 탈퇴 memberId, 탈퇴 시간") + @ApiResponses({ + @ApiResponse(responseCode = "SM007", description = "회원 탈퇴 성공."), + @ApiResponse(responseCode = "EM001", description = "해당 memberId를 가진 회원이 존재하지 않습니다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + }) + public ResultResponse deleteMember(@LoginMember Member member){ + Member deleteMember = memberService.deleteMember(member); + return ResultResponse.of(MemberResultCode.DELETE_MEMBER, memberConverter.toDeleteMemberInfo(deleteMember)); + } + } diff --git a/src/main/java/com/umc/naoman/domain/member/converter/MemberConverter.java b/src/main/java/com/umc/naoman/domain/member/converter/MemberConverter.java index e1fece0..6fe6acc 100644 --- a/src/main/java/com/umc/naoman/domain/member/converter/MemberConverter.java +++ b/src/main/java/com/umc/naoman/domain/member/converter/MemberConverter.java @@ -7,6 +7,7 @@ import com.umc.naoman.domain.member.dto.MemberResponse.MarketingAgreed; import com.umc.naoman.domain.member.dto.MemberResponse.MemberId; import com.umc.naoman.domain.member.dto.MemberResponse.MemberInfo; +import com.umc.naoman.domain.member.dto.MemberResponse; import com.umc.naoman.domain.member.entity.Member; import com.umc.naoman.domain.member.entity.SocialType; import io.jsonwebtoken.Claims; @@ -71,4 +72,10 @@ public MarketingAgreed toMarketingAgreed(Member member) { .build(); } + public MemberResponse.DeleteMemberInfo toDeleteMemberInfo(Member member) { + return MemberResponse.DeleteMemberInfo.builder() + .memberId(member.getId()) + .deletedAt(member.getDeletedAt()) + .build(); + } } diff --git a/src/main/java/com/umc/naoman/domain/member/dto/MemberResponse.java b/src/main/java/com/umc/naoman/domain/member/dto/MemberResponse.java index 1bd72b8..c32782f 100644 --- a/src/main/java/com/umc/naoman/domain/member/dto/MemberResponse.java +++ b/src/main/java/com/umc/naoman/domain/member/dto/MemberResponse.java @@ -1,9 +1,12 @@ package com.umc.naoman.domain.member.dto; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import java.time.LocalDateTime; + public abstract class MemberResponse { @Getter @AllArgsConstructor @@ -43,6 +46,15 @@ public static class MarketingAgreed { private Boolean marketingAgreed; } + @Builder + @Getter + @AllArgsConstructor + public static class DeleteMemberInfo { + private Long memberId; + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDateTime deletedAt; + } + @Getter @AllArgsConstructor public static class HasSamplePhoto { diff --git a/src/main/java/com/umc/naoman/domain/member/service/MemberService.java b/src/main/java/com/umc/naoman/domain/member/service/MemberService.java index 6526b89..fef068e 100644 --- a/src/main/java/com/umc/naoman/domain/member/service/MemberService.java +++ b/src/main/java/com/umc/naoman/domain/member/service/MemberService.java @@ -21,5 +21,5 @@ public interface MemberService { MemberId getMyMemberId(Member member); Member findMember(Long memberId); Member findMember(SocialType socialType, String authId); - + Member deleteMember(Member member); } diff --git a/src/main/java/com/umc/naoman/domain/member/service/MemberServiceImpl.java b/src/main/java/com/umc/naoman/domain/member/service/MemberServiceImpl.java index 3f40c18..68e1e8b 100644 --- a/src/main/java/com/umc/naoman/domain/member/service/MemberServiceImpl.java +++ b/src/main/java/com/umc/naoman/domain/member/service/MemberServiceImpl.java @@ -14,6 +14,9 @@ import com.umc.naoman.domain.member.repository.MemberRepository; import com.umc.naoman.domain.member.service.redis.RefreshTokenService; import com.umc.naoman.domain.photo.service.PhotoService; +import com.umc.naoman.domain.shareGroup.entity.Profile; +import com.umc.naoman.domain.shareGroup.entity.Role; +import com.umc.naoman.domain.shareGroup.service.ShareGroupService; import com.umc.naoman.global.error.BusinessException; import com.umc.naoman.global.security.util.JwtUtils; import io.jsonwebtoken.Claims; @@ -22,6 +25,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + import static com.umc.naoman.global.error.code.MemberErrorCode.*; @Service @@ -32,6 +37,8 @@ public class MemberServiceImpl implements MemberService { private final PhotoService photoService; private final MemberRepository memberRepository; private final MemberConverter memberConverter; + private final ShareGroupService shareGroupService; + private final JwtUtils jwtUtils; @Value("${jwt.access-token-validity-in-seconds}") private Long ACCESS_TOKEN_VALIDITY_IN_SECONDS; @@ -71,7 +78,6 @@ public LoginInfo login(LoginRequest request) { Member member = findMember(request.getSocialType(), request.getAuthId()); Long memberId = member.getId(); String role = "ROLE_DEFAULT"; - return createJwtAndGetLoginInfo(memberId, role); } @@ -116,4 +122,26 @@ public Member findMember(SocialType socialType, String authId) { return memberRepository.findBySocialTypeAndAuthId(socialType, authId) .orElseThrow(() -> new BusinessException(MEMBER_NOT_FOUND_BY_AUTH_ID_AND_SOCIAL_TYPE)); } + + @Override + public Member deleteMember(Member member) { + Long memberId = member.getId(); + List profileList = shareGroupService.findProfileListByMemberId(memberId); + for (Profile profile : profileList) { + Long shareGroupId = profile.getShareGroup().getId(); + if (profile.getRole() == Role.CREATOR) { + // 특정 공유 그룹의 사진을 모두 삭제 + photoService.deletePhotoListByShareGroupId(shareGroupId); + // 공유 그룹 삭제 + profile.getShareGroup().delete(); + } else { // creator가 아닌 경우 + photoService.deletePhotoListByFaceTag(memberId); + profile.delete(); + } + } + // 회원 샘플 사진 삭제 + photoService.deleteSamplePhotoList(member); + member.delete(); + return member; + } } diff --git a/src/main/java/com/umc/naoman/global/result/code/MemberResultCode.java b/src/main/java/com/umc/naoman/global/result/code/MemberResultCode.java index 3ab97ab..9a78fc4 100644 --- a/src/main/java/com/umc/naoman/global/result/code/MemberResultCode.java +++ b/src/main/java/com/umc/naoman/global/result/code/MemberResultCode.java @@ -12,10 +12,11 @@ public enum MemberResultCode implements ResultCode { MYPAGE_INFO(200, "SM001", "내 정보를 성공적으로 조회하였습니다."), EDIT_MYPAGE_INFO(200, "SM002", "내 정보를 성공적으로 수정하였습니다."), CHECK_MEMBER_REGISTRATION(200, "SM000", "해당 정보에 대응하는 회원의 가입 여부를 성공적으로 조회하였습니다."), - MEMBER_INFO (200,"SM005","회원 정보를 성공적으로 조회하였습니다."), - CHECK_MARKETING_AGREED(200,"SM006","마케팅 동의 여부를 성공적으로 조회하였습니다."), - GET_MY_MEMBERID(200,"SM000","자신의 memberId를 성공적으로 조회하였습니다."), - CHECK_HAS_SAMPLE_PHOTO(200,"SM000","자신의 샘플 사진 업로드 여부를 성공적으로 조회하였습니다."), + MEMBER_INFO(200, "SM005", "회원 정보를 성공적으로 조회하였습니다."), + CHECK_MARKETING_AGREED(200, "SM006", "마케팅동의여부를 성공적으로 조회하였습니다."), + DELETE_MEMBER(200, "SM007", "성공적으로 탈퇴하였습니다."), + GET_MY_MEMBERID(200, "SM000", "자신의 memberId를 성공적으로 조회하였습니다."), + CHECK_HAS_SAMPLE_PHOTO(200, "SM000", "자신의 샘플 사진 업로드 여부를 성공적으로 조회하였습니다."), ; private final int status; private final String code;