diff --git a/src/docs/asciidoc/member.adoc b/src/docs/asciidoc/member.adoc index 9d299924..f1ae2363 100644 --- a/src/docs/asciidoc/member.adoc +++ b/src/docs/asciidoc/member.adoc @@ -57,3 +57,14 @@ include::{snippets}/get-sidebar-info/http-response.adoc[] .Response Body's Fields include::{snippets}/get-sidebar-info/response-body.adoc[] + +== `PATCH`: 마이페이지 수정 + +.HTTP Request +include::{snippets}/myPage-update/http-request.adoc[] + +.HTTP Response +include::{snippets}/myPage-update/http-response.adoc[] + +.Path Parameters +include::{snippets}/myPage-update/path-parameters.adoc[] diff --git a/src/main/java/doore/member/api/MemberController.java b/src/main/java/doore/member/api/MemberController.java index 1611084f..410e8063 100644 --- a/src/main/java/doore/member/api/MemberController.java +++ b/src/main/java/doore/member/api/MemberController.java @@ -3,8 +3,10 @@ import doore.member.application.MemberCommandService; import doore.member.application.MemberQueryService; import doore.member.application.dto.response.MemberAndMyTeamsAndStudiesResponse; +import doore.member.application.dto.response.MyPageUpdateRequest; import doore.member.domain.Member; import doore.resolver.LoginMember; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; @@ -12,6 +14,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @Validated @@ -46,7 +49,15 @@ public ResponseEntity deleteMember(@LoginMember final Member member) { @GetMapping("/members/{memberId}") public ResponseEntity getSideBarInfo(@PathVariable final Long memberId, - @LoginMember final Member member) { + @LoginMember final Member member) { return ResponseEntity.ok(memberQueryService.getSideBarInfo(memberId, member.getId())); } + + @PatchMapping("/myPage/members/{memberId}") + public ResponseEntity updateMyPage(@Valid @RequestBody final MyPageUpdateRequest request, + @PathVariable final Long memberId, @LoginMember final Member member) { + memberCommandService.updateMyPage(request, memberId, member.getId()); + return ResponseEntity.noContent().build(); + } + } diff --git a/src/main/java/doore/member/application/MemberCommandService.java b/src/main/java/doore/member/application/MemberCommandService.java index 9bf4a165..3a272f08 100644 --- a/src/main/java/doore/member/application/MemberCommandService.java +++ b/src/main/java/doore/member/application/MemberCommandService.java @@ -1,9 +1,11 @@ package doore.member.application; import doore.login.application.dto.response.GoogleAccountProfileResponse; +import doore.member.application.convenience.MemberConvenience; import doore.member.application.convenience.MemberValidateAccessPermission; import doore.member.application.convenience.StudyRoleValidateAccessPermission; import doore.member.application.convenience.TeamRoleValidateAccessPermission; +import doore.member.application.dto.response.MyPageUpdateRequest; import doore.member.domain.Member; import doore.member.domain.StudyRole; import doore.member.domain.TeamRole; @@ -21,6 +23,8 @@ public class MemberCommandService { private final MemberRepository memberRepository; + private final MemberConvenience memberConvenience; + private final TeamRoleValidateAccessPermission teamRoleValidateAccessPermission; private final StudyRoleValidateAccessPermission studyRoleValidateAccessPermission; private final TeamValidateAccessPermission teamValidateAccessPermission; @@ -67,4 +71,11 @@ public void deleteMember(final Long memberId) { final Member member = memberValidateAccessPermission.getValidateExistMember(memberId); memberRepository.delete(member); } + + public void updateMyPage(final MyPageUpdateRequest request, final Long memberId, final Long tokenMemberId) { + final Member member = memberValidateAccessPermission.getValidateExistMember(memberId); + memberConvenience.checkSameMemberIdAndTokenMemberId(memberId, tokenMemberId); + member.updateMyPage(request.name()); + } + } diff --git a/src/main/java/doore/member/application/dto/response/MyPageUpdateRequest.java b/src/main/java/doore/member/application/dto/response/MyPageUpdateRequest.java new file mode 100644 index 00000000..eeae930f --- /dev/null +++ b/src/main/java/doore/member/application/dto/response/MyPageUpdateRequest.java @@ -0,0 +1,9 @@ +package doore.member.application.dto.response; + +import jakarta.validation.constraints.NotNull; + +public record MyPageUpdateRequest( + @NotNull(message = "이름을 입력해주세요.") + String name +) { +} diff --git a/src/main/java/doore/member/domain/Member.java b/src/main/java/doore/member/domain/Member.java index 8ebab57a..f5c2d38a 100644 --- a/src/main/java/doore/member/domain/Member.java +++ b/src/main/java/doore/member/domain/Member.java @@ -47,4 +47,8 @@ private Member(final Long id, final String name, final String googleId, final St this.imageUrl = imageUrl; this.isDeleted = false; } + + public void updateMyPage(String name) { + this.name = name; + } } diff --git a/src/test/java/doore/member/application/MemberCommandServiceTest.java b/src/test/java/doore/member/application/MemberCommandServiceTest.java index 3d98de2c..def3cc09 100644 --- a/src/test/java/doore/member/application/MemberCommandServiceTest.java +++ b/src/test/java/doore/member/application/MemberCommandServiceTest.java @@ -14,6 +14,7 @@ import doore.helper.IntegrationTest; import doore.login.application.dto.response.GoogleAccountProfileResponse; +import doore.member.application.dto.response.MyPageUpdateRequest; import doore.member.domain.Member; import doore.member.domain.StudyRole; import doore.member.domain.TeamRole; @@ -229,4 +230,28 @@ void init() { memberCommandService.transferStudyLeader(study.getId(), member.getId(), notStudyLeaderMember.getId()); }); } + + @Test + @DisplayName("[성공] 정상적으로 마이페이지 정보를 수정할 수 있다.") + void updateMyPage_정상적으로_마이페이지_정보를_수정할_수_있다_성공() { + final MyPageUpdateRequest request = new MyPageUpdateRequest("수정된 이름"); + final Member beforeMemberInfo = memberRepository.findById(member.getId()).orElseThrow(); + assertThat(beforeMemberInfo.getName()).isEqualTo("아마란스"); + + memberCommandService.updateMyPage(request, member.getId(), member.getId()); + final Member afterMemberInfo = memberRepository.findById(member.getId()).orElseThrow(); + + assertThat(afterMemberInfo.getName()).isEqualTo(request.name()); + } + + @Test + @DisplayName("[실패] 본인이 아니라면 마이페이지 정보를 수정할 수 없다.") + void updateMyPage_본인이_아니라면_마이페이지_정보를_수정할_수_없다_실패() { + final MyPageUpdateRequest request = new MyPageUpdateRequest("수정된 이름"); + final Member otherMember = memberRepository.save(미나()); + + assertThatThrownBy(() -> { + memberCommandService.updateMyPage(request, member.getId(), otherMember.getId()); + }).isInstanceOf(MemberException.class).hasMessage(UNAUTHORIZED.errorMessage()); + } } diff --git a/src/test/java/doore/restdocs/docs/MemberApiDocsTest.java b/src/test/java/doore/restdocs/docs/MemberApiDocsTest.java index fb472005..82e1828a 100644 --- a/src/test/java/doore/restdocs/docs/MemberApiDocsTest.java +++ b/src/test/java/doore/restdocs/docs/MemberApiDocsTest.java @@ -5,12 +5,14 @@ import static org.mockito.Mockito.when; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import doore.member.application.dto.response.MemberAndMyTeamsAndStudiesResponse; +import doore.member.application.dto.response.MyPageUpdateRequest; import doore.restdocs.RestDocsTest; import doore.study.application.dto.response.StudyNameResponse; import doore.team.application.dto.response.MyTeamsAndStudiesResponse; @@ -107,4 +109,23 @@ void setUp() { .andExpect(status().isOk()) .andDo(document("get-sidebar-info", pathParameters, responseFieldsSnippet)); } + + @Test + @DisplayName("[성공] 마이페이지를 수정한다.") + public void updateMyPage_마이페이지를_수정한다_성공() throws Exception { + final MyPageUpdateRequest request = new MyPageUpdateRequest("수정된 이름"); + + mockMvc.perform(RestDocumentationRequestBuilders.patch("/myPage/members/{memberId}", 1) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isNoContent()) + .andDo(document("myPage-update", + pathParameters( + parameterWithName("memberId").description("멤버 id") + ), + requestFields( + stringFieldWithPath("name", "수정할 이름") + ) + )); + } }