From cc7523aa45f876cf8fc42429e6e6a5a0e7a586ba Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:14:47 +0900 Subject: [PATCH 1/9] =?UTF-8?q?feat(volunteer-apply):=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../somemore/domains/VolunteerManagement.java | 25 ---- .../volunteerapply/domain/VolunteerApply.java | 69 ++++++++++ .../VolunteerApplyJpaRepository.java | 8 ++ .../repository/VolunteerApplyRepository.java | 18 +++ .../VolunteerApplyRepositoryImpl.java | 122 ++++++++++++++++++ 5 files changed, 217 insertions(+), 25 deletions(-) delete mode 100644 src/main/java/com/somemore/domains/VolunteerManagement.java create mode 100644 src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java create mode 100644 src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyJpaRepository.java create mode 100644 src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java create mode 100644 src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImpl.java diff --git a/src/main/java/com/somemore/domains/VolunteerManagement.java b/src/main/java/com/somemore/domains/VolunteerManagement.java deleted file mode 100644 index 0b0085bd4..000000000 --- a/src/main/java/com/somemore/domains/VolunteerManagement.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.somemore.domains; - -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.ColumnDefault; - -import java.util.UUID; - -@Getter -@Setter -@Entity -@Table(name = "Volunteer_management") -public class VolunteerManagement { - @Id - @GeneratedValue(strategy = GenerationType.UUID) - private UUID id; - @Column(name = "apply_status", nullable = false, length = 20) - private String applyStatus; - - @ColumnDefault("0") - @Column(name = "attended", nullable = false) - private Boolean attended = false; - -} \ No newline at end of file diff --git a/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java b/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java new file mode 100644 index 000000000..2f0a54615 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/domain/VolunteerApply.java @@ -0,0 +1,69 @@ +package com.somemore.volunteerapply.domain; + +import static com.somemore.volunteerapply.domain.ApplyStatus.APPROVED; + +import com.somemore.global.common.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.UUID; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +@Table(name = "volunteer_apply") +public class VolunteerApply extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "volunteer_id", nullable = false, columnDefinition = "BINARY(16)") + private UUID volunteerId; + + @Column(name = "recruit_board_id", nullable = false) + private Long recruitBoardId; + + @Enumerated(EnumType.STRING) + @Column(name = "status", nullable = false, length = 20) + private ApplyStatus status = ApplyStatus.WAITING; + + @Column(name = "attended", nullable = false) + private Boolean attended = false; + + @Builder + public VolunteerApply(UUID volunteerId, Long recruitBoardId, ApplyStatus status, + Boolean attended) { + this.volunteerId = volunteerId; + this.recruitBoardId = recruitBoardId; + this.status = status; + this.attended = attended; + } + + public void changeStatus(ApplyStatus status) { + if (isVolunteerActivityCompleted()) { + throw new IllegalStateException("이미 완료된 봉사활동에 대해서는 변경이 불가능합니다."); + } + this.status = status; + } + + public void changeAttended(Boolean attended) { + if (this.status != APPROVED) { + throw new IllegalStateException("승인되지 않은 봉사 지원은 참석 여부를 변경할 수 없습니다."); + } + this.attended = attended; + } + + public boolean isVolunteerActivityCompleted() { + return this.attended && this.status == APPROVED; + } +} diff --git a/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyJpaRepository.java b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyJpaRepository.java new file mode 100644 index 000000000..2958ee4d1 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyJpaRepository.java @@ -0,0 +1,8 @@ +package com.somemore.volunteerapply.repository; + +import com.somemore.volunteerapply.domain.VolunteerApply; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface VolunteerApplyJpaRepository extends JpaRepository { + +} diff --git a/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java new file mode 100644 index 000000000..5cd226417 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepository.java @@ -0,0 +1,18 @@ +package com.somemore.volunteerapply.repository; + +import com.somemore.volunteerapply.domain.VolunteerApply; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface VolunteerApplyRepository { + + VolunteerApply save(VolunteerApply volunteerApply); + Optional findById(Long id); + 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 new file mode 100644 index 000000000..3c0031234 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImpl.java @@ -0,0 +1,122 @@ +package com.somemore.volunteerapply.repository; + +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.somemore.volunteerapply.domain.QVolunteerApply; +import com.somemore.volunteerapply.domain.VolunteerApply; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Repository; + +@RequiredArgsConstructor +@Repository +public class VolunteerApplyRepositoryImpl implements VolunteerApplyRepository { + + private final VolunteerApplyJpaRepository volunteerApplyJpaRepository; + private final JPAQueryFactory queryFactory; + + private static final QVolunteerApply volunteerApply = QVolunteerApply.volunteerApply; + + @Override + public VolunteerApply save(VolunteerApply volunteerApply) { + return volunteerApplyJpaRepository.save(volunteerApply); + } + + @Override + public Optional findById(Long id) { + return findOne(volunteerApply.id.eq(id)); + } + + @Override + public List findVolunteerIdsByRecruitIds(List recruitIds) { + + BooleanExpression exp = volunteerApply.recruitBoardId + .in(recruitIds) + .and(isNotDeleted()); + + return queryFactory + .select(volunteerApply.volunteerId) + .from(volunteerApply) + .where(exp) + .fetch(); + } + + @Override + public Page findAllByRecruitId(Long recruitId, Pageable pageable) { + + BooleanExpression exp = volunteerApply.recruitBoardId + .eq(recruitId) + .and(isNotDeleted()); + + List content = queryFactory + .selectFrom(volunteerApply) + .where(exp) + .orderBy(toOrderSpecifiers(pageable.getSort())) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + return new PageImpl<>( + content, + pageable, + getCount(exp) + ); + } + + @Override + public Optional findByRecruitIdAndVolunteerId(Long recruitId, + UUID volunteerId) { + BooleanExpression exp = volunteerApply.recruitBoardId.eq(recruitId) + .and(volunteerApply.volunteerId.eq(volunteerId)); + return findOne(exp); + } + + private Long getCount(BooleanExpression exp) { + return queryFactory + .select(volunteerApply.count()) + .from(volunteerApply) + .where(exp) + .fetchOne(); + } + + private Optional findOne(BooleanExpression condition) { + + return Optional.ofNullable( + queryFactory + .selectFrom(volunteerApply) + .where( + condition, + isNotDeleted() + ) + .fetchOne() + ); + } + + private BooleanExpression isNotDeleted() { + return volunteerApply.deleted.isFalse(); + } + + private OrderSpecifier[] toOrderSpecifiers(Sort sort) { + + return sort.stream() + .map(order -> { + String property = order.getProperty(); + + if ("created_at".equals(property)) { + return order.isAscending() + ? volunteerApply.createdAt.asc() + : volunteerApply.createdAt.desc(); + } else { + throw new IllegalStateException("Invalid sort property: " + property); + } + }) + .toArray(OrderSpecifier[]::new); + } +} From 0f20bca944fbaca2a43f3a82bf29d24f91ef847c Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:15:11 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat(volunteer-apply):=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=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 --- .../domain/VolunteerApplyTest.java | 104 ++++++++++++++ .../VolunteerApplyRepositoryImplTest.java | 130 ++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java create mode 100644 src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java diff --git a/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java b/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java new file mode 100644 index 000000000..187068966 --- /dev/null +++ b/src/test/java/com/somemore/volunteerapply/domain/VolunteerApplyTest.java @@ -0,0 +1,104 @@ +package com.somemore.volunteerapply.domain; + +import static com.somemore.volunteerapply.domain.ApplyStatus.APPROVED; +import static com.somemore.volunteerapply.domain.ApplyStatus.REJECTED; +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 java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class VolunteerApplyTest { + + @DisplayName("지원 상태를 변경할 수 있다") + @Test + void changeStatus() { + // given + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(WAITING) + .attended(false) + .build(); + + // when + apply.changeStatus(APPROVED); + + // then + assertThat(apply.getStatus()).isEqualTo(APPROVED); + } + + @Test + @DisplayName("지원 상태 변경 실패 - 이미 완료된 봉사활동") + void changeStatusWhenCompletedActivity() { + // given + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(APPROVED) + .attended(true) + .build(); + + // when + // then + assertThatThrownBy( + () -> apply.changeStatus(REJECTED) + ).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("봉사 지원 상태를 변경") + @Test + void markAsAttended() { + // given + VolunteerApply volunteerApply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(APPROVED) + .attended(false) + .build(); + + // when + volunteerApply.changeAttended(true); + + // then + assertThat(volunteerApply.getAttended()).isTrue(); + } + + @Test + @DisplayName("참석 처리 실패 - 승인되지 않은 상태") + void changeAttendedWhenNotApproved() { + // given + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(WAITING) + .attended(false) + .build(); + + // when & then + assertThatThrownBy( + () -> apply.changeAttended(true) + ).isInstanceOf(IllegalStateException.class); + } + + @DisplayName("봉사 참석 여부 확인") + @Test + void isCompleted() { + // given + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(APPROVED) + .attended(true) + .build(); + + // when + boolean res = apply.isVolunteerActivityCompleted(); + + // then + assertThat(res).isTrue(); + } +} + diff --git a/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java b/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java new file mode 100644 index 000000000..ecc950324 --- /dev/null +++ b/src/test/java/com/somemore/volunteerapply/repository/VolunteerApplyRepositoryImplTest.java @@ -0,0 +1,130 @@ +package com.somemore.volunteerapply.repository; + + +import static org.assertj.core.api.Assertions.assertThat; + +import com.somemore.IntegrationTestSupport; +import com.somemore.volunteerapply.domain.ApplyStatus; +import com.somemore.volunteerapply.domain.VolunteerApply; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +class VolunteerApplyRepositoryImplTest extends IntegrationTestSupport { + + @Autowired + private VolunteerApplyRepositoryImpl volunteerApplyRepository; + + @BeforeEach + void setUp() { + // Given + for (int i = 1; i <= 15; i++) { + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(ApplyStatus.WAITING) + .attended(false) + .build(); + volunteerApplyRepository.save(apply); + } + + for (int i = 1; i <= 5; i++) { + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(2L) + .status(ApplyStatus.APPROVED) + .attended(true) + .build(); + volunteerApplyRepository.save(apply); + } + } + + @DisplayName("봉사 신청 저장 및 조회") + @Test + void saveAndFindById() { + // Given + VolunteerApply newApply = VolunteerApply.builder() + .volunteerId(UUID.randomUUID()) + .recruitBoardId(1L) + .status(ApplyStatus.APPROVED) + .attended(false) + .build(); + VolunteerApply savedApply = volunteerApplyRepository.save(newApply); + + // When + Optional foundApply = volunteerApplyRepository.findById(savedApply.getId()); + + // Then + assertThat(foundApply).isPresent(); + assertThat(foundApply.get().getId()).isEqualTo(savedApply.getId()); + assertThat(foundApply.get().getStatus()).isEqualTo(ApplyStatus.APPROVED); + } + + @DisplayName("모집글 ID 리스트로 봉사자 ID 리스트 조회") + @Test + void findVolunteerIdsByRecruitIds() { + // When + List volunteerIds = volunteerApplyRepository.findVolunteerIdsByRecruitIds( + List.of(1L, 2L)); + + // Then + assertThat(volunteerIds).hasSize(20); + } + + @DisplayName("모집글 ID로 페이징된 봉사 신청 조회") + @Test + void findAllByRecruitId() { + // Given + PageRequest firstPage = PageRequest.of(0, 10, Sort.by(Sort.Order.asc("created_at"))); + PageRequest secondPage = PageRequest.of(1, 10, Sort.by(Sort.Order.asc("created_at"))); + + // When + Page firstPageResult = volunteerApplyRepository.findAllByRecruitId(1L, + firstPage); + Page secondPageResult = volunteerApplyRepository.findAllByRecruitId(1L, + secondPage); + + // Then + assertThat(firstPageResult.getContent()).hasSize(10); + assertThat(firstPageResult.getTotalElements()).isEqualTo(15); + assertThat(firstPageResult.getTotalPages()).isEqualTo(2); + assertThat(firstPageResult.hasNext()).isTrue(); + assertThat(firstPageResult.hasPrevious()).isFalse(); + + assertThat(secondPageResult.getContent()).hasSize(5); + assertThat(secondPageResult.hasNext()).isFalse(); + assertThat(secondPageResult.hasPrevious()).isTrue(); + } + + @DisplayName("모집글 아이디와 봉사자 아이디로 봉사 지원을 조회할 수 있다.") + @Test + void findByRecruitIdAndVolunteerId() { + // given + Long recruitId = 1234L; + UUID volunteerId = UUID.randomUUID(); + + VolunteerApply newApply = VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(recruitId) + .status(ApplyStatus.APPROVED) + .attended(false) + .build(); + volunteerApplyRepository.save(newApply); + + // when + Optional findApply = volunteerApplyRepository.findByRecruitIdAndVolunteerId( + recruitId, volunteerId); + + // then + assertThat(findApply).isPresent(); + } +} From bf242948426a82cfb1ef67149b87e2d5b339d78b Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:15:55 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat(volunteer-apply):=20=EB=A6=AC=EB=B7=B0?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/VolunteerApplyQueryService.java | 39 +++++++++++++++++++ .../usecase/VolunteerApplyQueryUseCase.java | 12 ++++++ 2 files changed, 51 insertions(+) create mode 100644 src/main/java/com/somemore/volunteerapply/service/VolunteerApplyQueryService.java create mode 100644 src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyQueryUseCase.java diff --git a/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyQueryService.java b/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyQueryService.java new file mode 100644 index 000000000..23ab19182 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/service/VolunteerApplyQueryService.java @@ -0,0 +1,39 @@ +package com.somemore.volunteerapply.service; + +import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_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.VolunteerApplyQueryUseCase; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class VolunteerApplyQueryService implements VolunteerApplyQueryUseCase { + + private final VolunteerApplyRepository volunteerApplyRepository; + + @Override + public List getVolunteerIdsByRecruitIds(List recruitIds) { + + return volunteerApplyRepository.findVolunteerIdsByRecruitIds(recruitIds); + } + + @Override + public VolunteerApply getByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId) { + return getVolunteerApplyBy(recruitId, volunteerId); + } + + private VolunteerApply getVolunteerApplyBy(Long recruitBoardId, UUID volunteerId) { + return volunteerApplyRepository.findByRecruitIdAndVolunteerId(recruitBoardId, + volunteerId).orElseThrow( + () -> new BadRequestException(NOT_EXISTS_VOLUNTEER_APPLY.getMessage())); + } +} diff --git a/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyQueryUseCase.java b/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyQueryUseCase.java new file mode 100644 index 000000000..fe4aa4af0 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/usecase/VolunteerApplyQueryUseCase.java @@ -0,0 +1,12 @@ +package com.somemore.volunteerapply.usecase; + +import com.somemore.volunteerapply.domain.VolunteerApply; +import java.util.List; +import java.util.UUID; + +public interface VolunteerApplyQueryUseCase { + + List getVolunteerIdsByRecruitIds(List recruitIds); + VolunteerApply getByRecruitIdAndVolunteerId(Long recruitId, UUID volunteerId); + +} From 34fd9536f862f988ea0e5bb03ae0f68c76dd0b26 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:16:07 +0900 Subject: [PATCH 4/9] =?UTF-8?q?test(volunteer-apply):=20=EB=A6=AC=EB=B7=B0?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VolunteerApplyQueryServiceTest.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java diff --git a/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java b/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java new file mode 100644 index 000000000..d5816cee2 --- /dev/null +++ b/src/test/java/com/somemore/volunteerapply/service/VolunteerApplyQueryServiceTest.java @@ -0,0 +1,82 @@ +package com.somemore.volunteerapply.service; + +import com.somemore.IntegrationTestSupport; +import com.somemore.volunteerapply.domain.ApplyStatus; +import com.somemore.volunteerapply.domain.VolunteerApply; +import com.somemore.volunteerapply.repository.VolunteerApplyRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +@Transactional +class VolunteerApplyQueryServiceTest extends IntegrationTestSupport { + + @Autowired + private VolunteerApplyQueryService volunteerApplyQueryService; + + @Autowired + private VolunteerApplyRepository volunteerApplyRepository; + + @DisplayName("recruitIds로 봉사자 ID 리스트를 조회할 수 있다") + @Test + void getVolunteerIdsByRecruitIds() { + // Given + Long recruitId1 = 1L; + Long recruitId2 = 2L; + UUID volunteerId1 = UUID.randomUUID(); + UUID volunteerId2 = UUID.randomUUID(); + + VolunteerApply apply1 = createVolunteerApply(recruitId1, volunteerId1); + VolunteerApply apply2 = createVolunteerApply(recruitId2, volunteerId2); + + volunteerApplyRepository.save(apply1); + volunteerApplyRepository.save(apply2); + + // When + List volunteerIds = volunteerApplyQueryService.getVolunteerIdsByRecruitIds(List.of(recruitId1, recruitId2)); + + // Then + assertThat(volunteerIds) + .hasSize(2) + .containsExactlyInAnyOrder(volunteerId1, volunteerId2); + } + + private VolunteerApply createVolunteerApply(Long recruitId, UUID volunteerId) { + return VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(recruitId) + .status(ApplyStatus.WAITING) + .attended(false) + .build(); + } + + @DisplayName("모집글 아이디와 봉사자 아이디로 조회할 수 있다") + @Test + void getByRecruitIdAndVolunteerId() { + // given + Long recruitId = 1234L; + UUID volunteerId = UUID.randomUUID(); + + VolunteerApply newApply = VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(recruitId) + .status(ApplyStatus.APPROVED) + .attended(false) + .build(); + volunteerApplyRepository.save(newApply); + + // when + VolunteerApply apply = volunteerApplyQueryService.getByRecruitIdAndVolunteerId( + recruitId, volunteerId); + + // then + assertThat(apply.getRecruitBoardId()).isEqualTo(recruitId); + assertThat(apply.getVolunteerId()).isEqualTo(volunteerId); + } +} From 0ec00c1be101967d1d251972363a153f5272f7a4 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:17:12 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat(review):=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/somemore/domains/Review.java | 27 ---------- .../com/somemore/review/domain/Review.java | 53 +++++++++++++++++++ .../repository/ReviewJpaRepository.java | 15 ++++++ .../review/repository/ReviewRepository.java | 13 +++++ .../repository/ReviewRepositoryImpl.java | 30 +++++++++++ .../volunteerapply/domain/ApplyStatus.java | 7 +++ 6 files changed, 118 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/com/somemore/domains/Review.java create mode 100644 src/main/java/com/somemore/review/domain/Review.java create mode 100644 src/main/java/com/somemore/review/repository/ReviewJpaRepository.java create mode 100644 src/main/java/com/somemore/review/repository/ReviewRepository.java create mode 100644 src/main/java/com/somemore/review/repository/ReviewRepositoryImpl.java create mode 100644 src/main/java/com/somemore/volunteerapply/domain/ApplyStatus.java diff --git a/src/main/java/com/somemore/domains/Review.java b/src/main/java/com/somemore/domains/Review.java deleted file mode 100644 index ee4720bd6..000000000 --- a/src/main/java/com/somemore/domains/Review.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.somemore.domains; - -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; - -import java.util.UUID; - -@Getter -@Setter -@Entity -public class Review { - @Id - @GeneratedValue(strategy = GenerationType.UUID) - private UUID id; - - @Column(name = "center_id", nullable = false, length = 16) - private String centerId; - - @Lob - @Column(name = "content", nullable = false) - private String content; - - @Column(name = "img_url") - private String imgUrl; - -} \ No newline at end of file diff --git a/src/main/java/com/somemore/review/domain/Review.java b/src/main/java/com/somemore/review/domain/Review.java new file mode 100644 index 000000000..b4967407b --- /dev/null +++ b/src/main/java/com/somemore/review/domain/Review.java @@ -0,0 +1,53 @@ +package com.somemore.review.domain; + +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + +import com.somemore.global.common.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.Table; +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = PROTECTED) +@Entity +@Table(name = "review") +public class Review extends BaseEntity { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; + + @Column(name = "volunteer_apply_id", nullable = false) + private Long volunteerApplyId; + + @Column(name = "volunteer_id", nullable = false, length = 16) + private UUID volunteerId; + + @Column(name = "title", nullable = false) + private String title; + + @Lob + @Column(name = "content", nullable = false) + private String content; + + @Column(name = "img_url", nullable = false) + private String imgUrl; + + @Builder + public Review(Long volunteerApplyId, UUID volunteerId, String title, + String content, String imgUrl) { + this.volunteerApplyId = volunteerApplyId; + this.volunteerId = volunteerId; + this.title = title; + this.content = content; + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/somemore/review/repository/ReviewJpaRepository.java b/src/main/java/com/somemore/review/repository/ReviewJpaRepository.java new file mode 100644 index 000000000..694055295 --- /dev/null +++ b/src/main/java/com/somemore/review/repository/ReviewJpaRepository.java @@ -0,0 +1,15 @@ +package com.somemore.review.repository; + +import com.somemore.review.domain.Review; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface ReviewJpaRepository extends JpaRepository { + + Optional findByIdAndDeletedFalse(Long id); + + @Query("SELECT COUNT(r) > 0 FROM Review r WHERE r.volunteerApplyId = :volunteerId AND r.deleted = false") + boolean existsByVolunteerApplyId(Long volunteerId); + +} diff --git a/src/main/java/com/somemore/review/repository/ReviewRepository.java b/src/main/java/com/somemore/review/repository/ReviewRepository.java new file mode 100644 index 000000000..08b817fd8 --- /dev/null +++ b/src/main/java/com/somemore/review/repository/ReviewRepository.java @@ -0,0 +1,13 @@ +package com.somemore.review.repository; + +import com.somemore.review.domain.Review; +import java.util.Optional; + +public interface ReviewRepository { + + Review save(Review review); + + Optional findById(Long id); + + boolean existsByVolunteerApplyId(Long volunteerApplyId); +} diff --git a/src/main/java/com/somemore/review/repository/ReviewRepositoryImpl.java b/src/main/java/com/somemore/review/repository/ReviewRepositoryImpl.java new file mode 100644 index 000000000..856efe188 --- /dev/null +++ b/src/main/java/com/somemore/review/repository/ReviewRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.somemore.review.repository; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.somemore.review.domain.Review; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@RequiredArgsConstructor +@Repository +public class ReviewRepositoryImpl implements ReviewRepository { + + private final ReviewJpaRepository reviewJpaRepository; + private final JPAQueryFactory queryFactory; + + @Override + public Review save(Review review) { + return reviewJpaRepository.save(review); + } + + @Override + public Optional findById(Long id) { + return reviewJpaRepository.findByIdAndDeletedFalse(id); + } + + @Override + public boolean existsByVolunteerApplyId(Long volunteerApplyId) { + return reviewJpaRepository.existsByVolunteerApplyId(volunteerApplyId); + } +} diff --git a/src/main/java/com/somemore/volunteerapply/domain/ApplyStatus.java b/src/main/java/com/somemore/volunteerapply/domain/ApplyStatus.java new file mode 100644 index 000000000..998b52bc3 --- /dev/null +++ b/src/main/java/com/somemore/volunteerapply/domain/ApplyStatus.java @@ -0,0 +1,7 @@ +package com.somemore.volunteerapply.domain; + +public enum ApplyStatus { + WAITING, + APPROVED, + REJECTED, +} From b9b3ba3ad12859a4062cf9b1c400335a322301f0 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:17:39 +0900 Subject: [PATCH 6/9] =?UTF-8?q?test(review):=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=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 --- .../repository/ReviewRepositoryImplTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/test/java/com/somemore/review/repository/ReviewRepositoryImplTest.java diff --git a/src/test/java/com/somemore/review/repository/ReviewRepositoryImplTest.java b/src/test/java/com/somemore/review/repository/ReviewRepositoryImplTest.java new file mode 100644 index 000000000..5a7697c8a --- /dev/null +++ b/src/test/java/com/somemore/review/repository/ReviewRepositoryImplTest.java @@ -0,0 +1,62 @@ +package com.somemore.review.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.somemore.IntegrationTestSupport; +import com.somemore.review.domain.Review; +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; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +class ReviewRepositoryImplTest extends IntegrationTestSupport { + + @Autowired + private ReviewRepositoryImpl reviewRepository; + + @DisplayName("리뷰 생성 및 조회") + @Test + void saveAndFind() { + // given + Review review = Review.builder() + .volunteerApplyId(1L) + .volunteerId(UUID.randomUUID()) + .title("리뷰 제목") + .content("리뷰 내용") + .imgUrl("") + .build(); + reviewRepository.save(review); + + // when + Optional findReview = reviewRepository.findById(review.getId()); + + // then + assertThat(findReview).isPresent(); + assertThat(findReview.get().getId()).isEqualTo(review.getId()); + } + + @DisplayName("봉사 지원 아이디로 리뷰 존재 유무를 확인할 수 있다") + @Test + void existsByVolunteerApplyId() { + // given + Long volunteerApplyId = 1L; + Review review = Review.builder() + .volunteerApplyId(volunteerApplyId) + .volunteerId(UUID.randomUUID()) + .title("리뷰 제목") + .content("리뷰 내용") + .imgUrl("") + .build(); + reviewRepository.save(review); + + // when + boolean result = reviewRepository.existsByVolunteerApplyId(volunteerApplyId); + + // then + assertThat(result).isTrue(); + } + +} From f494ab595badc9050e05ffc190fc92c881ed83de Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:18:01 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat(review):=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ReviewCreateRequestDto.java | 36 +++++++++++++ .../review/service/CreateReviewService.java | 52 +++++++++++++++++++ .../review/usecase/CreateReviewUseCase.java | 11 ++++ 3 files changed, 99 insertions(+) create mode 100644 src/main/java/com/somemore/review/dto/request/ReviewCreateRequestDto.java create mode 100644 src/main/java/com/somemore/review/service/CreateReviewService.java create mode 100644 src/main/java/com/somemore/review/usecase/CreateReviewUseCase.java diff --git a/src/main/java/com/somemore/review/dto/request/ReviewCreateRequestDto.java b/src/main/java/com/somemore/review/dto/request/ReviewCreateRequestDto.java new file mode 100644 index 000000000..8a13cc331 --- /dev/null +++ b/src/main/java/com/somemore/review/dto/request/ReviewCreateRequestDto.java @@ -0,0 +1,36 @@ +package com.somemore.review.dto.request; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.somemore.review.domain.Review; +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(PropertyNamingStrategies.SnakeCaseStrategy.class) +@Builder +public record ReviewCreateRequestDto( + @Schema(description = "봉사 모집글 아이디", example = "1") + @NotNull(message = "봉사 모집글 아이디는 필수 값입니다.") + Long recruitBoardId, + @Schema(description = "리뷰 제목", example = "내 인생 최고의 봉사 활동") + @NotBlank(message = "리뷰 제목은 필수 값입니다.") + String title, + @Schema(description = "리뷰 내용", example = "담당자님도 정말 친절하였고 정말 보람찬 봉사였어요 더보기..
") + @NotBlank(message = "리뷰 내용은 필수 값입니다.") + String content +) { + + public Review toEntity(VolunteerApply apply, UUID volunteerId, String imgUrl) { + return Review.builder() + .volunteerApplyId(apply.getId()) + .volunteerId(volunteerId) + .title(title) + .content(content) + .imgUrl(imgUrl) + .build(); + } +} diff --git a/src/main/java/com/somemore/review/service/CreateReviewService.java b/src/main/java/com/somemore/review/service/CreateReviewService.java new file mode 100644 index 000000000..fa53b6255 --- /dev/null +++ b/src/main/java/com/somemore/review/service/CreateReviewService.java @@ -0,0 +1,52 @@ +package com.somemore.review.service; + +import static com.somemore.global.exception.ExceptionMessage.REVIEW_ALREADY_EXISTS; +import static com.somemore.global.exception.ExceptionMessage.REVIEW_RESTRICTED_TO_ATTENDED; + +import com.somemore.global.exception.BadRequestException; +import com.somemore.review.domain.Review; +import com.somemore.review.dto.request.ReviewCreateRequestDto; +import com.somemore.review.repository.ReviewRepository; +import com.somemore.review.usecase.CreateReviewUseCase; +import com.somemore.volunteerapply.domain.VolunteerApply; +import com.somemore.volunteerapply.usecase.VolunteerApplyQueryUseCase; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional +@Service +public class CreateReviewService implements CreateReviewUseCase { + + private final ReviewRepository reviewRepository; + private final VolunteerApplyQueryUseCase volunteerApplyQueryUseCase; + + @Override + public Long createReview(ReviewCreateRequestDto requestDto, UUID volunteerId, String imgUrl) { + VolunteerApply apply = getVolunteerApply(requestDto.recruitBoardId(), volunteerId); + validateReviewNotExist(apply); + validateActivityCompletion(apply); + + Review review = requestDto.toEntity(apply, volunteerId, imgUrl); + return reviewRepository.save(review).getId(); + } + + private VolunteerApply getVolunteerApply(Long recruitBoardId, UUID volunteerId) { + return volunteerApplyQueryUseCase.getByRecruitIdAndVolunteerId(recruitBoardId, volunteerId); + } + + private void validateReviewNotExist(VolunteerApply apply) { + if (reviewRepository.existsByVolunteerApplyId(apply.getId())) { + throw new BadRequestException(REVIEW_ALREADY_EXISTS.getMessage()); + } + } + + private void validateActivityCompletion(VolunteerApply apply) { + if (apply.isVolunteerActivityCompleted()) { + return; + } + throw new BadRequestException(REVIEW_RESTRICTED_TO_ATTENDED.getMessage()); + } +} diff --git a/src/main/java/com/somemore/review/usecase/CreateReviewUseCase.java b/src/main/java/com/somemore/review/usecase/CreateReviewUseCase.java new file mode 100644 index 000000000..ec2fb7f40 --- /dev/null +++ b/src/main/java/com/somemore/review/usecase/CreateReviewUseCase.java @@ -0,0 +1,11 @@ +package com.somemore.review.usecase; + +import com.somemore.review.dto.request.ReviewCreateRequestDto; +import java.util.UUID; + +public interface CreateReviewUseCase { + + Long createReview(ReviewCreateRequestDto requestDto, UUID volunteerId, String imgUrl); + + +} From 49a48d8fe34d0545d712ea459f032bee63c5a0bf Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:18:10 +0900 Subject: [PATCH 8/9] =?UTF-8?q?test(review):=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/CreateReviewServiceTest.java | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/test/java/com/somemore/review/service/CreateReviewServiceTest.java diff --git a/src/test/java/com/somemore/review/service/CreateReviewServiceTest.java b/src/test/java/com/somemore/review/service/CreateReviewServiceTest.java new file mode 100644 index 000000000..af86b7222 --- /dev/null +++ b/src/test/java/com/somemore/review/service/CreateReviewServiceTest.java @@ -0,0 +1,134 @@ +package com.somemore.review.service; + +import static com.somemore.global.exception.ExceptionMessage.REVIEW_ALREADY_EXISTS; +import static com.somemore.global.exception.ExceptionMessage.REVIEW_RESTRICTED_TO_ATTENDED; +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 static org.junit.jupiter.api.Assertions.*; + +import com.somemore.IntegrationTestSupport; +import com.somemore.global.exception.BadRequestException; +import com.somemore.global.exception.ExceptionMessage; +import com.somemore.review.domain.Review; +import com.somemore.review.dto.request.ReviewCreateRequestDto; +import com.somemore.review.repository.ReviewRepository; +import com.somemore.review.repository.ReviewRepositoryImpl; +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; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +class CreateReviewServiceTest extends IntegrationTestSupport { + + @Autowired + private CreateReviewService createReviewService; + + @Autowired + private ReviewRepository reviewRepository; + + @Autowired + private VolunteerApplyRepository volunteerApplyRepository; + + @DisplayName("리뷰 생성") + @Test + void createReview() { + // given + UUID volunteerId = UUID.randomUUID(); + Long recruitId = 200L; + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(200L) + .status(APPROVED) + .attended(true) + .build(); + volunteerApplyRepository.save(apply); + + ReviewCreateRequestDto requestDto = ReviewCreateRequestDto.builder() + .recruitBoardId(recruitId) + .title("리뷰 제목") + .content("리뷰 내용") + .build(); + + // when + Long reviewId = createReviewService.createReview(requestDto, volunteerId, ""); + + // then + Optional findReview = reviewRepository.findById(reviewId); + assertThat(findReview).isPresent(); + assertThat(findReview.get().getId()).isEqualTo(reviewId); + } + + @DisplayName("참석하지 않은 봉사 활동에 대해 리뷰를 생성하면 에러가 발생한다") + @Test + void createReviewWhenNotCompleted() { + // given + UUID volunteerId = UUID.randomUUID(); + Long recruitId = 200L; + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(200L) + .status(APPROVED) + .attended(false) + .build(); + volunteerApplyRepository.save(apply); + + ReviewCreateRequestDto requestDto = ReviewCreateRequestDto.builder() + .recruitBoardId(recruitId) + .title("리뷰 제목") + .content("리뷰 내용") + .build(); + + // when + // then + assertThatThrownBy( + () -> createReviewService.createReview(requestDto, volunteerId, "") + ).isInstanceOf(BadRequestException.class) + .hasMessage(REVIEW_RESTRICTED_TO_ATTENDED.getMessage()); + } + + @DisplayName("이미 작성한 봉사 활동에 대해 리뷰를 생성하면 에러가 발생한다") + @Test + void createReviewWhenExistsReview() { + // given + UUID volunteerId = UUID.randomUUID(); + Long recruitId = 200L; + VolunteerApply apply = VolunteerApply.builder() + .volunteerId(volunteerId) + .recruitBoardId(200L) + .status(APPROVED) + .attended(false) + .build(); + volunteerApplyRepository.save(apply); + + Review review = Review.builder() + .volunteerApplyId(apply.getId()) + .volunteerId(volunteerId) + .title("리뷰 제목") + .content("리뷰 내용") + .imgUrl("") + .build(); + + reviewRepository.save(review); + + ReviewCreateRequestDto requestDto = ReviewCreateRequestDto.builder() + .recruitBoardId(recruitId) + .title("리뷰 제목") + .content("리뷰 내용") + .build(); + + // when + // then + assertThatThrownBy( + () -> createReviewService.createReview(requestDto, volunteerId, "") + ).isInstanceOf(BadRequestException.class) + .hasMessage(REVIEW_ALREADY_EXISTS.getMessage()); + } + +} From 6fe2c08f0d9ae1520b31602f981d5d38641f7c71 Mon Sep 17 00:00:00 2001 From: leebs0521 Date: Sun, 1 Dec 2024 13:18:31 +0900 Subject: [PATCH 9/9] =?UTF-8?q?feat(review):=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/somemore/global/exception/ExceptionMessage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/somemore/global/exception/ExceptionMessage.java b/src/main/java/com/somemore/global/exception/ExceptionMessage.java index 43a1be574..63d57a856 100644 --- a/src/main/java/com/somemore/global/exception/ExceptionMessage.java +++ b/src/main/java/com/somemore/global/exception/ExceptionMessage.java @@ -21,6 +21,9 @@ public enum ExceptionMessage { FILE_SIZE_EXCEEDED("파일 크기가 허용된 한도를 초과했습니다."), EMPTY_FILE("파일이 존재하지 않습니다."), INSTANTIATION_NOT_ALLOWED("인스턴스화 할 수 없는 클래스 입니다."), + NOT_EXISTS_VOLUNTEER_APPLY("존재하지 않는 봉사 활동 지원입니다."), + REVIEW_ALREADY_EXISTS("이미 작성한 리뷰가 존재합니다."), + REVIEW_RESTRICTED_TO_ATTENDED("리뷰는 참석한 봉사에 한해서만 작성할 수 있습니다.") ; private final String message;