-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 내서재 동적검색 기능 구현 #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3a06361
bd130c0
a08c0f7
21daa1d
7a51a7f
74430fe
18d80d8
9a4433a
43fae80
ee7d032
1fb5894
ff6ad35
cef9e45
747ef27
1a143d1
17b7df1
a482901
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,18 +8,25 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse | |
| import io.swagger.v3.oas.annotations.responses.ApiResponses | ||
| import io.swagger.v3.oas.annotations.tags.Tag | ||
| import jakarta.validation.Valid | ||
| import org.springframework.data.domain.Page | ||
| import org.springframework.data.domain.Pageable | ||
| import org.springframework.data.domain.Sort | ||
| import org.springframework.data.web.PageableDefault | ||
| import org.springframework.http.ResponseEntity | ||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | ||
| import org.springframework.web.bind.annotation.GetMapping | ||
| import org.springframework.web.bind.annotation.PutMapping | ||
| import org.springframework.web.bind.annotation.RequestBody | ||
| import org.springframework.web.bind.annotation.RequestMapping | ||
| import org.springframework.web.bind.annotation.RequestParam | ||
| import org.yapp.apis.book.dto.request.BookDetailRequest | ||
| import org.yapp.apis.book.dto.request.BookSearchRequest | ||
| import org.yapp.apis.book.dto.request.UserBookRegisterRequest | ||
| import org.yapp.apis.book.dto.response.BookDetailResponse | ||
| import org.yapp.apis.book.dto.response.BookSearchResponse | ||
| import org.yapp.apis.book.dto.response.UserBookPageResponse | ||
| import org.yapp.apis.book.dto.response.UserBookResponse | ||
| import org.yapp.domain.userbook.BookStatus | ||
| import org.yapp.globalutils.exception.ErrorResponse | ||
| import java.util.UUID | ||
|
|
||
|
|
@@ -130,5 +137,12 @@ interface BookControllerApi { | |
| ] | ||
| ) | ||
| @GetMapping("/my-library") | ||
| fun getUserLibraryBooks(@AuthenticationPrincipal userId: UUID): ResponseEntity<List<UserBookResponse>> | ||
| fun getUserLibraryBooks( | ||
| @AuthenticationPrincipal userId: UUID, | ||
| @RequestParam(required = false) status: BookStatus?, | ||
| @RequestParam(required = false) sort: String?, | ||
| @PageableDefault(size = 10, sort = ["createdAt"], direction = Sort.Direction.DESC) | ||
| pageable: Pageable | ||
| ): ResponseEntity<UserBookPageResponse> | ||
|
Comment on lines
+140
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 동적 검색 API 인터페이스 개선 승인 사용자 서재 조회 API가 필터링, 정렬, 페이징을 지원하도록 확장되었습니다. 파라미터 설계와 기본값 설정이 적절합니다. 기본 페이지 크기(10)와 정렬 기준(createdAt DESC)이 사용자 경험에 적합한지 검토해보세요. 🤖 Prompt for AI Agents |
||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package org.yapp.apis.book.dto.response | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema | ||
| import org.springframework.data.domain.Page | ||
|
|
||
| @Schema(description = "사용자의 책 페이지 응답") | ||
| data class UserBookPageResponse private constructor( | ||
|
|
||
| @Schema(description = "책 목록 (페이지네이션)", implementation = UserBookResponse::class) | ||
| val books: Page<UserBookResponse>, | ||
|
|
||
| @Schema(description = "읽기 전 상태의 책 개수") | ||
| val beforeReadingCount: Long, | ||
|
|
||
| @Schema(description = "읽고 있는 책 개수") | ||
| val readingCount: Long, | ||
|
|
||
| @Schema(description = "완독한 책 개수") | ||
| val completedCount: Long | ||
| ) { | ||
| companion object { | ||
| fun of( | ||
| books: Page<UserBookResponse>, | ||
| beforeReadingCount: Long, | ||
| readingCount: Long, | ||
| completedCount: Long | ||
| ): UserBookPageResponse { | ||
| return UserBookPageResponse( | ||
| books = books, | ||
| beforeReadingCount = beforeReadingCount, | ||
| readingCount = readingCount, | ||
| completedCount = completedCount | ||
| ) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,7 @@ class BookManagementService( | |
| request.validIsbn(), | ||
| request.validTitle(), | ||
| request.validAuthor(), | ||
| request.validAuthor(), | ||
| request.validPublisher(), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굿굿! |
||
| request.coverImageUrl, | ||
| request.publicationYear, | ||
| request.description | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,16 @@ | ||
| package org.yapp.apis.book.service | ||
|
|
||
| import org.springframework.data.domain.Page | ||
| import org.springframework.data.domain.Pageable | ||
| import org.springframework.stereotype.Service | ||
| import org.yapp.apis.auth.dto.request.UserBooksByIsbnsRequest | ||
| import org.yapp.apis.book.dto.response.UserBookPageResponse | ||
| import org.yapp.apis.book.dto.response.UserBookResponse | ||
| import org.yapp.apis.book.dto.request.UpsertUserBookRequest | ||
| import org.yapp.domain.userbook.BookStatus | ||
| import org.yapp.domain.userbook.UserBookDomainService | ||
| import org.yapp.domain.userbook.vo.UserBookInfoVO | ||
| import org.yapp.domain.userbook.vo.UserBookStatusCountsVO | ||
| import java.util.UUID | ||
|
|
||
|
|
||
|
|
@@ -18,9 +23,9 @@ class UserBookService( | |
| userBookDomainService.upsertUserBook( | ||
| upsertUserBookRequest.userId, | ||
| upsertUserBookRequest.bookIsbn, | ||
| upsertUserBookRequest.bookPublisher, | ||
| upsertUserBookRequest.bookAuthor, | ||
| upsertUserBookRequest.bookTitle, | ||
| upsertUserBookRequest.bookAuthor, | ||
| upsertUserBookRequest.bookPublisher, | ||
| upsertUserBookRequest.bookCoverImageUrl, | ||
| upsertUserBookRequest.status | ||
| ) | ||
|
|
@@ -42,5 +47,30 @@ class UserBookService( | |
| .map { UserBookResponse.from(it) } | ||
| } | ||
|
|
||
| } | ||
| private fun findUserBooksByDynamicCondition( | ||
| userId: UUID, | ||
| status: BookStatus?, | ||
| sort: String?, | ||
| pageable: Pageable | ||
| ): Page<UserBookResponse> { | ||
| return userBookDomainService.findUserBooksByDynamicCondition(userId, status, sort, pageable) | ||
| .map { UserBookResponse.from(it) } | ||
| } | ||
|
|
||
| fun findUserBooksByDynamicConditionWithStatusCounts( | ||
| userId: UUID, | ||
| status: BookStatus?, | ||
| sort: String?, | ||
| pageable: Pageable | ||
| ): UserBookPageResponse { | ||
| val userBookResponsePage = findUserBooksByDynamicCondition(userId, status, sort, pageable) | ||
| val userBookStatusCountsVO = userBookDomainService.getUserBookStatusCounts(userId) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 변수명을 더 명확하게 개선할 수 있습니다. 과거 리뷰 의견을 반영하여 VO임을 명시적으로 드러내는 변수명을 사용하면 좋겠습니다. 다음과 같이 변수명을 개선해보세요: - val userBookStatusCountsVO = userBookDomainService.getUserBookStatusCounts(userId)
+ val statusCountsVO = userBookDomainService.getUserBookStatusCounts(userId)또는 VO임을 더 명확히 표현하려면: - val userBookStatusCountsVO = userBookDomainService.getUserBookStatusCounts(userId)
+ val bookStatusCountsVO = userBookDomainService.getUserBookStatusCounts(userId)🤖 Prompt for AI Agents |
||
|
|
||
| return UserBookPageResponse.of( | ||
| books = userBookResponsePage, | ||
| beforeReadingCount = userBookStatusCountsVO.beforeReadingCount, | ||
| readingCount = userBookStatusCountsVO.readingCount, | ||
| completedCount = userBookStatusCountsVO.completedCount | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| package org.yapp.apis.book.usecase | ||
|
|
||
| import org.springframework.beans.factory.annotation.Qualifier | ||
| import org.springframework.data.domain.Page | ||
| import org.springframework.data.domain.Pageable | ||
| import org.springframework.transaction.annotation.Transactional | ||
| import org.yapp.apis.auth.dto.request.UserBooksByIsbnsRequest | ||
| import org.yapp.apis.auth.service.UserAuthService | ||
|
|
@@ -10,12 +12,14 @@ import org.yapp.apis.book.dto.request.BookSearchRequest | |
| import org.yapp.apis.book.dto.request.UserBookRegisterRequest | ||
| import org.yapp.apis.book.dto.response.BookDetailResponse | ||
| import org.yapp.apis.book.dto.response.BookSearchResponse | ||
| import org.yapp.apis.book.dto.response.UserBookPageResponse | ||
| import org.yapp.apis.book.dto.response.UserBookResponse | ||
| import org.yapp.apis.book.constant.BookQueryServiceQualifier | ||
| import org.yapp.apis.book.dto.request.UpsertUserBookRequest | ||
| import org.yapp.apis.book.service.BookManagementService | ||
| import org.yapp.apis.book.service.BookQueryService | ||
| import org.yapp.apis.book.service.UserBookService | ||
| import org.yapp.domain.userbook.BookStatus | ||
| import org.yapp.globalutils.annotation.UseCase | ||
| import java.util.UUID | ||
|
|
||
|
|
@@ -66,9 +70,14 @@ class BookUseCase( | |
| return userBookResponse | ||
| } | ||
|
|
||
| fun getUserLibraryBooks(userId: UUID): List<UserBookResponse> { | ||
| fun getUserLibraryBooks( | ||
| userId: UUID, | ||
| status: BookStatus?, | ||
| sort: String?, | ||
| pageable: Pageable | ||
| ): UserBookPageResponse { | ||
| userAuthService.validateUserExists(userId) | ||
|
|
||
| return userBookService.findAllUserBooks(userId) | ||
| return userBookService.findUserBooksByDynamicConditionWithStatusCounts(userId, status, sort, pageable) | ||
| } | ||
|
Comment on lines
+73
to
82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 동적 검색 기능이 올바르게 구현되었습니다. 다음과 같은 좋은 점들이 있습니다:
다만 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,6 +75,26 @@ subprojects { | |
| } | ||
| } | ||
|
|
||
| // QueryDSL 설정 | ||
| val querydslDir = "${layout.buildDirectory.get()}/generated/querydsl" | ||
|
|
||
|
|
||
| sourceSets { | ||
| main { | ||
| kotlin { | ||
| srcDir(querydslDir) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| tasks.withType<org.jetbrains.kotlin.gradle.tasks.KaptGenerateStubs>().configureEach { | ||
| doFirst { | ||
| delete(querydslDir) | ||
| } | ||
| } | ||
|
Comment on lines
+91
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) KAPT 태스크 설정 확인 KAPT 실행 전 디렉토리 정리 로직은 적절하지만, 너무 공격적일 수 있습니다. 증분 빌드 최적화를 고려하여 필요한 경우에만 정리하는 것을 검토해보세요. 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| // 루트 프로젝트에서 모든 JaCoCo 설정 관리 | ||
| configure(subprojects) { | ||
| jacoco { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
정렬 파라미터에 대한 검증 추가를 고려해보세요.
sort파라미터가 String 타입으로 받아지고 있는데, 허용되는 정렬 필드에 대한 검증을 추가하는 것이 좋겠습니다. 이를 통해 잘못된 필드명으로 인한 오류를 방지할 수 있습니다.다음과 같은 검증 로직을 추가할 수 있습니다:
를
로 변경하거나, enum을 사용하는 방법도 고려해볼 수 있습니다.
🤖 Prompt for AI Agents