Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import kr.ac.kookmin.stream.api.app.AppApiUser;
import kr.ac.kookmin.stream.api.app.core.member.request.FcmTokenUpdateRequest;
import kr.ac.kookmin.stream.api.app.core.member.request.MemberSignUpRequest;
import kr.ac.kookmin.stream.api.app.core.member.request.PhoneNumberUpdateRequest;
import kr.ac.kookmin.stream.api.common.dto.ApiResponse;
import kr.ac.kookmin.stream.api.common.openapi.ApiErrorCode;
import kr.ac.kookmin.stream.common.CommonErrorCode;
Expand All @@ -13,7 +14,7 @@
/**
* 학생 앱 회원 API의 문서 명세. 구현은 {@link AppMemberController}가 맡는다.
*/
@Tag(name = "회원", description = "학생 앱 회원가입·FCM 토큰 등록")
@Tag(name = "회원", description = "학생 앱 회원가입·FCM 토큰 등록·전화번호 변경")
public interface AppMemberApi {

/** 회원가입. 로그인 응답의 signUpRequired가 true인 회원이 전화번호와 약관 동의 여부를 등록한다. */
Expand All @@ -38,4 +39,13 @@ public interface AppMemberApi {
@ApiErrorCode(type = CommonErrorCode.class, codes = {"INVALID_INPUT"})
@ApiErrorCode(type = MemberErrorCode.class, codes = {"MEMBER_NOT_FOUND"})
ApiResponse<Void> updateFcmToken(AppApiUser apiUser, FcmTokenUpdateRequest request);

/** 전화번호 변경. 로그인한 회원이 자기 전화번호를 바꾼다. */
@Operation(summary = "전화번호 변경",
description = """
로그인한 회원의 전화번호를 바꾼다. 전화번호는 하이픈을 넣어도 되고 빼도 된다.
지금 쓰는 번호와 같으면 바꾸지 않고 성공으로 응답한다. 다른 회원이 쓰는 번호로는 바꿀 수 없다.""")
@ApiErrorCode(type = CommonErrorCode.class, codes = {"INVALID_INPUT"})
@ApiErrorCode(type = MemberErrorCode.class, codes = {"MEMBER_NOT_FOUND", "PHONE_NUMBER_ALREADY_EXISTS"})
ApiResponse<Void> updatePhoneNumber(AppApiUser apiUser, PhoneNumberUpdateRequest request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import kr.ac.kookmin.stream.api.app.AppApiUser;
import kr.ac.kookmin.stream.api.app.core.member.request.FcmTokenUpdateRequest;
import kr.ac.kookmin.stream.api.app.core.member.request.MemberSignUpRequest;
import kr.ac.kookmin.stream.api.app.core.member.request.PhoneNumberUpdateRequest;
import kr.ac.kookmin.stream.api.common.dto.ApiResponse;
import kr.ac.kookmin.stream.member.domain.member.service.MemberService;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -39,4 +40,14 @@ public ApiResponse<Void> updateFcmToken(
memberService.updateFcmToken(apiUser.userId(), request.fcmToken());
return ApiResponse.success();
}

@Override
@PatchMapping("/me/phone-number")
public ApiResponse<Void> updatePhoneNumber(
AppApiUser apiUser,
@Valid @RequestBody PhoneNumberUpdateRequest request
) {
memberService.updatePhoneNumber(apiUser.userId(), request.toCommand());
return ApiResponse.success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kr.ac.kookmin.stream.api.app.core.member.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberPhoneNumberUpdateCommand;

public record PhoneNumberUpdateRequest(
// 가입 때 받은 번호와 형식이 달라지지 않도록 MemberSignUpRequest와 같은 규칙으로 검증한다
@NotBlank(message = "전화번호를 입력해 주세요.")
@Pattern(regexp = "^010-?\\d{4}-?\\d{4}$", message = "전화번호 형식이 올바르지 않습니다.")
String phoneNumber
) {

public MemberPhoneNumberUpdateCommand toCommand() {
return new MemberPhoneNumberUpdateCommand(phoneNumber);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ public boolean hasPhoneNumber() {
return phoneNumber != null;
}

// 회원이 바꾼 전화번호로 갱신한다. 바뀐 값이 있으면 true를 돌려준다
public boolean updatePhoneNumber(String phoneNumber) {
if (Objects.equals(this.phoneNumber, phoneNumber)) {
return false;
}
this.phoneNumber = phoneNumber;
return true;
}

// 앱이 Firebase에서 받은 등록 토큰으로 바꾼다. 바뀐 값이 있으면 true를 돌려준다
public boolean updateFcmToken(String fcmToken) {
if (Objects.equals(this.fcmToken, fcmToken)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kr.ac.kookmin.stream.member.domain.member.domain;

/**
* 전화번호 변경 요청. 전화번호는 하이픈을 지운 숫자만 담는다. 중복 검사와 저장이 같은 형식을 쓰게 하기 위함이다.
*/
public record MemberPhoneNumberUpdateCommand(String phoneNumber) {

public MemberPhoneNumberUpdateCommand {
phoneNumber = phoneNumber.replace("-", "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import java.util.Map;
import kr.ac.kookmin.stream.member.domain.member.domain.Member;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberPhoneNumberUpdateCommand;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberProfileCommand;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberSignUpCommand;

Expand All @@ -16,4 +17,5 @@ public interface MemberService {
Member signUp(Long memberId, MemberSignUpCommand command);
boolean isSignedUp(Long memberId);
void updateFcmToken(Long memberId, String fcmToken);
void updatePhoneNumber(Long memberId, MemberPhoneNumberUpdateCommand command);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import kr.ac.kookmin.stream.member.domain.member.domain.Department;
import kr.ac.kookmin.stream.member.domain.member.domain.Member;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberErrorCode;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberPhoneNumberUpdateCommand;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberProfileCommand;
import kr.ac.kookmin.stream.member.domain.member.domain.MemberSignUpCommand;
import kr.ac.kookmin.stream.member.domain.member.repository.MemberRepository;
Expand Down Expand Up @@ -95,6 +96,16 @@ public void updateFcmToken(Long memberId, String fcmToken) {
}
}

@Override
@Transactional
public void updatePhoneNumber(Long memberId, MemberPhoneNumberUpdateCommand command) {
Member member = getById(memberId);
validatePhoneNumberNotDuplicated(member, command.phoneNumber());
if (member.updatePhoneNumber(command.phoneNumber())) {
memberRepository.save(member);
}
}

// 전화번호와 필수 약관 동의가 모두 있어야 가입을 마친 것으로 본다
private boolean isSignedUp(Member member) {
return member.hasPhoneNumber() && memberTermService.hasAgreedRequiredTerms(member.getId());
Expand All @@ -106,7 +117,7 @@ private void validateNotSignedUp(Member member) {
}
}

// 필수 약관이 늘어 다시 가입하는 회원은 자기 번호를 그대로 보낼 수 있으므로 같은 번호면 중복 검사를 건너뛴다
// 필수 약관이 늘어 다시 가입하거나 같은 번호로 변경을 요청하는 회원은 자기 번호를 그대로 보낼 수 있으므로 같은 번호면 중복 검사를 건너뛴다
private void validatePhoneNumberNotDuplicated(Member member, String phoneNumber) {
if (phoneNumber.equals(member.getPhoneNumber())) {
return;
Expand Down
Loading