Skip to content

Commit

Permalink
feat: 온보딩 멤버 가입 신청 (#66)
Browse files Browse the repository at this point in the history
* rename: MemberService를 AdminMemberService로 변경

* feat: 회원 가입 신청 구현

* rename: signupMember로 변경

* refactor: 재학생 인증 상태 검증 추가
  • Loading branch information
Sangwook02 authored Feb 12, 2024
1 parent 03751fa commit fb4659d
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.gdschongik.gdsc.domain.member.api;

import com.gdschongik.gdsc.domain.member.application.MemberService;
import com.gdschongik.gdsc.domain.member.application.AdminMemberService;
import com.gdschongik.gdsc.domain.member.dto.request.MemberGrantRequest;
import com.gdschongik.gdsc.domain.member.dto.request.MemberQueryRequest;
import com.gdschongik.gdsc.domain.member.dto.request.MemberUpdateRequest;
Expand Down Expand Up @@ -28,41 +28,41 @@
@RequiredArgsConstructor
public class AdminMemberController {

private final MemberService memberService;
private final AdminMemberService adminMemberService;

@Operation(summary = "전체 회원 목록 조회", description = "전체 회원 목록을 조회합니다.")
@GetMapping
public ResponseEntity<Page<MemberFindAllResponse>> getMembers(MemberQueryRequest queryRequest, Pageable pageable) {
Page<MemberFindAllResponse> response = memberService.findAll(queryRequest, pageable);
Page<MemberFindAllResponse> response = adminMemberService.findAll(queryRequest, pageable);
return ResponseEntity.ok().body(response);
}

@Operation(summary = "회원 탈퇴", description = "회원을 탈퇴시킵니다.")
@DeleteMapping("/{memberId}")
public ResponseEntity<Void> withdrawMember(@PathVariable Long memberId) {
memberService.withdrawMember(memberId);
adminMemberService.withdrawMember(memberId);
return ResponseEntity.ok().build();
}

@Operation(summary = "대기중인 회원 목록 조회", description = "대기중인 회원 목록을 조회합니다.")
@GetMapping("/pending")
public ResponseEntity<Page<MemberPendingFindAllResponse>> getPendingMembers(Pageable pageable) {
Page<MemberPendingFindAllResponse> response = memberService.findAllPendingMembers(pageable);
Page<MemberPendingFindAllResponse> response = adminMemberService.findAllPendingMembers(pageable);
return ResponseEntity.ok().body(response);
}

@Operation(summary = "회원 정보 수정", description = "회원 정보를 수정합니다.")
@PutMapping("/{memberId}")
public ResponseEntity<Void> updateMember(
@PathVariable Long memberId, @Valid @RequestBody MemberUpdateRequest request) {
memberService.updateMember(memberId, request);
adminMemberService.updateMember(memberId, request);
return ResponseEntity.ok().build();
}

@Operation(summary = "회원 승인", description = "회원의 가입을 승인합니다.")
@PutMapping("/grant")
public ResponseEntity<MemberGrantResponse> grantMember(@Valid @RequestBody MemberGrantRequest request) {
MemberGrantResponse response = memberService.grantMember(request);
MemberGrantResponse response = adminMemberService.grantMember(request);
return ResponseEntity.ok().body(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.gdschongik.gdsc.domain.member.api;

import com.gdschongik.gdsc.domain.member.application.OnboardingMemberService;
import com.gdschongik.gdsc.domain.member.dto.request.MemberSignupRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Onboarding Member", description = "회원 온보딩 API입니다.")
@RestController
@RequestMapping("/onboarding/members")
@RequiredArgsConstructor
public class OnboardingMemberController {

private final OnboardingMemberService onboardingMemberService;

@Operation(summary = "회원 가입 신청", description = "회원 가입을 신청합니다.")
@PostMapping
public ResponseEntity<Void> signupMember(@Valid @RequestBody MemberSignupRequest request) {
onboardingMemberService.signupMember(request);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
public class AdminMemberService {

private final MemberRepository memberRepository;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.gdschongik.gdsc.domain.member.application;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.member.dto.request.MemberSignupRequest;
import com.gdschongik.gdsc.global.util.MemberUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class OnboardingMemberService {

private final MemberUtil memberUtil;

@Transactional
public void signupMember(MemberSignupRequest request) {
Member currentMember = memberUtil.getCurrentMember();
currentMember.signup(
request.studentId(),
request.name(),
request.phone(),
request.department(),
request.email(),
request.discordUsername(),
request.nickname());
}
}
26 changes: 26 additions & 0 deletions src/main/java/com/gdschongik/gdsc/domain/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ public static Member createGuestMember(String oauthId) {
.build();
}

public void signup(
String studentId,
String name,
String phone,
String department,
String email,
String discordUsername,
String nickname) {
validateStatusUpdatable();
validateUnivStatus();

this.studentId = studentId;
this.name = name;
this.phone = phone;
this.department = department;
this.email = email;
this.discordUsername = discordUsername;
this.nickname = nickname;
}

public void withdraw() {
if (isDeleted()) {
throw new CustomException(MEMBER_DELETED);
Expand Down Expand Up @@ -141,6 +161,12 @@ private void validateStatusUpdatable() {
}
}

private void validateUnivStatus() {
if (this.requirement.isUnivPending()) {
throw new CustomException(UNIV_NOT_VERIFIED);
}
}

public void grant() {
this.role = MemberRole.USER;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ public static Requirement createRequirement() {
.paymentStatus(PENDING)
.build();
}

public boolean isUnivPending() {
return this.univStatus == PENDING;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.gdschongik.gdsc.domain.member.dto.request;

import static com.gdschongik.gdsc.global.common.constant.RegexConstant.*;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

public record MemberSignupRequest(
@NotBlank
@Pattern(regexp = STUDENT_ID, message = "학번은 " + STUDENT_ID + " 형식이어야 합니다.")
@Schema(description = "학번", pattern = STUDENT_ID)
String studentId,
@NotBlank @Schema(description = "이름") String name,
@NotBlank
@Pattern(regexp = PHONE, message = "전화번호는 " + PHONE + " 형식이어야 합니다.")
@Schema(description = "전화번호", pattern = PHONE)
String phone,
@NotBlank @Schema(description = "학과") String department,
@NotBlank @Email @Schema(description = "이메일") String email,
@NotBlank @Schema(description = "discord username") String discordUsername,
@NotBlank
@Pattern(regexp = NICKNAME, message = "닉네임은 " + NICKNAME + " 형식이어야 합니다.")
@Schema(description = "커뮤니티 닉네임", pattern = NICKNAME)
String nickname) {}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ public enum ErrorCode {
MEMBER_FORBIDDEN(HttpStatus.CONFLICT, "차단된 회원입니다."),

// Parameter
INVALID_QUERY_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 쿼리 파라미터입니다.");
INVALID_QUERY_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 쿼리 파라미터입니다."),

// Requirement
UNIV_NOT_VERIFIED(HttpStatus.CONFLICT, "재학생 인증이 되지 않았습니다.");

private final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MemberServiceTest {
class AdminMemberServiceTest {
@Autowired
private MemberRepository memberRepository;

@Autowired
private MemberService memberService;
private AdminMemberService adminMemberService;

@Test
void status가_DELETED라면_예외_발생() {
Expand All @@ -29,7 +29,7 @@ class MemberServiceTest {
// when & then
MemberUpdateRequest requestBody = new MemberUpdateRequest(
"A111111", "name", "010-1234-5678", "department", "[email protected]", "discordUsername", "한글");
assertThatThrownBy(() -> memberService.updateMember(member.getId(), requestBody))
assertThatThrownBy(() -> adminMemberService.updateMember(member.getId(), requestBody))
.isInstanceOf(CustomException.class)
.hasMessage(ErrorCode.MEMBER_DELETED.getMessage());
}
Expand Down

0 comments on commit fb4659d

Please sign in to comment.