diff --git a/src/docs/asciidoc/api/library/library.adoc b/src/docs/asciidoc/api/library/library.adoc new file mode 100644 index 0000000..7654c23 --- /dev/null +++ b/src/docs/asciidoc/api/library/library.adoc @@ -0,0 +1,46 @@ +=== 서재 조회 +==== HTTP Request +include::{snippets}/library/get/http-request.adoc[] + +==== HTTP Response +include::{snippets}/library/get/http-response.adoc[] +include::{snippets}/library/get/response-fields.adoc[] + +=== 서재 생성 +==== HTTP Request +include::{snippets}/library/create/http-request.adoc[] +===== Request Body +include::{snippets}/library/create/request-body.adoc[] +include::{snippets}/library/create/request-fields.adoc[] + +==== HTTP Response +include::{snippets}/library/create/http-response.adoc[] +include::{snippets}/library/create/response-fields.adoc[] + +=== 서재 수정 +==== HTTP Request +include::{snippets}/library/edit/http-request.adoc[] +===== Request Body +include::{snippets}/library/edit/request-body.adoc[] +include::{snippets}/library/edit/request-fields.adoc[] + +==== HTTP Response +include::{snippets}/library/edit/http-response.adoc[] +include::{snippets}/library/edit/response-fields.adoc[] + +=== 서재 삭제 +==== HTTP Request +include::{snippets}/library/delete/http-request.adoc[] + +==== HTTP Response +include::{snippets}/library/delete/http-response.adoc[] +include::{snippets}/library/delete/response-fields.adoc[] + +=== 독서 상태 페이지 조회 +==== HTTP Request +include::{snippets}/library/get-status/http-request.adoc[] +include::{snippets}/library/get-status/query-parameters.adoc[] + +==== HTTP Response +include::{snippets}/library/get-status/http-response.adoc[] +include::{snippets}/library/get-status/response-fields.adoc[] diff --git a/src/docs/asciidoc/api/review/review.adoc b/src/docs/asciidoc/api/review/review.adoc index 954148f..39e156f 100644 --- a/src/docs/asciidoc/api/review/review.adoc +++ b/src/docs/asciidoc/api/review/review.adoc @@ -13,6 +13,15 @@ include::{snippets}/review/get-related-book/query-parameters.adoc[] include::{snippets}/review/get-related-book/http-response.adoc[] include::{snippets}/review/get-related-book/response-fields.adoc[] +=== 도서와 연관된 리뷰 개수 조회 +==== HTTP Request +include::{snippets}/review/get-related-book-count/http-request.adoc[] +include::{snippets}/review/get-related-book-count/path-parameters.adoc[] + +==== HTTP Response +include::{snippets}/review/get-related-book-count/http-response.adoc[] +include::{snippets}/review/get-related-book-count/response-fields.adoc[] + === 한줄평 생성 ==== HTTP Request diff --git a/src/docs/asciidoc/api/userlibrary/userlibrary.adoc b/src/docs/asciidoc/api/userlibrary/userlibrary.adoc deleted file mode 100644 index 2c11aa6..0000000 --- a/src/docs/asciidoc/api/userlibrary/userlibrary.adoc +++ /dev/null @@ -1,74 +0,0 @@ -=== 서재 단건 조회 - -image::https://jisungin-bucket.s3.ap-northeast-2.amazonaws.com/docs/get-userlibrary.png[] - -TIP: 상세 조회된 도서에 대한 사용자의 도서 상태를 조회 - -==== HTTP Request -include::{snippets}/user-library/get/http-request.adoc[] -include::{snippets}/user-library/get/query-parameters.adoc[] - -==== HTTP Response -include::{snippets}/user-library/get/http-response.adoc[] -===== Response Body -include::{snippets}/user-library/get/response-body.adoc[] -include::{snippets}/user-library/get/response-fields.adoc[] - -=== 서재 등록 - -TIP: 상세 조회된 도서에 대한 도서 상태를 생성 - -==== HTTP Request -include::{snippets}/user-library/create/http-request.adoc[] -===== Request Body -include::{snippets}/user-library/create/request-body.adoc[] -include::{snippets}/user-library/create/request-fields.adoc[] - -==== HTTP Response -include::{snippets}/user-library/create/http-response.adoc[] -===== Response Body -include::{snippets}/user-library/create/response-body.adoc[] -include::{snippets}/user-library/create/response-fields.adoc[] - -=== 서재 수정 - -TIP: 상세 조회된 도서에 대한 도서 상태를 수정 - -==== HTTP Request -include::{snippets}/user-library/edit/http-request.adoc[] -include::{snippets}/user-library/edit/path-parameters.adoc[] -===== Request Body -include::{snippets}/user-library/edit/request-body.adoc[] -include::{snippets}/user-library/edit/request-fields.adoc[] - -==== HTTP Response -include::{snippets}/user-library/edit/http-response.adoc[] -===== Response Body -include::{snippets}/user-library/edit/response-body.adoc[] -include::{snippets}/user-library/edit/response-fields.adoc[] - -=== 서재 삭제 - -TIP: 상세 조회된 도서에 대한 도서 상태를 삭제 - -==== HTTP Request -include::{snippets}/user-library/delete/http-request.adoc[] - -==== HTTP Response -include::{snippets}/user-library/delete/http-response.adoc[] -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/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 3a8c2b1..e0677a3 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -43,9 +43,9 @@ include::api/book/book.adoc[] == User API include::api/user/user.adoc[] -[[UserLibrary-API]] -== UserLibrary API -include::api/userlibrary/userlibrary.adoc[] +[[Library-API]] +== Library API +include::api/library/library.adoc[] [[Rating-API]] == Rating API diff --git a/src/main/java/com/jisungin/api/library/LibraryController.java b/src/main/java/com/jisungin/api/library/LibraryController.java new file mode 100644 index 0000000..79201d3 --- /dev/null +++ b/src/main/java/com/jisungin/api/library/LibraryController.java @@ -0,0 +1,59 @@ +package com.jisungin.api.library; + +import com.jisungin.api.ApiResponse; +import com.jisungin.api.library.request.LibraryCreateRequest; +import com.jisungin.api.library.request.LibraryEditRequest; +import com.jisungin.api.support.Auth; +import com.jisungin.application.library.LibraryService; +import com.jisungin.application.library.response.LibraryResponse; +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +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; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v1") +public class LibraryController { + + private final LibraryService libraryService; + + @GetMapping("/libraries") + public ApiResponse> findLibraries(@Auth Long userId) { + return ApiResponse.ok(libraryService.findLibraries(userId)); + } + + @PostMapping("/libraries") + public ApiResponse createLibrary(@Valid @RequestBody LibraryCreateRequest request, + @Auth Long userId + ) { + return ApiResponse.ok(libraryService.createLibrary(request.toServiceRequest(), userId)); + } + + @PatchMapping("/libraries/{libraryId}") + public ApiResponse editLibrary(@PathVariable("libraryId") Long libraryId, + @Valid @RequestBody LibraryEditRequest request, + @Auth Long userId + ) { + libraryService.editLibrary(libraryId, userId, request.toServiceRequest()); + + return ApiResponse.ok(); + } + + @DeleteMapping("/libraries/{libraryId}") + public ApiResponse deleteLibrary(@PathVariable("libraryId") Long libraryId, + @Auth Long userId + ) { + libraryService.deleteLibrary(libraryId, userId); + + return ApiResponse.ok(); + } + +} diff --git a/src/main/java/com/jisungin/api/userlibrary/request/UserLibraryEditRequest.java b/src/main/java/com/jisungin/api/library/request/LibraryCreateRequest.java similarity index 60% rename from src/main/java/com/jisungin/api/userlibrary/request/UserLibraryEditRequest.java rename to src/main/java/com/jisungin/api/library/request/LibraryCreateRequest.java index 664983e..06b4f30 100644 --- a/src/main/java/com/jisungin/api/userlibrary/request/UserLibraryEditRequest.java +++ b/src/main/java/com/jisungin/api/library/request/LibraryCreateRequest.java @@ -1,6 +1,6 @@ -package com.jisungin.api.userlibrary.request; +package com.jisungin.api.library.request; -import com.jisungin.application.userlibrary.request.UserLibraryEditServiceRequest; +import com.jisungin.application.library.request.LibraryCreateServiceRequest; import jakarta.validation.constraints.NotBlank; import lombok.Builder; import lombok.Getter; @@ -8,7 +8,7 @@ @Getter @NoArgsConstructor -public class UserLibraryEditRequest { +public class LibraryCreateRequest { @NotBlank(message = "책 isbn 입력은 필수 입니다.") private String isbn; @@ -17,13 +17,13 @@ public class UserLibraryEditRequest { private String readingStatus; @Builder - private UserLibraryEditRequest(String isbn, String readingStatus) { + private LibraryCreateRequest(String isbn, String readingStatus) { this.isbn = isbn; this.readingStatus = readingStatus; } - public UserLibraryEditServiceRequest toServiceRequest() { - return UserLibraryEditServiceRequest.builder() + public LibraryCreateServiceRequest toServiceRequest() { + return LibraryCreateServiceRequest.builder() .isbn(isbn) .readingStatus(readingStatus) .build(); diff --git a/src/main/java/com/jisungin/api/userlibrary/request/UserLibraryCreateRequest.java b/src/main/java/com/jisungin/api/library/request/LibraryEditRequest.java similarity index 60% rename from src/main/java/com/jisungin/api/userlibrary/request/UserLibraryCreateRequest.java rename to src/main/java/com/jisungin/api/library/request/LibraryEditRequest.java index 2203b73..f7ccc92 100644 --- a/src/main/java/com/jisungin/api/userlibrary/request/UserLibraryCreateRequest.java +++ b/src/main/java/com/jisungin/api/library/request/LibraryEditRequest.java @@ -1,6 +1,6 @@ -package com.jisungin.api.userlibrary.request; +package com.jisungin.api.library.request; -import com.jisungin.application.userlibrary.request.UserLibraryCreateServiceRequest; +import com.jisungin.application.library.request.LibraryEditServiceRequest; import jakarta.validation.constraints.NotBlank; import lombok.Builder; import lombok.Getter; @@ -8,7 +8,7 @@ @Getter @NoArgsConstructor -public class UserLibraryCreateRequest { +public class LibraryEditRequest { @NotBlank(message = "책 isbn 입력은 필수 입니다.") private String isbn; @@ -17,13 +17,13 @@ public class UserLibraryCreateRequest { private String readingStatus; @Builder - private UserLibraryCreateRequest(String isbn, String readingStatus) { + private LibraryEditRequest(String isbn, String readingStatus) { this.isbn = isbn; this.readingStatus = readingStatus; } - public UserLibraryCreateServiceRequest toServiceRequest() { - return UserLibraryCreateServiceRequest.builder() + public LibraryEditServiceRequest toServiceRequest() { + return LibraryEditServiceRequest.builder() .isbn(isbn) .readingStatus(readingStatus) .build(); diff --git a/src/main/java/com/jisungin/api/review/ReviewController.java b/src/main/java/com/jisungin/api/review/ReviewController.java index 75a6642..03c705f 100644 --- a/src/main/java/com/jisungin/api/review/ReviewController.java +++ b/src/main/java/com/jisungin/api/review/ReviewController.java @@ -29,6 +29,11 @@ public ApiResponse> findBookReviews( return ApiResponse.ok(reviewService.findBookReviews(isbn, OffsetLimit.of(page, size, order))); } + @GetMapping("/books/{isbn}/reviews/count") + public ApiResponse findBookReviewsCount(@PathVariable String isbn) { + return ApiResponse.ok(reviewService.findBookReviewsCount(isbn)); + } + @PostMapping("/reviews") public ApiResponse createReview(@Valid @RequestBody ReviewCreateRequest request, @Auth Long userId) { diff --git a/src/main/java/com/jisungin/api/user/UserController.java b/src/main/java/com/jisungin/api/user/UserController.java index 2a90592..11f0748 100644 --- a/src/main/java/com/jisungin/api/user/UserController.java +++ b/src/main/java/com/jisungin/api/user/UserController.java @@ -10,7 +10,7 @@ import com.jisungin.application.review.response.ReviewContentGetAllResponse; import com.jisungin.application.user.UserService; import com.jisungin.application.user.response.UserInfoResponse; -import com.jisungin.application.userlibrary.response.UserReadingStatusResponse; +import com.jisungin.application.library.response.UserReadingStatusResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; diff --git a/src/main/java/com/jisungin/api/user/request/UserReadingStatusGetAllRequest.java b/src/main/java/com/jisungin/api/user/request/UserReadingStatusGetAllRequest.java index cf59975..fc5a397 100644 --- a/src/main/java/com/jisungin/api/user/request/UserReadingStatusGetAllRequest.java +++ b/src/main/java/com/jisungin/api/user/request/UserReadingStatusGetAllRequest.java @@ -2,7 +2,7 @@ import com.jisungin.application.user.request.UserReadingStatusGetAllServiceRequest; import com.jisungin.domain.ReadingStatus; -import com.jisungin.domain.userlibrary.ReadingStatusOrderType; +import com.jisungin.domain.library.ReadingStatusOrderType; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/jisungin/api/userlibrary/UserLibraryController.java b/src/main/java/com/jisungin/api/userlibrary/UserLibraryController.java deleted file mode 100644 index b88bb4a..0000000 --- a/src/main/java/com/jisungin/api/userlibrary/UserLibraryController.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.jisungin.api.userlibrary; - -import com.jisungin.api.ApiResponse; -import com.jisungin.api.support.Auth; -import com.jisungin.api.support.GuestOrAuth; -import com.jisungin.api.userlibrary.request.UserLibraryCreateRequest; -import com.jisungin.api.userlibrary.request.UserLibraryEditRequest; -import com.jisungin.application.userlibrary.UserLibraryService; -import com.jisungin.application.userlibrary.response.UserLibraryResponse; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -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; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/v1") -public class UserLibraryController { - - private final UserLibraryService userLibraryService; - - @GetMapping("/user-libraries") - public ApiResponse getUserLibrary(@RequestParam String isbn, - @GuestOrAuth Long userId - ) { - return ApiResponse.ok(userLibraryService.getUserLibrary(userId, isbn)); - } - - @PostMapping("/user-libraries") - public ApiResponse createUserLibrary(@Valid @RequestBody UserLibraryCreateRequest request, - @Auth Long userId - ) { - return ApiResponse.ok(userLibraryService.createUserLibrary(request.toServiceRequest(), userId)); - } - - @PatchMapping("/user-libraries/{userLibraryId}") - public ApiResponse editUserLibrary(@PathVariable("userLibraryId") Long userLibraryId, - @Valid @RequestBody UserLibraryEditRequest request, - @Auth Long userId - ) { - userLibraryService.editUserLibrary(userLibraryId, userId, request.toServiceRequest()); - - return ApiResponse.ok(); - } - - @DeleteMapping("/user-libraries/{userLibraryId}") - public ApiResponse deleteUserLibrary(@PathVariable("userLibraryId") Long userLibraryId, - @Auth Long userId - ) { - userLibraryService.deleteUserLibrary(userLibraryId, userId); - - return ApiResponse.ok(); - } - -} diff --git a/src/main/java/com/jisungin/application/comment/CommentService.java b/src/main/java/com/jisungin/application/comment/CommentService.java index 8edf287..a74589c 100644 --- a/src/main/java/com/jisungin/application/comment/CommentService.java +++ b/src/main/java/com/jisungin/application/comment/CommentService.java @@ -15,7 +15,7 @@ import com.jisungin.domain.talkroom.repository.TalkRoomRoleRepository; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; -import com.jisungin.domain.userlibrary.repository.UserLibraryRepository; +import com.jisungin.domain.library.repository.LibraryRepository; import com.jisungin.exception.BusinessException; import com.jisungin.exception.ErrorCode; import java.time.LocalDateTime; @@ -34,7 +34,7 @@ public class CommentService { private final CommentRepository commentRepository; private final TalkRoomRepository talkRoomRepository; private final UserRepository userRepository; - private final UserLibraryRepository userLibraryRepository; + private final LibraryRepository libraryRepository; private final TalkRoomRoleRepository talkRoomRoleRepository; private final CommentImageRepository commentImageRepository; @@ -47,7 +47,7 @@ public CommentResponse writeComment(CommentCreateServiceRequest request, Long ta TalkRoom talkRoom = talkRoomRepository.findById(talkRoomId) .orElseThrow(() -> new BusinessException(ErrorCode.TALK_ROOM_NOT_FOUND)); - Optional userReadingStatus = userLibraryRepository.findByUserId(user.getId(), + Optional userReadingStatus = libraryRepository.findReadingStatusByUserId(user.getId(), talkRoom.getBook().getIsbn()); List talkRoomReadingStatus = talkRoomRoleRepository.findTalkRoomRoleByTalkRoomId( diff --git a/src/main/java/com/jisungin/application/userlibrary/UserLibraryService.java b/src/main/java/com/jisungin/application/library/LibraryService.java similarity index 52% rename from src/main/java/com/jisungin/application/userlibrary/UserLibraryService.java rename to src/main/java/com/jisungin/application/library/LibraryService.java index ff8576e..17e6287 100644 --- a/src/main/java/com/jisungin/application/userlibrary/UserLibraryService.java +++ b/src/main/java/com/jisungin/application/library/LibraryService.java @@ -1,18 +1,18 @@ -package com.jisungin.application.userlibrary; +package com.jisungin.application.library; -import com.jisungin.application.userlibrary.request.UserLibraryCreateServiceRequest; -import com.jisungin.application.userlibrary.request.UserLibraryEditServiceRequest; -import com.jisungin.application.userlibrary.response.UserLibraryResponse; +import com.jisungin.application.library.request.LibraryCreateServiceRequest; +import com.jisungin.application.library.request.LibraryEditServiceRequest; +import com.jisungin.application.library.response.LibraryResponse; import com.jisungin.domain.ReadingStatus; import com.jisungin.domain.book.Book; import com.jisungin.domain.book.repository.BookRepository; -import com.jisungin.domain.userlibrary.UserLibrary; +import com.jisungin.domain.library.Library; +import com.jisungin.domain.library.repository.LibraryRepository; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; -import com.jisungin.domain.userlibrary.repository.UserLibraryRepository; import com.jisungin.exception.BusinessException; import com.jisungin.exception.ErrorCode; -import java.util.Optional; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -22,68 +22,71 @@ @Service @RequiredArgsConstructor @Transactional(readOnly = true) -public class UserLibraryService { +public class LibraryService { private final UserRepository userRepository; private final BookRepository bookRepository; - private final UserLibraryRepository userLibraryRepository; + private final LibraryRepository libraryRepository; - public UserLibraryResponse getUserLibrary(Long userId, String isbn) { - return userLibraryRepository.findByUserIdAndBookId(userId, isbn) - .map(UserLibraryResponse::of) - .orElseGet(UserLibraryResponse::empty); + public List findLibraries(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + + return LibraryResponse.fromList(libraryRepository.findAllByUserId(user.getId())); } @Transactional - public UserLibraryResponse createUserLibrary(UserLibraryCreateServiceRequest request, Long userId) { + public LibraryResponse createLibrary(LibraryCreateServiceRequest request, Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); Book book = bookRepository.findById(request.getIsbn()) .orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); - if (userLibraryRepository.existsByUserIdAndBookId(user.getId(), book.getIsbn())) { + if (libraryRepository.existsByUserIdAndBookId(user.getId(), book.getIsbn())) { throw new BusinessException(ErrorCode.USER_LIBRARY_ALREADY_EXIST); } - return UserLibraryResponse.of(userLibraryRepository.save(request.toEntity(user, book))); + Library savedLibrary = libraryRepository.save(request.toEntity(user, book)); + + return LibraryResponse.of(savedLibrary.getId(), book.getIsbn(), savedLibrary.getStatus().getText()); } @Transactional - public void editUserLibrary(Long userLibraryId, Long userId, UserLibraryEditServiceRequest request) { + public void editLibrary(Long userLibraryId, Long userId, LibraryEditServiceRequest request) { User user = userRepository.findById(userId) .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); Book book = bookRepository.findById(request.getIsbn()) .orElseThrow(() -> new BusinessException(ErrorCode.BOOK_NOT_FOUND)); - UserLibrary userLibrary = userLibraryRepository.findByIdWithBookAndUser(userLibraryId) + Library library = libraryRepository.findByIdWithBookAndUser(userLibraryId) .orElseThrow(() -> new BusinessException(ErrorCode.USER_LIBRARY_NOT_FOUND)); - if (!userLibrary.isUserLibraryOwner(user.getId())) { + if (!library.isLibraryOwner(user.getId())) { throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST); } - if (!userLibrary.isSameBook(book.getIsbn())) { + if (!library.isSameBook(book.getIsbn())) { throw new BusinessException(ErrorCode.BOOK_INVALID_INFO); } - userLibrary.editReadingStatus(ReadingStatus.createReadingStatus(request.getReadingStatus())); + library.editReadingStatus(ReadingStatus.createReadingStatus(request.getReadingStatus())); } @Transactional - public void deleteUserLibrary(Long userLibraryId, Long userId) { + public void deleteLibrary(Long userLibraryId, Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); - UserLibrary userLibrary = userLibraryRepository.findByIdWithBookAndUser(userLibraryId) + Library library = libraryRepository.findByIdWithBookAndUser(userLibraryId) .orElseThrow(() -> new BusinessException(ErrorCode.USER_LIBRARY_NOT_FOUND)); - if (!userLibrary.isUserLibraryOwner(user.getId())) { + if (!library.isLibraryOwner(user.getId())) { throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST); } - userLibraryRepository.deleteById(userLibrary.getId()); + libraryRepository.deleteById(library.getId()); } } diff --git a/src/main/java/com/jisungin/application/userlibrary/request/UserLibraryCreateServiceRequest.java b/src/main/java/com/jisungin/application/library/request/LibraryCreateServiceRequest.java similarity index 62% rename from src/main/java/com/jisungin/application/userlibrary/request/UserLibraryCreateServiceRequest.java rename to src/main/java/com/jisungin/application/library/request/LibraryCreateServiceRequest.java index 68e7119..e85be48 100644 --- a/src/main/java/com/jisungin/application/userlibrary/request/UserLibraryCreateServiceRequest.java +++ b/src/main/java/com/jisungin/application/library/request/LibraryCreateServiceRequest.java @@ -1,8 +1,8 @@ -package com.jisungin.application.userlibrary.request; +package com.jisungin.application.library.request; import com.jisungin.domain.ReadingStatus; import com.jisungin.domain.book.Book; -import com.jisungin.domain.userlibrary.UserLibrary; +import com.jisungin.domain.library.Library; import com.jisungin.domain.user.User; import lombok.Builder; import lombok.Getter; @@ -10,19 +10,19 @@ @Getter @NoArgsConstructor -public class UserLibraryCreateServiceRequest { +public class LibraryCreateServiceRequest { private String isbn; private String readingStatus; @Builder - private UserLibraryCreateServiceRequest(String isbn, String readingStatus) { + private LibraryCreateServiceRequest(String isbn, String readingStatus) { this.isbn = isbn; this.readingStatus = readingStatus; } - public UserLibrary toEntity(User user, Book book) { - return UserLibrary.builder() + public Library toEntity(User user, Book book) { + return Library.builder() .user(user) .book(book) .status(ReadingStatus.createReadingStatus(readingStatus)) diff --git a/src/main/java/com/jisungin/application/userlibrary/request/UserLibraryEditServiceRequest.java b/src/main/java/com/jisungin/application/library/request/LibraryEditServiceRequest.java similarity index 51% rename from src/main/java/com/jisungin/application/userlibrary/request/UserLibraryEditServiceRequest.java rename to src/main/java/com/jisungin/application/library/request/LibraryEditServiceRequest.java index e0fc085..0961752 100644 --- a/src/main/java/com/jisungin/application/userlibrary/request/UserLibraryEditServiceRequest.java +++ b/src/main/java/com/jisungin/application/library/request/LibraryEditServiceRequest.java @@ -1,19 +1,18 @@ -package com.jisungin.application.userlibrary.request; +package com.jisungin.application.library.request; -import com.jisungin.api.userlibrary.request.UserLibraryCreateRequest; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @NoArgsConstructor -public class UserLibraryEditServiceRequest { +public class LibraryEditServiceRequest { private String isbn; private String readingStatus; @Builder - private UserLibraryEditServiceRequest(String isbn, String readingStatus) { + private LibraryEditServiceRequest(String isbn, String readingStatus) { this.isbn = isbn; this.readingStatus = readingStatus; } diff --git a/src/main/java/com/jisungin/application/library/response/LibraryResponse.java b/src/main/java/com/jisungin/application/library/response/LibraryResponse.java new file mode 100644 index 0000000..8a22b93 --- /dev/null +++ b/src/main/java/com/jisungin/application/library/response/LibraryResponse.java @@ -0,0 +1,44 @@ +package com.jisungin.application.library.response; + +import com.jisungin.domain.library.LibraryQueryEntity; +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +@Getter +public class LibraryResponse { + + private Long id; + private String bookIsbn; + private String status; + + @Builder + private LibraryResponse(Long id, String bookIsbn, String status) { + this.id = id; + this.bookIsbn = bookIsbn; + this.status = status; + } + + public static LibraryResponse of(Long id, String bookIsbn, String status) { + return LibraryResponse.builder() + .id(id) + .bookIsbn(bookIsbn) + .status(status) + .build(); + } + + public static LibraryResponse of(LibraryQueryEntity library) { + return LibraryResponse.builder() + .id(library.getId()) + .bookIsbn(library.getBookIsbn()) + .status(library.getReadingStatus()) + .build(); + } + + public static List fromList(List libraries) { + return libraries.stream() + .map(LibraryResponse::of) + .toList(); + } + +} diff --git a/src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java b/src/main/java/com/jisungin/application/library/response/UserReadingStatusResponse.java similarity index 91% rename from src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java rename to src/main/java/com/jisungin/application/library/response/UserReadingStatusResponse.java index bf86f2b..285e8a6 100644 --- a/src/main/java/com/jisungin/application/userlibrary/response/UserReadingStatusResponse.java +++ b/src/main/java/com/jisungin/application/library/response/UserReadingStatusResponse.java @@ -1,4 +1,4 @@ -package com.jisungin.application.userlibrary.response; +package com.jisungin.application.library.response; import com.querydsl.core.annotations.QueryProjection; import lombok.Builder; diff --git a/src/main/java/com/jisungin/application/review/ReviewService.java b/src/main/java/com/jisungin/application/review/ReviewService.java index bceee3d..7587d22 100644 --- a/src/main/java/com/jisungin/application/review/ReviewService.java +++ b/src/main/java/com/jisungin/application/review/ReviewService.java @@ -37,6 +37,13 @@ public SliceResponse findBookReviews(String isbn, Offs offsetLimit.getOrder()); } + public Long findBookReviewsCount(String isbn) { + Book book = bookRepository.findById(isbn) + .orElseThrow(() -> new BusinessException(BOOK_NOT_FOUND)); + + return reviewRepository.countByBookId(book.getIsbn()); + } + @Transactional public void createReview(ReviewCreateServiceRequest request, Long userId) { User user = userRepository.findById(userId) diff --git a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java index 040a423..6bf4b4b 100644 --- a/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java +++ b/src/main/java/com/jisungin/application/talkroom/response/TalkRoomFindOneResponse.java @@ -21,6 +21,7 @@ public class TalkRoomFindOneResponse { private String username; private String title; private String content; + private String bookIsbn; private String bookName; private String bookAuthor; private String bookThumbnail; @@ -33,14 +34,15 @@ public class TalkRoomFindOneResponse { @Builder @QueryProjection public TalkRoomFindOneResponse(Long id, String profileImage, String username, String title, String content, - String bookName, String bookAuthor, String bookThumbnail, Long likeCount, - List readingStatuses, - LocalDateTime registeredDateTime, List images, Long creatorId) { + String bookIsbn, String bookName, String bookAuthor, String bookThumbnail, + Long likeCount, List readingStatuses, LocalDateTime registeredDateTime, + List images, Long creatorId) { this.id = id; this.profileImage = profileImage; this.username = username; this.title = title; this.content = content; + this.bookIsbn = bookIsbn; this.bookName = bookName; this.bookAuthor = bookAuthor; this.bookThumbnail = bookThumbnail; @@ -59,6 +61,7 @@ public static TalkRoomFindOneResponse of(TalkRoom talkRoom, Book book, User user .username(user.getName()) .title(talkRoom.getTitle()) .content(talkRoom.getContent()) + .bookIsbn(book.getIsbn()) .bookName(book.getTitle()) .bookAuthor(book.getAuthors()) .bookThumbnail(book.getThumbnail()) @@ -78,6 +81,7 @@ public static TalkRoomFindOneResponse of(TalkRoomQueryResponse talkRoom, List getUserRatings(Long userId, UserRatingGetAllServiceRequest request) { User user = userRepository.findById(userId) @@ -68,7 +68,7 @@ public PageResponse getUserReadingStatuses( User user = userRepository.findById(userId) .orElseThrow(() -> new BusinessException(USER_NOT_FOUND)); - return userLibraryRepository.findAllReadingStatusOrderBy( + return libraryRepository.findAllReadingStatusOrderBy( user.getId(), request.getReadingStatus(), request.getOrderType(), request.getSize(), request.getOffset()); } diff --git a/src/main/java/com/jisungin/application/user/request/UserReadingStatusGetAllServiceRequest.java b/src/main/java/com/jisungin/application/user/request/UserReadingStatusGetAllServiceRequest.java index f7bf7b3..4f758d2 100644 --- a/src/main/java/com/jisungin/application/user/request/UserReadingStatusGetAllServiceRequest.java +++ b/src/main/java/com/jisungin/application/user/request/UserReadingStatusGetAllServiceRequest.java @@ -1,7 +1,7 @@ package com.jisungin.application.user.request; import com.jisungin.domain.ReadingStatus; -import com.jisungin.domain.userlibrary.ReadingStatusOrderType; +import com.jisungin.domain.library.ReadingStatusOrderType; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/jisungin/application/userlibrary/response/UserLibraryResponse.java b/src/main/java/com/jisungin/application/userlibrary/response/UserLibraryResponse.java deleted file mode 100644 index d97a3cd..0000000 --- a/src/main/java/com/jisungin/application/userlibrary/response/UserLibraryResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.jisungin.application.userlibrary.response; - - -import com.jisungin.domain.userlibrary.UserLibrary; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class UserLibraryResponse { - - private Long id; - private String status; - private Boolean hasReadingStatus; - - @Builder - private UserLibraryResponse(Long id, String status, Boolean hasReadingStatus) { - this.id = id; - this.status = status; - this.hasReadingStatus = hasReadingStatus; - } - - public static UserLibraryResponse of(UserLibrary userLibrary) { - return UserLibraryResponse.builder() - .id(userLibrary.getId()) - .status(userLibrary.getStatus().getText()) - .hasReadingStatus(true) - .build(); - } - - public static UserLibraryResponse empty() { - return UserLibraryResponse.builder() - .hasReadingStatus(false) - .build(); - } - -} diff --git a/src/main/java/com/jisungin/domain/userlibrary/UserLibrary.java b/src/main/java/com/jisungin/domain/library/Library.java similarity index 76% rename from src/main/java/com/jisungin/domain/userlibrary/UserLibrary.java rename to src/main/java/com/jisungin/domain/library/Library.java index addf24a..eecd0da 100644 --- a/src/main/java/com/jisungin/domain/userlibrary/UserLibrary.java +++ b/src/main/java/com/jisungin/domain/library/Library.java @@ -1,4 +1,4 @@ -package com.jisungin.domain.userlibrary; +package com.jisungin.domain.library; import com.jisungin.domain.BaseEntity; import com.jisungin.domain.ReadingStatus; @@ -10,11 +10,11 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class UserLibrary extends BaseEntity { +public class Library extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_library_id") + @Column(name = "library_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @@ -26,17 +26,17 @@ public class UserLibrary extends BaseEntity { private Book book; @Enumerated(EnumType.STRING) - @Column(name = "user_library_reading_status") + @Column(name = "library_reading_status") private ReadingStatus status; @Builder - private UserLibrary(User user, Book book, ReadingStatus status) { + private Library(User user, Book book, ReadingStatus status) { this.user = user; this.book = book; this.status = status; } - public boolean isUserLibraryOwner(Long userId) { + public boolean isLibraryOwner(Long userId) { return user.isMe(userId); } diff --git a/src/main/java/com/jisungin/domain/library/LibraryQueryEntity.java b/src/main/java/com/jisungin/domain/library/LibraryQueryEntity.java new file mode 100644 index 0000000..5148464 --- /dev/null +++ b/src/main/java/com/jisungin/domain/library/LibraryQueryEntity.java @@ -0,0 +1,21 @@ +package com.jisungin.domain.library; + +import com.jisungin.domain.ReadingStatus; +import com.querydsl.core.annotations.QueryProjection; +import lombok.Getter; + +@Getter +public class LibraryQueryEntity { + + private Long id; + private String bookIsbn; + private String readingStatus; + + @QueryProjection + public LibraryQueryEntity(Long id, String bookIsbn, ReadingStatus readingStatus) { + this.id = id; + this.bookIsbn = bookIsbn; + this.readingStatus = readingStatus.getText(); + } + +} diff --git a/src/main/java/com/jisungin/domain/userlibrary/ReadingStatusOrderType.java b/src/main/java/com/jisungin/domain/library/ReadingStatusOrderType.java similarity index 88% rename from src/main/java/com/jisungin/domain/userlibrary/ReadingStatusOrderType.java rename to src/main/java/com/jisungin/domain/library/ReadingStatusOrderType.java index 73e125c..1a4210b 100644 --- a/src/main/java/com/jisungin/domain/userlibrary/ReadingStatusOrderType.java +++ b/src/main/java/com/jisungin/domain/library/ReadingStatusOrderType.java @@ -1,4 +1,4 @@ -package com.jisungin.domain.userlibrary; +package com.jisungin.domain.library; import java.util.Locale; diff --git a/src/main/java/com/jisungin/domain/library/repository/LibraryRepository.java b/src/main/java/com/jisungin/domain/library/repository/LibraryRepository.java new file mode 100644 index 0000000..8bb91f5 --- /dev/null +++ b/src/main/java/com/jisungin/domain/library/repository/LibraryRepository.java @@ -0,0 +1,25 @@ +package com.jisungin.domain.library.repository; + +import com.jisungin.domain.ReadingStatus; +import com.jisungin.domain.library.Library; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface LibraryRepository extends JpaRepository, LibraryRepositoryCustom { + + @Query( + "SELECT l.status FROM Library l JOIN l.user u JOIN l.book b WHERE u.id = :id AND b.isbn = :isbn" + ) + Optional findReadingStatusByUserId(@Param("id") Long userId, @Param("isbn") String isbn); + + @Query( + "SELECT l FROM Library l " + + "JOIN FETCH l.book " + + "JOIN FETCH l.user " + + "WHERE l.id = :id" + ) + Optional findByIdWithBookAndUser(@Param("id") Long id); + +} diff --git a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryCustom.java b/src/main/java/com/jisungin/domain/library/repository/LibraryRepositoryCustom.java similarity index 57% rename from src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryCustom.java rename to src/main/java/com/jisungin/domain/library/repository/LibraryRepositoryCustom.java index 5cd1315..db9522d 100644 --- a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryCustom.java +++ b/src/main/java/com/jisungin/domain/library/repository/LibraryRepositoryCustom.java @@ -1,11 +1,15 @@ -package com.jisungin.domain.userlibrary.repository; +package com.jisungin.domain.library.repository; import com.jisungin.application.PageResponse; -import com.jisungin.application.userlibrary.response.UserReadingStatusResponse; +import com.jisungin.domain.library.LibraryQueryEntity; +import com.jisungin.application.library.response.UserReadingStatusResponse; import com.jisungin.domain.ReadingStatus; -import com.jisungin.domain.userlibrary.ReadingStatusOrderType; +import com.jisungin.domain.library.ReadingStatusOrderType; +import java.util.List; -public interface UserLibraryRepositoryCustom { +public interface LibraryRepositoryCustom { + + List findAllByUserId(Long userId); PageResponse findAllReadingStatusOrderBy( Long userId, ReadingStatus readingStatus, ReadingStatusOrderType orderType, int size, int offset); diff --git a/src/main/java/com/jisungin/domain/library/repository/LibraryRepositoryImpl.java b/src/main/java/com/jisungin/domain/library/repository/LibraryRepositoryImpl.java new file mode 100644 index 0000000..8b34f5f --- /dev/null +++ b/src/main/java/com/jisungin/domain/library/repository/LibraryRepositoryImpl.java @@ -0,0 +1,94 @@ +package com.jisungin.domain.library.repository; + +import static com.jisungin.domain.book.QBook.book; +import static com.jisungin.domain.library.QLibrary.library; +import static com.jisungin.domain.rating.QRating.rating1; +import static com.jisungin.domain.user.QUser.user; + +import com.jisungin.application.PageResponse; +import com.jisungin.application.library.response.QUserReadingStatusResponse; +import com.jisungin.application.library.response.UserReadingStatusResponse; +import com.jisungin.domain.ReadingStatus; +import com.jisungin.domain.library.LibraryQueryEntity; +import com.jisungin.domain.library.QLibraryQueryEntity; +import com.jisungin.domain.library.ReadingStatusOrderType; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public class LibraryRepositoryImpl implements LibraryRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findAllByUserId(Long userId) { + return queryFactory.select(new QLibraryQueryEntity( + library.id.as("id"), + book.isbn.as("bookIsbn"), + library.status.as("readingStatus") + )) + .from(library) + .join(library.book, book) + .join(library.user, user) + .where(library.user.id.eq(userId)) + .fetch(); + } + + @Override + public PageResponse findAllReadingStatusOrderBy( + Long userId, ReadingStatus readingStatus, ReadingStatusOrderType orderType, int size, int offset) { + log.info("--------------start--------------"); + List userReadingStatuses = queryFactory + .select(new QUserReadingStatusResponse( + library.book.isbn, library.book.imageUrl, library.book.title, rating1.rating.avg())) + .from(library) + .join(rating1).on(library.book.eq(rating1.book)) + .where(library.user.id.eq(userId), library.status.eq(readingStatus)) + .groupBy(library.book.isbn) + .orderBy(createSpecifier(orderType)) + .offset(offset) + .limit(size) + .fetch(); + + return PageResponse.builder() + .queryResponse(userReadingStatuses) + .totalCount(getTotalCount(userId, readingStatus)) + .size(size) + .build(); + } + + @Override + public Boolean existsByUserIdAndBookId(Long userId, String bookIsbn) { + Integer fetchOne = queryFactory + .selectOne() + .from(library) + .join(library.book, book) + .join(library.user, user) + .where(library.user.id.eq(userId) + .and(library.book.isbn.eq(bookIsbn))) + .fetchFirst(); + + return fetchOne != null; + } + + private long getTotalCount(Long userId, ReadingStatus readingStatus) { + return queryFactory + .select(library.count()) + .from(library) + .where(library.user.id.eq(userId), library.status.eq(readingStatus)) + .fetchOne(); + } + + private OrderSpecifier createSpecifier(ReadingStatusOrderType orderType) { + if (orderType.equals(ReadingStatusOrderType.RATING_AVG_DESC)) { + return rating1.rating.avg().desc(); + } + + return library.book.title.asc(); + } + +} diff --git a/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryCustom.java b/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryCustom.java index e15019f..8ff7f8a 100644 --- a/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryCustom.java +++ b/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryCustom.java @@ -13,4 +13,6 @@ PageResponse findAllReviewContentOrderBy( SliceResponse findAllByBookId(String isbn, Integer offset, Integer limit, String order); + Long countByBookId(String isbn); + } 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 9417041..63f908a 100644 --- a/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryImpl.java +++ b/src/main/java/com/jisungin/domain/review/repository/ReviewRepositoryImpl.java @@ -96,6 +96,14 @@ private List getReviewContents( .fetch(); } + public Long countByBookId(String isbn) { + return queryFactory.select(review.count()) + .from(review) + .join(review.book, book) + .where(book.isbn.eq(isbn)) + .fetchOne(); + } + private long getTotalCount(Long userId, Double rating) { return queryFactory .select(review.count()) diff --git a/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java b/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java index c95c069..9ae021a 100644 --- a/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java +++ b/src/main/java/com/jisungin/domain/talkroom/repository/TalkRoomRepositoryImpl.java @@ -11,6 +11,7 @@ import com.jisungin.application.talkroom.response.QTalkRoomQueryResponse; import com.jisungin.application.talkroom.response.TalkRoomQueryResponse; +import com.jisungin.domain.talkroom.TalkRoom; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; @@ -51,6 +52,7 @@ public List findTalkRoomsRelatedBook(String isbn, long of user.name.as("username"), talkRoom.title, talkRoom.content, + book.isbn.as("bookIsbn"), book.title.as("bookName"), book.authors.as("bookAuthor"), book.thumbnail.as("bookThumbnail"), @@ -68,7 +70,6 @@ public List findTalkRoomsRelatedBook(String isbn, long of .limit(size) .orderBy(talkRoomLike.count().desc()) .fetch(); - } public Long countTalkRoomsRelatedBook(String isbn) { @@ -95,6 +96,7 @@ public List findByTalkRoomOwner(Integer offset, Integer s user.name.as("username"), talkRoom.title, talkRoom.content, + book.isbn.as("bookIsbn"), book.title.as("bookName"), book.authors.as("bookAuthor"), book.thumbnail.as("bookThumbnail"), @@ -141,6 +143,7 @@ private List findTalkRoomBySearch(long offset, int size, user.name.as("userName"), talkRoom.title, talkRoom.content, + book.isbn.as("bookIsbn"), book.title, book.authors.as("bookAuthor"), book.thumbnail.as("bookThumbnail"), @@ -202,6 +205,7 @@ private TalkRoomQueryResponse findTalkRoomByTalkRoomId(Long talkRoomId) { user.name.as("username"), talkRoom.title, talkRoom.content, + book.isbn.as("bookIsbn"), book.title, book.authors.as("bookAuthor"), book.thumbnail.as("bookImage"), diff --git a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepository.java b/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepository.java deleted file mode 100644 index 7bac095..0000000 --- a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepository.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jisungin.domain.userlibrary.repository; - -import com.jisungin.domain.ReadingStatus; -import com.jisungin.domain.userlibrary.UserLibrary; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -public interface UserLibraryRepository extends JpaRepository, UserLibraryRepositoryCustom { - - @Query( - "SELECT ul.status FROM UserLibrary ul JOIN ul.user u JOIN ul.book b WHERE u.id = :id AND b.isbn = :isbn" - ) - Optional findByUserId(@Param("id") Long userId, @Param("isbn") String isbn); - - @Query( - "SELECT ul FROM UserLibrary ul " - + "JOIN FETCH ul.book " - + "JOIN FETCH ul.user " - + "WHERE ul.id = :id" - ) - Optional findByIdWithBookAndUser(@Param("id") Long id); - - @Query( - "SELECT ul FROM UserLibrary ul " - + "JOIN FETCH ul.book " - + "JOIN FETCH ul.user " - + "WHERE ul.user.id = :userId AND " - + "ul.book.isbn = :bookIsbn" - ) - Optional findByUserIdAndBookId(@Param("userId") Long userId, @Param("bookIsbn") String bookIsbn); - -} diff --git a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java b/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java deleted file mode 100644 index 790185e..0000000 --- a/src/main/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImpl.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.jisungin.domain.userlibrary.repository; - -import static com.jisungin.domain.book.QBook.book; -import static com.jisungin.domain.rating.QRating.*; -import static com.jisungin.domain.user.QUser.user; -import static com.jisungin.domain.userlibrary.QUserLibrary.userLibrary; - -import com.jisungin.application.PageResponse; -import com.jisungin.application.userlibrary.response.QUserReadingStatusResponse; -import com.jisungin.application.userlibrary.response.UserReadingStatusResponse; -import com.jisungin.domain.ReadingStatus; -import com.jisungin.domain.userlibrary.ReadingStatusOrderType; -import com.querydsl.core.types.OrderSpecifier; -import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@RequiredArgsConstructor -public class UserLibraryRepositoryImpl implements UserLibraryRepositoryCustom { - - private final JPAQueryFactory queryFactory; - - @Override - public PageResponse findAllReadingStatusOrderBy( - Long userId, ReadingStatus readingStatus, ReadingStatusOrderType orderType, int size, int offset) { - log.info("--------------start--------------"); - List userReadingStatuses = queryFactory - .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)) - .groupBy(userLibrary.book.isbn) - .orderBy(createSpecifier(orderType)) - .offset(offset) - .limit(size) - .fetch(); - - return PageResponse.builder() - .queryResponse(userReadingStatuses) - .totalCount(getTotalCount(userId, readingStatus)) - .size(size) - .build(); - - } - - @Override - public Boolean existsByUserIdAndBookId(Long userId, String bookIsbn) { - Integer fetchOne = queryFactory - .selectOne() - .from(userLibrary) - .join(userLibrary.book, book) - .join(userLibrary.user, user) - .where(userLibrary.user.id.eq(userId) - .and(userLibrary.book.isbn.eq(bookIsbn))) - .fetchFirst(); - - return fetchOne != null; - } - - private long getTotalCount(Long userId, ReadingStatus readingStatus) { - return queryFactory - .select(userLibrary.count()) - .from(userLibrary) - .where(userLibrary.user.id.eq(userId), userLibrary.status.eq(readingStatus)) - .fetchOne(); - } - - private OrderSpecifier createSpecifier(ReadingStatusOrderType orderType) { - if (orderType.equals(ReadingStatusOrderType.RATING_AVG_DESC)) { - return rating1.rating.avg().desc(); - } - - return userLibrary.book.title.asc(); - } - -} diff --git a/src/test/java/com/jisungin/ControllerTestSupport.java b/src/test/java/com/jisungin/ControllerTestSupport.java index 7922edf..d7ba1bd 100644 --- a/src/test/java/com/jisungin/ControllerTestSupport.java +++ b/src/test/java/com/jisungin/ControllerTestSupport.java @@ -12,7 +12,7 @@ import com.jisungin.api.talkroom.TalkRoomController; import com.jisungin.api.talkroomlike.TalkRoomLikeController; import com.jisungin.api.user.UserController; -import com.jisungin.api.userlibrary.UserLibraryController; +import com.jisungin.api.library.LibraryController; import com.jisungin.application.book.BestSellerService; import com.jisungin.application.book.BookService; import com.jisungin.application.comment.CommentService; @@ -24,7 +24,7 @@ import com.jisungin.application.talkroom.TalkRoomService; import com.jisungin.application.talkroomlike.TalkRoomLikeService; import com.jisungin.application.user.UserService; -import com.jisungin.application.userlibrary.UserLibraryService; +import com.jisungin.application.library.LibraryService; import com.jisungin.config.SecurityConfig; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -47,7 +47,7 @@ ReviewLikeController.class, ImageController.class, SearchController.class, - UserLibraryController.class + LibraryController.class }, excludeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class) @@ -96,7 +96,7 @@ public abstract class ControllerTestSupport { protected SearchService searchService; @MockBean - protected UserLibraryService userLibraryService; + protected LibraryService libraryService; protected MockHttpSession mockHttpSession; diff --git a/src/test/java/com/jisungin/api/userlibrary/UserLibraryControllerTest.java b/src/test/java/com/jisungin/api/library/LibraryControllerTest.java similarity index 68% rename from src/test/java/com/jisungin/api/userlibrary/UserLibraryControllerTest.java rename to src/test/java/com/jisungin/api/library/LibraryControllerTest.java index bf03f76..f491951 100644 --- a/src/test/java/com/jisungin/api/userlibrary/UserLibraryControllerTest.java +++ b/src/test/java/com/jisungin/api/library/LibraryControllerTest.java @@ -1,4 +1,4 @@ -package com.jisungin.api.userlibrary; +package com.jisungin.api.library; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -10,22 +10,18 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.jisungin.ControllerTestSupport; -import com.jisungin.api.userlibrary.request.UserLibraryCreateRequest; -import com.jisungin.api.userlibrary.request.UserLibraryEditRequest; +import com.jisungin.api.library.request.LibraryCreateRequest; +import com.jisungin.api.library.request.LibraryEditRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -public class UserLibraryControllerTest extends ControllerTestSupport { +public class LibraryControllerTest extends ControllerTestSupport { @Test @DisplayName("서재 정보를 조회한다.") - public void getUserLibrary() throws Exception { - // given - String isbn = "00001"; - + public void findLibraries() throws Exception { // when // then - mockMvc.perform(get("/v1/user-libraries") - .param("isbn", isbn) + mockMvc.perform(get("/v1/libraries") .accept(APPLICATION_JSON) .session(mockHttpSession)) .andExpect(status().isOk()) @@ -35,29 +31,18 @@ public void getUserLibrary() throws Exception { .andDo(print()); } - @Test - @DisplayName("서재 정보 조회 시 책 isbn 입력은 필수이다.") - public void getUserLibraryWithoutIsbn() throws Exception { - // when // then - mockMvc.perform(get("/v1/user-libraries") - .accept(APPLICATION_JSON)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value("400")) - .andExpect(jsonPath("$.message").value("유효하지 않은 파라미터 입니다.")) - .andDo(print()); - } - @Test @DisplayName("서재 정보를 생성한다.") - public void createUseLibrary() throws Exception { + public void createLibrary() throws Exception { // given - UserLibraryCreateRequest request = UserLibraryCreateRequest.builder() + LibraryCreateRequest request = LibraryCreateRequest.builder() .isbn("00001") .readingStatus("want") .build(); // when // then - mockMvc.perform(post("/v1/user-libraries") + mockMvc.perform(post("/v1/libraries") + .accept(APPLICATION_JSON) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .session(mockHttpSession)) @@ -70,14 +55,14 @@ public void createUseLibrary() throws Exception { @Test @DisplayName("서재 정보 등록 시 isbn 입력은 필수이다.") - public void createUserLibraryWithoutIsbn() throws Exception { + public void createLibraryWithoutIsbn() throws Exception { // given - UserLibraryCreateRequest request = UserLibraryCreateRequest.builder() + LibraryCreateRequest request = LibraryCreateRequest.builder() .readingStatus("want") .build(); // when // then - mockMvc.perform(post("/v1/user-libraries") + mockMvc.perform(post("/v1/libraries") .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .session(mockHttpSession)) @@ -89,14 +74,14 @@ public void createUserLibraryWithoutIsbn() throws Exception { @Test @DisplayName("사재 정보 등록 시 독서 상태 입력은 필수이다.") - public void createUserLibraryWithoutReadingStatus() throws Exception { + public void createLibraryWithoutReadingStatus() throws Exception { // given - UserLibraryCreateRequest request = UserLibraryCreateRequest.builder() + LibraryCreateRequest request = LibraryCreateRequest.builder() .isbn("00001") .build(); // when // then - mockMvc.perform(post("/v1/user-libraries") + mockMvc.perform(post("/v1/libraries") .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .session(mockHttpSession)) @@ -108,17 +93,17 @@ public void createUserLibraryWithoutReadingStatus() throws Exception { @Test @DisplayName("서재 정보를 수정한다.") - public void editUserLibrary() throws Exception { + public void editLibrary() throws Exception { // given - Long userLibraryId = 1L; + Long libraryId = 1L; - UserLibraryEditRequest request = UserLibraryEditRequest.builder() + LibraryEditRequest request = LibraryEditRequest.builder() .isbn("00001") .readingStatus("want") .build(); // when // then - mockMvc.perform(patch("/v1/user-libraries/{userLibraryId}", userLibraryId) + mockMvc.perform(patch("/v1/libraries/{libraryId}", libraryId) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .session(mockHttpSession)) @@ -131,16 +116,16 @@ public void editUserLibrary() throws Exception { @Test @DisplayName("서재 정보를 수정시 isbn 입력은 필수이다.") - public void editUserLibraryWithoutIsbn() throws Exception { + public void editLibraryWithoutIsbn() throws Exception { // given - Long userLibraryId = 1L; + Long libraryId = 1L; - UserLibraryEditRequest request = UserLibraryEditRequest.builder() + LibraryEditRequest request = LibraryEditRequest.builder() .readingStatus("want") .build(); // when // then - mockMvc.perform(patch("/v1/user-libraries/{userLibraryId}", userLibraryId) + mockMvc.perform(patch("/v1/libraries/{libraryId}", libraryId) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .session(mockHttpSession)) @@ -152,16 +137,16 @@ public void editUserLibraryWithoutIsbn() throws Exception { @Test @DisplayName("서재 정보를 수정시 독서 상태 정보 입력은 필수이다.") - public void editUserLibraryWithoutReadingStatus() throws Exception { + public void editLibraryWithoutReadingStatus() throws Exception { // given - Long userLibraryId = 1L; + Long libraryId = 1L; - UserLibraryEditRequest request = UserLibraryEditRequest.builder() + LibraryEditRequest request = LibraryEditRequest.builder() .isbn("00001") .build(); // when // then - mockMvc.perform(patch("/v1/user-libraries/{userLibraryId}", userLibraryId) + mockMvc.perform(patch("/v1/libraries/{libraryId}", libraryId) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) .session(mockHttpSession)) @@ -173,12 +158,12 @@ public void editUserLibraryWithoutReadingStatus() throws Exception { @Test @DisplayName("서재 정보를 삭제한다.") - public void deleteUserLibrary() throws Exception { + public void deleteLibrary() throws Exception { // given - Long userLibraryId = 1L; + Long libraryId = 1L; // when // then - mockMvc.perform(delete("/v1/user-libraries/{userLibraryId}", userLibraryId) + mockMvc.perform(delete("/v1/libraries/{libraryId}", libraryId) .session(mockHttpSession)) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value("200")) diff --git a/src/test/java/com/jisungin/api/review/ReviewControllerTest.java b/src/test/java/com/jisungin/api/review/ReviewControllerTest.java index 9a3c33c..66b4b60 100644 --- a/src/test/java/com/jisungin/api/review/ReviewControllerTest.java +++ b/src/test/java/com/jisungin/api/review/ReviewControllerTest.java @@ -16,6 +16,7 @@ class ReviewControllerTest extends ControllerTestSupport { @DisplayName("도서와 연관된 리뷰를 조회한다.") + @Test void findBookReviews() throws Exception { // given String isbn = "000000000000"; @@ -26,9 +27,30 @@ void findBookReviews() throws Exception { .param("size", "5") .param("order", "like") .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(jsonPath("code").value("200")) + .andExpect(jsonPath("status").value("OK")) + .andExpect(jsonPath("message").value("OK")) + .andDo(print()); + } + + @DisplayName("도서와 연관된 리뷰의 개수를 조회한다.") + @Test + void findBookReviewsCount() throws Exception { + // given + String isbn = "000000000000"; + + // when // then + mockMvc.perform(get("/v1/books/{isbn}/reviews/count", isbn) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("code").value("200")) + .andExpect(jsonPath("status").value("OK")) + .andExpect(jsonPath("message").value("OK")) + .andDo(print()); } + @DisplayName("유저가 리뷰를 등록한다.") @Test void createReview() throws Exception { diff --git a/src/test/java/com/jisungin/application/comment/CommentServiceTest.java b/src/test/java/com/jisungin/application/comment/CommentServiceTest.java index 9629e08..703a6f9 100644 --- a/src/test/java/com/jisungin/application/comment/CommentServiceTest.java +++ b/src/test/java/com/jisungin/application/comment/CommentServiceTest.java @@ -26,8 +26,8 @@ import com.jisungin.domain.user.OauthType; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; -import com.jisungin.domain.userlibrary.UserLibrary; -import com.jisungin.domain.userlibrary.repository.UserLibraryRepository; +import com.jisungin.domain.library.Library; +import com.jisungin.domain.library.repository.LibraryRepository; import com.jisungin.exception.BusinessException; import java.time.LocalDateTime; import java.util.ArrayList; @@ -65,7 +65,7 @@ class CommentServiceTest extends ServiceTestSupport { UserRepository userRepository; @Autowired - UserLibraryRepository userLibraryRepository; + LibraryRepository libraryRepository; @Autowired CommentService commentService; @@ -78,7 +78,7 @@ void tearDown() { talkRoomImageRepository.deleteAllInBatch(); talkRoomRoleRepository.deleteAllInBatch(); talkRoomRepository.deleteAllInBatch(); - userLibraryRepository.deleteAllInBatch(); + libraryRepository.deleteAllInBatch(); userRepository.deleteAllInBatch(); bookRepository.deleteAllInBatch(); } @@ -96,13 +96,13 @@ void writeComment() { TalkRoom talkRoom = createTalkRoom(book, user); talkRoomRepository.save(talkRoom); - UserLibrary userLibrary = UserLibrary.builder() + Library library = Library.builder() .user(user) .book(book) .status(ReadingStatus.READING) .build(); - userLibraryRepository.save(userLibrary); + libraryRepository.save(library); createTalkRoomRole(talkRoom); @@ -133,13 +133,13 @@ void writeCommentWithInvalidStatus() { TalkRoom talkRoom = createTalkRoom(book, user); talkRoomRepository.save(talkRoom); - UserLibrary userLibrary = UserLibrary.builder() + Library library = Library.builder() .user(user) .book(book) .status(ReadingStatus.PAUSE) .build(); - userLibraryRepository.save(userLibrary); + libraryRepository.save(library); createTalkRoomRole(talkRoom); @@ -167,12 +167,12 @@ void writeCommentWithStatusEmpty() { TalkRoom talkRoom = createTalkRoom(book, user); talkRoomRepository.save(talkRoom); - UserLibrary userLibrary = UserLibrary.builder() + Library library = Library.builder() .user(user) .book(book) .build(); - userLibraryRepository.save(userLibrary); + libraryRepository.save(library); createTalkRoomRole(talkRoom); @@ -232,13 +232,13 @@ void writeCommentWithImages() { TalkRoom talkRoom = createTalkRoom(book, user); talkRoomRepository.save(talkRoom); - UserLibrary userLibrary = UserLibrary.builder() + Library library = Library.builder() .user(user) .book(book) .status(ReadingStatus.READING) .build(); - userLibraryRepository.save(userLibrary); + libraryRepository.save(library); createTalkRoomRole(talkRoom); diff --git a/src/test/java/com/jisungin/application/userlibrary/UserLibraryServiceTest.java b/src/test/java/com/jisungin/application/library/LibraryServiceTest.java similarity index 58% rename from src/test/java/com/jisungin/application/userlibrary/UserLibraryServiceTest.java rename to src/test/java/com/jisungin/application/library/LibraryServiceTest.java index 92aec4d..ea2dff7 100644 --- a/src/test/java/com/jisungin/application/userlibrary/UserLibraryServiceTest.java +++ b/src/test/java/com/jisungin/application/library/LibraryServiceTest.java @@ -1,31 +1,32 @@ -package com.jisungin.application.userlibrary; +package com.jisungin.application.library; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.jisungin.ServiceTestSupport; -import com.jisungin.application.userlibrary.request.UserLibraryCreateServiceRequest; -import com.jisungin.application.userlibrary.request.UserLibraryEditServiceRequest; -import com.jisungin.application.userlibrary.response.UserLibraryResponse; +import com.jisungin.application.library.request.LibraryCreateServiceRequest; +import com.jisungin.application.library.request.LibraryEditServiceRequest; +import com.jisungin.application.library.response.LibraryResponse; import com.jisungin.domain.ReadingStatus; import com.jisungin.domain.book.Book; import com.jisungin.domain.book.repository.BookRepository; -import com.jisungin.domain.userlibrary.UserLibrary; +import com.jisungin.domain.library.Library; +import com.jisungin.domain.library.repository.LibraryRepository; import com.jisungin.domain.user.OauthId; import com.jisungin.domain.user.OauthType; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; -import com.jisungin.domain.userlibrary.repository.UserLibraryRepository; import com.jisungin.exception.BusinessException; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; +import java.util.stream.IntStream; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -public class UserLibraryServiceTest extends ServiceTestSupport { +public class LibraryServiceTest extends ServiceTestSupport { @Autowired private UserRepository userRepository; @@ -34,180 +35,156 @@ public class UserLibraryServiceTest extends ServiceTestSupport { private BookRepository bookRepository; @Autowired - private UserLibraryRepository userLibraryRepository; + private LibraryRepository libraryRepository; @Autowired - private UserLibraryService userLibraryService; + private LibraryService libraryService; - @BeforeEach + @AfterEach public void tearDown() { - userLibraryRepository.deleteAllInBatch(); + libraryRepository.deleteAllInBatch(); bookRepository.deleteAllInBatch(); userRepository.deleteAllInBatch(); } @Test @DisplayName("사용자가 서재 정보를 조회한다.") - public void getUserLibrary() { + public void findLibraries() { // given User user = userRepository.save(createUser()); - Book book = bookRepository.save(createBook()); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); - - // when - UserLibraryResponse response = userLibraryService.getUserLibrary(user.getId(), book.getIsbn()); - - // then - assertThat(response.getId()).isEqualTo(userLibrary.getId()); - assertThat(response.getStatus()).isEqualTo(userLibrary.getStatus().getText()); - assertThat(response.getHasReadingStatus()).isTrue(); - } - - @Test - @DisplayName("비로그인으로 서재 정보 조회시 빈 응답을 받는다.") - public void getUserLibraryForUnAuthenticatedUser() { - // given - String bookIsbn = "0000X"; + List books = bookRepository.saveAll(createBooks()); + List libraries = libraryRepository.saveAll(createLibraries(user, books)); // when - UserLibraryResponse response = userLibraryService.getUserLibrary(null, bookIsbn); + List result = libraryService.findLibraries(user.getId()); // then - assertThat(response).isNotNull(); - assertThat(response.getId()).isNull(); - assertThat(response.getStatus()).isNull(); - assertThat(response.getHasReadingStatus()).isFalse(); + assertThat(result).hasSize(5) + .extracting("bookIsbn") + .containsExactly("1", "2", "3", "4", "5"); } @Test - @DisplayName("서재 정보 조회 시 isbn이 없는 경우 빈 응답을 받는다.") - public void getUserLibraryWithNonIsbn() { + @DisplayName("서재 정보 조회할 때 서재 정보가 없으면 빈 리스트를 반환한다.") + public void findLibrariesWithoutLibraries() { // given - String invalidIsbn = "0000X"; User user = userRepository.save(createUser()); // when - UserLibraryResponse response = userLibraryService.getUserLibrary(user.getId(), invalidIsbn); + List result = libraryService.findLibraries(user.getId()); // then - assertThat(response).isNotNull(); - assertThat(response.getId()).isNull(); - assertThat(response.getStatus()).isNull(); - assertThat(response.getHasReadingStatus()).isFalse(); + assertThat(result).isEmpty(); } @Test - @DisplayName("서재 정보 조회 시 서재 정보가 없을 시 빈 응답을 받는다.") - public void getUserLibraryWhenLibraryEmpty() { + @DisplayName("서재 정보 조회 시 사용자 정보가 존재해야 한다.") + public void findLibrariesWithoutUser() { // given - User user = userRepository.save(createUser()); - Book book = bookRepository.save(createBook()); + Long invalidUserId = 1L; - // when - UserLibraryResponse response = userLibraryService.getUserLibrary(user.getId(), book.getIsbn()); - - // then - assertThat(response).isNotNull(); - assertThat(response.getId()).isNull(); - assertThat(response.getStatus()).isNull(); - assertThat(response.getHasReadingStatus()).isFalse(); + // when // then + assertThatThrownBy(() -> libraryService.findLibraries(invalidUserId)) + .hasMessage("사용자를 찾을 수 없습니다.") + .isInstanceOf(BusinessException.class); } @Test @DisplayName("사용자가 서재 정보를 생성한다.") - public void createUserLibrary() { + public void createLibrary() { // given User user = userRepository.save(createUser()); Book book = bookRepository.save(createBook()); - UserLibraryCreateServiceRequest request = UserLibraryCreateServiceRequest.builder() + LibraryCreateServiceRequest request = LibraryCreateServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("want") .build(); // when - UserLibraryResponse response = userLibraryService.createUserLibrary(request, user.getId()); + LibraryResponse result = libraryService.createLibrary(request, user.getId()); // then - UserLibrary savedUserLibrary = userLibraryRepository.findAll().get(0); + Library savedLibrary = libraryRepository.findAll().get(0); - assertThat(response.getId()).isEqualTo(savedUserLibrary.getId()); - assertThat(response.getStatus()).isEqualTo(ReadingStatus.WANT.getText()); + assertThat(result.getId()).isEqualTo(savedLibrary.getId()); + assertThat(result.getBookIsbn()).isEqualTo(book.getIsbn()); + assertThat(result.getStatus()).isEqualTo(ReadingStatus.WANT.getText()); } @Test @DisplayName("서재 등록시 사용자 정보가 존재해야 한다.") - public void createUserLibraryWithoutUser() { + public void createLibraryWithoutUser() { // given Long invalidUserId = -1L; Book book = bookRepository.save(createBook()); - UserLibraryCreateServiceRequest request = UserLibraryCreateServiceRequest.builder() + LibraryCreateServiceRequest request = LibraryCreateServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("want") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.createUserLibrary(request, invalidUserId)) + assertThatThrownBy(() -> libraryService.createLibrary(request, invalidUserId)) .isInstanceOf(BusinessException.class) .hasMessage("사용자를 찾을 수 없습니다."); } @Test @DisplayName("서재 등록 시 책 정보가 존재해야 한다.") - public void createUserLibraryWithoutBook() { + public void createLibraryWithoutBook() { // given String invalidIsbn = "XXXXXXXXXXX"; User user = userRepository.save(createUser()); - UserLibraryCreateServiceRequest request = UserLibraryCreateServiceRequest.builder() + LibraryCreateServiceRequest request = LibraryCreateServiceRequest.builder() .isbn(invalidIsbn) .readingStatus("want") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.createUserLibrary(request, user.getId())) + assertThatThrownBy(() -> libraryService.createLibrary(request, user.getId())) .isInstanceOf(BusinessException.class) .hasMessage("책을 찾을 수 없습니다."); } @Test @DisplayName("서재 등록 시 동일한 정보의 서재가 존재하지 않아야 한다.") - public void createUserLibraryAlreadyExists() { + public void createLibraryAlreadyExists() { // given User user = userRepository.save(createUser()); Book book = bookRepository.save(createBook()); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); + Library library = libraryRepository.save(create(user, book)); - UserLibraryCreateServiceRequest request = UserLibraryCreateServiceRequest.builder() + LibraryCreateServiceRequest request = LibraryCreateServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("reading") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.createUserLibrary(request, user.getId())) + assertThatThrownBy(() -> libraryService.createLibrary(request, user.getId())) .isInstanceOf(BusinessException.class) .hasMessage("이미 등록된 서재 정보 입니다."); } @Test @DisplayName("서재 정보를 수정한다.") - public void editUserLibrary() { + public void editLibrary() { // given User user = userRepository.save(createUser()); Book book = bookRepository.save(createBook()); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); + Library library = libraryRepository.save(create(user, book)); - UserLibraryEditServiceRequest request = UserLibraryEditServiceRequest.builder() + LibraryEditServiceRequest request = LibraryEditServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("read") .build(); // when - userLibraryService.editUserLibrary(userLibrary.getId(), user.getId(), request); + libraryService.editLibrary(library.getId(), user.getId(), request); // then - Optional savedLibrary = userLibraryRepository.findById(userLibrary.getId()); + Optional savedLibrary = libraryRepository.findById(library.getId()); assertThat(savedLibrary).isNotEmpty(); assertThat(savedLibrary.get().getStatus()).isEqualTo(ReadingStatus.READ); @@ -215,163 +192,163 @@ public void editUserLibrary() { @Test @DisplayName("서재 정보 수정 시 사용자 정보가 존재해야 한다.") - public void editUserLibraryWithoutUser() { + public void editLibraryWithoutUser() { // given Long userLibraryId = 1L; Long userId = 1L; Book book = bookRepository.save(createBook()); - UserLibraryEditServiceRequest request = UserLibraryEditServiceRequest.builder() + LibraryEditServiceRequest request = LibraryEditServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("read") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.editUserLibrary(userLibraryId, userId, request)) + assertThatThrownBy(() -> libraryService.editLibrary(userLibraryId, userId, request)) .isInstanceOf(BusinessException.class) .hasMessage("사용자를 찾을 수 없습니다."); } @Test @DisplayName("서재 정보 수정 시 책 정보가 존재해야 한다.") - public void editUserLibraryWithoutBook() { + public void editLibraryWithoutBook() { // given Long userLibraryId = 1L; String bookIsbn = "0000X"; User user = userRepository.save(createUser()); - UserLibraryEditServiceRequest request = UserLibraryEditServiceRequest.builder() + LibraryEditServiceRequest request = LibraryEditServiceRequest.builder() .isbn(bookIsbn) .readingStatus("read") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.editUserLibrary(userLibraryId, user.getId(), request)) + assertThatThrownBy(() -> libraryService.editLibrary(userLibraryId, user.getId(), request)) .isInstanceOf(BusinessException.class) .hasMessage("책을 찾을 수 없습니다."); } @Test @DisplayName("서재 정보 수정 시 서재 정보가 존재해야 한다.") - public void editUserLibraryWithoutUserLibrary() { + public void editLibraryWithoutLibrary() { // given Long userLibraryId = 1L; User user = userRepository.save(createUser()); Book book = bookRepository.save(createBook()); - UserLibraryEditServiceRequest request = UserLibraryEditServiceRequest.builder() + LibraryEditServiceRequest request = LibraryEditServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("read") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.editUserLibrary(userLibraryId, user.getId(), request)) + assertThatThrownBy(() -> libraryService.editLibrary(userLibraryId, user.getId(), request)) .isInstanceOf(BusinessException.class) .hasMessage("서재 정보를 찾을 수 없습니다."); } @Test @DisplayName("서재 정보 수정 시 서재 정보와 사용자 정보는 일치해야 한다.") - public void editUserLibraryInvalidUser() { + public void editLibraryInvalidUser() { // given User user = userRepository.save(createUser()); User anotherUser = userRepository.save(createAnotherUser()); Book book = bookRepository.save(createBook()); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); + Library library = libraryRepository.save(create(user, book)); - UserLibraryEditServiceRequest request = UserLibraryEditServiceRequest.builder() + LibraryEditServiceRequest request = LibraryEditServiceRequest.builder() .isbn(book.getIsbn()) .readingStatus("read") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.editUserLibrary(userLibrary.getId(), anotherUser.getId(), request)) + assertThatThrownBy(() -> libraryService.editLibrary(library.getId(), anotherUser.getId(), request)) .isInstanceOf(BusinessException.class) .hasMessage("권한이 없는 사용자입니다."); } @Test @DisplayName("서재 정보 수정 시 서재 정보와 도서 정보는 일치해야 한다.") - public void editUserLibraryInvalidBook() { + public void editLibraryInvalidBook() { // given User user = userRepository.save(createUser()); Book book = bookRepository.save(createBookWithIsbn("00001")); Book anotherBook = bookRepository.save(createBookWithIsbn("00002")); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); + Library library = libraryRepository.save(create(user, book)); - UserLibraryEditServiceRequest request = UserLibraryEditServiceRequest.builder() + LibraryEditServiceRequest request = LibraryEditServiceRequest.builder() .isbn(anotherBook.getIsbn()) .readingStatus("read") .build(); // when // then - assertThatThrownBy(() -> userLibraryService.editUserLibrary(userLibrary.getId(), user.getId(), request)) + assertThatThrownBy(() -> libraryService.editLibrary(library.getId(), user.getId(), request)) .isInstanceOf(BusinessException.class) .hasMessage("올바르지 않은 책 정보 입니다."); } @Test @DisplayName("서재 정보를 삭제한다.") - public void deleteUserLibrary() { + public void deleteLibrary() { // given User user = userRepository.save(createUser()); Book book = bookRepository.save(createBook()); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); + Library library = libraryRepository.save(create(user, book)); // when - userLibraryService.deleteUserLibrary(userLibrary.getId(), user.getId()); + libraryService.deleteLibrary(library.getId(), user.getId()); // then - List response = userLibraryRepository.findAll(); + List response = libraryRepository.findAll(); assertThat(response).isEmpty(); } @Test @DisplayName("서재 정보 삭제 시 사용자 정보가 존재해야 한다.") - public void deleteUserLibraryWithoutUser() { + public void deleteLibraryWithoutUser() { // given Long userLibraryId = 1L; Long userId = 1L; Book book = bookRepository.save(createBook()); // when // then - assertThatThrownBy(() -> userLibraryService.deleteUserLibrary(userLibraryId, userId)) + assertThatThrownBy(() -> libraryService.deleteLibrary(userLibraryId, userId)) .isInstanceOf(BusinessException.class) .hasMessage("사용자를 찾을 수 없습니다."); } @Test @DisplayName("서재 정보 삭제 시 서재 정보가 존재해야 한다.") - public void deleteUserLibraryWithoutUserLibrary() { + public void deleteLibraryWithoutLibrary() { // given Long userLibraryId = 1L; User user = userRepository.save(createUser()); // when // then - assertThatThrownBy(() -> userLibraryService.deleteUserLibrary(userLibraryId, user.getId())) + assertThatThrownBy(() -> libraryService.deleteLibrary(userLibraryId, user.getId())) .isInstanceOf(BusinessException.class) .hasMessage("서재 정보를 찾을 수 없습니다."); } @Test @DisplayName("서재 정보 삭제 시 서재 정보와 사용자 정보는 일치해야 한다.") - public void deleteUserLibraryInvalidUser() { + public void deleteLibraryInvalidUser() { // given User user = userRepository.save(createUser()); User anotherUser = userRepository.save(createAnotherUser()); Book book = bookRepository.save(createBook()); - UserLibrary userLibrary = userLibraryRepository.save(create(user, book)); + Library library = libraryRepository.save(create(user, book)); // when // then assertThatThrownBy( - () -> userLibraryService.deleteUserLibrary(userLibrary.getId(), anotherUser.getId())) + () -> libraryService.deleteLibrary(library.getId(), anotherUser.getId())) .isInstanceOf(BusinessException.class) .hasMessage("권한이 없는 사용자입니다."); } @@ -428,12 +405,24 @@ private static Book createBookWithIsbn(String isbn) { .build(); } - public static UserLibrary create(User user, Book book) { - return UserLibrary.builder() + private static List createBooks() { + return IntStream.rangeClosed(1, 5) + .mapToObj(i -> createBookWithIsbn(String.valueOf(i))) + .toList(); + } + + public static Library create(User user, Book book) { + return Library.builder() .user(user) .book(book) .status(ReadingStatus.WANT) .build(); } + public static List createLibraries(User user, List books) { + return IntStream.range(0, 5) + .mapToObj(i -> create(user, books.get(i))) + .toList(); + } + } diff --git a/src/test/java/com/jisungin/application/review/ReviewServiceTest.java b/src/test/java/com/jisungin/application/review/ReviewServiceTest.java index b266184..9695b09 100644 --- a/src/test/java/com/jisungin/application/review/ReviewServiceTest.java +++ b/src/test/java/com/jisungin/application/review/ReviewServiceTest.java @@ -1,5 +1,8 @@ package com.jisungin.application.review; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import com.jisungin.ServiceTestSupport; import com.jisungin.application.OffsetLimit; import com.jisungin.application.SliceResponse; @@ -7,26 +10,23 @@ import com.jisungin.application.review.response.ReviewWithRatingResponse; import com.jisungin.domain.book.Book; import com.jisungin.domain.book.repository.BookRepository; +import com.jisungin.domain.review.Review; +import com.jisungin.domain.review.repository.ReviewRepository; import com.jisungin.domain.reviewlike.ReviewLike; import com.jisungin.domain.reviewlike.repository.ReviewLikeRepository; import com.jisungin.domain.user.OauthId; import com.jisungin.domain.user.OauthType; -import com.jisungin.domain.review.Review; -import com.jisungin.domain.review.repository.ReviewRepository; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; import com.jisungin.exception.BusinessException; +import java.time.LocalDateTime; +import java.util.List; import java.util.stream.IntStream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.time.LocalDateTime; -import java.util.List; - -import static org.assertj.core.api.Assertions.*; - class ReviewServiceTest extends ServiceTestSupport { @Autowired @@ -92,6 +92,34 @@ void findBookReviewsWithoutBook() { .hasMessage("책을 찾을 수 없습니다."); } + @DisplayName("도서와 연관된 리뷰 개수를 조회한다.") + @Test + void findBookReviewsCount() { + // given + Book book = bookRepository.save(createBook()); + + List users = userRepository.saveAll(createUsers()); + List reviews = reviewRepository.saveAll(createReviews(users, book)); + + // when + Long result = reviewService.findBookReviewsCount(book.getIsbn()); + + // then + assertThat(result).isEqualTo(20L); + } + + @DisplayName("도서와 연관된 리뷰 개수 조회시 도서가 존재해야 한다.") + @Test + void findBookReviewsCountWithoutBook() { + // given + String invalidIsbn = "0000X"; + + // when // then + assertThatThrownBy(() -> reviewService.findBookReviewsCount(invalidIsbn)) + .hasMessage("책을 찾을 수 없습니다.") + .isInstanceOf(BusinessException.class); + } + @DisplayName("유저가 리뷰를 등록한다.") @Test void createReview() { diff --git a/src/test/java/com/jisungin/application/user/UserServiceTest.java b/src/test/java/com/jisungin/application/user/UserServiceTest.java index de6eb74..0dabb2f 100644 --- a/src/test/java/com/jisungin/application/user/UserServiceTest.java +++ b/src/test/java/com/jisungin/application/user/UserServiceTest.java @@ -5,23 +5,26 @@ import static com.jisungin.domain.ReadingStatus.READING; import static com.jisungin.domain.ReadingStatus.STOP; import static com.jisungin.domain.ReadingStatus.WANT; -import static com.jisungin.domain.review.RatingOrderType.*; -import static com.jisungin.domain.userlibrary.ReadingStatusOrderType.DICTIONARY; +import static com.jisungin.domain.library.ReadingStatusOrderType.DICTIONARY; +import static com.jisungin.domain.review.RatingOrderType.RATING_ASC; +import static com.jisungin.domain.review.RatingOrderType.RATING_AVG_ASC; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; import com.jisungin.ServiceTestSupport; import com.jisungin.application.PageResponse; +import com.jisungin.application.library.response.UserReadingStatusResponse; import com.jisungin.application.rating.response.RatingGetResponse; import com.jisungin.application.review.response.ReviewContentGetAllResponse; 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.domain.ReadingStatus; import com.jisungin.domain.book.Book; import com.jisungin.domain.book.repository.BookRepository; +import com.jisungin.domain.library.Library; +import com.jisungin.domain.library.repository.LibraryRepository; import com.jisungin.domain.rating.Rating; import com.jisungin.domain.rating.repository.RatingRepository; import com.jisungin.domain.review.Review; @@ -32,15 +35,11 @@ import com.jisungin.domain.user.OauthType; import com.jisungin.domain.user.User; import com.jisungin.domain.user.repository.UserRepository; -import com.jisungin.domain.userlibrary.UserLibrary; -import com.jisungin.domain.userlibrary.repository.UserLibraryRepository; - import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -64,14 +63,14 @@ class UserServiceTest extends ServiceTestSupport { private ReviewLikeRepository reviewLikeRepository; @Autowired - private UserLibraryRepository userLibraryRepository; + private LibraryRepository libraryRepository; @Autowired private UserService userService; @AfterEach void tearDown() { - userLibraryRepository.deleteAllInBatch(); + libraryRepository.deleteAllInBatch(); reviewLikeRepository.deleteAllInBatch(); reviewRepository.deleteAllInBatch(); ratingRepository.deleteAllInBatch(); @@ -154,7 +153,7 @@ void getReadingStatuses() { User user2 = userRepository.save(createUser("2")); List books = bookRepository.saveAll(createBooks()); List ratings1 = ratingRepository.saveAll(createRatings(user1, books)); - List userLibraries = userLibraryRepository.saveAll(createUserLibraries(user1, books)); + List userLibraries = libraryRepository.saveAll(createUserLibraries(user1, books)); // 읽고 싶은 상태인 책을 사전 순으로 정렬하고 1페이지를 가져온다. UserReadingStatusGetAllServiceRequest request = UserReadingStatusGetAllServiceRequest.builder() @@ -258,22 +257,22 @@ private static User createUser(String oauthId) { .build(); } - private static List createUserLibraries(User user, List books) { - List userLibraries = new ArrayList<>(); + private static List createUserLibraries(User user, List books) { + List userLibraries = new ArrayList<>(); List statuses = List.of(WANT, READING, READ, PAUSE, STOP); IntStream.rangeClosed(1, 20) .forEach(i -> { ReadingStatus readingStatus = statuses.get((i - 1) % statuses.size()); - UserLibrary userLibrary = createUserLibrary(user, books.get(i - 1), readingStatus); - userLibraries.add(userLibrary); + Library library = createUserLibrary(user, books.get(i - 1), readingStatus); + userLibraries.add(library); }); return userLibraries; } - private static UserLibrary createUserLibrary(User user, Book book, ReadingStatus readingStatus) { - return UserLibrary.builder() + private static Library createUserLibrary(User user, Book book, ReadingStatus readingStatus) { + return Library.builder() .user(user) .book(book) .status(readingStatus) diff --git a/src/test/java/com/jisungin/docs/userlibrary/UserLibraryControllerDocsTest.java b/src/test/java/com/jisungin/docs/library/LibraryControllerDocsTest.java similarity index 67% rename from src/test/java/com/jisungin/docs/userlibrary/UserLibraryControllerDocsTest.java rename to src/test/java/com/jisungin/docs/library/LibraryControllerDocsTest.java index 00034a2..1a7ec3d 100644 --- a/src/test/java/com/jisungin/docs/userlibrary/UserLibraryControllerDocsTest.java +++ b/src/test/java/com/jisungin/docs/library/LibraryControllerDocsTest.java @@ -1,9 +1,8 @@ -package com.jisungin.docs.userlibrary; +package com.jisungin.docs.library; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyLong; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; @@ -14,7 +13,7 @@ import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.JsonFieldType.BOOLEAN; +import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; import static org.springframework.restdocs.payload.JsonFieldType.OBJECT; import static org.springframework.restdocs.payload.JsonFieldType.STRING; @@ -23,80 +22,77 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.jisungin.api.userlibrary.UserLibraryController; -import com.jisungin.api.userlibrary.request.UserLibraryCreateRequest; -import com.jisungin.api.userlibrary.request.UserLibraryEditRequest; -import com.jisungin.application.userlibrary.UserLibraryService; -import com.jisungin.application.userlibrary.request.UserLibraryCreateServiceRequest; -import com.jisungin.application.userlibrary.response.UserLibraryResponse; +import com.jisungin.api.library.LibraryController; +import com.jisungin.api.library.request.LibraryCreateRequest; +import com.jisungin.api.library.request.LibraryEditRequest; +import com.jisungin.application.library.LibraryService; +import com.jisungin.application.library.request.LibraryCreateServiceRequest; +import com.jisungin.application.library.response.LibraryResponse; import com.jisungin.docs.RestDocsSupport; +import java.util.List; +import java.util.stream.LongStream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -public class UserLibraryControllerDocsTest extends RestDocsSupport { +public class LibraryControllerDocsTest extends RestDocsSupport { - private final UserLibraryService userLibraryService = mock(UserLibraryService.class); + private final LibraryService libraryService = mock(LibraryService.class); @Override protected Object initController() { - return new UserLibraryController(userLibraryService); + return new LibraryController(libraryService); } @Test - @DisplayName("서재 단건 조회 API") - public void getUserLibrary() throws Exception { - String isbn = "000000000001"; - - given(userLibraryService.getUserLibrary(anyLong(), anyString())) - .willReturn(createUserLibraryResponse()); - - mockMvc.perform(get("/v1/user-libraries") - .param("isbn", isbn) + @DisplayName("서재 조회 API") + public void findLibraries() throws Exception { + // given + given(libraryService.findLibraries(anyLong())) + .willReturn(createLibraryResponses()); + + // when // then + mockMvc.perform(get("/v1/libraries") .accept(APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("user-library/get", + .andDo(document("library/get", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), - queryParameters( - parameterWithName("isbn").description("도서 ISBN") - ), responseFields( fieldWithPath("code").type(NUMBER).description("코드"), fieldWithPath("status").type(STRING).description("상태"), fieldWithPath("message").type(STRING).description("메세지"), - fieldWithPath("data").type(OBJECT).description("응답 데이터"), - fieldWithPath("data.id").type(NUMBER).description("서재 ID"), - fieldWithPath("data.status").type(STRING).description("서재 도서 상태"), - fieldWithPath("data.hasReadingStatus").type(BOOLEAN).description("서재 도서 상태 존재 여부") + fieldWithPath("data[]").type(ARRAY).description("응답 데이터"), + fieldWithPath("data[].id").type(NUMBER).description("서재 ID"), + fieldWithPath("data[].bookIsbn").type(STRING).description("도서 ISBN"), + fieldWithPath("data[].status").type(STRING).description("서재 도서 상태") ) )); } @Test @DisplayName("서재 생성 API") - public void createUserLibrary() throws Exception { + public void createLibrary() throws Exception { String isbn = "000000000001"; - UserLibraryCreateRequest request = UserLibraryCreateRequest.builder() + LibraryCreateRequest request = LibraryCreateRequest.builder() .isbn(isbn) .readingStatus("read") .build(); - given(userLibraryService.createUserLibrary(any(UserLibraryCreateServiceRequest.class), anyLong())) - .willReturn(createUserLibraryResponse()); + given(libraryService.createLibrary(any(LibraryCreateServiceRequest.class), anyLong())) + .willReturn(createLibraryResponse(1L, isbn)); - mockMvc.perform(post("/v1/user-libraries") + mockMvc.perform(post("/v1/libraries") .accept(APPLICATION_JSON) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("user-library/create", + .andDo(document("library/create", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields( @@ -110,8 +106,8 @@ public void createUserLibrary() throws Exception { fieldWithPath("message").type(STRING).description("메세지"), fieldWithPath("data").type(OBJECT).description("응답 데이터"), fieldWithPath("data.id").type(NUMBER).description("서재 ID"), - fieldWithPath("data.status").type(STRING).description("서재 도서 상태"), - fieldWithPath("data.hasReadingStatus").type(BOOLEAN).description("서재 도서 상태 존재 여부") + fieldWithPath("data.bookIsbn").type(STRING).description("도서 ISBN"), + fieldWithPath("data.status").type(STRING).description("서재 도서 상태") ) )); } @@ -121,21 +117,21 @@ public void createUserLibrary() throws Exception { public void editUserLibrary() throws Exception { String isbn = "000000000001"; - UserLibraryEditRequest request = UserLibraryEditRequest.builder() + LibraryEditRequest request = LibraryEditRequest.builder() .isbn(isbn) .readingStatus("pause") .build(); - mockMvc.perform(patch("/v1/user-libraries/{userLibraryId}", 1L) + mockMvc.perform(patch("/v1/libraries/{libraryId}", 1L) .contentType(APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("user-library/edit", + .andDo(document("library/edit", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( - parameterWithName("userLibraryId").description("서재 ID") + parameterWithName("libraryId").description("서재 ID") ), requestFields( fieldWithPath("isbn").description("도서 ISBN"), @@ -154,15 +150,15 @@ public void editUserLibrary() throws Exception { @Test @DisplayName("서재 삭제 API") - public void deleteUserLibrary() throws Exception { - mockMvc.perform(delete("/v1/user-libraries/{userLibraryId}", 1L)) + public void deleteLibrary() throws Exception { + mockMvc.perform(delete("/v1/libraries/{libraryId}", 1L)) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("user-library/delete", + .andDo(document("library/delete", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( - parameterWithName("userLibraryId").description("서재 ID") + parameterWithName("libraryId").description("서재 ID") ), responseFields( fieldWithPath("code").type(NUMBER).description("코드"), @@ -174,12 +170,18 @@ public void deleteUserLibrary() throws Exception { } - private UserLibraryResponse createUserLibraryResponse() { - return UserLibraryResponse.builder() - .id(1L) + private LibraryResponse createLibraryResponse(Long id, String bookIsbn) { + return LibraryResponse.builder() + .id(id) + .bookIsbn(bookIsbn) .status("읽음") - .hasReadingStatus(true) .build(); } + private List createLibraryResponses() { + return LongStream.rangeClosed(1, 5) + .mapToObj(i -> createLibraryResponse(i, String.valueOf(i))) + .toList(); + } + } diff --git a/src/test/java/com/jisungin/docs/review/ReviewControllerDocsTest.java b/src/test/java/com/jisungin/docs/review/ReviewControllerDocsTest.java index e4d2b09..3924912 100644 --- a/src/test/java/com/jisungin/docs/review/ReviewControllerDocsTest.java +++ b/src/test/java/com/jisungin/docs/review/ReviewControllerDocsTest.java @@ -131,6 +131,39 @@ void findBookReviews() throws Exception { ); } + @DisplayName("도서와 연관된 리뷰 개수 조회 API") + @Test + void findBookReviewsCount() throws Exception { + // given + String isbn = "000000000001"; + + given(reviewService.findBookReviewsCount(anyString())) + .willReturn(20L); + + // when // then + mockMvc.perform(get("/v1/books/{isbn}/reviews/count", isbn) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("review/get-related-book-count", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("isbn").description("도서 ISBN") + ), + responseFields( + fieldWithPath("code").type(JsonFieldType.NUMBER) + .description("코드"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("상태"), + fieldWithPath("message").type(JsonFieldType.STRING) + .description("메세지"), + fieldWithPath("data").type(JsonFieldType.NUMBER) + .description("도서와 연관된 리뷰 총 개수") + ) + )); + } + @DisplayName("한줄평을 생성하는 API") @Test void createReview() throws Exception { diff --git a/src/test/java/com/jisungin/docs/talkroom/TalkRoomControllerDocsTest.java b/src/test/java/com/jisungin/docs/talkroom/TalkRoomControllerDocsTest.java index 15ce881..e935617 100644 --- a/src/test/java/com/jisungin/docs/talkroom/TalkRoomControllerDocsTest.java +++ b/src/test/java/com/jisungin/docs/talkroom/TalkRoomControllerDocsTest.java @@ -76,6 +76,7 @@ void crateTalkRoom() throws Exception { .username("작성자 이름") .title("토론방 제목") .content("토론방 본문") + .bookIsbn("1111111") .bookName("책 제목") .bookAuthor("책 저자") .bookThumbnail("책 이미지 URL") @@ -129,6 +130,8 @@ void crateTalkRoom() throws Exception { .description("토론방 본문"), fieldWithPath("data.images").type(JsonFieldType.ARRAY) .description("토론방 이미지 URL"), + fieldWithPath("data.bookIsbn").type(JsonFieldType.STRING) + .description("책 ISBN"), fieldWithPath("data.bookName").type(JsonFieldType.STRING) .description("책 제목"), fieldWithPath("data.bookAuthor").type(JsonFieldType.STRING) @@ -316,6 +319,7 @@ void findOneTalkRoom() throws Exception { .username("작성자 이름") .title("토론방 제목") .content("토론방 본문") + .bookIsbn("000000000000") .bookName("책 제목") .bookAuthor("책 저자") .bookThumbnail("책 이미지 URL") @@ -362,6 +366,8 @@ void findOneTalkRoom() throws Exception { .description("토론방 본문"), fieldWithPath("data.images").type(JsonFieldType.ARRAY) .description("토론방 이미지 URL"), + fieldWithPath("data.bookIsbn").type(JsonFieldType.STRING) + .description("책 ISBN"), fieldWithPath("data.bookName").type(JsonFieldType.STRING) .description("책 제목"), fieldWithPath("data.bookAuthor").type(JsonFieldType.STRING) diff --git a/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java b/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java index d061fa2..cb8485f 100644 --- a/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java +++ b/src/test/java/com/jisungin/docs/user/UserControllerDocsTest.java @@ -10,7 +10,7 @@ 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.application.library.response.UserReadingStatusResponse; import com.jisungin.docs.RestDocsSupport; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -225,7 +225,7 @@ void getReadingStatuses() throws Exception { .andExpect(jsonPath("$.status").value("OK")) .andExpect(jsonPath("$.message").value("OK")) .andDo(print()) - .andDo(document("user-library/get-status", + .andDo(document("library/get-status", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), queryParameters( diff --git a/src/test/java/com/jisungin/domain/book/repository/BookRepositoryTest.java b/src/test/java/com/jisungin/domain/book/repository/BookRepositoryTest.java index f2c39f0..122ae81 100644 --- a/src/test/java/com/jisungin/domain/book/repository/BookRepositoryTest.java +++ b/src/test/java/com/jisungin/domain/book/repository/BookRepositoryTest.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.stream.IntStream; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -36,6 +37,15 @@ public class BookRepositoryTest extends RepositoryTestSupport { @Autowired private CommentRepository commentRepository; + @AfterEach + void tearDown() { + commentRepository.deleteAllInBatch(); + talkRoomRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + bookRepository.deleteAllInBatch(); + } + + @Test @DisplayName("최근 등록된 책 페이지 조회 쿼리") public void getBooksByRecent() { diff --git a/src/test/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImplTest.java b/src/test/java/com/jisungin/domain/library/repository/LibraryRepositoryImplTest.java similarity index 72% rename from src/test/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImplTest.java rename to src/test/java/com/jisungin/domain/library/repository/LibraryRepositoryImplTest.java index 24a62a8..9a6b3b9 100644 --- a/src/test/java/com/jisungin/domain/userlibrary/repository/UserLibraryRepositoryImplTest.java +++ b/src/test/java/com/jisungin/domain/library/repository/LibraryRepositoryImplTest.java @@ -1,8 +1,9 @@ -package com.jisungin.domain.userlibrary.repository; +package com.jisungin.domain.library.repository; import com.jisungin.RepositoryTestSupport; import com.jisungin.application.PageResponse; -import com.jisungin.application.userlibrary.response.UserReadingStatusResponse; +import com.jisungin.domain.library.LibraryQueryEntity; +import com.jisungin.application.library.response.UserReadingStatusResponse; import com.jisungin.domain.ReadingStatus; import com.jisungin.domain.book.Book; import com.jisungin.domain.book.repository.BookRepository; @@ -10,7 +11,7 @@ import com.jisungin.domain.rating.repository.RatingRepository; import com.jisungin.domain.review.Review; import com.jisungin.domain.review.repository.ReviewRepository; -import com.jisungin.domain.userlibrary.UserLibrary; +import com.jisungin.domain.library.Library; import com.jisungin.domain.user.OauthId; import com.jisungin.domain.user.OauthType; import com.jisungin.domain.user.User; @@ -27,10 +28,10 @@ import java.util.stream.IntStream; import static com.jisungin.domain.ReadingStatus.*; -import static com.jisungin.domain.userlibrary.ReadingStatusOrderType.*; +import static com.jisungin.domain.library.ReadingStatusOrderType.*; import static org.assertj.core.api.Assertions.*; -class UserLibraryRepositoryImplTest extends RepositoryTestSupport { +class LibraryRepositoryImplTest extends RepositoryTestSupport { @Autowired private UserRepository userRepository; @@ -45,17 +46,46 @@ class UserLibraryRepositoryImplTest extends RepositoryTestSupport { private RatingRepository ratingRepository; @Autowired - private UserLibraryRepository userLibraryRepository; + private LibraryRepository libraryRepository; @AfterEach void tearDown() { - userLibraryRepository.deleteAllInBatch(); + libraryRepository.deleteAllInBatch(); reviewRepository.deleteAllInBatch(); ratingRepository.deleteAllInBatch(); bookRepository.deleteAllInBatch(); userRepository.deleteAllInBatch(); } + @DisplayName("유저 아이디에 대한 독서 상태를 가져온다.") + @Test + void findAllByUserId() { + // given + User user = userRepository.save(createUser("1")); + List books = bookRepository.saveAll(createBooks()); + List libraries = libraryRepository.saveAll(createUserLibraries(user, books)); + + // when + List result = libraryRepository.findAllByUserId(user.getId()); + + // then + assertThat(result).hasSize(20); + } + + @DisplayName("유저 아이디에 대한 독서 상태가 존재하지 않는 경우 빈 배열을 반환한다.") + @Test + void findAllByUserIdWithoutLibrary() { + // given + User user = userRepository.save(createUser("1")); + List books = bookRepository.saveAll(createBooks()); + + // when + List result = libraryRepository.findAllByUserId(user.getId()); + + // then + assertThat(result).hasSize(0); + } + @DisplayName("유저가 저장한 모든 독서 상태를 가져온다.") @Test void findAllReadingStatusOrderBy() { @@ -64,10 +94,10 @@ void findAllReadingStatusOrderBy() { User user2 = userRepository.save(createUser("2")); List books = bookRepository.saveAll(createBooks()); List ratings = ratingRepository.saveAll(createRatings(user1, books)); - List userLibraries = userLibraryRepository.saveAll(createUserLibraries(user1, books)); + List userLibraries = libraryRepository.saveAll(createUserLibraries(user1, books)); //when - PageResponse result = userLibraryRepository.findAllReadingStatusOrderBy( + PageResponse result = libraryRepository.findAllReadingStatusOrderBy( user1.getId(), WANT, DICTIONARY, 4, 0); //then @@ -91,7 +121,7 @@ void exitsByUserIdAndBookId() { Book book = bookRepository.save(createBook("도서 제목", "도서 내용", "0000X")); // when - Boolean result = userLibraryRepository.existsByUserIdAndBookId(user.getId(), book.getIsbn()); + Boolean result = libraryRepository.existsByUserIdAndBookId(user.getId(), book.getIsbn()); // then assertThat(result).isFalse(); @@ -103,11 +133,11 @@ void existsByUserIdAndBookIdAlreadyExists() { // given User user = userRepository.save(createUser("1")); Book book = bookRepository.save(createBook("도서 제목", "도서 내용", "0000X")); - UserLibrary userLibrary = userLibraryRepository.save(createUserLibrary(user, book, WANT)); + Library library = libraryRepository.save(createUserLibrary(user, book, WANT)); // when - Boolean result = userLibraryRepository.existsByUserIdAndBookId(user.getId(), book.getIsbn()); + Boolean result = libraryRepository.existsByUserIdAndBookId(user.getId(), book.getIsbn()); // then assertThat(result).isTrue(); @@ -162,22 +192,22 @@ private static Review createReview(User user, Book book, Double rating) { .build(); } - private static List createUserLibraries(User user, List books) { - List userLibraries = new ArrayList<>(); + private static List createUserLibraries(User user, List books) { + List userLibraries = new ArrayList<>(); List statuses = List.of(WANT, READING, READ, PAUSE, STOP); IntStream.rangeClosed(1, 20) .forEach(i -> { ReadingStatus readingStatus = statuses.get((i - 1) % statuses.size()); - UserLibrary userLibrary = createUserLibrary(user, books.get(i - 1), readingStatus); - userLibraries.add(userLibrary); + Library library = createUserLibrary(user, books.get(i - 1), readingStatus); + userLibraries.add(library); }); return userLibraries; } - private static UserLibrary createUserLibrary(User user, Book book, ReadingStatus readingStatus) { - return UserLibrary.builder() + private static Library createUserLibrary(User user, Book book, ReadingStatus readingStatus) { + return Library.builder() .user(user) .book(book) .status(readingStatus) diff --git a/src/test/java/com/jisungin/domain/review/repository/ReviewRepositoryTest.java b/src/test/java/com/jisungin/domain/review/repository/ReviewRepositoryTest.java index 3b1c409..5542d21 100644 --- a/src/test/java/com/jisungin/domain/review/repository/ReviewRepositoryTest.java +++ b/src/test/java/com/jisungin/domain/review/repository/ReviewRepositoryTest.java @@ -242,6 +242,35 @@ public void findAllBookIdOrderByRatingAscWithoutRating() { assertThat(result.getContent()).hasSize(0); } + @DisplayName("도서와 연관된 리뷰의 개수를 조회한다.") + @Test + public void findBookReviewsCount() { + // given + Book book = bookRepository.save(createBook("도서 제목", "도서 내용", "00001", "저자명", "출판사")); + + List users = userRepository.saveAll(createUsers()); + List reviews = reviewRepository.saveAll(createReviewsForBook(users, book)); + + // when + Long result = reviewRepository.countByBookId(book.getIsbn()); + + // then + assertThat(result).isEqualTo(20L); + } + + @DisplayName("도서와 연관된 리뷰가 없는 경우 0을 리턴한다.") + @Test + public void findBookReviewsCountWithoutReview() { + // given + Book book = bookRepository.save(createBook("도서 제목", "도서 내용", "00001", "저자명", "출판사")); + + // when + Long result = reviewRepository.countByBookId(book.getIsbn()); + + // then + assertThat(result).isEqualTo(0L); + } + private static List createBooks() { return IntStream.rangeClosed(1, 20) .mapToObj(i -> createBook(