From a8f2528ae11706ed6798be57669c77a1a49ffee8 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Thu, 25 Jul 2024 11:49:52 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=82=B4=EA=B0=80=20=EB=B0=9B=EC=9D=80?= =?UTF-8?q?=20=EB=A6=AC=EB=B7=B0=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/controller/ReviewController.java | 9 + .../review/repository/ReviewRepository.java | 15 ++ .../review/service/ReviewService.java | 50 ++++- .../java/reviewme/fixture/MemberFixture.java | 2 + .../review/service/ReviewServiceTest.java | 179 +++++++----------- 5 files changed, 139 insertions(+), 116 deletions(-) diff --git a/backend/src/main/java/reviewme/review/controller/ReviewController.java b/backend/src/main/java/reviewme/review/controller/ReviewController.java index 955492d8c..aded5cfdf 100644 --- a/backend/src/main/java/reviewme/review/controller/ReviewController.java +++ b/backend/src/main/java/reviewme/review/controller/ReviewController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reviewme.review.dto.request.CreateReviewRequest; +import reviewme.review.dto.response.ReceivedReviewsResponse; import reviewme.review.dto.response.ReviewDetailResponse; import reviewme.review.service.ReviewService; @@ -32,4 +33,12 @@ public ResponseEntity findReview(@PathVariable long id, ReviewDetailResponse response = reviewService.findReview(id, memberId); return ResponseEntity.ok(response); } + + @GetMapping("/reviews") + public ResponseEntity findMyReceivedReview(@RequestParam long memberId, + @RequestParam(defaultValue = "9999") long lastReviewId, + @RequestParam(defaultValue = "10") int size) { + ReceivedReviewsResponse myReceivedReview = reviewService.findMyReceivedReview(memberId, lastReviewId, size); + return ResponseEntity.ok(myReceivedReview); + } } diff --git a/backend/src/main/java/reviewme/review/repository/ReviewRepository.java b/backend/src/main/java/reviewme/review/repository/ReviewRepository.java index b9c2a19ab..5a454d413 100644 --- a/backend/src/main/java/reviewme/review/repository/ReviewRepository.java +++ b/backend/src/main/java/reviewme/review/repository/ReviewRepository.java @@ -1,6 +1,10 @@ package reviewme.review.repository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import reviewme.member.domain.Member; import reviewme.member.domain.ReviewerGroup; @@ -15,4 +19,15 @@ public interface ReviewRepository extends JpaRepository { default Review getReviewById(Long id) { return findById(id).orElseThrow(ReviewNotFoundException::new); } + + @Query(""" + SELECT r + FROM Review r + WHERE r.reviewee.id = :revieweeId + AND r.id < :lastViewedReviewId + ORDER BY r.id DESC + """ + ) + Page findAllByRevieweeBeforeLastViewedId(@Param("revieweeId") long revieweeId, + @Param("lastViewedReviewId") long lastViewedReviewId, Pageable pageable); } diff --git a/backend/src/main/java/reviewme/review/service/ReviewService.java b/backend/src/main/java/reviewme/review/service/ReviewService.java index 38614f6a6..eb0083fa4 100644 --- a/backend/src/main/java/reviewme/review/service/ReviewService.java +++ b/backend/src/main/java/reviewme/review/service/ReviewService.java @@ -2,6 +2,8 @@ import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import reviewme.keyword.domain.Keyword; @@ -10,10 +12,13 @@ import reviewme.member.domain.Member; import reviewme.member.domain.ReviewerGroup; import reviewme.member.repository.MemberRepository; -import reviewme.member.repository.ReviewerGroupRepository; import reviewme.review.domain.Review; import reviewme.review.domain.ReviewContent; import reviewme.review.dto.request.CreateReviewRequest; +import reviewme.review.dto.response.ReceivedReviewKeywordsResponse; +import reviewme.review.dto.response.ReceivedReviewResponse; +import reviewme.review.dto.response.ReceivedReviewReviewerGroupResponse; +import reviewme.review.dto.response.ReceivedReviewsResponse; import reviewme.review.dto.response.ReviewDetailResponse; import reviewme.review.dto.response.ReviewDetailReviewContentResponse; import reviewme.review.dto.response.ReviewDetailReviewerGroupResponse; @@ -27,7 +32,6 @@ public class ReviewService { private final ReviewRepository reviewRepository; private final MemberRepository memberRepository; - private final ReviewerGroupRepository reviewerGroupRepository; private final ReviewContentRepository reviewContentRepository; private final KeywordRepository keywordRepository; @@ -75,4 +79,46 @@ public ReviewDetailResponse findReview(long reviewId, long memberId) { keywordContents ); } + + public ReceivedReviewsResponse findMyReceivedReview(long memberId, long lastReviewId, int size) { + PageRequest pageRequest = PageRequest.of(0, size); + Page reviews = reviewRepository.findAllByRevieweeBeforeLastViewedId(memberId, lastReviewId, pageRequest); + + return new ReceivedReviewsResponse( + reviews.getContent().size(), + reviews.getContent().get(reviews.getContent().size() - 1).getId(), + reviews.getContent().stream() + .map(review -> new ReceivedReviewResponse( + review.getId(), + review.isPublic(), + review.getCreatedAt().toLocalDate(), + getReviewContentPreview(review), + new ReceivedReviewReviewerGroupResponse( + review.getReviewerGroup().getId(), + review.getReviewerGroup().getGroupName(), + review.getReviewerGroup().getThumbnailUrl() + ), + getKeywordResponse(review))) + .toList()); + } + + private String getReviewContentPreview(Review review) { + String answer = reviewContentRepository.findAllByReviewId(review.getId()) + .get(0) + .getAnswer(); + if (answer.length() > 150) { + return answer.substring(0, 150); + } + return answer; + } + + private List getKeywordResponse(Review review) { + return review.getKeywords().getKeywordIds().stream() + .map(keywordRepository::getKeywordById) + .map(keyword -> new ReceivedReviewKeywordsResponse( + keyword.getId(), + keyword.getContent() + )) + .toList(); + } } diff --git a/backend/src/test/java/reviewme/fixture/MemberFixture.java b/backend/src/test/java/reviewme/fixture/MemberFixture.java index 8959a9616..b278ee8ce 100644 --- a/backend/src/test/java/reviewme/fixture/MemberFixture.java +++ b/backend/src/test/java/reviewme/fixture/MemberFixture.java @@ -10,6 +10,8 @@ public enum MemberFixture { 회원_산초("산초", 1L), 회원_아루("아루", 2L), + 회원_커비("커비", 3L), + 회원_테드("테드", 4L), ; private final String name; diff --git a/backend/src/test/java/reviewme/review/service/ReviewServiceTest.java b/backend/src/test/java/reviewme/review/service/ReviewServiceTest.java index 20ba55c12..be515b1c1 100644 --- a/backend/src/test/java/reviewme/review/service/ReviewServiceTest.java +++ b/backend/src/test/java/reviewme/review/service/ReviewServiceTest.java @@ -1,11 +1,13 @@ -/* package reviewme.review.service; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static reviewme.fixture.KeywordFixture.꼼꼼하게_기록해요; +import static org.junit.jupiter.api.Assertions.assertAll; +import static reviewme.fixture.KeywordFixture.추진력이_좋아요; import static reviewme.fixture.KeywordFixture.회의를_이끌어요; -import static reviewme.fixture.ReviewerGroupFixture.리뷰_그룹; +import static reviewme.fixture.MemberFixture.회원_산초; +import static reviewme.fixture.MemberFixture.회원_아루; +import static reviewme.fixture.MemberFixture.회원_커비; +import static reviewme.fixture.MemberFixture.회원_테드; import java.time.LocalDateTime; import java.util.List; @@ -13,19 +15,16 @@ import org.springframework.beans.factory.annotation.Autowired; import reviewme.keyword.domain.Keyword; import reviewme.keyword.repository.KeywordRepository; -import reviewme.member.domain.GithubReviewerGroup; +import reviewme.member.domain.GithubId; import reviewme.member.domain.Member; import reviewme.member.domain.ReviewerGroup; -import reviewme.member.repository.GithubReviewerGroupRepository; import reviewme.member.repository.MemberRepository; import reviewme.member.repository.ReviewerGroupRepository; +import reviewme.review.domain.Question; import reviewme.review.domain.Review; -import reviewme.review.domain.exception.DeadlineExpiredException; -import reviewme.review.dto.request.CreateReviewContentRequest; -import reviewme.review.dto.request.CreateReviewRequest; -import reviewme.review.dto.response.ReviewDetailResponse; -import reviewme.review.exception.GithubReviewerGroupUnAuthorizedException; -import reviewme.review.exception.ReviewAlreadySubmittedException; +import reviewme.review.domain.ReviewContent; +import reviewme.review.dto.response.ReceivedReviewsResponse; +import reviewme.review.repository.QuestionRepository; import reviewme.review.repository.ReviewContentRepository; import reviewme.review.repository.ReviewRepository; import reviewme.support.ServiceTest; @@ -45,124 +44,76 @@ class ReviewServiceTest { @Autowired ReviewerGroupRepository reviewerGroupRepository; - @Autowired - GithubReviewerGroupRepository githubReviewerGroupRepository; - @Autowired KeywordRepository keywordRepository; @Autowired ReviewContentRepository reviewContentRepository; + @Autowired + QuestionRepository questionRepository; + @Test - void 리뷰를_작성한다() { + void 내가_받은_리뷰를_조회한다(){ // given - memberRepository.save(new Member("산초", "sancho")); - Member reviewee = memberRepository.save(new Member("아루", "aru")); - ReviewerGroup reviewerGroup = reviewerGroupRepository.save( - new ReviewerGroup(reviewee, "그룹A", "그룹 설명", LocalDateTime.now().minusDays(1)) - ); - githubReviewerGroupRepository.save(new GithubReviewerGroup("sancho", reviewerGroup)); - Keyword keyword1 = keywordRepository.save(꼼꼼하게_기록해요.create()); + Member reviewee = memberRepository.save(회원_아루.create()); + Member reviewerSancho = memberRepository.save(회원_산초.create()); + Member reviewerKirby = memberRepository.save(회원_커비.create()); + Member reviewerTed = memberRepository.save(회원_테드.create()); + Keyword keyword1 = keywordRepository.save(추진력이_좋아요.create()); Keyword keyword2 = keywordRepository.save(회의를_이끌어요.create()); - - CreateReviewContentRequest contentRequest1 = new CreateReviewContentRequest( - 1L, "소프트스킬이 어떤가요?", "소통을 잘해요" + ReviewerGroup reviewerGroup = reviewerGroupRepository.save(new ReviewerGroup( + reviewee, + List.of(new GithubId(회원_산초.getGithubId()), new GithubId(회원_커비.getGithubId()), + new GithubId(회원_테드.getGithubId())), + "빼깬드그룹", + "빼깬드그룹 설명", + LocalDateTime.now().plusDays(3) + )); + Question question1 = questionRepository.save(new Question("질문1")); + + Review sanchoReview = reviewRepository.save( + new Review(reviewerSancho, reviewee, reviewerGroup, List.of(keyword1), LocalDateTime.now().minusDays(1)) ); - CreateReviewContentRequest contentRequest2 = new CreateReviewContentRequest( - 2L, "기술역량이 어떤가요?", "스트림을 잘다뤄요" + reviewContentRepository.save( + new ReviewContent(sanchoReview, question1, "산초의 답변1".repeat(50)) ); - CreateReviewRequest createReviewRequest = new CreateReviewRequest( - 1L, - 1L, - List.of(contentRequest1, contentRequest2), - List.of(keyword1.getId(), keyword2.getId()) + Review kirbyReview = reviewRepository.save( + new Review(reviewerKirby, reviewee, reviewerGroup, List.of(keyword2), LocalDateTime.now()) ); - - // when - reviewService.createReview(createReviewRequest); - - // then - List actual = reviewRepository.findAll(); - assertThat(actual).hasSize(1); - } - - @Test - void 리뷰를_조회한다() { - // given - Member reviewer = memberRepository.save(new Member("테드", "ted")); - Member reviewee = memberRepository.save(new Member("아루", "aru")); - memberRepository.save(new Member("산초", "sancho")); - ReviewerGroup reviewerGroup = reviewerGroupRepository.save(리뷰_그룹.create(reviewee)); - Review review = reviewRepository.save(new Review(reviewer, reviewerGroup, LocalDateTime.now())); - - // when - ReviewDetailResponse response = reviewService.findReview(review.getId()); - - // then - Long id = response.id(); - assertThat(id).isEqualTo(review.getId()); - } - - @Test - void 리뷰어_그룹에_속하지_않는_리뷰어가_리뷰를_작성할_경우_예외를_발생한다() { - // given - Member reviewee = memberRepository.save(new Member("아루", "aru")); - Member reviewer = memberRepository.save(new Member("테드", "ted")); - ReviewerGroup reviewerGroup = reviewerGroupRepository.save(리뷰_그룹.create(reviewee)); - githubReviewerGroupRepository.save(new GithubReviewerGroup("kirby", reviewerGroup)); - - CreateReviewRequest createReviewRequest = new CreateReviewRequest( - reviewer.getId(), - reviewerGroup.getId(), - List.of(), - List.of() + reviewContentRepository.save( + new ReviewContent(kirbyReview, question1, "커비의 답변1".repeat(50)) ); - - // when, then - assertThatThrownBy(() -> reviewService.createReview(createReviewRequest)) - .isInstanceOf(GithubReviewerGroupUnAuthorizedException.class); - } - - @Test - void 이미_작성한_리뷰가_있는데_리뷰를_작성할_경우_예외를_발생한다() { - // given - Member reviewee = memberRepository.save(new Member("아루", "aru")); - Member reviewer = memberRepository.save(new Member("테드", "ted")); - ReviewerGroup reviewerGroup = reviewerGroupRepository.save(리뷰_그룹.create(reviewee)); - githubReviewerGroupRepository.save(new GithubReviewerGroup("ted", reviewerGroup)); - - CreateReviewRequest createReviewRequest = new CreateReviewRequest( - reviewer.getId(), - reviewerGroup.getId(), - List.of(), - List.of() + Review tedReview = reviewRepository.save( + new Review(reviewerTed, reviewee, reviewerGroup, List.of(keyword1, keyword2), LocalDateTime.now().plusDays(1)) + ); + reviewContentRepository.save( + new ReviewContent(tedReview, question1, "테드의 답변1".repeat(50)) ); - reviewRepository.save(new Review(reviewer, reviewerGroup, LocalDateTime.now())); - - // when, then - assertThatThrownBy(() -> reviewService.createReview(createReviewRequest)) - .isInstanceOf(ReviewAlreadySubmittedException.class); - } + // when + ReceivedReviewsResponse 가장_최근에_받은_리뷰_조회 + = reviewService.findMyReceivedReview(reviewee.getId(), 999, 2); + ReceivedReviewsResponse 특정_리뷰_이전_리뷰_조회 + = reviewService.findMyReceivedReview(reviewee.getId(), 2, 2); - @Test - void 데드라인이_지난_리뷰그룹에_대해_리뷰를_작성하려하면_예외가_발생한다() { - // given - memberRepository.save(new Member("산초", "sancho")); - Member reviewee = memberRepository.save(new Member("아루", "aru")); - LocalDateTime createdAt = LocalDateTime.now().minusDays(7).minusMinutes(1); - ReviewerGroup reviewerGroup = reviewerGroupRepository.save( - new ReviewerGroup(reviewee, "그룹A", "그룹 설명", createdAt) - ); - githubReviewerGroupRepository.save(new GithubReviewerGroup("sancho", reviewerGroup)); - CreateReviewRequest createReviewRequest = new CreateReviewRequest( - 1L, 1L, List.of(), List.of() + // then + assertAll( + () -> assertThat(가장_최근에_받은_리뷰_조회.reviews().size()) + .isEqualTo(2), + () -> assertThat(가장_최근에_받은_리뷰_조회.reviews().get(0).id()) + .isEqualTo(tedReview.getId()), + () -> assertThat(가장_최근에_받은_리뷰_조회.reviews().get(1).id()) + .isEqualTo(kirbyReview. getId()), + () -> assertThat(가장_최근에_받은_리뷰_조회.reviews().get(0).contentPreview().length()) + .isLessThanOrEqualTo(150), + + () -> assertThat(특정_리뷰_이전_리뷰_조회.reviews().size()) + .isEqualTo(1), + () -> assertThat(특정_리뷰_이전_리뷰_조회.reviews().get(0).id()) + .isEqualTo(sanchoReview.getId()), + () -> assertThat(특정_리뷰_이전_리뷰_조회.reviews().get(0).contentPreview().length()) + .isLessThanOrEqualTo(150) ); - - // when, then - assertThatThrownBy(() -> reviewService.createReview(createReviewRequest)) - .isInstanceOf(DeadlineExpiredException.class); } } -*/