diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/api/AdminMemberController.java b/src/main/java/com/gdschongik/gdsc/domain/member/api/AdminMemberController.java index f1189e103..dcedf66c3 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/api/AdminMemberController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/api/AdminMemberController.java @@ -7,7 +7,9 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -23,4 +25,10 @@ public ResponseEntity> getMembers(MemberQueryRequest Page response = memberService.findAll(queryRequest, pageable); return ResponseEntity.ok().body(response); } + + @DeleteMapping("/{memberId}") + public ResponseEntity withdrawMember(@PathVariable Long memberId) { + memberService.withdrawMember(memberId); + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/application/MemberService.java b/src/main/java/com/gdschongik/gdsc/domain/member/application/MemberService.java index 208f4c6e6..2933d7d2a 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/application/MemberService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/application/MemberService.java @@ -1,9 +1,12 @@ package com.gdschongik.gdsc.domain.member.application; +import static com.gdschongik.gdsc.global.exception.ErrorCode.*; + import com.gdschongik.gdsc.domain.member.dao.MemberRepository; import com.gdschongik.gdsc.domain.member.domain.Member; import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest; import com.gdschongik.gdsc.domain.member.dto.response.MemberFindAllResponse; +import com.gdschongik.gdsc.global.exception.CustomException; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -21,4 +24,10 @@ public Page findAll(MemberQueryRequest queryRequest, Page Page members = memberRepository.findAll(queryRequest, pageable); return members.map(MemberFindAllResponse::of); } + + @Transactional + public void withdrawMember(Long memberId) { + Member member = memberRepository.findById(memberId).orElseThrow(() -> new CustomException(MEMBER_NOT_FOUND)); + member.withdraw(); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepository.java b/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepository.java index b7458d7d6..85a6a9436 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepository.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepository.java @@ -2,9 +2,12 @@ import com.gdschongik.gdsc.domain.member.domain.Member; import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface MemberCustomRepository { Page findAll(MemberQueryRequest queryRequest, Pageable pageable); + + Optional findNormalByOauthId(String oauthId); } diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepositoryImpl.java b/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepositoryImpl.java index e8ca112d0..e2e0f1844 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepositoryImpl.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberCustomRepositoryImpl.java @@ -3,12 +3,14 @@ import static com.gdschongik.gdsc.domain.member.domain.QMember.*; import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.member.domain.MemberStatus; import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -34,6 +36,22 @@ public Page findAll(MemberQueryRequest queryRequest, Pageable pageable) return PageableExecutionUtils.getPage(fetch, pageable, countQuery::fetchOne); } + @Override + public Optional findNormalByOauthId(String oauthId) { + return Optional.ofNullable(queryFactory + .selectFrom(member) + .where(eqOauthId(oauthId), eqStatus(MemberStatus.NORMAL)) + .fetchOne()); + } + + private BooleanExpression eqOauthId(String oauthId) { + return member.oauthId.eq(oauthId); + } + + private BooleanExpression eqStatus(MemberStatus status) { + return member.status.eq(status); + } + private BooleanBuilder queryOption(MemberQueryRequest queryRequest) { BooleanBuilder booleanBuilder = new BooleanBuilder(); diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberRepository.java b/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberRepository.java index 2839662a2..5fc3e0c88 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberRepository.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/dao/MemberRepository.java @@ -1,10 +1,6 @@ package com.gdschongik.gdsc.domain.member.dao; import com.gdschongik.gdsc.domain.member.domain.Member; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -public interface MemberRepository extends JpaRepository, MemberCustomRepository { - - Optional findByOauthId(String oauthId); -} +public interface MemberRepository extends JpaRepository, MemberCustomRepository {} diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java b/src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java index ce5375d50..5c41d7947 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java @@ -1,6 +1,9 @@ package com.gdschongik.gdsc.domain.member.domain; +import static com.gdschongik.gdsc.global.exception.ErrorCode.*; + import com.gdschongik.gdsc.domain.common.model.BaseTimeEntity; +import com.gdschongik.gdsc.global.exception.CustomException; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -86,4 +89,15 @@ public static Member createGuestMember(String oauthId) { .status(MemberStatus.NORMAL) .build(); } + + public void withdraw() { + if (isDeleted()) { + throw new CustomException(MEMBER_DELETED); + } + this.status = MemberStatus.DELETED; + } + + public boolean isDeleted() { + return this.status.isDeleted(); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/member/domain/MemberStatus.java b/src/main/java/com/gdschongik/gdsc/domain/member/domain/MemberStatus.java index efb05ce20..ac8cb7265 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/member/domain/MemberStatus.java +++ b/src/main/java/com/gdschongik/gdsc/domain/member/domain/MemberStatus.java @@ -11,4 +11,8 @@ public enum MemberStatus { FORBIDDEN("FORBIDDEN"); private final String value; + + public boolean isDeleted() { + return this.equals(DELETED); + } } diff --git a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java index 319412314..4bf8434d3 100644 --- a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java +++ b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java @@ -14,7 +14,11 @@ public enum ErrorCode { EXPIRED_JWT_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 JWT 토큰입니다."), // Parameter - INVALID_QUERY_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 쿼리 파라미터입니다."); + INVALID_QUERY_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 쿼리 파라미터입니다."), + + // Member + MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 회원입니다."), + MEMBER_DELETED(HttpStatus.CONFLICT, "탈퇴한 회원입니다."); private final HttpStatus status; private final String message; diff --git a/src/main/java/com/gdschongik/gdsc/global/security/CustomUserService.java b/src/main/java/com/gdschongik/gdsc/global/security/CustomUserService.java index 5b5a08d68..affb8e41b 100644 --- a/src/main/java/com/gdschongik/gdsc/global/security/CustomUserService.java +++ b/src/main/java/com/gdschongik/gdsc/global/security/CustomUserService.java @@ -23,7 +23,7 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic } private Member fetchOrCreate(OAuth2User oAuth2User) { - return memberRepository.findByOauthId(oAuth2User.getName()).orElseGet(() -> registerMember(oAuth2User)); + return memberRepository.findNormalByOauthId(oAuth2User.getName()).orElseGet(() -> registerMember(oAuth2User)); } private Member registerMember(OAuth2User oAuth2User) {