Skip to content

Commit 927a2e4

Browse files
authored
Merge pull request #24 from YAPP-Github/BOOK-78-feature/#23
feat: 로그아웃 API 연동
2 parents 99a9f8f + 711ee4d commit 927a2e4

File tree

13 files changed

+288
-19
lines changed

13 files changed

+288
-19
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ import com.ninecraft.booket.core.model.LoginModel
44

55
interface AuthRepository {
66
suspend fun login(accessToken: String): Result<LoginModel>
7+
suspend fun logout(): Result<Unit>
8+
suspend fun saveTokens(accessToken: String, refreshToken: String)
9+
suspend fun clearTokens()
710
}

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,40 @@ package com.ninecraft.booket.core.data.impl.repository
33
import com.ninecraft.booket.core.common.utils.runSuspendCatching
44
import com.ninecraft.booket.core.data.api.repository.AuthRepository
55
import com.ninecraft.booket.core.data.impl.mapper.toModel
6+
import com.ninecraft.booket.core.datastore.api.datasource.TokenPreferencesDataSource
67
import com.ninecraft.booket.core.network.request.LoginRequest
7-
import com.ninecraft.booket.core.network.service.BooketService
8+
import com.ninecraft.booket.core.network.service.AuthService
9+
import com.ninecraft.booket.core.network.service.NoAuthService
810
import javax.inject.Inject
911

1012
private const val KAKAO_PROVIDER_TYPE = "KAKAO"
1113

1214
internal class DefaultAuthRepository @Inject constructor(
13-
private val service: BooketService,
15+
private val noAuthService: NoAuthService,
16+
private val authService: AuthService,
17+
private val tokenDatasource: TokenPreferencesDataSource,
1418
) : AuthRepository {
1519
override suspend fun login(accessToken: String) = runSuspendCatching {
16-
service.login(
20+
noAuthService.login(
1721
LoginRequest(
1822
providerType = KAKAO_PROVIDER_TYPE,
1923
oauthToken = accessToken,
2024
),
2125
).toModel()
2226
}
27+
28+
override suspend fun logout() = runSuspendCatching {
29+
authService.logout()
30+
}
31+
32+
override suspend fun saveTokens(accessToken: String, refreshToken: String) {
33+
tokenDatasource.apply {
34+
setAccessToken(accessToken)
35+
setRefreshToken(refreshToken)
36+
}
37+
}
38+
39+
override suspend fun clearTokens() {
40+
tokenDatasource.clearTokens()
41+
}
2342
}

core/network/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ android {
2929

3030
dependencies {
3131
implementations(
32+
projects.core.datastore.api,
33+
3234
libs.logger,
3335
)
3436
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.ninecraft.booket.core.network
2+
3+
import com.ninecraft.booket.core.datastore.api.datasource.TokenPreferencesDataSource
4+
import kotlinx.coroutines.runBlocking
5+
import okhttp3.Interceptor
6+
import okhttp3.Response
7+
import javax.inject.Inject
8+
9+
internal class TokenInterceptor @Inject constructor(
10+
@Suppress("unused")
11+
private val tokenDataSource: TokenPreferencesDataSource,
12+
) : Interceptor {
13+
override fun intercept(chain: Interceptor.Chain): Response {
14+
val accessToken = runBlocking { tokenDataSource.getAccessToken() }
15+
16+
return chain.proceed(
17+
chain.request().newBuilder()
18+
.addHeader("Authorization", "Bearer $accessToken")
19+
.build(),
20+
)
21+
}
22+
}

core/network/src/main/kotlin/com/ninecraft/booket/core/network/di/NetworkModule.kt

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.ninecraft.booket.core.network.di
22

3-
import com.orhanobut.logger.Logger
3+
import android.util.Log
44
import dagger.Module
55
import dagger.Provides
66
import dagger.hilt.InstallIn
@@ -12,7 +12,11 @@ import okhttp3.logging.HttpLoggingInterceptor
1212
import retrofit2.Retrofit
1313
import retrofit2.converter.kotlinx.serialization.asConverterFactory
1414
import com.ninecraft.booket.core.network.BuildConfig
15-
import com.ninecraft.booket.core.network.service.BooketService
15+
import com.ninecraft.booket.core.network.TokenInterceptor
16+
import com.ninecraft.booket.core.network.service.AuthService
17+
import com.ninecraft.booket.core.network.service.NoAuthService
18+
import com.orhanobut.logger.AndroidLogAdapter
19+
import com.orhanobut.logger.PrettyFormatStrategy
1620
import retrofit2.create
1721
import java.util.concurrent.TimeUnit
1822
import javax.inject.Singleton
@@ -34,9 +38,26 @@ internal object NetworkModule {
3438

3539
@Singleton
3640
@Provides
37-
internal fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
41+
internal fun provideNetworkLogAdapter(): AndroidLogAdapter {
42+
val networkFormatStrategy = PrettyFormatStrategy.newBuilder()
43+
.showThreadInfo(false) // 스레드 정보 제거
44+
.methodCount(0) // 메서드 스택 제거
45+
.methodOffset(0) // 오프셋 제거
46+
.tag("NETWORK") // API 호출 전용 태그
47+
.build()
48+
49+
return AndroidLogAdapter(networkFormatStrategy)
50+
}
51+
52+
@Singleton
53+
@Provides
54+
internal fun provideHttpLoggingInterceptor(
55+
networkLogAdapter: AndroidLogAdapter,
56+
): HttpLoggingInterceptor {
3857
return HttpLoggingInterceptor { message ->
39-
Logger.d(message)
58+
if (message.isNotBlank()) {
59+
networkLogAdapter.log(Log.DEBUG, null, message)
60+
}
4061
}.apply {
4162
level = if (BuildConfig.DEBUG) {
4263
HttpLoggingInterceptor.Level.BODY
@@ -46,9 +67,26 @@ internal object NetworkModule {
4667
}
4768
}
4869

70+
@AuthOkHttpClient
71+
@Singleton
72+
@Provides
73+
internal fun provideAuthOkHttpClient(
74+
httpLoggingInterceptor: HttpLoggingInterceptor,
75+
tokenInterceptor: TokenInterceptor,
76+
): OkHttpClient {
77+
return OkHttpClient.Builder()
78+
.connectTimeout(MaxTimeoutMillis, TimeUnit.MILLISECONDS)
79+
.readTimeout(MaxTimeoutMillis, TimeUnit.MILLISECONDS)
80+
.writeTimeout(MaxTimeoutMillis, TimeUnit.MILLISECONDS)
81+
.addInterceptor(tokenInterceptor)
82+
.addInterceptor(httpLoggingInterceptor)
83+
.build()
84+
}
85+
86+
@NoAuthOkHttpClient
4987
@Singleton
5088
@Provides
51-
internal fun provideOkHttpClient(
89+
internal fun provideNoAuthOkHttpClient(
5290
httpLoggingInterceptor: HttpLoggingInterceptor,
5391
): OkHttpClient {
5492
return OkHttpClient.Builder()
@@ -59,10 +97,11 @@ internal object NetworkModule {
5997
.build()
6098
}
6199

100+
@AuthRetrofit
62101
@Singleton
63102
@Provides
64-
internal fun provideRetrofit(
65-
okHttpClient: OkHttpClient,
103+
internal fun provideAuthRetrofit(
104+
@AuthOkHttpClient okHttpClient: OkHttpClient,
66105
): Retrofit {
67106
return Retrofit.Builder()
68107
.baseUrl(BuildConfig.SERVER_BASE_URL)
@@ -71,11 +110,32 @@ internal object NetworkModule {
71110
.build()
72111
}
73112

113+
@NoAuthRetrofit
114+
@Singleton
115+
@Provides
116+
internal fun provideNoAuthRetrofit(
117+
@NoAuthOkHttpClient okHttpClient: OkHttpClient,
118+
): Retrofit {
119+
return Retrofit.Builder()
120+
.baseUrl(BuildConfig.SERVER_BASE_URL)
121+
.client(okHttpClient)
122+
.addConverterFactory(jsonConverterFactory)
123+
.build()
124+
}
125+
126+
@Singleton
127+
@Provides
128+
internal fun provideAuthService(
129+
@AuthRetrofit retrofit: Retrofit,
130+
): AuthService {
131+
return retrofit.create()
132+
}
133+
74134
@Singleton
75135
@Provides
76-
internal fun provideBooketService(
77-
retrofit: Retrofit,
78-
): BooketService {
136+
internal fun provideNoAuthService(
137+
@NoAuthRetrofit retrofit: Retrofit,
138+
): NoAuthService {
79139
return retrofit.create()
80140
}
81141
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.ninecraft.booket.core.network.di
2+
3+
import javax.inject.Qualifier
4+
5+
@Qualifier
6+
@Retention(AnnotationRetention.BINARY)
7+
annotation class AuthOkHttpClient
8+
9+
@Qualifier
10+
@Retention(AnnotationRetention.BINARY)
11+
annotation class NoAuthOkHttpClient
12+
13+
@Qualifier
14+
@Retention(AnnotationRetention.BINARY)
15+
annotation class AuthRetrofit
16+
17+
@Qualifier
18+
@Retention(AnnotationRetention.BINARY)
19+
annotation class NoAuthRetrofit
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.ninecraft.booket.core.network.service
2+
3+
import retrofit2.http.POST
4+
5+
interface AuthService {
6+
@POST("api/v1/auth/signout")
7+
suspend fun logout()
8+
}

core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/BooketService.kt renamed to core/network/src/main/kotlin/com/ninecraft/booket/core/network/service/NoAuthService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.ninecraft.booket.core.network.response.LoginResponse
55
import retrofit2.http.Body
66
import retrofit2.http.POST
77

8-
interface BooketService {
8+
interface NoAuthService {
99
@POST("api/v1/auth/signin")
1010
suspend fun login(@Body loginRequest: LoginRequest): LoginResponse
1111
}

feature/library/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ ksp {
1616

1717
dependencies {
1818
implementations(
19+
projects.feature.login,
20+
1921
libs.logger,
2022
)
2123
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.ninecraft.booket.feature.library
2+
3+
import android.widget.Toast
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.LaunchedEffect
6+
import androidx.compose.ui.platform.LocalContext
7+
8+
@Composable
9+
internal fun HandleLibrarySideEffects(
10+
state: LibraryScreen.State,
11+
eventSink: (LibraryScreen.Event) -> Unit,
12+
) {
13+
val context = LocalContext.current
14+
15+
LaunchedEffect(state.sideEffect) {
16+
when (state.sideEffect) {
17+
is LibraryScreen.SideEffect.ShowToast -> {
18+
Toast.makeText(context, state.sideEffect.message, Toast.LENGTH_SHORT).show()
19+
}
20+
21+
null -> {}
22+
}
23+
24+
if (state.sideEffect != null) {
25+
eventSink(LibraryScreen.Event.InitSideEffect)
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)