Skip to content

Commit

Permalink
feat: 유저가 참여한 모임을 취소한다. (#35)
Browse files Browse the repository at this point in the history
* feat: 유저가 참여한 모임에 모임을 취소한다.

* test: 모임 참여 취소에 대한 테스트를 작성한다.

- 참여된 모임의 참여 취소를 성공한다.
- 참여하지 않은 모임에 대한 예외 케이스
- 종료된 모임에 대한 예외 케이스
  • Loading branch information
ddingmin authored Jan 7, 2024
1 parent be0aa7e commit 0f92d66
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public MeetingResponse addParticipant(@PathVariable("meetingId") Long meetingId)
return meetingService.addParticipant(meetingId, userId);
}

@DeleteMapping("/{meetingId}/participants")
@ResponseStatus(HttpStatus.OK)
public void deleteParticipant(@PathVariable("meetingId") Long meetingId) {
Long userId = securityService.getCurrentUserId();
meetingService.cancelParticipant(meetingId, userId);
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResponse handleIllegalArgumentException(IllegalArgumentException illegalArgumentException) {
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/net/teumteum/meeting/domain/Meeting.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ public void addParticipant(Long userId) {
participantUserIds.add(userId);
}

public void cancelParticipant(Long userId) {
participantUserIds.remove(userId);
}

public boolean alreadyParticipant(Long userId) {
return participantUserIds.contains(userId);
}
Expand Down Expand Up @@ -85,5 +89,4 @@ private void assertTitle() {
private void assertParticipantUserIds() {
Assert.isTrue(participantUserIds.size() + 1 <= numberOfRecruits, "최대 참여자 수에 도달한 모임에 참여할 수 없습니다." + "[최대 참여자 수] : " + numberOfRecruits + "[현재 참여자 수] : " + participantUserIds.size());
}

}
16 changes: 16 additions & 0 deletions src/main/java/net/teumteum/meeting/service/MeetingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,20 @@ public MeetingResponse addParticipant(Long meetingId, Long userId) {
existMeeting.addParticipant(userId);
return MeetingResponse.of(existMeeting);
}

@Transactional
public void cancelParticipant(Long meetingId, Long userId) {
var existMeeting = meetingRepository.findById(meetingId)
.orElseThrow(() -> new IllegalArgumentException("meetingId에 해당하는 모임을 찾을 수 없습니다. \"" + meetingId + "\""));

if (!existMeeting.isOpen()) {
throw new IllegalArgumentException("종료된 모임에서 참여를 취소할 수 없습니다.");
}

if (!existMeeting.alreadyParticipant(userId)) {
throw new IllegalArgumentException("참여하지 않은 모임입니다.");
}

existMeeting.cancelParticipant(userId);
}
}
6 changes: 6 additions & 0 deletions src/test/java/net/teumteum/integration/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,10 @@ ResponseSpec joinMeeting(String token, Long meetingId) {
.exchange();
}

ResponseSpec cancelMeeting(String token, Long meetingId) {
return webTestClient.delete()
.uri("/meetings/" + meetingId + "/participants")
.header(HttpHeaders.AUTHORIZATION, token)
.exchange();
}
}
60 changes: 60 additions & 0 deletions src/test/java/net/teumteum/integration/MeetingIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,64 @@ void Return_400_bad_request_if_exceed_max_number_of_recruits_meeting_id_received
.expectBody(ErrorResponse.class);
}
}

@Nested
@DisplayName("미팅 참여 취소 API는")
class Cancel_meeting_api {

@Test
@DisplayName("존재하는 모임의 id가 주어지면, 모임에 참여를 취소한다.")
void Cancel_meeting_if_exist_meeting_id_received() {
// given
var me = repository.saveAndGetUser();
var meeting = repository.saveAndGetOpenMeeting();

loginContext.setUserId(me.getId());
api.joinMeeting(VALID_TOKEN, meeting.getId());
// when
var result = api.cancelMeeting(VALID_TOKEN, meeting.getId());
// then
result.expectStatus().isOk();
}

@Test
@DisplayName("참여하지 않은 모임의 id가 주어지면, 400 Bad Request를 응답한다.")
void Return_400_bad_request_if_not_joined_meeting_id_received() {
// given
var me = repository.saveAndGetUser();
var meeting = repository.saveAndGetOpenMeeting();

loginContext.setUserId(me.getId());
// when
var result = api.cancelMeeting(VALID_TOKEN, meeting.getId());
// then
Assertions.assertThat(result.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.returnResult()
.getResponseBody()
)
.extracting(ErrorResponse::getMessage)
.isEqualTo("참여하지 않은 모임입니다.");
}

@Test
@DisplayName("종료된 모임의 id가 주어진다면, 400 Bad Request를 응답한다.")
void Return_400_bad_request_if_closed_meeting_id_received() {
// given
var me = repository.saveAndGetUser();
var meeting = repository.saveAndGetCloseMeeting();

loginContext.setUserId(me.getId());
// when
var result = api.cancelMeeting(VALID_TOKEN, meeting.getId());
// then
Assertions.assertThat(result.expectStatus().isBadRequest()
.expectBody(ErrorResponse.class)
.returnResult()
.getResponseBody()
)
.extracting(ErrorResponse::getMessage)
.isEqualTo("종료된 모임에서 참여를 취소할 수 없습니다.");
}
}
}

0 comments on commit 0f92d66

Please sign in to comment.