diff --git a/apis/src/main/kotlin/org/yapp/apis/auth/util/IsbnConverter.kt b/apis/src/main/kotlin/org/yapp/apis/auth/util/IsbnConverter.kt index caa5ba26..90a005f9 100644 --- a/apis/src/main/kotlin/org/yapp/apis/auth/util/IsbnConverter.kt +++ b/apis/src/main/kotlin/org/yapp/apis/auth/util/IsbnConverter.kt @@ -11,13 +11,8 @@ object IsbnConverter { fun toIsbn13(isbn10: String?): String? { val sanitized = isbn10?.replace("-", "")?.uppercase() - - if (sanitized.isNullOrBlank() || sanitized.length != ISBN10_LENGTH) { - return null - } - if (!sanitized.matches(Regex(RegexUtils.ISBN10_PATTERN))) { - return null - } + ?.takeIf { it.length == ISBN10_LENGTH && it.matches(Regex(RegexUtils.ISBN10_PATTERN)) } + ?: return null val stem = ISBN13_PREFIX + sanitized.substring(0, ISBN10_LENGTH - 1) diff --git a/apis/src/main/kotlin/org/yapp/apis/book/dto/response/BookDetailResponse.kt b/apis/src/main/kotlin/org/yapp/apis/book/dto/response/BookDetailResponse.kt index 14011d0c..7765ac2f 100644 --- a/apis/src/main/kotlin/org/yapp/apis/book/dto/response/BookDetailResponse.kt +++ b/apis/src/main/kotlin/org/yapp/apis/book/dto/response/BookDetailResponse.kt @@ -26,11 +26,15 @@ data class BookDetailResponse private constructor( companion object { private const val DEFAULT_MAX_PAGE_COUNT = 4032 - + fun from(response: AladinBookDetailResponse, userBookStatus: BookStatus = BookStatus.BEFORE_REGISTRATION): BookDetailResponse { val item = response.item.firstOrNull() ?: throw IllegalArgumentException("No book item found in detail response.") + val isbn13 = item.isbn13?.takeIf { it.isNotBlank() } + ?: IsbnConverter.toIsbn13(item.isbn?.takeIf { it.isNotBlank() }) + ?: throw IllegalArgumentException("Either isbn13 or isbn must be provided") + return BookDetailResponse( version = response.version, title = item.title, @@ -39,7 +43,7 @@ data class BookDetailResponse private constructor( pubDate = item.pubDate ?: "", description = item.description ?: "", mallType = item.mallType, - isbn13 = item.isbn13 ?: IsbnConverter.toIsbn13(item.isbn) ?: throw IllegalArgumentException("Either isbn13 or isbn must be provided"), + isbn13 = isbn13, coverImageUrl = item.cover, categoryName = item.categoryName, publisher = item.publisher ?: "", diff --git a/apis/src/main/kotlin/org/yapp/apis/book/service/AladinBookQueryService.kt b/apis/src/main/kotlin/org/yapp/apis/book/service/AladinBookQueryService.kt index 02ca2d99..c6a94a54 100644 --- a/apis/src/main/kotlin/org/yapp/apis/book/service/AladinBookQueryService.kt +++ b/apis/src/main/kotlin/org/yapp/apis/book/service/AladinBookQueryService.kt @@ -10,6 +10,8 @@ import org.yapp.apis.book.dto.response.BookDetailResponse import org.yapp.apis.book.dto.response.BookSearchResponse import org.yapp.apis.book.exception.BookErrorCode import org.yapp.apis.book.exception.BookException +import org.yapp.apis.util.IsbnConverter +import org.yapp.globalutils.validator.IsbnValidator import org.yapp.infra.external.aladin.AladinApi import org.yapp.infra.external.aladin.request.AladinBookLookupRequest import org.yapp.infra.external.aladin.request.AladinBookSearchRequest @@ -42,7 +44,31 @@ class AladinBookQueryService( log.error("Failed to call Aladin search API for request: '$request'", exception) throw BookException(BookErrorCode.ALADIN_API_SEARCH_FAILED, exception.message) } - return BookSearchResponse.from(response) + + val filteredItems = response.item.filter { item -> + val isbn13 = item.isbn13?.takeIf { it.isNotBlank() } + ?: item.isbn?.let { IsbnConverter.toIsbn13(it) } + + isbn13?.let { + IsbnValidator.isValidIsbn(it) && !it.startsWith("K", ignoreCase = true) + } ?: false + } + + val filteredResponse = AladinSearchResponse( + version = response.version, + title = response.title, + link = response.link, + pubDate = response.pubDate, + totalResults = filteredItems.size, + startIndex = response.startIndex, + itemsPerPage = response.itemsPerPage, + query = response.query, + searchCategoryId = response.searchCategoryId, + searchCategoryName = response.searchCategoryName, + item = filteredItems + ) + + return BookSearchResponse.from(filteredResponse) } override fun getBookDetail(@Valid request: BookDetailRequest): BookDetailResponse { diff --git a/global-utils/src/main/kotlin/org/yapp/globalutils/validator/IsbnValidator.kt b/global-utils/src/main/kotlin/org/yapp/globalutils/validator/IsbnValidator.kt index 2177f14f..ab55042a 100644 --- a/global-utils/src/main/kotlin/org/yapp/globalutils/validator/IsbnValidator.kt +++ b/global-utils/src/main/kotlin/org/yapp/globalutils/validator/IsbnValidator.kt @@ -1,9 +1,12 @@ package org.yapp.globalutils.validator +import org.yapp.globalutils.util.RegexUtils + object IsbnValidator { - private val ISBN_REGEX = Regex("^(.{10}|.{13})$") + private val ISBN10_REGEX = Regex(RegexUtils.ISBN10_PATTERN) + private val ISBN13_REGEX = Regex(RegexUtils.ISBN13_PATTERN) fun isValidIsbn(isbn: String): Boolean { - return isbn.matches(ISBN_REGEX) + return isbn.matches(ISBN10_REGEX) || isbn.matches(ISBN13_REGEX) } } diff --git a/infra/src/main/kotlin/org/yapp/infra/external/aladin/response/AladinSearchResponse.kt b/infra/src/main/kotlin/org/yapp/infra/external/aladin/response/AladinSearchResponse.kt index 925d631c..2ec90915 100644 --- a/infra/src/main/kotlin/org/yapp/infra/external/aladin/response/AladinSearchResponse.kt +++ b/infra/src/main/kotlin/org/yapp/infra/external/aladin/response/AladinSearchResponse.kt @@ -5,7 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import java.math.BigDecimal @JsonIgnoreProperties(ignoreUnknown = true) -data class AladinSearchResponse internal constructor( +data class AladinSearchResponse( @JsonProperty("version") val version: String?, @JsonProperty("title") val title: String?, @JsonProperty("link") val link: String?, @@ -20,7 +20,7 @@ data class AladinSearchResponse internal constructor( ) @JsonIgnoreProperties(ignoreUnknown = true) -data class AladinSearchItem internal constructor( +data class AladinSearchItem( @JsonProperty("title") val title: String, @JsonProperty("link") val link: String, @JsonProperty("author") val author: String?,