Skip to content

Commit

Permalink
feat: 멤버 탈퇴 api 구현 (#38)
Browse files Browse the repository at this point in the history
* feat: 멤버 탈퇴 api 구현

* feat: 멤버 탈퇴 service 구현

* feat: 멤버 관련 에러 코드 추가

* refactor: refresh 토큰 삭제 로직 추가

* feat: 쿠키 제거 로직 추가

* remove: 쿠키 제거 로직 제거

* feat: 멤버 softDelete 메서드 추가

* refactor: 어드민 멤버 삭제 softDelete로 변경

* fix: 이미 상태가 delete인 경우 예외 처리

* refactor: soft deleted 회원 로그인 시도 시 예외 처리

* refactor: 상태 확인 로직 MemberStatus로 이동

* refactor: 조건 수정

* fix: 재가입 가능하도록 수정

* remove: 사용하지 않는 메서드 제거

* fix: 에러 코드 수정

* fix: 메서드명 수정

* remove: 사용하지 않는 의존성 제거

* fix: 상태코드 수정
  • Loading branch information
Sangwook02 authored Feb 9, 2024
1 parent a2fc43b commit a223438
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -23,4 +25,10 @@ public ResponseEntity<Page<MemberFindAllResponse>> getMembers(MemberQueryRequest
Page<MemberFindAllResponse> response = memberService.findAll(queryRequest, pageable);
return ResponseEntity.ok().body(response);
}

@DeleteMapping("/{memberId}")
public ResponseEntity<Void> withdrawMember(@PathVariable Long memberId) {
memberService.withdrawMember(memberId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -21,4 +24,10 @@ public Page<MemberFindAllResponse> findAll(MemberQueryRequest queryRequest, Page
Page<Member> 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Member> findAll(MemberQueryRequest queryRequest, Pageable pageable);

Optional<Member> findNormalByOauthId(String oauthId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,6 +36,22 @@ public Page<Member> findAll(MemberQueryRequest queryRequest, Pageable pageable)
return PageableExecutionUtils.getPage(fetch, pageable, countQuery::fetchOne);
}

@Override
public Optional<Member> 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();

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Member, Long>, MemberCustomRepository {

Optional<Member> findByOauthId(String oauthId);
}
public interface MemberRepository extends JpaRepository<Member, Long>, MemberCustomRepository {}
14 changes: 14 additions & 0 deletions src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ public enum MemberStatus {
FORBIDDEN("FORBIDDEN");

private final String value;

public boolean isDeleted() {
return this.equals(DELETED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit a223438

Please sign in to comment.