From 056ca040d9d23a529ff2fe05a758130b834800ad Mon Sep 17 00:00:00 2001 From: kimdohyung Date: Thu, 30 May 2024 16:54:08 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=EB=8F=85=EC=84=9C=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?rest=20docs=20=EC=B6=94=EA=B0=80=20(#109)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asciidoc/api/userlibrary/userlibrary.adoc | 12 +++ .../application/rating/RatingService.java | 6 +- .../response/UserReadingStatusResponse.java | 5 +- .../repository/UserLibraryRepositoryImpl.java | 3 +- .../application/rating/RatingServiceTest.java | 18 +++- .../docs/user/UserControllerDocsTest.java | 82 +++++++++++++++++++ 6 files changed, 122 insertions(+), 4 deletions(-) diff --git a/src/docs/asciidoc/api/userlibrary/userlibrary.adoc b/src/docs/asciidoc/api/userlibrary/userlibrary.adoc index b09859d..2c11aa6 100644 --- a/src/docs/asciidoc/api/userlibrary/userlibrary.adoc +++ b/src/docs/asciidoc/api/userlibrary/userlibrary.adoc @@ -60,3 +60,15 @@ include::{snippets}/user-library/delete/path-parameters.adoc[] ===== Response Body include::{snippets}/user-library/delete/response-body.adoc[] include::{snippets}/user-library/delete/response-fields.adoc[] + +=== 독서 상태 페이지 조회 + +==== HTTP Request +include::{snippets}/user-library/get-status/http-request.adoc[] +include::{snippets}/user-library/get-status/query-parameters.adoc[] + +==== HTTP Response +include::{snippets}/user-library/get-status/http-response.adoc[] +===== Response Body +include::{snippets}/user-library/get-status/response-body.adoc[] +include::{snippets}/user-library/get-status/response-fields.adoc[] \ No newline at end of file diff --git a/src/main/java/com/jisungin/application/rating/RatingService.java b/src/main/java/com/jisungin/application/rating/RatingService.java index 84d6550..56d01bd 100644 --- a/src/main/java/com/jisungin/application/rating/RatingService.java +++ b/src/main/java/com/jisungin/application/rating/RatingService.java @@ -54,7 +54,11 @@ public RatingGetOneResponse getRating(Long userId, String isbn) { .orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); Rating rating = ratingRepository.findRatingByUserAndBook(user, book) - .orElseThrow(() -> new BusinessException(RATING_NOT_FOUND)); + .orElse(null); + + if (rating == null) { + return RatingGetOneResponse.of(null, null, book.getIsbn()); + } return RatingGetOneResponse.of(rating.getId(), rating.getRating(), book.getIsbn()); } diff --git a/src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java b/src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java index 596f708..bf86f2b 100644 --- a/src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java +++ b/src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java @@ -9,6 +9,8 @@ @NoArgsConstructor public class UserReadingStatusResponse { + private String isbn; + private String bookImage; private String bookTitle; @@ -17,7 +19,8 @@ public class UserReadingStatusResponse { @QueryProjection @Builder - public UserReadingStatusResponse(String bookImage, String bookTitle, Double ratingAvg) { + public UserReadingStatusResponse(String isbn, String bookImage, String bookTitle, Double ratingAvg) { + this.isbn = isbn; this.bookImage = bookImage; this.bookTitle = bookTitle; this.ratingAvg = ratingAvg; diff --git a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java b/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java index 669b77d..790185e 100644 --- a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java +++ b/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java @@ -27,7 +27,8 @@ public PageResponse findAllReadingStatusOrderBy( Long userId, ReadingStatus readingStatus, ReadingStatusOrderType orderType, int size, int offset) { log.info("--------------start--------------"); List userReadingStatuses = queryFactory - .select(new QUserReadingStatusResponse(userLibrary.book.imageUrl, userLibrary.book.title, rating1.rating.avg())) + .select(new QUserReadingStatusResponse( + userLibrary.book.isbn, userLibrary.book.imageUrl, userLibrary.book.title, rating1.rating.avg())) .from(userLibrary) .join(rating1).on(userLibrary.book.eq(rating1.book)) .where(userLibrary.user.id.eq(userId), userLibrary.status.eq(readingStatus)) diff --git a/src/test/java/com/jisungin/application/rating/RatingServiceTest.java b/src/test/java/com/jisungin/application/rating/RatingServiceTest.java index 7b62f73..d8c5d98 100644 --- a/src/test/java/com/jisungin/application/rating/RatingServiceTest.java +++ b/src/test/java/com/jisungin/application/rating/RatingServiceTest.java @@ -85,7 +85,7 @@ void createRatingTwice() { .hasMessage("이미 별점이 존재합니다."); } - @DisplayName("유저가 해당 책의 별점을 조회한다.") + @DisplayName("유저가 해당 등록한 별점을 조회한다.") @Test void getRating() { //given @@ -102,6 +102,22 @@ void getRating() { assertThat(result.getIsbn()).isEqualTo(savadRating.getBook().getIsbn()); } + @DisplayName("유저가 해당 등록하지 않은 책의 별점을 조회한다.") + @Test + void getRatingWithEmpty() { + //given + User user = userRepository.save(createUser("1")); + Book book = bookRepository.save(createBook("제목1", "내용1", "1234")); + + //when + RatingGetOneResponse result = ratingService.getRating(user.getId(), book.getIsbn()); + + //then + assertThat(result.getId()).isNull(); + assertThat(result.getRating()).isNull(); + assertThat(result.getIsbn()).isEqualTo(book.getIsbn()); + } + @DisplayName("유저가 별점을 수정한다.") @Test void updateRating() { diff --git a/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java b/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java index 0d893df..53eb2b8 100644 --- a/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java +++ b/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java @@ -8,7 +8,9 @@ import com.jisungin.application.user.UserService; import com.jisungin.application.user.request.ReviewContentGetAllServiceRequest; import com.jisungin.application.user.request.UserRatingGetAllServiceRequest; +import com.jisungin.application.user.request.UserReadingStatusGetAllServiceRequest; import com.jisungin.application.user.response.UserInfoResponse; +import com.jisungin.application.userlibrary.response.UserReadingStatusResponse; import com.jisungin.docs.RestDocsSupport; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -192,6 +194,75 @@ void getUserReviews() throws Exception { )); } + @DisplayName("유저 독서 상태 페이징 조회 API") + @Test + void getReadingStatuses() throws Exception { + List readingStatusesResponse = createReadingStatusResponse(); + + PageResponse response = PageResponse.builder() + .size(10) + .totalCount(10) + .queryResponse(readingStatusesResponse) + .build(); + + given(userService.getUserReadingStatuses(anyLong(), any(UserReadingStatusGetAllServiceRequest.class))) + .willReturn(response); + + mockMvc.perform(get("/v1/users/statuses") + .param("page", "1") + .param("size", "10") + .param("order", "dictionary") + .param("status", "want") + .contentType(APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value("200")) + .andExpect(jsonPath("$.status").value("OK")) + .andExpect(jsonPath("$.message").value("OK")) + .andDo(print()) + .andDo(document("user-library/get-status", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + queryParameters( + parameterWithName("page") + .description("페이지 번호"), + parameterWithName("size") + .description("페이지 사이즈"), + parameterWithName("order") + .description( + "정렬 기준 : dictionary(가나다순), rating_avg_desc(평균 별점 높은 순)"), + parameterWithName("status") + .description( + "선택 기준 : want(읽고 싶은), reading(읽는 중), pause(잠시 멈춤)," + + "stop(중단), none(상관없음)") + ), + responseFields( + fieldWithPath("code").type(JsonFieldType.NUMBER) + .description("코드"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("상태"), + fieldWithPath("message").type(JsonFieldType.STRING) + .description("메시지"), + fieldWithPath("data").type(JsonFieldType.OBJECT) + .description("응답 데이터"), + fieldWithPath("data.queryResponse").type(JsonFieldType.ARRAY) + .description("책 목록"), + fieldWithPath("data.queryResponse[].isbn").type(JsonFieldType.STRING) + .description("책 isbn"), + fieldWithPath("data.queryResponse[].bookTitle").type(JsonFieldType.STRING) + .description("책 제목"), + fieldWithPath("data.queryResponse[].bookImage").type(JsonFieldType.STRING) + .description("책 표지"), + fieldWithPath("data.queryResponse[].ratingAvg").type(JsonFieldType.NUMBER) + .description("책 평균 별점"), + fieldWithPath("data.totalCount").type(JsonFieldType.NUMBER) + .description("데이터 총 개수"), + fieldWithPath("data.size").type(JsonFieldType.NUMBER) + .description("해당 페이지 데이터 개수") + ) + )); + } + @DisplayName("유저 상세 조회 API") @Test void getUserInfo() throws Exception { @@ -263,4 +334,15 @@ private List createLikeReviewIds() { .collect(Collectors.toList()); } + private List createReadingStatusResponse() { + return IntStream.range(0, 10) + .mapToObj(i -> UserReadingStatusResponse.builder() + .isbn(String.valueOf(i)) + .bookTitle("책 제목" + i) + .bookImage("책 표지" + i) + .ratingAvg(i % 5.0 + 1) + .build()) + .toList(); + } + } From 5afa03b24bf511b0831c811330daf104db6bd07f Mon Sep 17 00:00:00 2001 From: kimdohyung Date: Thu, 30 May 2024 22:14:38 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EA=B0=80=20=EB=B3=84=EC=A0=90=20=EB=8B=A8=EC=9D=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=8B=9C=20=EC=98=88=EC=99=B8=EA=B0=80=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#109)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/rating/RatingService.java | 4 ++-- .../application/rating/RatingServiceTest.java | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/jisungin/application/rating/RatingService.java b/src/main/java/com/jisungin/application/rating/RatingService.java index 56d01bd..95bf632 100644 --- a/src/main/java/com/jisungin/application/rating/RatingService.java +++ b/src/main/java/com/jisungin/application/rating/RatingService.java @@ -48,7 +48,7 @@ public RatingCreateResponse creatingRating(Long userId, RatingCreateServiceReque public RatingGetOneResponse getRating(Long userId, String isbn) { User user = userRepository.findById(userId) - .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + .orElse(null); Book book = bookRepository.findById(isbn) .orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); @@ -56,7 +56,7 @@ public RatingGetOneResponse getRating(Long userId, String isbn) { Rating rating = ratingRepository.findRatingByUserAndBook(user, book) .orElse(null); - if (rating == null) { + if (rating == null || user == null) { return RatingGetOneResponse.of(null, null, book.getIsbn()); } diff --git a/src/test/java/com/jisungin/application/rating/RatingServiceTest.java b/src/test/java/com/jisungin/application/rating/RatingServiceTest.java index d8c5d98..1b0cb5a 100644 --- a/src/test/java/com/jisungin/application/rating/RatingServiceTest.java +++ b/src/test/java/com/jisungin/application/rating/RatingServiceTest.java @@ -118,6 +118,21 @@ void getRatingWithEmpty() { assertThat(result.getIsbn()).isEqualTo(book.getIsbn()); } + @DisplayName("게스트가 책의 별점을 조회한다.") + @Test + void getRatingWithGuest() { + //given + Book book = bookRepository.save(createBook("제목1", "내용1", "1234")); + + //when + RatingGetOneResponse result = ratingService.getRating(-1L, book.getIsbn()); + + //then + assertThat(result.getId()).isNull(); + assertThat(result.getRating()).isNull(); + assertThat(result.getIsbn()).isEqualTo(book.getIsbn()); + } + @DisplayName("유저가 별점을 수정한다.") @Test void updateRating() { From bd6909c5e90acdd608beab4f7ee4aadd62e9d63f Mon Sep 17 00:00:00 2001 From: kimdohyung Date: Fri, 31 May 2024 20:51:39 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=ED=95=9C=EC=A4=84=ED=8F=89=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20?= =?UTF-8?q?=EC=A0=80=EC=9E=90=EC=99=80=20=EC=B6=9C=ED=8C=90=EC=82=AC?= =?UTF-8?q?=EB=8F=84=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#109)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/response/ReviewContentResponse.java | 12 ++++++++---- .../review/repository/ReviewRepositoryImpl.java | 3 ++- .../jisungin/docs/user/UserControllerDocsTest.java | 9 +++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/jisungin/application/review/response/ReviewContentResponse.java b/src/main/java/com/jisungin/application/review/response/ReviewContentResponse.java index 862c9ec..16807ea 100644 --- a/src/main/java/com/jisungin/application/review/response/ReviewContentResponse.java +++ b/src/main/java/com/jisungin/application/review/response/ReviewContentResponse.java @@ -25,11 +25,14 @@ public class ReviewContentResponse { private String bookImage; + private String authors; + + private String publisher; + @Builder @QueryProjection - public ReviewContentResponse( - Long reviewId, String userImage, String userName, Double rating, String content, - String isbn, String title, String bookImage) { + public ReviewContentResponse(Long reviewId, String userImage, String userName, Double rating, String content, + String isbn, String title, String bookImage, String authors, String publisher) { this.reviewId = reviewId; this.userImage = userImage; this.userName = userName; @@ -38,6 +41,7 @@ public ReviewContentResponse( this.isbn = isbn; this.title = title; this.bookImage = bookImage; + this.authors = authors; + this.publisher = publisher; } - } diff --git a/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryImpl.java b/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryImpl.java index 9050df5..7b01aae 100644 --- a/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryImpl.java +++ b/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryImpl.java @@ -82,7 +82,8 @@ private List getReviewContents( return queryFactory .select(new QReviewContentResponse( review.id, review.user.profileImage, review.user.name, rating1.rating, review.content, - review.book.isbn, review.book.title, review.book.imageUrl + review.book.isbn, review.book.title, review.book.imageUrl, review.book.authors, + review.book.publisher )) .from(review) .leftJoin(rating1).on(review.user.eq(rating1.user), review.book.eq(rating1.book)) diff --git a/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java b/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java index 53eb2b8..00015ae 100644 --- a/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java +++ b/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java @@ -181,9 +181,12 @@ void getUserReviews() throws Exception { .description("책 ISBN"), fieldWithPath("data.reviewContents.queryResponse[].title").type(JsonFieldType.STRING) .description("책 제목"), - fieldWithPath("data.reviewContents.queryResponse[].bookImage").type( - JsonFieldType.STRING) + fieldWithPath("data.reviewContents.queryResponse[].bookImage").type(JsonFieldType.STRING) .description("책 표지"), + fieldWithPath("data.reviewContents.queryResponse[].authors").type(JsonFieldType.STRING) + .description("책 저자"), + fieldWithPath("data.reviewContents.queryResponse[].publisher").type(JsonFieldType.STRING) + .description("책 출판사"), fieldWithPath("data.reviewContents.totalCount").type(JsonFieldType.NUMBER) .description("총 리뷰 개수"), fieldWithPath("data.reviewContents.size").type(JsonFieldType.NUMBER) @@ -323,6 +326,8 @@ private List createReviewFindAllResponse() { .isbn(String.valueOf(i)) .title("title" + i) .bookImage("bookImage" + i) + .authors("저자" + i) + .publisher("출판사" + i) .build()) .toList(); }