diff --git a/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java b/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java index 64c413054..fe8a4e258 100644 --- a/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java +++ b/src/main/java/com/clova/anifriends/domain/review/controller/ReviewController.java @@ -3,6 +3,7 @@ import com.clova.anifriends.domain.auth.resolver.LoginUser; import com.clova.anifriends.domain.review.dto.request.RegisterReviewRequest; import com.clova.anifriends.domain.review.dto.response.FindReviewResponse; +import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsByVolunteerResponse; import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsResponse; import com.clova.anifriends.domain.review.dto.response.FindVolunteerReviewsResponse; import com.clova.anifriends.domain.review.service.ReviewService; @@ -58,4 +59,14 @@ public ResponseEntity findVolunteerReviews( ) { return ResponseEntity.ok(reviewService.findVolunteerReviews(volunteerId, pageable)); } + + @GetMapping("/volunteers/shelters/{shelterId}/reviews") + public ResponseEntity findShelterReviewsByVolunteer( + @PathVariable("shelterId") Long shelterId, + Pageable pageable + ) { + return ResponseEntity.ok( + reviewService.findShelterReviewsByVolunteer(shelterId, pageable) + ); + } } diff --git a/src/main/java/com/clova/anifriends/domain/review/dto/response/FindShelterReviewsByVolunteerResponse.java b/src/main/java/com/clova/anifriends/domain/review/dto/response/FindShelterReviewsByVolunteerResponse.java new file mode 100644 index 000000000..e22a7df53 --- /dev/null +++ b/src/main/java/com/clova/anifriends/domain/review/dto/response/FindShelterReviewsByVolunteerResponse.java @@ -0,0 +1,49 @@ +package com.clova.anifriends.domain.review.dto.response; + +import com.clova.anifriends.domain.common.PageInfo; +import com.clova.anifriends.domain.review.Review; +import java.time.LocalDateTime; +import java.util.List; +import org.springframework.data.domain.Page; + +public record FindShelterReviewsByVolunteerResponse( + List reviews, + PageInfo pageInfo +) { + + public record FindShelterReviewByVolunteerResponse( + Long reviewId, + Integer temperature, + LocalDateTime createdAt, + String content, + String email, + List reviewImageUrls + ) { + + public static FindShelterReviewByVolunteerResponse from( + Review review + ) { + return new FindShelterReviewByVolunteerResponse( + review.getReviewId(), + review.getApplicant().getVolunteer().getTemperature(), + review.getCreatedAt(), + review.getContent(), + review.getApplicant().getVolunteer().getEmail(), + review.getImageUrls() + ); + } + } + + public static FindShelterReviewsByVolunteerResponse from( + Page reviewPage + ) { + PageInfo pageInfo = PageInfo.of(reviewPage.getTotalElements(), reviewPage.hasNext()); + + List reviews = reviewPage + .map(FindShelterReviewByVolunteerResponse::from) + .stream() + .toList(); + + return new FindShelterReviewsByVolunteerResponse(reviews, pageInfo); + } +} diff --git a/src/main/java/com/clova/anifriends/domain/review/service/ReviewService.java b/src/main/java/com/clova/anifriends/domain/review/service/ReviewService.java index 47b7c4dc8..54ba68368 100644 --- a/src/main/java/com/clova/anifriends/domain/review/service/ReviewService.java +++ b/src/main/java/com/clova/anifriends/domain/review/service/ReviewService.java @@ -5,6 +5,7 @@ import com.clova.anifriends.domain.common.dto.PageInfo; import com.clova.anifriends.domain.review.Review; import com.clova.anifriends.domain.review.dto.response.FindReviewResponse; +import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsByVolunteerResponse; import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsResponse; import com.clova.anifriends.domain.review.dto.response.FindVolunteerReviewsResponse; import com.clova.anifriends.domain.review.exception.ApplicantNotFoundException; @@ -54,6 +55,17 @@ public Long registerReview(Long userId, Long applicationId, String content, return review.getReviewId(); } + @Transactional(readOnly = true) + public FindShelterReviewsByVolunteerResponse findShelterReviewsByVolunteer( + Long shelterId, + Pageable pageable + ) { + Page reviewPage + = reviewRepository.findAllByShelterId(shelterId, pageable); + + return FindShelterReviewsByVolunteerResponse.from(reviewPage); + } + private void validateNotExistReview(Applicant applicant) { if (applicant.hasReview()) { throw new ReviewBadRequestException("이미 작성된 리뷰가 존재합니다."); diff --git a/src/test/java/com/clova/anifriends/domain/review/controller/ReviewControllerTest.java b/src/test/java/com/clova/anifriends/domain/review/controller/ReviewControllerTest.java index 759e0b5ce..93f314fff 100644 --- a/src/test/java/com/clova/anifriends/domain/review/controller/ReviewControllerTest.java +++ b/src/test/java/com/clova/anifriends/domain/review/controller/ReviewControllerTest.java @@ -41,6 +41,7 @@ import com.clova.anifriends.domain.review.Review; import com.clova.anifriends.domain.review.dto.request.RegisterReviewRequest; import com.clova.anifriends.domain.review.dto.response.FindReviewResponse; +import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsByVolunteerResponse; import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsResponse; import com.clova.anifriends.domain.review.dto.response.FindVolunteerReviewsResponse; import com.clova.anifriends.domain.shelter.Shelter; @@ -258,4 +259,62 @@ void findVolunteerReviews() throws Exception { ) )); } + + @Test + @DisplayName("성공: 봉사자가 받은 봉사자 리뷰 목록 조회 api 호출") + void findShelterReviewsByVolunteer() throws Exception { + //given + Long shelterId = 1L; + Shelter shelter = shelter(); + ShelterImage shelterImage = ShelterImageFixture.shelterImage(shelter); + shelter.updateShelterImage(shelterImage); + Recruitment recruitment = recruitment(shelter); + Volunteer volunteer = volunteer(); + VolunteerImage volunteerImage = VolunteerImageFixture.volunteerImage(volunteer); + volunteer.updateVolunteerImage(volunteerImage); + Applicant applicant = applicant(recruitment, volunteer, ATTENDANCE); + Review review = review(applicant); + ReflectionTestUtils.setField(review, "reviewId", 1L); + ReflectionTestUtils.setField(review, "createdAt", LocalDateTime.now()); + PageImpl reviewPage = new PageImpl<>(List.of(review)); + FindShelterReviewsByVolunteerResponse response = FindShelterReviewsByVolunteerResponse.from( + reviewPage); + + given(reviewService.findShelterReviewsByVolunteer(anyLong(), any())).willReturn(response); + + //when + ResultActions resultActions + = mockMvc.perform(get("/api/volunteers/shelters/{shelterId}/reviews", shelterId) + .header(AUTHORIZATION, volunteerAccessToken) + .param("pageNumber", "0") + .param("pageSize", "10")); + + //then + resultActions.andExpect(status().isOk()) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("봉사자 액세스 토큰") + ), + pathParameters( + parameterWithName("shelterId").description("보호소 ID") + ), + queryParameters( + parameterWithName("pageNumber").description("페이지 번호"), + parameterWithName("pageSize").description("페이지 사이즈") + ), + responseFields( + fieldWithPath("reviews").type(ARRAY).description("리뷰 리스트"), + fieldWithPath("reviews[].reviewId").type(NUMBER).description("리뷰 ID"), + fieldWithPath("reviews[].createdAt").type(STRING).description("리뷰 생성일"), + fieldWithPath("reviews[].content").type(STRING).description("리뷰 내용"), + fieldWithPath("reviews[].reviewImageUrls").type(ARRAY) + .description("리뷰 이미지 url 리스트"), + fieldWithPath("reviews[].email").type(STRING).description("봉사자 이메일"), + fieldWithPath("reviews[].temperature").type(NUMBER).description("봉사자 온도"), + fieldWithPath("pageInfo").type(OBJECT).description("페이지 정보"), + fieldWithPath("pageInfo.totalElements").type(NUMBER).description("총 요소 개수"), + fieldWithPath("pageInfo.hasNext").type(BOOLEAN).description("다음 페이지 여부") + ) + )); + } } diff --git a/src/test/java/com/clova/anifriends/domain/review/service/ReviewServiceTest.java b/src/test/java/com/clova/anifriends/domain/review/service/ReviewServiceTest.java index 020942571..ecd3a889f 100644 --- a/src/test/java/com/clova/anifriends/domain/review/service/ReviewServiceTest.java +++ b/src/test/java/com/clova/anifriends/domain/review/service/ReviewServiceTest.java @@ -23,6 +23,7 @@ import com.clova.anifriends.domain.recruitment.Recruitment; import com.clova.anifriends.domain.review.Review; import com.clova.anifriends.domain.review.dto.response.FindReviewResponse; +import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsByVolunteerResponse; import com.clova.anifriends.domain.review.dto.response.FindShelterReviewsResponse; import com.clova.anifriends.domain.review.dto.response.FindVolunteerReviewsResponse; import com.clova.anifriends.domain.review.exception.ApplicantNotFoundException; @@ -218,4 +219,37 @@ void findVolunteerReviews() { .isEqualTo(expected); } } + + @Nested + @DisplayName("findShelterReviewsByVolunteer 메서드 실행 시") + class FindShelterReviewsByVolunteerTest { + + @Test + @DisplayName("성공") + void findShelterReviewsByVolunteer() { + //given + Long shelterId = 1L; + PageRequest pageRequest = PageRequest.of(0, 10); + Shelter shelter = shelter(); + Recruitment recruitment = recruitment(shelter); + Volunteer volunteer = volunteer(); + Applicant applicant = applicant(recruitment, volunteer, ATTENDANCE); + Review review = review(applicant); + PageImpl reviewPage = new PageImpl<>(List.of(review)); + FindShelterReviewsByVolunteerResponse expected = FindShelterReviewsByVolunteerResponse.from( + reviewPage); + + given(reviewRepository.findAllByShelterId(anyLong(), any())) + .willReturn(reviewPage); + + //then + FindShelterReviewsByVolunteerResponse response + = reviewService.findShelterReviewsByVolunteer(shelterId, pageRequest); + + //then + assertThat(response).usingRecursiveComparison() + .ignoringFields("reviewId") + .isEqualTo(expected); + } + } }