Skip to content

Commit

Permalink
feat-be: 동아리 이메일, 비밀번호 정보 수정 (#962)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Kwoun Ki Ho <[email protected]>
  • Loading branch information
github-actions[bot] and Chocochip101 authored Jan 1, 2025
1 parent 45273d9 commit 8397c42
Show file tree
Hide file tree
Showing 13 changed files with 437 additions and 6 deletions.
24 changes: 24 additions & 0 deletions backend/src/docs/asciidoc/member.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,27 @@ operation::member/signup-fail/invalid-request[snippets="http-request,request-fie
==== 실패: 인증되지 않은 이메일

operation::member/signup-fail/not-verified-email[snippets="http-request,request-fields,http-response"]

=== 사용자 이메일 변경

==== 성공

operation::member/change-email[snippets="http-request,request-cookies,path-parameters,request-fields,http-response"]

==== 실패: 인증되지 않은 사용자 이메일

operation::member/change-email-fail/not-verified-email[snippets="http-request,request-cookies,path-parameters,request-fields,http-response"]

==== 실패: 적절하지 않은 이메일 형식

operation::member/change-email-fail/invalid-email[snippets="http-request,request-cookies,path-parameters,request-fields,http-response"]

=== 사용자 비밀번호 변경

==== 성공

operation::member/change-password[snippets="http-request,request-cookies,path-parameters,request-fields,http-response"]

==== 실패: 적절하지 않은 비밀번호 형식

operation::member/change-password-fail/invalid-password[snippets="http-request,request-cookies,path-parameters,request-fields,http-response"]
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package com.cruru.member.controller;

import com.cruru.auth.annotation.RequireAuth;
import com.cruru.auth.annotation.ValidAuth;
import com.cruru.global.LoginProfile;
import com.cruru.member.controller.request.EmailChangeRequest;
import com.cruru.member.controller.request.MemberCreateRequest;
import com.cruru.member.controller.request.PasswordChangeRequest;
import com.cruru.member.domain.Member;
import com.cruru.member.facade.MemberFacade;
import jakarta.validation.Valid;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -23,4 +31,24 @@ public ResponseEntity<Void> create(@RequestBody @Valid MemberCreateRequest reque
long memberId = memberFacade.create(request);
return ResponseEntity.created(URI.create("/v1/members/" + memberId)).build();
}

@PatchMapping("/{memberId}/email")
@ValidAuth
public ResponseEntity<Void> changeEmail(
@RequireAuth(targetDomain = Member.class) @PathVariable Long memberId,
@RequestBody @Valid EmailChangeRequest request,
LoginProfile loginProfile) {
memberFacade.changeEmail(request, memberId);
return ResponseEntity.ok().build();
}

@PatchMapping("/{memberId}/password")
@ValidAuth
public ResponseEntity<Void> changePassword(
@RequireAuth(targetDomain = Member.class) @PathVariable Long memberId,
@RequestBody @Valid PasswordChangeRequest request,
LoginProfile loginProfile) {
memberFacade.changePassword(request, memberId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.cruru.member.controller.request;

import jakarta.validation.constraints.Email;

public record EmailChangeRequest(
@Email
String email
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.cruru.member.controller.request;

import jakarta.validation.constraints.NotBlank;

public record PasswordChangeRequest(
@NotBlank(message = "비밀번호를 입력해주세요.")
String password
) {

}
8 changes: 7 additions & 1 deletion backend/src/main/java/com/cruru/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.cruru.member.domain.MemberRole.CLUB_OWNER;

import com.cruru.BaseEntity;
import com.cruru.auth.util.SecureResource;
import com.cruru.member.exception.badrequest.MemberIllegalPhoneNumberException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand All @@ -22,7 +23,7 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
public class Member extends BaseEntity {
public class Member extends BaseEntity implements SecureResource {

private static final Pattern VALID_PHONE_NUMBER_PATTERN = Pattern.compile(
"^(010)\\d{3,4}\\d{4}$|^(02|0[3-6][1-5])\\d{3,4}\\d{4}$");
Expand Down Expand Up @@ -62,6 +63,11 @@ private void validatePhoneNumber(String phoneNumber) {
}
}

@Override
public boolean isAuthorizedBy(Member member) {
return member.id.equals(this.id);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@
import com.cruru.member.domain.Member;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

public interface MemberRepository extends JpaRepository<Member, Long> {

boolean existsByEmail(String email);

Optional<Member> findByEmail(String email);

@Transactional
@Modifying
@Query("UPDATE Member m SET m.email = :email WHERE m.id = :memberId")
void updateEmailById(long memberId, String email);

@Transactional
@Modifying
@Query("UPDATE Member m SET m.password = :password WHERE m.id = :memberId")
void updatePasswordById(long memberId, String password);

@Query("SELECT m FROM Member m WHERE m.id = :id")
Optional<Member> findByIdFetchingMember(Long id);
}
13 changes: 13 additions & 0 deletions backend/src/main/java/com/cruru/member/facade/MemberFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.cruru.club.service.ClubService;
import com.cruru.email.service.EmailRedisClient;
import com.cruru.member.controller.request.EmailChangeRequest;
import com.cruru.member.controller.request.MemberCreateRequest;
import com.cruru.member.controller.request.PasswordChangeRequest;
import com.cruru.member.domain.Member;
import com.cruru.member.service.MemberService;
import lombok.RequiredArgsConstructor;
Expand All @@ -25,4 +27,15 @@ public long create(MemberCreateRequest request) {
clubService.create(request.clubName(), savedMember);
return savedMember.getId();
}

@Transactional
public void changeEmail(EmailChangeRequest request, long memberId) {
emailRedisClient.verifyEmail(request.email());
memberService.updateEmail(memberId, request.email());
}

@Transactional
public void changePassword(PasswordChangeRequest request, long memberId) {
memberService.updatePassword(memberId, request.password());
}
}
18 changes: 13 additions & 5 deletions backend/src/main/java/com/cruru/member/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,14 @@ public Member create(MemberCreateRequest request) {
throw new MemberEmailDuplicatedException();
}

String encodedPassword = generateEncodedPassword(request);
String encodedPassword = encodePassword(request.password());
Member newMember = new Member(request.email(), encodedPassword, request.phone());
return memberRepository.save(newMember);
}

private String generateEncodedPassword(MemberCreateRequest request) {
String rawPassword = request.password();
validatePassword(rawPassword);
return passwordValidator.encode(rawPassword);
private String encodePassword(String password) {
validatePassword(password);
return passwordValidator.encode(password);
}

private void validatePassword(String rawPassword) {
Expand All @@ -66,4 +65,13 @@ public Member findByEmail(String email) {
public boolean existsByEmail(String email) {
return memberRepository.existsByEmail(email);
}

public void updateEmail(long memberId, String email) {
memberRepository.updateEmailById(memberId, email);
}

public void updatePassword(long memberId, String password) {
String encodedPassword = encodePassword(password);
memberRepository.updatePasswordById(memberId, encodedPassword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.cruru.member.acceptance;

import static org.mockito.Mockito.doNothing;

import com.cruru.auth.service.AuthService;
import com.cruru.club.domain.repository.ClubRepository;
import com.cruru.email.service.EmailRedisClient;
import com.cruru.member.controller.request.EmailChangeRequest;
import com.cruru.member.controller.request.PasswordChangeRequest;
import com.cruru.member.domain.Member;
import com.cruru.member.domain.repository.MemberRepository;
import com.cruru.util.AcceptanceTest;
import com.cruru.util.fixture.ClubFixture;
import com.cruru.util.fixture.MemberFixture;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;

public class MemberAcceptanceTest extends AcceptanceTest {

@MockBean
private EmailRedisClient emailRedisClient;

@Autowired
private MemberRepository memberRepository;

@Autowired
private ClubRepository clubRepository;

@Autowired
private AuthService authService;

private Member member;
private String newToken;

@BeforeEach
void setUp() {
member = memberRepository.save(MemberFixture.DOBBY);
clubRepository.save(ClubFixture.create(member));
newToken = authService.createAccessToken(member.getEmail(), member.getRole()).getToken();
}

@DisplayName("사용자는 다른 사용자의 이메일을 변경할 수 없다.")
@Test
void userCannotChangeAnotherUsersEmail() {
// given
String changeEmail = "[email protected]";
EmailChangeRequest request = new EmailChangeRequest(changeEmail);
doNothing().when(emailRedisClient).verifyEmail(request.email());

// when&then
RestAssured.given().log().all()
.contentType(ContentType.JSON)
.cookie("accessToken", newToken)
.body(request)
.when().patch("/v1/members/{memberId}/email", defaultMember.getId())
.then().log().all().statusCode(403);
}

@DisplayName("사용자는 다른 사용자의 비밀번호를 변경할 수 없다.")
@Test
void userCannotChangeAnotherUsersPassword() {
// given
String changePassword = "NewPassword123!!";
PasswordChangeRequest request = new PasswordChangeRequest(changePassword);

// when&then
RestAssured.given().log().all()
.contentType(ContentType.JSON)
.cookie("accessToken", newToken)
.body(request)
.when().patch("/v1/members/{memberId}/password", defaultMember.getId())
.then().log().all().statusCode(403);
}
}
Loading

0 comments on commit 8397c42

Please sign in to comment.