-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* ♻️ [STMT-193] 공통 응답 객체에 성공시 데이터가 전달되지 않는 경우에 대한 코드 추가 * ♻️ [STMT-193] 스터디 탈퇴시에 대한 성공 코드 추가 * ✨ [STMT-193] 스터디 탈퇴 기능 구현 * ✅ [STMT-193] 스터디 탈퇴 기능에 대한 테스트 코드 추가
- Loading branch information
Showing
11 changed files
with
292 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
src/main/java/com/stumeet/server/studymember/adapter/in/web/StudyMemberLeaveApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.stumeet.server.studymember.adapter.in.web; | ||
|
||
import com.stumeet.server.common.annotation.WebAdapter; | ||
import com.stumeet.server.common.auth.model.LoginMember; | ||
import com.stumeet.server.common.model.ApiResponse; | ||
import com.stumeet.server.common.response.SuccessCode; | ||
import com.stumeet.server.studymember.application.port.in.StudyMemberLeaveUseCase; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
|
||
@WebAdapter | ||
@RequestMapping("/api/v1") | ||
@RequiredArgsConstructor | ||
public class StudyMemberLeaveApi { | ||
|
||
private final StudyMemberLeaveUseCase studyMemberLeaveUseCase; | ||
|
||
@DeleteMapping("/studies/{studyId}/members/me") | ||
public ResponseEntity<ApiResponse<Void>> leave( | ||
@PathVariable Long studyId, | ||
@AuthenticationPrincipal LoginMember member | ||
) { | ||
studyMemberLeaveUseCase.leave(studyId, member.getMember().getId()); | ||
return new ResponseEntity<>(ApiResponse.success(SuccessCode.STUDY_LEAVE_SUCCESS), HttpStatus.OK); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
...tumeet/server/studymember/adapter/out/persistence/StudyMemberLeavePersistenceAdapter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.stumeet.server.studymember.adapter.out.persistence; | ||
|
||
import com.stumeet.server.common.annotation.PersistenceAdapter; | ||
import com.stumeet.server.studymember.application.port.out.StudyMemberLeavePort; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@PersistenceAdapter | ||
@RequiredArgsConstructor | ||
public class StudyMemberLeavePersistenceAdapter implements StudyMemberLeavePort { | ||
private final JpaStudyMemberRepository jpaStudyMemberRepository; | ||
|
||
@Override | ||
public void leave(Long studyId, Long memberId) { | ||
jpaStudyMemberRepository.deleteByStudyIdAndMemberId(studyId, memberId); | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...main/java/com/stumeet/server/studymember/application/port/in/StudyMemberLeaveUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.stumeet.server.studymember.application.port.in; | ||
|
||
public interface StudyMemberLeaveUseCase { | ||
void leave(Long studyId, Long memberId); | ||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/stumeet/server/studymember/application/port/out/StudyMemberLeavePort.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.stumeet.server.studymember.application.port.out; | ||
|
||
public interface StudyMemberLeavePort { | ||
void leave(Long studyId, Long memberId); | ||
} |
27 changes: 27 additions & 0 deletions
27
...main/java/com/stumeet/server/studymember/application/service/StudyMemberLeaveService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.stumeet.server.studymember.application.service; | ||
|
||
import com.stumeet.server.common.annotation.UseCase; | ||
import com.stumeet.server.study.application.port.in.StudyValidationUseCase; | ||
import com.stumeet.server.studymember.application.port.in.StudyMemberLeaveUseCase; | ||
import com.stumeet.server.studymember.application.port.in.StudyMemberValidationUseCase; | ||
import com.stumeet.server.studymember.application.port.out.StudyMemberLeavePort; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@UseCase | ||
@Transactional | ||
@RequiredArgsConstructor | ||
public class StudyMemberLeaveService implements StudyMemberLeaveUseCase { | ||
private final StudyValidationUseCase studyValidationUseCase; | ||
private final StudyMemberValidationUseCase studyMemberValidationUseCase; | ||
private final StudyMemberLeavePort studyMemberLeavePort; | ||
|
||
|
||
@Override | ||
public void leave(Long studyId, Long memberId) { | ||
studyValidationUseCase.checkById(studyId); | ||
studyMemberValidationUseCase.checkStudyJoinMember(studyId, memberId); | ||
|
||
studyMemberLeavePort.leave(studyId, memberId); | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
src/test/java/com/stumeet/server/studymember/adapter/in/web/StudyMemberLeaveApiTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package com.stumeet.server.studymember.adapter.in.web; | ||
|
||
import com.stumeet.server.common.auth.model.AuthenticationHeader; | ||
import com.stumeet.server.helper.WithMockMember; | ||
import com.stumeet.server.stub.StudyStub; | ||
import com.stumeet.server.stub.TokenStub; | ||
import com.stumeet.server.template.ApiTest; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; | ||
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; | ||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; | ||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; | ||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; | ||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; | ||
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; | ||
|
||
class StudyMemberLeaveApiTest extends ApiTest { | ||
|
||
@Nested | ||
@DisplayName("스터디 멤버 탈퇴 API") | ||
class Leave { | ||
|
||
private final String path = "/api/v1/studies/{studyId}/members/me"; | ||
|
||
@Test | ||
@WithMockMember | ||
@DisplayName("[성공] 스터디 멤버 탈퇴에 성공한다.") | ||
void successTest() throws Exception { | ||
Long studyId = StudyStub.getStudyId(); | ||
|
||
mockMvc.perform(delete(path, studyId) | ||
.header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken())) | ||
.andExpect(status().isOk()) | ||
.andDo(document("leave-study/success", | ||
preprocessRequest(prettyPrint()), | ||
preprocessResponse(prettyPrint()), | ||
requestHeaders(headerWithName(AuthenticationHeader.ACCESS_TOKEN.getName()).description("서버로부터 전달받은 액세스 토큰")), | ||
pathParameters( | ||
parameterWithName("studyId").description("스터디 ID") | ||
), | ||
responseFields( | ||
fieldWithPath("code").description("응답 코드"), | ||
fieldWithPath("message").description("응답 메시지") | ||
))); | ||
} | ||
|
||
@Test | ||
@WithMockMember | ||
@DisplayName("[실패] 스터디가 존재하지 않는 경우 스터디 멤버 탈퇴에 실패한다.") | ||
void notExistStudyTest() throws Exception { | ||
Long invalidStudyId = StudyStub.getInvalidStudyId(); | ||
|
||
mockMvc.perform(delete(path, invalidStudyId) | ||
.header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken())) | ||
.andExpect(status().isNotFound()) | ||
.andDo(document("leave-study/fail/not-exist-study", | ||
preprocessRequest(prettyPrint()), | ||
preprocessResponse(prettyPrint()), | ||
requestHeaders(headerWithName(AuthenticationHeader.ACCESS_TOKEN.getName()).description("서버로부터 전달받은 액세스 토큰")), | ||
pathParameters( | ||
parameterWithName("studyId").description("스터디 ID") | ||
), | ||
responseFields( | ||
fieldWithPath("code").description("응답 코드"), | ||
fieldWithPath("message").description("응답 메시지") | ||
))); | ||
} | ||
|
||
@Test | ||
@WithMockMember(id = 0L) | ||
@DisplayName("[실패] 스터디에 가입된 멤버가 아닌 경우 스터디 멤버 탈퇴에 실패한다.") | ||
void notStudyJoinMemberTest() throws Exception { | ||
Long studyId = StudyStub.getStudyId(); | ||
|
||
mockMvc.perform(delete(path, studyId) | ||
.header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken())) | ||
.andExpect(status().isForbidden()) | ||
.andDo(document("leave-study/fail/not-joined-member", | ||
preprocessRequest(prettyPrint()), | ||
preprocessResponse(prettyPrint()), | ||
requestHeaders(headerWithName(AuthenticationHeader.ACCESS_TOKEN.getName()).description("서버로부터 전달받은 액세스 토큰")), | ||
pathParameters( | ||
parameterWithName("studyId").description("스터디 ID") | ||
), | ||
responseFields( | ||
fieldWithPath("code").description("응답 코드"), | ||
fieldWithPath("message").description("응답 메시지") | ||
))); | ||
} | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
.../java/com/stumeet/server/studymember/application/service/StudyMemberLeaveServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.stumeet.server.studymember.application.service; | ||
|
||
import com.stumeet.server.stub.MemberStub; | ||
import com.stumeet.server.stub.StudyStub; | ||
import com.stumeet.server.study.application.port.in.StudyValidationUseCase; | ||
import com.stumeet.server.study.domain.exception.StudyNotExistsException; | ||
import com.stumeet.server.studymember.application.port.in.StudyMemberValidationUseCase; | ||
import com.stumeet.server.studymember.application.port.out.StudyMemberLeavePort; | ||
import com.stumeet.server.studymember.domain.exception.StudyMemberNotJoinedException; | ||
import com.stumeet.server.template.UnitTest; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
|
||
import static org.assertj.core.api.Assertions.assertThatCode; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.BDDMockito.then; | ||
import static org.mockito.BDDMockito.willThrow; | ||
|
||
class StudyMemberLeaveServiceTest extends UnitTest { | ||
|
||
@InjectMocks | ||
private StudyMemberLeaveService studyMemberLeaveService; | ||
|
||
@Mock | ||
private StudyValidationUseCase studyValidationUseCase; | ||
|
||
@Mock | ||
private StudyMemberValidationUseCase studyMemberValidationUseCase; | ||
|
||
@Mock | ||
private StudyMemberLeavePort studyMemberLeavePort; | ||
|
||
@Nested | ||
@DisplayName("스터디 멤버 탈퇴") | ||
class Leave { | ||
|
||
@Test | ||
@DisplayName("[성공] 스터디 멤버 탈퇴에 성공한다.") | ||
void successTest() { | ||
Long studyId = StudyStub.getStudyId(); | ||
Long memberId = MemberStub.getMemberId(); | ||
|
||
studyMemberLeaveService.leave(studyId, memberId); | ||
|
||
then(studyMemberLeavePort).should().leave(any(), any()); | ||
} | ||
|
||
@Test | ||
@DisplayName("[실패] 스터디가 존재하지 않는 경우 예외가 발생한다.") | ||
void studyNotFoundTest() { | ||
Long studyId = StudyStub.getInvalidStudyId(); | ||
Long memberId = MemberStub.getMemberId(); | ||
|
||
willThrow(StudyNotExistsException.class) | ||
.given(studyValidationUseCase).checkById(studyId); | ||
|
||
assertThatCode(() -> studyMemberLeaveService.leave(studyId, memberId)) | ||
.isInstanceOf(StudyNotExistsException.class); | ||
} | ||
|
||
@Test | ||
@DisplayName("[실패] 해당 스터디에 가입한 회원이 아닌 경우 예외가 발생한다.") | ||
void notJoinMemberTest() { | ||
Long studyId = StudyStub.getStudyId(); | ||
Long memberId = MemberStub.getMemberId(); | ||
|
||
willThrow(StudyMemberNotJoinedException.class) | ||
.given(studyMemberValidationUseCase).checkStudyJoinMember(studyId, memberId); | ||
|
||
assertThatCode(() -> studyMemberLeaveService.leave(studyId, memberId)) | ||
.isInstanceOf(StudyMemberNotJoinedException.class); | ||
} | ||
} | ||
} |