Skip to content

Commit d181491

Browse files
committed
Merge branch 'develop' into BOOK-212-feature/#98
# Conflicts: # core/common/src/main/kotlin/com/ninecraft/booket/core/common/extensions/String.kt # core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/RecordRepository.kt # core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/mapper/ResponseToModel.kt # core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultRecordRepository.kt # core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/ReedService.kt
2 parents 1078d34 + b430c06 commit d181491

File tree

22 files changed

+474
-165
lines changed

22 files changed

+474
-165
lines changed

.github/workflows/android-cd.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Android CD
2+
3+
env:
4+
GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4g -Dorg.gradle.daemon=false"
5+
GRADLE_BUILD_ACTION_CACHE_DEBUG_ENABLED: true
6+
7+
on:
8+
pull_request:
9+
branches:
10+
- main
11+
12+
jobs:
13+
cd-build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
with:
20+
# 최근 태그를 확인하기 위해 필요
21+
fetch-depth: 0
22+
23+
- name: Set up JDK 17
24+
uses: actions/setup-java@v4
25+
with:
26+
distribution: 'corretto'
27+
java-version: 17
28+
29+
- name: Generate reed.jks
30+
run: echo '${{ secrets.REED_JAVA_KEYSTORE }}' | base64 -d > ./reed.jks
31+
32+
- name: Generate local.properties
33+
run: echo '${{ secrets.LOCAL_PROPERTIES }}' | base64 -d > ./local.properties
34+
35+
- name: Generate keystore.properties
36+
run: echo '${{ secrets.KEYSTORE_PROPERTIES }}' | base64 -d > ./keystore.properties
37+
38+
- name: Generate google-services.json
39+
run: echo '${{ secrets.GOOGLE_SERVICES }}' | base64 -d > ./app/google-services.json
40+
41+
- name: Extract Version Name from ApplicationConstants.kt
42+
run: |
43+
set -euo pipefail
44+
VERSION=$(grep "VERSION_NAME" build-logic/src/main/kotlin/com/ninecraft/booket/convention/ApplicationConstants.kt | sed -E 's/.*VERSION_NAME\s*=\s*"([^"]+)".*/\1/')
45+
if [[ -z "$VERSION" ]]; then
46+
echo "Error: ApplicationConstants.kt에서 VERSION_NAME 값을 추출하지 못했습니다." >&2
47+
exit 1
48+
fi
49+
echo "version=v${VERSION}" >> "$GITHUB_OUTPUT"
50+
echo "Version extracted from ApplicationConstants.kt: v${VERSION}"
51+
id: extract_version
52+
53+
- name: Generate Firebase Release Note
54+
id: firebase_release_note
55+
env:
56+
PR_TITLE: ${{ github.event.pull_request.title }}
57+
run: |
58+
# PR_TITLE은 env에서 안전하게 전달됨
59+
# 가장 최근 태그 찾기 (현재 버전 이전의 태그)
60+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
61+
62+
# 릴리스 노트 내용 생성
63+
NOTES="## 🚀 변경사항: ${PR_TITLE}\n\n"
64+
65+
if [ -n "$LATEST_TAG" ]; then
66+
NOTES="${NOTES}### 이전 버전($LATEST_TAG)부터의 변경사항:\n"
67+
# 최근 태그부터 현재까지의 커밋만 가져옴
68+
COMMITS=$(git log --pretty=format:"- %h %s (%an)" ${LATEST_TAG}..HEAD --no-merges)
69+
NOTES="${NOTES}${COMMITS}"
70+
else
71+
NOTES="${NOTES}### 커밋 내역:\n"
72+
# 태그가 없는 경우 최근 10개 커밋만 표시
73+
COMMITS=$(git log --pretty=format:"- %h %s (%an)" --no-merges -n 10)
74+
NOTES="${NOTES}${COMMITS}\n\n(이전 릴리스 태그가 없어 최근 10개 커밋만 표시)"
75+
fi
76+
77+
# 환경 변수로 저장
78+
echo "notes<<EOF" >> $GITHUB_OUTPUT
79+
echo -e "$NOTES" >> $GITHUB_OUTPUT
80+
echo "EOF" >> $GITHUB_OUTPUT
81+
82+
- name: Build Release AAB
83+
run: |
84+
./gradlew :app:bundleRelease
85+
86+
- name: Upload Release Build to Artifacts
87+
uses: actions/upload-artifact@v4
88+
with:
89+
name: release-artifacts
90+
path: app/build/outputs/bundle/release/
91+
if-no-files-found: error
92+
93+
- name: Create Github Release
94+
uses: softprops/action-gh-release@v2
95+
with:
96+
tag_name: ${{ steps.extract_version.outputs.version }}
97+
release_name: ${{ steps.extract_version.outputs.version }}
98+
generate_release_notes: true
99+
100+
- name: Upload artifact to Firebase App Distribution
101+
uses: wzieba/Firebase-Distribution-Github-Action@v1
102+
with:
103+
appId: ${{secrets.FIREBASE_RELEASE_APP_ID}}
104+
serviceCredentialsFileContent: ${{ secrets.CREDENTIAL_FILE_CONTENT }}
105+
groups: testers
106+
file: app/build/outputs/bundle/release/app-release.aab
107+
releaseNotes: ${{ steps.firebase_release_note.outputs.notes }}

.github/workflows/android-ci.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,10 @@ jobs:
3636
gradle-home-cache-cleanup: true
3737

3838
- name: Generate local.properties
39-
run: |
40-
echo '${{ secrets.LOCAL_PROPERTIES }}' >> ./local.properties
39+
run: echo '${{ secrets.LOCAL_PROPERTIES }}' | base64 -d > ./local.properties
4140

4241
- name: Generate keystore.properties
43-
run: |
44-
echo '${{ secrets.KEYSTORE_PROPERTIES }}' >> ./keystore.properties
42+
run: echo '${{ secrets.KEYSTORE_PROPERTIES }}' | base64 -d > ./keystore.properties
4543

4644
- name: Generate google-services.json
4745
run: echo '${{ secrets.GOOGLE_SERVICES }}' | base64 -d > ./app/google-services.json

build-logic/src/main/kotlin/AndroidRetrofitConventionPlugin.kt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@ internal class AndroidRetrofitConventionPlugin : Plugin<Project> {
1717
"booket.kotlin.library.serialization",
1818
)
1919

20-
extensions.configure<LibraryExtension> {
21-
configureAndroid(this)
22-
23-
defaultConfig.apply {
24-
targetSdk = ApplicationConstants.TARGET_SDK
25-
}
26-
}
27-
2820
dependencies {
2921
implementation(libs.retrofit)
3022
implementation(libs.retrofit.kotlinx.serialization.converter)

core/common/src/main/kotlin/com/ninecraft/booket/core/common/extensions/String.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.ninecraft.booket.core.common.extensions
22

3+
import java.time.LocalDateTime
4+
import java.time.format.DateTimeFormatter
5+
import java.time.format.DateTimeParseException
6+
37
fun String.decodeHtmlEntities(): String {
48
return this
59
.replace("&lt;", "<")
@@ -17,3 +21,14 @@ fun String.formatPublishYear(): String {
1721
val year = this.substringBefore("-")
1822
return "${year}"
1923
}
24+
25+
fun String.toFormattedDate(): String {
26+
return try {
27+
val inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS")
28+
val outputFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd")
29+
val parsedDate = LocalDateTime.parse(this, inputFormatter)
30+
parsedDate.format(outputFormatter)
31+
} catch (e: DateTimeParseException) {
32+
""
33+
}
34+
}

core/data/api/src/main/kotlin/com/ninecraft/booket/core/data/api/repository/RecordRepository.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.ninecraft.booket.core.data.api.repository
22

3-
import com.ninecraft.booket.core.model.ReadingRecordsModel
43
import com.ninecraft.booket.core.model.RecordRegisterModel
4+
import com.ninecraft.booket.core.model.ReadingRecordsModel
5+
import com.ninecraft.booket.core.model.RecordDetailModel
56

67
interface RecordRepository {
78
suspend fun postRecord(
@@ -18,4 +19,8 @@ interface RecordRepository {
1819
page: Int,
1920
size: Int,
2021
): Result<ReadingRecordsModel>
22+
23+
suspend fun getRecordDetail(
24+
readingRecordId: String,
25+
): Result<RecordDetailModel>
2126
}

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/mapper/ResponseToModel.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.ninecraft.booket.core.data.impl.mapper
22

33
import com.ninecraft.booket.core.common.extensions.decodeHtmlEntities
4+
import com.ninecraft.booket.core.common.extensions.toFormattedDate
45
import com.ninecraft.booket.core.model.BookDetailModel
56
import com.ninecraft.booket.core.model.BookSearchModel
67
import com.ninecraft.booket.core.model.BookSummaryModel
@@ -15,6 +16,7 @@ import com.ninecraft.booket.core.model.PageInfoModel
1516
import com.ninecraft.booket.core.model.ReadingRecordModel
1617
import com.ninecraft.booket.core.model.ReadingRecordsModel
1718
import com.ninecraft.booket.core.model.RecentBookModel
19+
import com.ninecraft.booket.core.model.RecordDetailModel
1820
import com.ninecraft.booket.core.model.RecordRegisterModel
1921
import com.ninecraft.booket.core.model.SeedModel
2022
import com.ninecraft.booket.core.model.UserProfileModel
@@ -31,6 +33,7 @@ import com.ninecraft.booket.core.network.response.PageInfo
3133
import com.ninecraft.booket.core.network.response.ReadingRecord
3234
import com.ninecraft.booket.core.network.response.ReadingRecordsResponse
3335
import com.ninecraft.booket.core.network.response.RecentBook
36+
import com.ninecraft.booket.core.network.response.RecordDetailResponse
3437
import com.ninecraft.booket.core.network.response.RecordRegisterResponse
3538
import com.ninecraft.booket.core.network.response.SeedResponse
3639
import com.ninecraft.booket.core.network.response.UserProfileResponse
@@ -183,6 +186,23 @@ internal fun ReadingRecord.toModel(): ReadingRecordModel {
183186
)
184187
}
185188

189+
internal fun RecordDetailResponse.toModel(): RecordDetailModel {
190+
return RecordDetailModel(
191+
id = id,
192+
userBookId = userBookId,
193+
pageNumber = pageNumber,
194+
quote = quote,
195+
review = review,
196+
emotionTags = emotionTags,
197+
createdAt = createdAt.toFormattedDate(),
198+
updatedAt = updatedAt.toFormattedDate(),
199+
bookTitle = bookTitle,
200+
bookPublisher = bookPublisher,
201+
bookCoverImageUrl = bookCoverImageUrl,
202+
author = author,
203+
)
204+
}
205+
186206
internal fun HomeResponse.toModel(): HomeModel {
187207
return HomeModel(
188208
recentBooks = recentBooks.map { it.toModel() },

core/data/impl/src/main/kotlin/com/ninecraft/booket/core/data/impl/repository/DefaultRecordRepository.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ class DefaultRecordRepository @Inject constructor(
2828
) = runSuspendCatching {
2929
service.getReadingRecords(userBookId, sort, page, size).toModel()
3030
}
31+
32+
override suspend fun getRecordDetail(readingRecordId: String) = runSuspendCatching {
33+
service.getRecordDetail(readingRecordId).toModel()
34+
}
3135
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.ninecraft.booket.core.model
2+
3+
import androidx.compose.runtime.Stable
4+
5+
@Stable
6+
data class RecordDetailModel(
7+
val id: String = "",
8+
val userBookId: String = "",
9+
val pageNumber: Int = 0,
10+
val quote: String = "",
11+
val review: String = "",
12+
val emotionTags: List<String> = emptyList(),
13+
val createdAt: String = "",
14+
val updatedAt: String = "",
15+
val bookTitle: String = "",
16+
val bookPublisher: String = "",
17+
val bookCoverImageUrl: String = "",
18+
val author: String = "",
19+
)

core/network/src/main/kotlin/com/ninecraft/booket/core/network/response/LibraryResponse.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ data class LibraryResponse(
88
@SerialName("books")
99
val books: LibraryBooks,
1010
@SerialName("totalCount")
11-
val totalCount: Int = 0,
11+
val totalCount: Int,
1212
@SerialName("beforeReadingCount")
1313
val beforeReadingCount: Int,
1414
@SerialName("readingCount")
@@ -40,7 +40,7 @@ data class LibraryBookSummary(
4040
@SerialName("status")
4141
val status: String,
4242
@SerialName("recordCount")
43-
val recordCount: Int = 0,
43+
val recordCount: Int,
4444
@SerialName("coverImageUrl")
4545
val coverImageUrl: String,
4646
@SerialName("publisher")
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.ninecraft.booket.core.network.response
2+
3+
import kotlinx.serialization.SerialName
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
data class RecordDetailResponse(
8+
@SerialName("id")
9+
val id: String,
10+
@SerialName("userBookId")
11+
val userBookId: String,
12+
@SerialName("pageNumber")
13+
val pageNumber: Int,
14+
@SerialName("quote")
15+
val quote: String,
16+
@SerialName("review")
17+
val review: String,
18+
@SerialName("emotionTags")
19+
val emotionTags: List<String>,
20+
@SerialName("createdAt")
21+
val createdAt: String,
22+
@SerialName("updatedAt")
23+
val updatedAt: String,
24+
@SerialName("bookTitle")
25+
val bookTitle: String,
26+
@SerialName("bookPublisher")
27+
val bookPublisher: String,
28+
@SerialName("bookCoverImageUrl")
29+
val bookCoverImageUrl: String,
30+
@SerialName("author")
31+
val author: String,
32+
)

0 commit comments

Comments
 (0)