From 5b63fcf976efc5c418faa03df573060ee8c89e37 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:36:10 +0900 Subject: [PATCH 01/19] =?UTF-8?q?refactor(recruit-board):=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/query/RecruitBoardQueryService.java | 16 +++++++++------- .../usecase/query/RecruitBoardQueryUseCase.java | 4 +++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/somemore/recruitboard/service/query/RecruitBoardQueryService.java b/src/main/java/com/somemore/recruitboard/service/query/RecruitBoardQueryService.java index 15047157c..f2c38c53d 100644 --- a/src/main/java/com/somemore/recruitboard/service/query/RecruitBoardQueryService.java +++ b/src/main/java/com/somemore/recruitboard/service/query/RecruitBoardQueryService.java @@ -33,8 +33,15 @@ public class RecruitBoardQueryService implements RecruitBoardQueryUseCase { private final CenterQueryUseCase centerQueryUseCase; @Override - public RecruitBoardResponseDto getById(Long id) { - RecruitBoard recruitBoard = getRecruitBoard(id); + public RecruitBoard getById(Long id) { + return recruitBoardRepository.findById(id).orElseThrow( + () -> new BadRequestException(NOT_EXISTS_RECRUIT_BOARD.getMessage()) + ); + } + + @Override + public RecruitBoardResponseDto getRecruitBoardById(Long id) { + RecruitBoard recruitBoard = getById(id); return RecruitBoardResponseDto.from(recruitBoard); } @@ -75,9 +82,4 @@ public List getNotCompletedIdsByCenterIds(UUID centerId) { return recruitBoardRepository.findNotCompletedIdsByCenterId(centerId); } - private RecruitBoard getRecruitBoard(Long id) { - return recruitBoardRepository.findById(id).orElseThrow( - () -> new BadRequestException(NOT_EXISTS_RECRUIT_BOARD.getMessage()) - ); - } } diff --git a/src/main/java/com/somemore/recruitboard/usecase/query/RecruitBoardQueryUseCase.java b/src/main/java/com/somemore/recruitboard/usecase/query/RecruitBoardQueryUseCase.java index 4ce52f9b6..f0a4b5554 100644 --- a/src/main/java/com/somemore/recruitboard/usecase/query/RecruitBoardQueryUseCase.java +++ b/src/main/java/com/somemore/recruitboard/usecase/query/RecruitBoardQueryUseCase.java @@ -1,5 +1,6 @@ package com.somemore.recruitboard.usecase.query; +import com.somemore.recruitboard.domain.RecruitBoard; import com.somemore.recruitboard.dto.condition.RecruitBoardNearByCondition; import com.somemore.recruitboard.dto.condition.RecruitBoardSearchCondition; import com.somemore.recruitboard.dto.response.RecruitBoardDetailResponseDto; @@ -13,7 +14,8 @@ public interface RecruitBoardQueryUseCase { - RecruitBoardResponseDto getById(Long id); + RecruitBoard getById(Long id); + RecruitBoardResponseDto getRecruitBoardById(Long id); RecruitBoardWithLocationResponseDto getWithLocationById(Long id); From 8671add47cd00a8ea29630e51ff5195fa22c686f Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:36:22 +0900 Subject: [PATCH 02/19] =?UTF-8?q?test(recruit-board):=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/fixture/RecruitBoardFixture.java | 45 ++++++++++++++++--- .../query/RecruitBoardQueryServiceTest.java | 4 +- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java b/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java index 36fd6e65d..a375514b4 100644 --- a/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java +++ b/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java @@ -1,6 +1,7 @@ package com.somemore.common.fixture; import static com.somemore.common.fixture.LocalDateTimeFixture.createStartDateTime; +import static com.somemore.recruitboard.domain.RecruitStatus.COMPLETED; import static com.somemore.recruitboard.domain.VolunteerCategory.OTHER; import com.somemore.recruitboard.domain.RecruitBoard; @@ -216,7 +217,8 @@ public static RecruitBoard createRecruitBoard(UUID centerId, Long locationId) { .build(); } - public static RecruitBoard createRecruitBoard(String region, VolunteerCategory volunteerCategory) { + public static RecruitBoard createRecruitBoard(String region, + VolunteerCategory volunteerCategory) { RecruitmentInfo recruitmentInfo = RecruitmentInfo.builder() .region(region) @@ -258,7 +260,29 @@ public static RecruitBoard createRecruitBoard(Long locationId, String title) { .build(); } - public static RecruitBoard createCompletedRecruitBoard(UUID centerId, VolunteerCategory category) { + public static RecruitBoard createRecruitBoard(LocalDateTime start, LocalDateTime end) { + + RecruitmentInfo recruitmentInfo = RecruitmentInfo.builder() + .region(REGION) + .recruitmentCount(RECRUITMENT_COUNT) + .volunteerStartDateTime(start) + .volunteerEndDateTime(end) + .volunteerCategory(VOLUNTEER_CATEGORY) + .admitted(ADMITTED) + .build(); + + return RecruitBoard.builder() + .centerId(UUID.randomUUID()) + .locationId(LOCATION_ID) + .title(TITLE) + .content(CONTENT) + .imgUrl(IMG_URL) + .recruitmentInfo(recruitmentInfo) + .build(); + } + + public static RecruitBoard createCompletedRecruitBoard(UUID centerId, + VolunteerCategory category) { RecruitmentInfo recruitmentInfo = RecruitmentInfo.builder() .region(REGION) .recruitmentCount(RECRUITMENT_COUNT) @@ -277,29 +301,36 @@ public static RecruitBoard createCompletedRecruitBoard(UUID centerId, VolunteerC .recruitmentInfo(recruitmentInfo) .build(); - setRecruitStatusCompleted(recruitBoard); + setRecruitStatus(recruitBoard, COMPLETED); return recruitBoard; } public static RecruitBoard createCompletedRecruitBoard(VolunteerCategory category) { RecruitBoard recruitBoard = createCompletedRecruitBoard(UUID.randomUUID(), category); - setRecruitStatusCompleted(recruitBoard); + setRecruitStatus(recruitBoard, COMPLETED); return recruitBoard; } public static RecruitBoard createCompletedRecruitBoard() { RecruitBoard recruitBoard = createCompletedRecruitBoard(UUID.randomUUID(), VOLUNTEER_CATEGORY); - setRecruitStatusCompleted(recruitBoard); + setRecruitStatus(recruitBoard, COMPLETED); + return recruitBoard; + } + + public static RecruitBoard createCloseRecruitBoard() { + RecruitBoard recruitBoard = createCompletedRecruitBoard(UUID.randomUUID(), + VOLUNTEER_CATEGORY); + setRecruitStatus(recruitBoard, COMPLETED); return recruitBoard; } - private static void setRecruitStatusCompleted(RecruitBoard recruitBoard) { + private static void setRecruitStatus(RecruitBoard recruitBoard, RecruitStatus status) { try { Field recruitStatusField = RecruitBoard.class.getDeclaredField("recruitStatus"); recruitStatusField.setAccessible(true); // private 필드 접근 가능 설정 - recruitStatusField.set(recruitBoard, RecruitStatus.COMPLETED); // 필드 값 설정 + recruitStatusField.set(recruitBoard, status); // 필드 값 설정 } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException("리플렉션으로 recruitStatus를 설정하는 것에 실패했습니다", e); } diff --git a/src/test/java/com/somemore/recruitboard/service/query/RecruitBoardQueryServiceTest.java b/src/test/java/com/somemore/recruitboard/service/query/RecruitBoardQueryServiceTest.java index 89ee5d8bd..a36a44dac 100644 --- a/src/test/java/com/somemore/recruitboard/service/query/RecruitBoardQueryServiceTest.java +++ b/src/test/java/com/somemore/recruitboard/service/query/RecruitBoardQueryServiceTest.java @@ -67,7 +67,7 @@ void getByIdWithExistsId() { Long id = recruitBoard.getId(); // when - RecruitBoardResponseDto dto = recruitBoardQueryService.getById(id); + RecruitBoardResponseDto dto = recruitBoardQueryService.getRecruitBoardById(id); // then assertThat(dto.id()).isEqualTo(recruitBoard.getId()); @@ -82,7 +82,7 @@ void getByIdWithDoesNotExistId() { // when // then assertThatThrownBy( - () -> recruitBoardQueryService.getById(wrongId) + () -> recruitBoardQueryService.getRecruitBoardById(wrongId) ).isInstanceOf(BadRequestException.class) .hasMessage(NOT_EXISTS_RECRUIT_BOARD.getMessage()); } From 191a6a7ec068c812141701eb3e98d38a6d91ad2e Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:36:54 +0900 Subject: [PATCH 03/19] =?UTF-8?q?feat(recruit-board):=20=EB=AA=A8=EC=A7=91?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recruitboard/domain/RecruitBoard.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java b/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java index 3eca63285..33fceec45 100644 --- a/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java +++ b/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java @@ -57,7 +57,7 @@ public class RecruitBoard extends BaseEntity { @Builder public RecruitBoard(UUID centerId, Long locationId, String title, String content, - RecruitmentInfo recruitmentInfo, String imgUrl) { + RecruitmentInfo recruitmentInfo, String imgUrl) { this.centerId = centerId; this.locationId = locationId; this.title = title; @@ -92,13 +92,17 @@ public void changeRecruitStatus(RecruitStatus newStatus, LocalDateTime currentDa this.recruitStatus = newStatus; } + public boolean isApplicationOpen() { + return this.recruitStatus == RECRUITING; + } + private void updateRecruitmentInfo(RecruitBoardUpdateRequestDto dto) { recruitmentInfo.updateWith( - dto.recruitmentCount(), - dto.volunteerCategory(), - dto.volunteerStartDateTime(), - dto.volunteerEndDateTime(), - dto.admitted() + dto.recruitmentCount(), + dto.volunteerCategory(), + dto.volunteerStartDateTime(), + dto.volunteerEndDateTime(), + dto.admitted() ); } From 26cb27a9e9b61f8eb70808e0cc590d11e2123a63 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:37:04 +0900 Subject: [PATCH 04/19] =?UTF-8?q?test(recruit-board):=20=EB=AA=A8=EC=A7=91?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/somemore/global/exception/ExceptionMessage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/somemore/global/exception/ExceptionMessage.java b/src/main/java/com/somemore/global/exception/ExceptionMessage.java index 613c87fc7..7aa62511b 100644 --- a/src/main/java/com/somemore/global/exception/ExceptionMessage.java +++ b/src/main/java/com/somemore/global/exception/ExceptionMessage.java @@ -29,7 +29,9 @@ public enum ExceptionMessage { REVIEW_ALREADY_EXISTS("이미 작성한 리뷰가 존재합니다."), REVIEW_RESTRICTED_TO_ATTENDED("리뷰는 참석한 봉사에 한해서만 작성할 수 있습니다."), NOT_EXISTS_REVIEW("존재하지 않는 리뷰입니다."), - ; + RECRUITMENT_NOT_OPEN("현재 모집 진행 중이 아닙니다."), + DUPLICATE_APPLICATION("이미 신청한 봉사 모집 공고입니다."), + ; private final String message; } From 404c409d7853ea15675f4900e8183f0fa47783a7 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:37:09 +0900 Subject: [PATCH 05/19] =?UTF-8?q?test(recruit-board):=20=EB=AA=A8=EC=A7=91?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recruitboard/domain/RecruitBoardTest.java | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java b/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java index e6a5e822c..1718c428e 100644 --- a/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java +++ b/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java @@ -3,6 +3,8 @@ import static com.somemore.common.fixture.LocalDateTimeFixture.createCurrentDateTime; import static com.somemore.common.fixture.LocalDateTimeFixture.createStartDateTime; import static com.somemore.common.fixture.LocalDateTimeFixture.createUpdateStartDateTime; +import static com.somemore.common.fixture.RecruitBoardFixture.createCloseRecruitBoard; +import static com.somemore.common.fixture.RecruitBoardFixture.createRecruitBoard; import static com.somemore.recruitboard.domain.RecruitStatus.CLOSED; import static com.somemore.recruitboard.domain.RecruitStatus.COMPLETED; import static com.somemore.recruitboard.domain.RecruitStatus.RECRUITING; @@ -41,11 +43,10 @@ void createRecruitBoardWithDefaultStatus() { void testCalculateVolunteerTime() { // given int hours = 3; - UUID centerId = UUID.randomUUID(); LocalDateTime startDateTime = createStartDateTime(); LocalDateTime endDateTime = startDateTime.plusHours(hours); - RecruitBoard board = createRecruitBoard(centerId, startDateTime, endDateTime); + RecruitBoard board = createRecruitBoard(startDateTime, endDateTime); // when LocalTime volunteerTime = board.getVolunteerHours(); @@ -65,13 +66,13 @@ void updateRecruitBoard() { LocalDateTime endDateTime = startDateTime.plusHours(2); RecruitBoardUpdateRequestDto dto = RecruitBoardUpdateRequestDto.builder() - .title("봉사 모집글 작성 수정") - .content("봉사 하실분을 모집합니다. 수정
") - .recruitmentCount(10) - .volunteerStartDateTime(startDateTime) - .volunteerEndDateTime(endDateTime) - .volunteerCategory(OTHER) - .admitted(true).build(); + .title("봉사 모집글 작성 수정") + .content("봉사 하실분을 모집합니다. 수정
") + .recruitmentCount(10) + .volunteerStartDateTime(startDateTime) + .volunteerEndDateTime(endDateTime) + .volunteerCategory(OTHER) + .admitted(true).build(); // when board.updateWith(dto, imgUrl); @@ -169,7 +170,7 @@ void changeStatusWhenInvalidStatus() { // when & then assertThatThrownBy(() -> recruitBoard.changeRecruitStatus(COMPLETED, currentDateTime)) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(IllegalArgumentException.class); } @DisplayName("봉사 시작일 자정 이후 모집 상태를 변경할 경우 에러가 발생한다") @@ -180,44 +181,40 @@ void changeStatusWhenDeadLineAfter(Long secondsOffset) { UUID centerId = UUID.randomUUID(); RecruitBoard recruitBoard = createRecruitBoard(centerId); LocalDateTime deadLineDateTime = recruitBoard.getRecruitmentInfo() - .getVolunteerStartDateTime().toLocalDate().atStartOfDay(); + .getVolunteerStartDateTime().toLocalDate().atStartOfDay(); LocalDateTime currentDateTime = deadLineDateTime.plusSeconds(secondsOffset); // when // then assertThatThrownBy( - () -> recruitBoard.changeRecruitStatus(CLOSED, currentDateTime) + () -> recruitBoard.changeRecruitStatus(CLOSED, currentDateTime) ).isInstanceOf(IllegalStateException.class); } - private static RecruitBoard createRecruitBoard(UUID centerId) { - LocalDateTime startDateTime = createStartDateTime(); - LocalDateTime endDateTime = startDateTime.plusHours(1); + @DisplayName("모집중일 경우 지원이 가능하다") + @Test + void isApplicationOpen() { + // given + RecruitBoard board = createRecruitBoard(); - return createRecruitBoard(centerId, startDateTime, endDateTime); - } + // when + boolean result = board.isApplicationOpen(); - private static RecruitBoard createRecruitBoard(UUID centerId, LocalDateTime startDateTime, - LocalDateTime endDateTime) { - - RecruitmentInfo recruitmentInfo = RecruitmentInfo.builder() - .region("경기") - .recruitmentCount(1) - .volunteerStartDateTime(startDateTime) - .volunteerEndDateTime(endDateTime) - .volunteerCategory(OTHER) - .admitted(true) - .build(); - - return RecruitBoard.builder() - .centerId(centerId) - .locationId(1L) - .title("봉사모집제목") - .content("봉사모집내용") - .imgUrl("https://image.domain.com/links") - .recruitmentInfo(recruitmentInfo) - .build(); + // then + assertThat(result).isTrue(); } + @DisplayName("모집중이 아닐 경우 지원이 불가능하다") + @Test + void isApplicationOpenWhenNotRECRUTING() { + // given + RecruitBoard board = createCloseRecruitBoard(); + + // when + boolean result = board.isApplicationOpen(); + + // then + assertThat(result).isFalse(); + } } From 7ccf7ddaff60c80b97dc71b3e2e9d563bddbbd05 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:37:45 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EB=AA=A8=EC=A7=91=EA=B8=80=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/VolunteerApplyCreateRequestDto.java | 30 +++++++++++ .../repository/VolunteerApplyRepository.java | 5 +- .../VolunteerApplyRepositoryImpl.java | 10 ++++ .../service/VolunteerApplyCommandService.java | 54 +++++++++++++++++++ .../usecase/VolunteerApplyCommandUseCase.java | 10 ++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java create mode 100644 src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java create mode 100644 src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java diff --git a/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java b/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java new file mode 100644 index 000000000..438de410a --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java @@ -0,0 +1,30 @@ +package com.somemore.volunteerapply.dto; + +import static com.somemore.volunteerapply.domain.ApplyStatus.WAITING; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.somemore.volunteerapply.domain.VolunteerApply; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import java.util.UUID; +import lombok.Builder; + +@JsonNaming(SnakeCaseStrategy.class) +@Builder +public record VolunteerApplyCreateRequestDto( + @Schema(description = "봉사 모집글 아이디", example = "1L") + @NotBlank(message = "모집글 아이디는 필수 값입니다.") + Long recruitBoardId +) { + + public VolunteerApply toEntity(UUID volunteerId) { + return VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(recruitBoardId) + .status(WAITING) + .attended(false) + .build(); + } + +} diff --git a/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java index b79438b93..b01c29438 100644 --- a/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java +++ b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java @@ -15,9 +15,12 @@ public interface VolunteerApplyRepository { Optional findById(Long id); + Optional findByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId); + + boolean existsByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId); + List findVolunteerIdsByRecruitIds(List recruitIds); Page findAllByRecruitId(Long recruitId, Pageable pageable); - Optional findByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId); } diff --git a/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImpl.java b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImpl.java index 9e53aa1a5..91a7dacb7 100644 --- a/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImpl.java +++ b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImpl.java @@ -83,6 +83,16 @@ public Optional findByRecruitIdAndVolunteerId(Long recruitId, return findOne(exp); } + @Override + public boolean existsByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId) { + return queryFactory + .selectFrom(volunteerApply) + .where(volunteerApply.recruitBoardId.eq(recruitId) + .and(volunteerApply.volunteerId.eq(volunteerId)) + .and(isNotDeleted())) + .fetchFirst() != null; + } + private Long getCount(BooleanExpression exp) { return queryFactory .select(volunteerApply.count()) diff --git a/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java b/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java new file mode 100644 index 000000000..955a60261 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java @@ -0,0 +1,54 @@ +package com.somemore.volunteerapply.service; + +import static com.somemore.global.exception.ExceptionMessage.DUPLICATE_APPLICATION; +import static com.somemore.global.exception.ExceptionMessage.RECRUITMENT_NOT_OPEN; + +import com.somemore.global.exception.BadRequestException; +import com.somemore.recruitboard.domain.RecruitBoard; +import com.somemore.recruitboard.usecase.query.RecruitBoardQueryUseCase; +import com.somemore.volunteerapply.domain.VolunteerApply; +import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; +import com.somemore.volunteerapply.repository.VolunteerApplyRepository; +import com.somemore.volunteerapply.usecase.VolunteerApplyCommandUseCase; +import java.time.LocalDateTime; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional +@Service +public class VolunteerApplyCommandService implements VolunteerApplyCommandUseCase { + + private final VolunteerApplyRepository volunteerApplyRepository; + private final RecruitBoardQueryUseCase recruitBoardQueryUseCase; + + @Override + public Long apply(VolunteerApplyCreateRequestDto requestDto, UUID volunteerId) { + + RecruitBoard board = recruitBoardQueryUseCase.getById(requestDto.recruitBoardId()); + validateCanApply(board); + validateDuplicatedApply(volunteerId, board); + + VolunteerApply apply = requestDto.toEntity(volunteerId); + volunteerApplyRepository.save(apply); + + return apply.getId(); + } + + private void validateCanApply(RecruitBoard board) { + if (board.isApplicationOpen()) { + return; + } + throw new BadRequestException(RECRUITMENT_NOT_OPEN); + } + + private void validateDuplicatedApply(UUID volunteerId, RecruitBoard board) { + boolean isDuplicate = volunteerApplyRepository.existsByRecruitIdAndVolunteerId(board.getId(), + volunteerId); + if (isDuplicate) { + throw new BadRequestException(DUPLICATE_APPLICATION); + } + } +} diff --git a/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java b/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java new file mode 100644 index 000000000..a821c4b0d --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java @@ -0,0 +1,10 @@ +package com.somemore.volunteerapply.usecase; + +import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; +import java.util.UUID; + +public interface VolunteerApplyCommandUseCase { + + Long apply(VolunteerApplyCreateRequestDto requestDto, UUID volunteerId); + +} From 012e7a939fa151ddd2561dab3907a026eab161b2 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:37:56 +0900 Subject: [PATCH 07/19] =?UTF-8?q?test(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EB=AA=A8=EC=A7=91=EA=B8=80=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VolunteerApplyRepositoryImplTest.java | 18 +++ .../VolunteerApplyCommandServiceTest.java | 106 ++++++++++++++++++ .../VolunteerApplyQueryServiceTest.java | 4 +- 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java diff --git a/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java b/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java index 5ee125c8f..f83c9c67b 100644 --- a/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java +++ b/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java @@ -117,6 +117,24 @@ void findByRecruitIdAndVolunteerId() { assertThat(findApply).isPresent(); } + @DisplayName("모집글 아이디와 봉사자 아이디로 봉사 지원 존재 유무를 확인 할 수 있다.") + @Test + void existsByRecruitIdAndVolunteerId() { + // given + Long recruitId = 1234L; + UUID volunteerId = UUID.randomUUID(); + + VolunteerApply newApply = createApply(volunteerId, recruitId); + volunteerApplyRepository.save(newApply); + + // when + boolean result = volunteerApplyRepository.existsByRecruitIdAndVolunteerId(recruitId, + volunteerId); + + // then + assertThat(result).isTrue(); + } + private static VolunteerApply createApply(UUID volunteerId, Long recruitId) { return VolunteerApply.builder() .volunteerId(volunteerId) diff --git a/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java b/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java new file mode 100644 index 000000000..0ce55b3ea --- /dev/null +++ b/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java @@ -0,0 +1,106 @@ +package com.somemore.volunteerapply.service; + +import static com.somemore.common.fixture.RecruitBoardFixture.createCloseRecruitBoard; +import static com.somemore.common.fixture.RecruitBoardFixture.createRecruitBoard; +import static com.somemore.global.exception.ExceptionMessage.RECRUITMENT_NOT_OPEN; +import static com.somemore.volunteerapply.domain.ApplyStatus.WAITING; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.somemore.IntegrationTestSupport; +import com.somemore.global.exception.BadRequestException; +import com.somemore.recruitboard.domain.RecruitBoard; +import com.somemore.recruitboard.repository.RecruitBoardRepository; +import com.somemore.volunteerapply.domain.VolunteerApply; +import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; +import com.somemore.volunteerapply.repository.VolunteerApplyRepository; +import java.util.Optional; +import java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class VolunteerApplyCommandServiceTest extends IntegrationTestSupport { + + @Autowired + private VolunteerApplyCommandService volunteerApplyCommandService; + + @Autowired + private VolunteerApplyRepository volunteerApplyRepository; + + @Autowired + private RecruitBoardRepository recruitBoardRepository; + + @DisplayName("모집중인 봉사 모집글에 지원할 수 있다") + @Test + void apply() { + // given + RecruitBoard board = createRecruitBoard(); + recruitBoardRepository.save(board); + + VolunteerApplyCreateRequestDto dto = VolunteerApplyCreateRequestDto.builder() + .recruitBoardId(board.getId()) + .build(); + + UUID volunteerId = UUID.randomUUID(); + + // when + Long applyId = volunteerApplyCommandService.apply(dto, volunteerId); + + // then + Optional apply = volunteerApplyRepository.findById(applyId); + + assertThat(apply).isPresent(); + assertThat(apply.get().getRecruitBoardId()).isEqualTo(board.getId()); + } + + @DisplayName("모집중이지 않는 봉사 모집글에 신청하면 에러가 발생한다.") + @Test + void applyWhenCLOSE() { + // given + RecruitBoard board = createCloseRecruitBoard(); + recruitBoardRepository.save(board); + + VolunteerApplyCreateRequestDto dto = VolunteerApplyCreateRequestDto.builder() + .recruitBoardId(board.getId()) + .build(); + + UUID volunteerId = UUID.randomUUID(); + + // when + // then + assertThatThrownBy( + () -> volunteerApplyCommandService.apply(dto, volunteerId) + ).isInstanceOf(BadRequestException.class) + .hasMessage(RECRUITMENT_NOT_OPEN.getMessage()); + } + + @DisplayName("중복으로 지원할 수 없다.") + @Test + void applyWhenDuplicate() { + // given + RecruitBoard board = createCloseRecruitBoard(); + recruitBoardRepository.save(board); + + UUID volunteerId = UUID.randomUUID(); + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(board.getId()) + .status(WAITING) + .attended(false) + .build(); + volunteerApplyRepository.save(apply); + + VolunteerApplyCreateRequestDto dto = VolunteerApplyCreateRequestDto.builder() + .recruitBoardId(board.getId()) + .build(); + + // when + // then + assertThatThrownBy( + () -> volunteerApplyCommandService.apply(dto, volunteerId) + ).isInstanceOf(BadRequestException.class) + .hasMessage(RECRUITMENT_NOT_OPEN.getMessage()); + } + +} diff --git a/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java b/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java index f5285a143..29896be23 100644 --- a/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java +++ b/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java @@ -26,8 +26,8 @@ class VolunteerApplyQueryServiceTest extends IntegrationTestSupport { @Test void getVolunteerIdsByRecruitIds() { // Given - Long recruitId1 = 1L; - Long recruitId2 = 2L; + Long recruitId1 = 10L; + Long recruitId2 = 20L; UUID volunteerId1 = UUID.randomUUID(); UUID volunteerId2 = UUID.randomUUID(); From 793bb340b1cb5221a7c8d3ce9ea1c2c0c0224ab6 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:51:58 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EB=AA=A8=EC=A7=91=EA=B8=80=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VolunteerApplyCommandApiController.java | 40 +++++++++++++++++++ .../dto/VolunteerApplyCreateRequestDto.java | 5 ++- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java diff --git a/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java b/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java new file mode 100644 index 000000000..ab208216c --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java @@ -0,0 +1,40 @@ +package com.somemore.volunteerapply.controller; + +import com.somemore.auth.annotation.CurrentUser; +import com.somemore.global.common.response.ApiResponse; +import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; +import com.somemore.volunteerapply.usecase.VolunteerApplyCommandUseCase; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Volunteer Apply Command API", description = "봉사 활동 지원, 철회 관련 API") +@RequiredArgsConstructor +@RequestMapping("/api") +@RestController +public class VolunteerApplyCommandApiController { + + private final VolunteerApplyCommandUseCase volunteerApplyCommandUseCase; + + @Secured("ROLE_VOLUNTEER") + @Operation(summary = "봉사 활동 지원", description = "봉사 활동에 지원합니다.") + @PostMapping("/volunteer-apply") + public ApiResponse apply( + @CurrentUser UUID volunteerId, + @Valid @RequestBody VolunteerApplyCreateRequestDto requestDto + ) { + return ApiResponse.ok( + 201, + volunteerApplyCommandUseCase.apply(requestDto, volunteerId), + "봉사 활동 지원 성공" + ); + } + +} diff --git a/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java b/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java index 438de410a..afe325604 100644 --- a/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java +++ b/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java @@ -7,14 +7,15 @@ import com.somemore.volunteerapply.domain.VolunteerApply; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import java.util.UUID; import lombok.Builder; @JsonNaming(SnakeCaseStrategy.class) @Builder public record VolunteerApplyCreateRequestDto( - @Schema(description = "봉사 모집글 아이디", example = "1L") - @NotBlank(message = "모집글 아이디는 필수 값입니다.") + @Schema(description = "봉사 모집글 아이디", example = "1") + @NotNull(message = "모집글 아이디는 필수 값입니다.") Long recruitBoardId ) { From 97faef7a6bf21445698b652984d06eafb3d5095d Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 14:52:06 +0900 Subject: [PATCH 09/19] =?UTF-8?q?test(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EB=AA=A8=EC=A7=91=EA=B8=80=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?API=20=EC=97=B0=EA=B2=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...olunteerApplyCommandApiControllerTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java diff --git a/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java b/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java new file mode 100644 index 000000000..9dfbf42a6 --- /dev/null +++ b/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java @@ -0,0 +1,71 @@ +package com.somemore.volunteerapply.controller; + +import static com.somemore.common.fixture.LocalDateTimeFixture.createStartDateTime; +import static com.somemore.recruitboard.domain.VolunteerCategory.OTHER; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.somemore.ControllerTestSupport; +import com.somemore.WithMockCustomUser; +import com.somemore.location.dto.request.LocationCreateRequestDto; +import com.somemore.recruitboard.dto.request.RecruitBoardCreateRequestDto; +import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; +import com.somemore.volunteerapply.usecase.VolunteerApplyCommandUseCase; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.UUID; +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; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; + +class VolunteerApplyCommandApiControllerTest extends ControllerTestSupport { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private VolunteerApplyCommandUseCase volunteerApplyCommandUseCase; + + @Test + @DisplayName("봉사 활동 지원 성공 테스트") + @WithMockCustomUser(role = "VOLUNTEER") + void apply() throws Exception { + // given + VolunteerApplyCreateRequestDto dto = VolunteerApplyCreateRequestDto.builder() + .recruitBoardId(1L) + .build(); + + Long applyId = 1L; + + given(volunteerApplyCommandUseCase.apply(any(), any(UUID.class))) + .willReturn(applyId); + + String requestBody = objectMapper.writeValueAsString(dto); + + // when + mockMvc.perform(post("/api/volunteer-apply") + .content(requestBody) + .contentType(APPLICATION_JSON) + .header("Authorization", "Bearer access-token")) + // then + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(201)) + .andExpect(jsonPath("$.data").value(applyId)) + .andExpect(jsonPath("$.message").value("봉사 활동 지원 성공")); + } +} From c464977ad4553dadb96d8d36f605c9df2c50ef75 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:01:36 +0900 Subject: [PATCH 10/19] =?UTF-8?q?refactor(volunteer-apply):=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=20-=20VolunteerApplyCommand*=20->=20ApplyVolunteerApply*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VolunteerApplyCommandApiController.java | 6 +++--- ...e.java => ApplyVolunteerApplyService.java} | 5 ++--- ...e.java => ApplyVolunteerApplyUseCase.java} | 2 +- ...olunteerApplyCommandApiControllerTest.java | 19 ++++--------------- ...va => ApplyVolunteerApplyServiceTest.java} | 4 ++-- 5 files changed, 12 insertions(+), 24 deletions(-) rename src/main/java/com/somemore/volunteerapply/service/{VolunteerApplyCommandService.java => ApplyVolunteerApplyService.java} (91%) rename src/main/java/com/somemore/volunteerapply/usecase/{VolunteerApplyCommandUseCase.java => ApplyVolunteerApplyUseCase.java} (82%) rename src/test/java/com/somemore/volunteerapply/service/{VolunteerApplyCommandServiceTest.java => ApplyVolunteerApplyServiceTest.java} (96%) diff --git a/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java b/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java index ab208216c..6e8dc29f3 100644 --- a/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java +++ b/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java @@ -3,7 +3,7 @@ import com.somemore.auth.annotation.CurrentUser; import com.somemore.global.common.response.ApiResponse; import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; -import com.somemore.volunteerapply.usecase.VolunteerApplyCommandUseCase; +import com.somemore.volunteerapply.usecase.ApplyVolunteerApplyUseCase; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -21,7 +21,7 @@ @RestController public class VolunteerApplyCommandApiController { - private final VolunteerApplyCommandUseCase volunteerApplyCommandUseCase; + private final ApplyVolunteerApplyUseCase applyVolunteerApplyUseCase; @Secured("ROLE_VOLUNTEER") @Operation(summary = "봉사 활동 지원", description = "봉사 활동에 지원합니다.") @@ -32,7 +32,7 @@ public ApiResponse apply( ) { return ApiResponse.ok( 201, - volunteerApplyCommandUseCase.apply(requestDto, volunteerId), + applyVolunteerApplyUseCase.apply(requestDto, volunteerId), "봉사 활동 지원 성공" ); } diff --git a/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java b/src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java similarity index 91% rename from src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java rename to src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java index 955a60261..af75516ec 100644 --- a/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyCommandService.java +++ b/src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java @@ -9,8 +9,7 @@ import com.somemore.volunteerapply.domain.VolunteerApply; import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; import com.somemore.volunteerapply.repository.VolunteerApplyRepository; -import com.somemore.volunteerapply.usecase.VolunteerApplyCommandUseCase; -import java.time.LocalDateTime; +import com.somemore.volunteerapply.usecase.ApplyVolunteerApplyUseCase; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -19,7 +18,7 @@ @RequiredArgsConstructor @Transactional @Service -public class VolunteerApplyCommandService implements VolunteerApplyCommandUseCase { +public class ApplyVolunteerApplyService implements ApplyVolunteerApplyUseCase { private final VolunteerApplyRepository volunteerApplyRepository; private final RecruitBoardQueryUseCase recruitBoardQueryUseCase; diff --git a/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java b/src/main/java/com/somemore/volunteerapply/usecase/ApplyVolunteerApplyUseCase.java similarity index 82% rename from src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java rename to src/main/java/com/somemore/volunteerapply/usecase/ApplyVolunteerApplyUseCase.java index a821c4b0d..601fd64cf 100644 --- a/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyCommandUseCase.java +++ b/src/main/java/com/somemore/volunteerapply/usecase/ApplyVolunteerApplyUseCase.java @@ -3,7 +3,7 @@ import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; import java.util.UUID; -public interface VolunteerApplyCommandUseCase { +public interface ApplyVolunteerApplyUseCase { Long apply(VolunteerApplyCreateRequestDto requestDto, UUID volunteerId); diff --git a/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java b/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java index 9dfbf42a6..0ff6f57a3 100644 --- a/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java +++ b/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java @@ -1,13 +1,8 @@ package com.somemore.volunteerapply.controller; -import static com.somemore.common.fixture.LocalDateTimeFixture.createStartDateTime; -import static com.somemore.recruitboard.domain.VolunteerCategory.OTHER; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.http.MediaType.MULTIPART_FORM_DATA; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -15,19 +10,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.somemore.ControllerTestSupport; import com.somemore.WithMockCustomUser; -import com.somemore.location.dto.request.LocationCreateRequestDto; -import com.somemore.recruitboard.dto.request.RecruitBoardCreateRequestDto; import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; -import com.somemore.volunteerapply.usecase.VolunteerApplyCommandUseCase; -import java.math.BigDecimal; -import java.time.LocalDateTime; +import com.somemore.volunteerapply.usecase.ApplyVolunteerApplyUseCase; import java.util.UUID; 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; -import org.springframework.http.MediaType; -import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; class VolunteerApplyCommandApiControllerTest extends ControllerTestSupport { @@ -39,11 +28,11 @@ class VolunteerApplyCommandApiControllerTest extends ControllerTestSupport { private ObjectMapper objectMapper; @MockBean - private VolunteerApplyCommandUseCase volunteerApplyCommandUseCase; + private ApplyVolunteerApplyUseCase applyVolunteerApplyUseCase; @Test @DisplayName("봉사 활동 지원 성공 테스트") - @WithMockCustomUser(role = "VOLUNTEER") + @WithMockCustomUser void apply() throws Exception { // given VolunteerApplyCreateRequestDto dto = VolunteerApplyCreateRequestDto.builder() @@ -52,7 +41,7 @@ void apply() throws Exception { Long applyId = 1L; - given(volunteerApplyCommandUseCase.apply(any(), any(UUID.class))) + given(applyVolunteerApplyUseCase.apply(any(), any(UUID.class))) .willReturn(applyId); String requestBody = objectMapper.writeValueAsString(dto); diff --git a/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java b/src/test/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyServiceTest.java similarity index 96% rename from src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java rename to src/test/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyServiceTest.java index 0ce55b3ea..4309a95d1 100644 --- a/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyCommandServiceTest.java +++ b/src/test/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyServiceTest.java @@ -20,10 +20,10 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -class VolunteerApplyCommandServiceTest extends IntegrationTestSupport { +class ApplyVolunteerApplyServiceTest extends IntegrationTestSupport { @Autowired - private VolunteerApplyCommandService volunteerApplyCommandService; + private ApplyVolunteerApplyService volunteerApplyCommandService; @Autowired private VolunteerApplyRepository volunteerApplyRepository; From 452b1923bb92344b35b4e1b5df9980184a69afa3 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:38:43 +0900 Subject: [PATCH 11/19] =?UTF-8?q?feat(volunteer-apply):=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/somemore/volunteerapply/domain/VolunteerApply.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java b/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java index 2f0a54615..e89258033 100644 --- a/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java +++ b/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java @@ -63,6 +63,11 @@ public void changeAttended(Boolean attended) { this.attended = attended; } + public boolean isOwnApplication(UUID volunteerId) { + return this.volunteerId.equals(volunteerId); + } + + public boolean isVolunteerActivityCompleted() { return this.attended && this.status == APPROVED; } From 01809761cb97099379cda059fdfdf9cc24d477bf Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:38:54 +0900 Subject: [PATCH 12/19] =?UTF-8?q?test(volunteer-apply):=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/VolunteerApplyTest.java | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java b/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java index 187068966..771a724c6 100644 --- a/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java +++ b/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java @@ -16,12 +16,7 @@ class VolunteerApplyTest { @Test void changeStatus() { // given - VolunteerApply apply = VolunteerApply.builder() - .volunteerId(UUID.randomUUID()) - .recruitBoardId(1L) - .status(WAITING) - .attended(false) - .build(); + VolunteerApply apply = createApply(UUID.randomUUID(), WAITING, false); // when apply.changeStatus(APPROVED); @@ -34,12 +29,7 @@ void changeStatus() { @DisplayName("지원 상태 변경 실패 - 이미 완료된 봉사활동") void changeStatusWhenCompletedActivity() { // given - VolunteerApply apply = VolunteerApply.builder() - .volunteerId(UUID.randomUUID()) - .recruitBoardId(1L) - .status(APPROVED) - .attended(true) - .build(); + VolunteerApply apply = createApply(UUID.randomUUID(), APPROVED, true); // when // then @@ -52,12 +42,7 @@ void changeStatusWhenCompletedActivity() { @Test void markAsAttended() { // given - VolunteerApply volunteerApply = VolunteerApply.builder() - .volunteerId(UUID.randomUUID()) - .recruitBoardId(1L) - .status(APPROVED) - .attended(false) - .build(); + VolunteerApply volunteerApply = createApply(UUID.randomUUID(), APPROVED, false); // when volunteerApply.changeAttended(true); @@ -70,12 +55,7 @@ void markAsAttended() { @DisplayName("참석 처리 실패 - 승인되지 않은 상태") void changeAttendedWhenNotApproved() { // given - VolunteerApply apply = VolunteerApply.builder() - .volunteerId(UUID.randomUUID()) - .recruitBoardId(1L) - .status(WAITING) - .attended(false) - .build(); + VolunteerApply apply = createApply(UUID.randomUUID(), WAITING, false); // when & then assertThatThrownBy( @@ -87,12 +67,7 @@ void changeAttendedWhenNotApproved() { @Test void isCompleted() { // given - VolunteerApply apply = VolunteerApply.builder() - .volunteerId(UUID.randomUUID()) - .recruitBoardId(1L) - .status(APPROVED) - .attended(true) - .build(); + VolunteerApply apply = createApply(UUID.randomUUID(), APPROVED, true); // when boolean res = apply.isVolunteerActivityCompleted(); @@ -100,5 +75,27 @@ void isCompleted() { // then assertThat(res).isTrue(); } -} + @DisplayName("지원자 아이디로 본인이 작성한 지원인지 확인할 수있다.") + @Test + void isOwnApplication() { + // given + UUID volunteerId = UUID.randomUUID(); + VolunteerApply apply = createApply(volunteerId, APPROVED, false); + + // when + boolean result = apply.isOwnApplication(volunteerId); + + // then + assertThat(result).isTrue(); + } + + private VolunteerApply createApply(UUID volunteerId, ApplyStatus status, boolean attended) { + return VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(1L) + .status(status) + .attended(attended) + .build(); + } +} From 697e6aa51b94d43f864a464b9dfb66ebf6395069 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:39:15 +0900 Subject: [PATCH 13/19] =?UTF-8?q?feat(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=A7=80=EC=9B=90=20=EC=B2=A0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/exception/ExceptionMessage.java | 1 + .../WithdrawVolunteerApplyService.java | 44 +++++++++++++++++++ .../WithdrawVolunteerApplyUseCase.java | 9 ++++ 3 files changed, 54 insertions(+) create mode 100644 src/main/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyService.java create mode 100644 src/main/java/com/somemore/volunteerapply/usecase/WithdrawVolunteerApplyUseCase.java diff --git a/src/main/java/com/somemore/global/exception/ExceptionMessage.java b/src/main/java/com/somemore/global/exception/ExceptionMessage.java index 7aa62511b..556c45ff4 100644 --- a/src/main/java/com/somemore/global/exception/ExceptionMessage.java +++ b/src/main/java/com/somemore/global/exception/ExceptionMessage.java @@ -31,6 +31,7 @@ public enum ExceptionMessage { NOT_EXISTS_REVIEW("존재하지 않는 리뷰입니다."), RECRUITMENT_NOT_OPEN("현재 모집 진행 중이 아닙니다."), DUPLICATE_APPLICATION("이미 신청한 봉사 모집 공고입니다."), + UNAUTHORIZED_VOLUNTEER_APPLY("해당 지원에 권한이 없습니다."), ; private final String message; diff --git a/src/main/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyService.java b/src/main/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyService.java new file mode 100644 index 000000000..d40d9a5aa --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyService.java @@ -0,0 +1,44 @@ +package com.somemore.volunteerapply.service; + +import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER_APPLY; +import static com.somemore.global.exception.ExceptionMessage.UNAUTHORIZED_VOLUNTEER_APPLY; + +import com.somemore.global.exception.BadRequestException; +import com.somemore.volunteerapply.domain.VolunteerApply; +import com.somemore.volunteerapply.repository.VolunteerApplyRepository; +import com.somemore.volunteerapply.usecase.WithdrawVolunteerApplyUseCase; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional +@Service +public class WithdrawVolunteerApplyService implements WithdrawVolunteerApplyUseCase { + + private final VolunteerApplyRepository volunteerApplyRepository; + + @Override + public void withdraw(Long id, UUID volunteerId) { + VolunteerApply apply = getApply(id); + validateVolunteerIdentity(apply, volunteerId); + + apply.markAsDeleted(); + volunteerApplyRepository.save(apply); + } + + private VolunteerApply getApply(Long id) { + return volunteerApplyRepository.findById(id).orElseThrow( + () -> new BadRequestException(NOT_EXISTS_VOLUNTEER_APPLY) + ); + } + + private void validateVolunteerIdentity(VolunteerApply apply, UUID volunteerId) { + if (apply.isOwnApplication(volunteerId)) { + return; + } + + throw new BadRequestException(UNAUTHORIZED_VOLUNTEER_APPLY); + } +} diff --git a/src/main/java/com/somemore/volunteerapply/usecase/WithdrawVolunteerApplyUseCase.java b/src/main/java/com/somemore/volunteerapply/usecase/WithdrawVolunteerApplyUseCase.java new file mode 100644 index 000000000..c80a80627 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/usecase/WithdrawVolunteerApplyUseCase.java @@ -0,0 +1,9 @@ +package com.somemore.volunteerapply.usecase; + +import java.util.UUID; + +public interface WithdrawVolunteerApplyUseCase { + + void withdraw(Long id, UUID volunteerId); + +} From fcb83a47b908d28276a0b4f0d3ccffb4af8e3265 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:39:25 +0900 Subject: [PATCH 14/19] =?UTF-8?q?test(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=A7=80=EC=9B=90=20=EC=B2=A0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WithdrawVolunteerApplyServiceTest.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java diff --git a/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java b/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java new file mode 100644 index 000000000..ca1ddd0e8 --- /dev/null +++ b/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java @@ -0,0 +1,70 @@ +package com.somemore.volunteerapply.service; + +import static com.somemore.global.exception.ExceptionMessage.UNAUTHORIZED_VOLUNTEER_APPLY; +import static com.somemore.volunteerapply.domain.ApplyStatus.APPROVED; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.somemore.IntegrationTestSupport; +import com.somemore.global.exception.BadRequestException; +import com.somemore.volunteerapply.domain.ApplyStatus; +import com.somemore.volunteerapply.domain.VolunteerApply; +import com.somemore.volunteerapply.repository.VolunteerApplyRepository; +import java.util.Optional; +import java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class WithdrawVolunteerApplyServiceTest extends IntegrationTestSupport { + + @Autowired + private WithdrawVolunteerApplyService withdrawVolunteerApplyService; + + @Autowired + private VolunteerApplyRepository volunteerApplyRepository; + + @DisplayName("봉사 지원을 철회할 수 있다.") + @Test + void withdraw() { + // given + UUID volunteerId = UUID.randomUUID(); + + VolunteerApply apply = createApply(volunteerId, APPROVED, false); + volunteerApplyRepository.save(apply); + + // when + withdrawVolunteerApplyService.withdraw(apply.getId(), volunteerId); + + // then + Optional withdraw = volunteerApplyRepository.findById(apply.getId()); + + assertThat(withdraw).isEmpty(); + } + + @DisplayName("지원한 본인이 아닐 경우 에러가 발생한다.") + @Test + void withdrawWhenWrongVolunteerId() { + // given + UUID wrongId = UUID.randomUUID(); + + VolunteerApply apply = createApply(UUID.randomUUID(), APPROVED, false); + volunteerApplyRepository.save(apply); + + // when + // then + assertThatThrownBy( + () -> withdrawVolunteerApplyService.withdraw(apply.getId(), wrongId) + ).isInstanceOf(BadRequestException.class) + .hasMessage(UNAUTHORIZED_VOLUNTEER_APPLY.getMessage()); + } + + private VolunteerApply createApply(UUID volunteerId, ApplyStatus status, boolean attended) { + return VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(1L) + .status(status) + .attended(attended) + .build(); + } +} From b48788069d6bdadf4f92a720900305ed2759496e Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:39:36 +0900 Subject: [PATCH 15/19] =?UTF-8?q?feat(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=A7=80=EC=9B=90=20=EC=B2=A0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VolunteerApplyCommandApiController.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java b/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java index 6e8dc29f3..b6babc6e2 100644 --- a/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java +++ b/src/main/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiController.java @@ -4,12 +4,15 @@ import com.somemore.global.common.response.ApiResponse; import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; import com.somemore.volunteerapply.usecase.ApplyVolunteerApplyUseCase; +import com.somemore.volunteerapply.usecase.WithdrawVolunteerApplyUseCase; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.security.access.annotation.Secured; +import org.springframework.web.bind.annotation.DeleteMapping; +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; @@ -22,6 +25,7 @@ public class VolunteerApplyCommandApiController { private final ApplyVolunteerApplyUseCase applyVolunteerApplyUseCase; + private final WithdrawVolunteerApplyUseCase withdrawVolunteerApplyUseCase; @Secured("ROLE_VOLUNTEER") @Operation(summary = "봉사 활동 지원", description = "봉사 활동에 지원합니다.") @@ -37,4 +41,15 @@ public ApiResponse apply( ); } + @Secured("ROLE_VOLUNTEER") + @Operation(summary = "봉사 활동 지원 철회", description = "봉사 활동 지원을 철회합니다.") + @DeleteMapping("/volunteer-apply/{id}") + public ApiResponse withdraw( + @CurrentUser UUID volunteerId, + @PathVariable Long id + ) { + withdrawVolunteerApplyUseCase.withdraw(id, volunteerId); + return ApiResponse.ok("봉사 활동 지원 철회 성공"); + } + } From d0511e9dabc9c6e8eddc3e61c2dd80042f9c85fb Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:39:43 +0900 Subject: [PATCH 16/19] =?UTF-8?q?test(volunteer-apply):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=A7=80=EC=9B=90=20=EC=B2=A0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20API=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...olunteerApplyCommandApiControllerTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java b/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java index 0ff6f57a3..931918e1d 100644 --- a/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java +++ b/src/test/java/com/somemore/volunteerapply/controller/VolunteerApplyCommandApiControllerTest.java @@ -2,7 +2,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willDoNothing; import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -12,6 +14,7 @@ import com.somemore.WithMockCustomUser; import com.somemore.volunteerapply.dto.VolunteerApplyCreateRequestDto; import com.somemore.volunteerapply.usecase.ApplyVolunteerApplyUseCase; +import com.somemore.volunteerapply.usecase.WithdrawVolunteerApplyUseCase; import java.util.UUID; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -30,6 +33,9 @@ class VolunteerApplyCommandApiControllerTest extends ControllerTestSupport { @MockBean private ApplyVolunteerApplyUseCase applyVolunteerApplyUseCase; + @MockBean + private WithdrawVolunteerApplyUseCase withdrawVolunteerApplyUseCase; + @Test @DisplayName("봉사 활동 지원 성공 테스트") @WithMockCustomUser @@ -57,4 +63,24 @@ void apply() throws Exception { .andExpect(jsonPath("$.data").value(applyId)) .andExpect(jsonPath("$.message").value("봉사 활동 지원 성공")); } + + @Test + @DisplayName("봉사 활동 철회 성공 테스트") + @WithMockCustomUser + void withdraw () throws Exception { + // given + Long id = 1L; + + willDoNothing().given(withdrawVolunteerApplyUseCase) + .withdraw(any(), any(UUID.class)); + + // when + mockMvc.perform(delete("/api/volunteer-apply/{id}", id) + .header("Authorization", "Bearer access-token")) + // then + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.data").value("")) + .andExpect(jsonPath("$.message").value("봉사 활동 지원 철회 성공")); + } } From c6bd639f1cde613f1ac44e60eff1b8eab7d39fef Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 15:50:13 +0900 Subject: [PATCH 17/19] =?UTF-8?q?fix(volunteer-apply):=20sonar=20qube=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../volunteerapply/dto/VolunteerApplyCreateRequestDto.java | 1 - .../com/somemore/common/fixture/RecruitBoardFixture.java | 3 ++- .../service/WithdrawVolunteerApplyServiceTest.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java b/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java index afe325604..9426c4614 100644 --- a/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java +++ b/src/main/java/com/somemore/volunteerapply/dto/VolunteerApplyCreateRequestDto.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming; import com.somemore.volunteerapply.domain.VolunteerApply; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.util.UUID; import lombok.Builder; diff --git a/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java b/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java index a375514b4..49fff9c33 100644 --- a/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java +++ b/src/test/java/com/somemore/common/fixture/RecruitBoardFixture.java @@ -1,6 +1,7 @@ package com.somemore.common.fixture; import static com.somemore.common.fixture.LocalDateTimeFixture.createStartDateTime; +import static com.somemore.recruitboard.domain.RecruitStatus.CLOSED; import static com.somemore.recruitboard.domain.RecruitStatus.COMPLETED; import static com.somemore.recruitboard.domain.VolunteerCategory.OTHER; @@ -322,7 +323,7 @@ public static RecruitBoard createCompletedRecruitBoard() { public static RecruitBoard createCloseRecruitBoard() { RecruitBoard recruitBoard = createCompletedRecruitBoard(UUID.randomUUID(), VOLUNTEER_CATEGORY); - setRecruitStatus(recruitBoard, COMPLETED); + setRecruitStatus(recruitBoard, CLOSED); return recruitBoard; } diff --git a/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java b/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java index ca1ddd0e8..697e170fe 100644 --- a/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java +++ b/src/test/java/com/somemore/volunteerapply/service/WithdrawVolunteerApplyServiceTest.java @@ -46,15 +46,15 @@ void withdraw() { @Test void withdrawWhenWrongVolunteerId() { // given - UUID wrongId = UUID.randomUUID(); - VolunteerApply apply = createApply(UUID.randomUUID(), APPROVED, false); volunteerApplyRepository.save(apply); + UUID wrongId = UUID.randomUUID(); + Long applyId = apply.getId(); // when // then assertThatThrownBy( - () -> withdrawVolunteerApplyService.withdraw(apply.getId(), wrongId) + () -> withdrawVolunteerApplyService.withdraw(applyId, wrongId) ).isInstanceOf(BadRequestException.class) .hasMessage(UNAUTHORIZED_VOLUNTEER_APPLY.getMessage()); } From 72d09fa36ea93760e0266b2e473f044e4711aca4 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 16:33:42 +0900 Subject: [PATCH 18/19] =?UTF-8?q?refactor(recruit-board):=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=B3=80=EA=B2=BD=20-=20isApplicationOpen=20->=20i?= =?UTF-8?q?sRecruitOpen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/somemore/recruitboard/domain/RecruitBoard.java | 2 +- .../volunteerapply/service/ApplyVolunteerApplyService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java b/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java index 33fceec45..d93b8f337 100644 --- a/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java +++ b/src/main/java/com/somemore/recruitboard/domain/RecruitBoard.java @@ -92,7 +92,7 @@ public void changeRecruitStatus(RecruitStatus newStatus, LocalDateTime currentDa this.recruitStatus = newStatus; } - public boolean isApplicationOpen() { + public boolean isRecruitOpen() { return this.recruitStatus == RECRUITING; } diff --git a/src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java b/src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java index af75516ec..388f6f410 100644 --- a/src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java +++ b/src/main/java/com/somemore/volunteerapply/service/ApplyVolunteerApplyService.java @@ -37,7 +37,7 @@ public Long apply(VolunteerApplyCreateRequestDto requestDto, UUID volunteerId) { } private void validateCanApply(RecruitBoard board) { - if (board.isApplicationOpen()) { + if (board.isRecruitOpen()) { return; } throw new BadRequestException(RECRUITMENT_NOT_OPEN); From 95e46bd5a3950d03878b1201ba740a0886b4f21b Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Tue, 3 Dec 2024 16:34:06 +0900 Subject: [PATCH 19/19] =?UTF-8?q?test(recruit-board):=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B0=8F=20=EB=B6=80=EC=A0=81=EC=A0=88?= =?UTF-8?q?=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recruitboard/domain/RecruitBoardTest.java | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java b/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java index 1718c428e..35f47a461 100644 --- a/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java +++ b/src/test/java/com/somemore/recruitboard/domain/RecruitBoardTest.java @@ -3,7 +3,6 @@ import static com.somemore.common.fixture.LocalDateTimeFixture.createCurrentDateTime; import static com.somemore.common.fixture.LocalDateTimeFixture.createStartDateTime; import static com.somemore.common.fixture.LocalDateTimeFixture.createUpdateStartDateTime; -import static com.somemore.common.fixture.RecruitBoardFixture.createCloseRecruitBoard; import static com.somemore.common.fixture.RecruitBoardFixture.createRecruitBoard; import static com.somemore.recruitboard.domain.RecruitStatus.CLOSED; import static com.somemore.recruitboard.domain.RecruitStatus.COMPLETED; @@ -192,29 +191,17 @@ void changeStatusWhenDeadLineAfter(Long secondsOffset) { } - @DisplayName("모집중일 경우 지원이 가능하다") + @DisplayName("모집중일 경우 True 반환한다.") @Test - void isApplicationOpen() { + void isRecruitOpen() { // given RecruitBoard board = createRecruitBoard(); // when - boolean result = board.isApplicationOpen(); + boolean result = board.isRecruitOpen(); // then assertThat(result).isTrue(); } - @DisplayName("모집중이 아닐 경우 지원이 불가능하다") - @Test - void isApplicationOpenWhenNotRECRUTING() { - // given - RecruitBoard board = createCloseRecruitBoard(); - - // when - boolean result = board.isApplicationOpen(); - - // then - assertThat(result).isFalse(); - } }