Skip to content

Commit 1d279ec

Browse files
authored
refactor: 저자 정보 추출 로직 개선 및 데이터 생성 안정성 강화 (#104)
* refactor: apis, global-utils - (지은이) 외에 (글)도 저자 표시로 함께 처리하도록 변경 * chore: global-utils - 정규식을 유틸클래스에서 가져와 사용하도록 변경 * refactor: apis - 기본값을 지정해서 예상치 못한 에러에 대응 * [BOOK-276] fix: apis - 누락된 필드 수정 및 제목 default value 추가 * [BOOK-276] refactor: apis, global-utils - 코드레빗 리뷰 반영
1 parent 3793330 commit 1d279ec

File tree

5 files changed

+50
-15
lines changed

5 files changed

+50
-15
lines changed

apis/src/main/kotlin/org/yapp/apis/book/dto/request/BookCreateRequest.kt

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,31 @@ data class BookCreateRequest private constructor(
9090
fun validCoverImageUrl(): String = coverImageUrl!!
9191

9292
companion object {
93+
private const val UNKNOWN_TITLE = "제목 정보 없음"
94+
private const val UNKNOWN_AUTHOR = "저자 정보 없음"
95+
private const val UNKNOWN_PUBLISHER = "출판사 정보 없음"
96+
private const val DEFAULT_COVER_IMAGE = "https://github.com/user-attachments/assets/7ba556a4-3a76-4f27-aecb-e58924e66843"
97+
9398
fun from(bookDetailResponse: BookDetailResponse): BookCreateRequest {
9499
val finalIsbn13 = bookDetailResponse.isbn13
95-
?: throw IllegalArgumentException("ISBN13이 존재하지 않습니다.")
100+
?: throw IllegalArgumentException("ISBN13이 존재하지 않습니다.")
96101

97102
return BookCreateRequest(
98103
isbn13 = finalIsbn13,
99-
title = bookDetailResponse.title,
100-
author = bookDetailResponse.author,
101-
publisher = bookDetailResponse.publisher,
104+
title = provideDefaultIfBlank(bookDetailResponse.title, UNKNOWN_TITLE),
105+
author = provideDefaultIfBlank(bookDetailResponse.author, UNKNOWN_AUTHOR),
106+
publisher = provideDefaultIfBlank(bookDetailResponse.publisher, UNKNOWN_PUBLISHER),
102107
publicationYear = parsePublicationYear(bookDetailResponse.pubDate),
103-
coverImageUrl = bookDetailResponse.coverImageUrl,
104-
description = bookDetailResponse.description,
108+
coverImageUrl = provideDefaultIfBlank(bookDetailResponse.coverImageUrl, DEFAULT_COVER_IMAGE),
109+
description = bookDetailResponse.description
105110
)
106111
}
107112

113+
private fun provideDefaultIfBlank(input: String?, defaultValue: String): String {
114+
val trimmed = input?.trim()
115+
return if (trimmed.isNullOrEmpty()) defaultValue else trimmed
116+
}
117+
108118
private fun parsePublicationYear(pubDate: String?): Int? {
109119
return pubDate
110120
?.takeIf { it.length >= 4 && it.substring(0, 4).all { ch -> ch.isDigit() } }
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
11
package org.yapp.apis.book.util
22

3+
import org.yapp.globalutils.util.RegexUtils
4+
35
object AuthorExtractor {
4-
private const val AUTHOR_MARKER = "(지은이)"
6+
private val AUTHOR_MARKER_REGEX = Regex(RegexUtils.AUTHOR_MARKER_PATTERN)
57
private const val CLOSING_PAREN = ")"
68
private const val DELIMITER = "), "
9+
private const val EXPECTED_PARTS_ON_SPLIT = 2
10+
private const val AUTHOR_PART_INDEX = 0
711

812
fun extractAuthors(authorString: String?): String {
9-
if (authorString.isNullOrBlank() || !authorString.contains(AUTHOR_MARKER)) {
13+
if (authorString.isNullOrBlank()) {
1014
return ""
1115
}
1216

13-
var authorsPart = authorString.substringBefore(" $AUTHOR_MARKER")
17+
val partBeforeMarker = getPartBeforeMarker(authorString) ?: return ""
18+
val finalAuthor = cleanUpContributors(partBeforeMarker)
19+
20+
return finalAuthor.trim()
21+
}
22+
23+
private fun getPartBeforeMarker(text: String): String? {
24+
val parts = text.split(AUTHOR_MARKER_REGEX, limit = EXPECTED_PARTS_ON_SPLIT)
1425

15-
if (authorsPart.contains(CLOSING_PAREN)) {
16-
authorsPart = authorsPart.substringAfterLast(DELIMITER)
26+
return if (parts.size == EXPECTED_PARTS_ON_SPLIT) {
27+
parts[AUTHOR_PART_INDEX]
28+
} else {
29+
null
1730
}
31+
}
1832

19-
return authorsPart.trim()
33+
private fun cleanUpContributors(authorPart: String): String {
34+
return if (authorPart.contains(CLOSING_PAREN)) {
35+
authorPart.substringAfterLast(DELIMITER, missingDelimiterValue = authorPart)
36+
} else {
37+
authorPart
38+
}
2039
}
2140
}

global-utils/src/main/kotlin/org/yapp/globalutils/util/RegexUtils.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ package org.yapp.globalutils.util
33
object RegexUtils {
44
const val ISBN10_PATTERN = "^[0-9]{9}[0-9X]$"
55
const val ISBN13_PATTERN = "^(978|979)\\d{10}$"
6+
const val AUTHOR_MARKER_PATTERN = "\\s*\\((?:지은이|글)\\)"
7+
const val PARENTHESIS_PATTERN = "\\s*\\([^)]*\\)\\s*"
8+
const val EMAIL_PATTERN="^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"
69
}

global-utils/src/main/kotlin/org/yapp/globalutils/validator/BookDataValidator.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package org.yapp.globalutils.validator
22

3-
object BookDataValidator {
3+
import org.yapp.globalutils.util.RegexUtils
44

5-
private val PARENTHESIS_REGEX = "\\s*\\([^)]*\\)\\s*".toRegex()
5+
object BookDataValidator {
6+
private val PARENTHESIS_REGEX = Regex(RegexUtils.PARENTHESIS_PATTERN)
67

78
fun removeParenthesesFromAuthor(author: String): String {
89
return author.replace(PARENTHESIS_REGEX, "")

global-utils/src/main/kotlin/org/yapp/globalutils/validator/EmailValidator.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.yapp.globalutils.validator
22

3+
import org.yapp.globalutils.util.RegexUtils
4+
35
object EmailValidator {
4-
private val EMAIL_REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$".toRegex()
6+
private val EMAIL_REGEX = Regex(RegexUtils.EMAIL_PATTERN)
57

68
fun isValidEmail(email: String): Boolean {
79
return email.matches(EMAIL_REGEX)

0 commit comments

Comments
 (0)