Skip to content

Commit

Permalink
Feature/#238 교직원 정보 수정 api 구현 (#240)
Browse files Browse the repository at this point in the history
* refactor: 비밀번호 변경 api의 위치를 command service 레이어로 이동

#238

* feat: 회원의 기본정보(이름, 전화번호)수정 API 구현 및 테스트 코드 구현

#238

* refactor: 변경 도메인이 상단에 존재하도록 request 파일 명 변경

#238
  • Loading branch information
llddang authored Jan 18, 2025
1 parent 67c8f20 commit a7aecbc
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 34 deletions.
14 changes: 13 additions & 1 deletion backend/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ include::{snippets}/faculty-find-all/http-response.adoc[]
include::{snippets}/faculty-find-all/response-fields.adoc[]


=== `PATCH`: 비밀번호 수정
=== `PATCH`: 자신의 비밀번호 수정

.HTTP Request
include::{snippets}/member-change-password/http-request.adoc[]
Expand All @@ -65,6 +65,18 @@ include::{snippets}/member-change-password/request-fields.adoc[]
.HTTP Response
include::{snippets}/member-change-password/http-response.adoc[]


=== `PATCH`: 자신의 기본 정보 수정

.HTTP Request
include::{snippets}/member-change-info/http-request.adoc[]

.Request Body
include::{snippets}/member-change-info/request-fields.adoc[]

.HTTP Response
include::{snippets}/member-change-info/http-response.adoc[]

== 학과

=== `GET`: 단과대학 목록 조회
Expand Down
16 changes: 13 additions & 3 deletions backend/src/main/java/sw_css/member/api/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sw_css.member.application.MemberCommandService;
import sw_css.member.application.MemberQueryService;
import sw_css.member.application.dto.request.ChangePasswordRequest;
import sw_css.member.application.dto.request.MemberChangePasswordRequest;
import sw_css.member.application.dto.request.MemberChangeInfoRequest;
import sw_css.member.application.dto.response.StudentMemberResponse;
import sw_css.member.domain.Member;
import sw_css.utils.annotation.MemberInterface;
Expand All @@ -24,6 +26,7 @@
@Transactional
public class MemberController {
private final MemberQueryService memberQueryService;
private final MemberCommandService memberCommandService;

@GetMapping("/{memberId}")
public ResponseEntity<StudentMemberResponse> findStudent(@PathVariable final Long memberId) {
Expand All @@ -32,8 +35,15 @@ public ResponseEntity<StudentMemberResponse> findStudent(@PathVariable final Lon

@PatchMapping("/change-password")
public ResponseEntity<Void> changeMemberPassword(@MemberInterface Member me,
@RequestBody @Valid ChangePasswordRequest request) {
memberQueryService.changePassword(me, request.oldPassword(), request.newPassword());
@RequestBody @Valid MemberChangePasswordRequest request) {
memberCommandService.changePassword(me, request.oldPassword(), request.newPassword());
return ResponseEntity.noContent().build();
}

@PatchMapping("/change-info")
public ResponseEntity<Void> changeMemberInfo(@MemberInterface Member me,
@RequestBody @Valid MemberChangeInfoRequest request){
memberCommandService.changeDefaultInfo(me, request.name(), request.phoneNumber());
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package sw_css.member.application;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sw_css.member.domain.Member;
import sw_css.member.domain.embedded.Password;
import sw_css.member.domain.repository.MemberRepository;
import sw_css.member.exception.MemberException;
import sw_css.member.exception.MemberExceptionType;

@Service
@RequiredArgsConstructor
@Transactional
public class MemberCommandService {

private final MemberRepository memberRepository;

public void changePassword(Member me, String oldPassword, String newPassword) {
if (me.isWrongPassword(oldPassword)) {
throw new MemberException(MemberExceptionType.MEMBER_WRONG_PASSWORD);
}

String encodedPassword = Password.encode(newPassword);
me.setPassword(encodedPassword);

memberRepository.save(me);
}

public void changeDefaultInfo(final Member me, final String name, final String phoneNumber) {
me.setName(name);
me.setPhoneNumber(phoneNumber);

memberRepository.save(me);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,5 @@ public StudentMemberResponse findStudentMember(final Long memberId) {
.orElseThrow(() -> new MemberException(MemberExceptionType.NOT_FOUND_STUDENT));
return StudentMemberResponse.from(student);
}

public void changePassword(Member me, String oldPassword, String newPassword) {
if (me.isWrongPassword(oldPassword)) {
throw new MemberException(MemberExceptionType.MEMBER_WRONG_PASSWORD);
}

String encodedPassword = Password.encode(newPassword);
me.setPassword(encodedPassword);

memberRepository.save(me);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sw_css.member.application.dto.request;

import jakarta.validation.constraints.Pattern;
import sw_css.member.domain.embedded.PhoneNumber;
import sw_css.member.domain.embedded.RealName;

public record MemberChangeInfoRequest(
@Pattern(regexp = RealName.NAME_REGEX, message = RealName.NAME_INVALID)
String name,
@Pattern(regexp = PhoneNumber.PHONE_NUMBER_REGEX, message = PhoneNumber.PHONE_NUMBER_INVALID)
String phoneNumber) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package sw_css.member.application.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import sw_css.member.domain.embedded.Password;

public record MemberChangePasswordRequest(
@NotBlank(message = "이전 비밀번호 값을 입력해주세요.")
String oldPassword,
@Pattern(regexp = Password.PASSWORD_REGEX, message = Password.PASSWORD_INVALID)
String newPassword) {

public static MemberChangePasswordRequest from(String oldPassword, String newPassword) {
return new MemberChangePasswordRequest(oldPassword, newPassword);
}
}
2 changes: 2 additions & 0 deletions backend/src/main/java/sw_css/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ public class Member extends BaseEntity {
@Column(nullable = false)
private String email;

@Setter(AccessLevel.PUBLIC)
@Column(nullable = false)
private String name;

@Setter(AccessLevel.PUBLIC)
@Column(nullable = false)
private String password;

@Setter(AccessLevel.PUBLIC)
@Column(nullable = false)
private String phoneNumber;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

public enum MemberExceptionType implements BaseExceptionType {
MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 회원을 찾을 수 없습니다."),
MEMBER_WRONG_PASSWORD(HttpStatus.BAD_REQUEST, "비밀번호가 잘못되었습니다."),
MEMBER_WRONG_PASSWORD(HttpStatus.BAD_REQUEST, "입력한 이전 비밀번호가 일치하지 않습니다."),
NOT_FOUND_STUDENT(HttpStatus.NOT_FOUND, "해당하는 학생이 존재하지 않습니다."),
INVALID_SEARCH_FIELD_ID(HttpStatus.BAD_REQUEST, "검색 유형이 올바르지 않습니다."),
;
Expand Down
4 changes: 4 additions & 0 deletions backend/src/test/java/sw_css/restdocs/RestDocsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import sw_css.hackathon.application.HackathonTeamVoteQueryService;
import sw_css.helper.ApiTestHelper;
import sw_css.major.application.MajorQueryService;
import sw_css.member.application.MemberCommandService;
import sw_css.member.application.MemberQueryService;
import sw_css.member.domain.repository.MemberRepository;
import sw_css.milestone.application.MilestoneHistoryCommandService;
Expand Down Expand Up @@ -68,6 +69,9 @@ public abstract class RestDocsTest extends ApiTestHelper {
@MockBean
protected MemberQueryService memberQueryService;

@MockBean
protected MemberCommandService memberCommandService;

@MockBean
protected MemberAdminQueryService memberAdminQueryService;

Expand Down
33 changes: 30 additions & 3 deletions backend/src/test/java/sw_css/restdocs/docs/MemberApiDocsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
import org.springframework.restdocs.payload.ResponseFieldsSnippet;
import org.springframework.restdocs.request.PathParametersSnippet;
import sw_css.member.api.MemberController;
import sw_css.member.application.dto.request.ChangePasswordRequest;
import sw_css.member.application.dto.request.MemberChangePasswordRequest;
import sw_css.member.application.dto.request.MemberChangeInfoRequest;
import sw_css.member.application.dto.response.StudentMemberResponse;
import sw_css.member.domain.Member;
import sw_css.restdocs.RestDocsTest;
Expand Down Expand Up @@ -77,10 +78,10 @@ public void changePassword() throws Exception {
final String newPassword = "asdf1234!";
final String token = "Bearer AccessToken";

final ChangePasswordRequest request = new ChangePasswordRequest(oldPassword, newPassword);
final MemberChangePasswordRequest request = new MemberChangePasswordRequest(oldPassword, newPassword);

// when
doNothing().when(memberQueryService).changePassword(me, oldPassword, newPassword);
doNothing().when(memberCommandService).changePassword(me, oldPassword, newPassword);

// then
mockMvc.perform(RestDocumentationRequestBuilders.patch("/members/change-password")
Expand All @@ -90,4 +91,30 @@ public void changePassword() throws Exception {
.andExpect(status().isNoContent())
.andDo(document("member-change-password", requestFields));
}

@Test
@DisplayName("[성공] 회원은 이름과 전화번호를 변경할 수 있다.")
public void changeDefaultInfo() throws Exception {
// given
final RequestFieldsSnippet requestFields = requestFields(
fieldWithPath("name").type(JsonFieldType.STRING).description("회원의 이름"),
fieldWithPath("phoneNumber").type(JsonFieldType.STRING).description("회원의 전화번호")
);

final Member me = new Member(1L, "[email protected]", "ddang", "qwer1234!", "01012341234");
final String token = "Bearer AccessToken";

final MemberChangeInfoRequest request = new MemberChangeInfoRequest("이다은", "01031315656");

// when
doNothing().when(memberCommandService).changePassword(me, request.name(), request.phoneNumber());

// then
mockMvc.perform(RestDocumentationRequestBuilders.patch("/members/change-info")
.contentType(APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
.header(HttpHeaders.AUTHORIZATION, token))
.andExpect(status().isNoContent())
.andDo(document("member-change-info", requestFields));
}
}

0 comments on commit a7aecbc

Please sign in to comment.