Skip to content

Commit b63d33e

Browse files
authored
Merge pull request #21 from YAPP-Github/feature/#18-login-api
[Feature/#18] 로그인 api 연동
2 parents a03e99d + 5869a40 commit b63d33e

File tree

46 files changed

+525
-142
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+525
-142
lines changed

app/src/main/java/com/threegap/bitnagil/di/core/DataStoreModule.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.threegap.bitnagil.di.core
33
import android.content.Context
44
import com.threegap.bitnagil.datastore.auth.crypto.TokenCrypto
55
import com.threegap.bitnagil.datastore.auth.serializer.AuthTokenSerializer
6+
import com.threegap.bitnagil.datastore.auth.serializer.AuthTokenSerializerImpl
67
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenDataStore
78
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenStorageFactory
89
import com.threegap.bitnagil.security.crypto.Crypto
@@ -26,6 +27,11 @@ object DataStoreModule {
2627
override fun decrypt(bytes: ByteArray): ByteArray = crypto.decrypt(bytes)
2728
}
2829

30+
@Provides
31+
@Singleton
32+
fun provideAuthTokenSerializer(tokenCrypto: TokenCrypto): AuthTokenSerializer =
33+
AuthTokenSerializerImpl(tokenCrypto)
34+
2935
@Provides
3036
@Singleton
3137
fun provideAuthTokenStorage(

app/src/main/java/com/threegap/bitnagil/di/core/NetworkModule.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import dagger.Module
88
import dagger.Provides
99
import dagger.hilt.InstallIn
1010
import dagger.hilt.components.SingletonComponent
11-
import kotlinx.coroutines.flow.first
11+
import kotlinx.coroutines.flow.firstOrNull
1212
import kotlinx.serialization.json.Json
1313
import okhttp3.Interceptor
1414
import okhttp3.MediaType.Companion.toMediaType
@@ -54,17 +54,25 @@ object NetworkModule {
5454
}
5555
}
5656

57+
@Provides
58+
@Singleton
59+
fun provideTokenStore(dataStore: AuthTokenDataStore): TokenProvider =
60+
object : TokenProvider {
61+
override suspend fun getAccessToken(): String? = dataStore.tokenFlow.firstOrNull()?.accessToken
62+
}
63+
5764
@Provides
5865
@Singleton
5966
@Auth
60-
fun provideAuthInterceptor(authInterceptor: AuthInterceptor): Interceptor = authInterceptor
67+
fun provideAuthInterceptor(tokenProvider: TokenProvider): Interceptor =
68+
AuthInterceptor(tokenProvider)
6169

6270
@Provides
6371
@Singleton
6472
@Auth
6573
fun provideAuthOkHttpClient(
6674
httpLoggingInterceptor: HttpLoggingInterceptor,
67-
authInterceptor: Interceptor,
75+
@Auth authInterceptor: Interceptor,
6876
): OkHttpClient = OkHttpClient.Builder()
6977
.addInterceptor(authInterceptor)
7078
.addInterceptor(httpLoggingInterceptor)
@@ -110,11 +118,4 @@ object NetworkModule {
110118
.addConverterFactory(converterFactory)
111119
.client(okHttpClient)
112120
.build()
113-
114-
@Provides
115-
@Singleton
116-
fun provideTokenStore(dataStore: AuthTokenDataStore): TokenProvider =
117-
object : TokenProvider {
118-
override suspend fun getToken(): String? = dataStore.tokenFlow.first().accessToken
119-
}
120121
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.threegap.bitnagil.di.data
2+
3+
import com.threegap.bitnagil.data.auth.datasource.AuthLocalDataSource
4+
import com.threegap.bitnagil.data.auth.datasource.AuthRemoteDataSource
5+
import com.threegap.bitnagil.data.auth.datasourceimpl.AuthLocalDataSourceImpl
6+
import com.threegap.bitnagil.data.auth.datasourceimpl.AuthRemoteDataSourceImpl
7+
import dagger.Binds
8+
import dagger.Module
9+
import dagger.hilt.InstallIn
10+
import dagger.hilt.components.SingletonComponent
11+
import javax.inject.Singleton
12+
13+
@Module
14+
@InstallIn(SingletonComponent::class)
15+
abstract class DataSourceModule {
16+
17+
@Binds
18+
@Singleton
19+
abstract fun bindAuthDataSource(authDataSourceImpl: AuthRemoteDataSourceImpl): AuthRemoteDataSource
20+
21+
@Binds
22+
@Singleton
23+
abstract fun bindAuthLocalDataSource(authLocalDataSourceImpl: AuthLocalDataSourceImpl): AuthLocalDataSource
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.threegap.bitnagil.di.data
2+
3+
import com.threegap.bitnagil.data.auth.repositoryimpl.AuthRepositoryImpl
4+
import com.threegap.bitnagil.domain.auth.repository.AuthRepository
5+
import dagger.Binds
6+
import dagger.Module
7+
import dagger.hilt.InstallIn
8+
import dagger.hilt.components.SingletonComponent
9+
import javax.inject.Singleton
10+
11+
@Module
12+
@InstallIn(SingletonComponent::class)
13+
abstract class RepositoryModule {
14+
15+
@Binds
16+
@Singleton
17+
abstract fun bindAuthRepository(authRepositoryImpl: AuthRepositoryImpl): AuthRepository
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.threegap.bitnagil.di.data
2+
3+
import com.threegap.bitnagil.data.auth.service.AuthService
4+
import com.threegap.bitnagil.di.core.Auth
5+
import dagger.Module
6+
import dagger.Provides
7+
import dagger.hilt.InstallIn
8+
import dagger.hilt.components.SingletonComponent
9+
import retrofit2.Retrofit
10+
import javax.inject.Singleton
11+
12+
@Module
13+
@InstallIn(SingletonComponent::class)
14+
object ServiceModule {
15+
16+
@Provides
17+
@Singleton
18+
fun provideAuthService(@Auth retrofit: Retrofit): AuthService =
19+
retrofit.create(AuthService::class.java)
20+
}

core/datastore/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ android {
88
}
99

1010
dependencies {
11-
implementation(libs.androidx.datastore.preferences)
11+
api(libs.androidx.datastore.preferences)
1212
implementation(libs.kotlinx.serialization.json)
1313

1414
testImplementation(libs.androidx.junit)

core/datastore/src/main/java/com/threegap/bitnagil/datastore/auth/serializer/AuthTokenSerializerImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.threegap.bitnagil.datastore.auth.serializer
22

3-
import androidx.datastore.core.Serializer
43
import com.threegap.bitnagil.datastore.auth.crypto.TokenCrypto
54
import com.threegap.bitnagil.datastore.auth.model.AuthToken
65
import kotlinx.coroutines.Dispatchers
@@ -12,7 +11,7 @@ import java.util.Base64
1211

1312
class AuthTokenSerializerImpl(
1413
private val crypto: TokenCrypto,
15-
) : Serializer<AuthToken> {
14+
) : AuthTokenSerializer {
1615
override val defaultValue: AuthToken
1716
get() = AuthToken()
1817

core/datastore/src/main/java/com/threegap/bitnagil/datastore/auth/storage/AuthTokenDataStore.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import kotlinx.coroutines.flow.Flow
66
interface AuthTokenDataStore {
77
val tokenFlow: Flow<AuthToken>
88

9-
suspend fun updateAuthToken(authToken: AuthToken): AuthToken
9+
suspend fun updateAuthToken(accessToken: String, refreshToken: String)
1010

11-
suspend fun updateAccessToken(accessToken: String): AuthToken
11+
suspend fun updateAccessToken(accessToken: String)
1212

13-
suspend fun updateRefreshToken(refreshToken: String): AuthToken
13+
suspend fun updateRefreshToken(refreshToken: String)
1414

15-
suspend fun clearAuthToken(): AuthToken
15+
suspend fun clearAuthToken()
1616
}

core/datastore/src/main/java/com/threegap/bitnagil/datastore/auth/storage/AuthTokenDataStoreImpl.kt

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.threegap.bitnagil.datastore.auth.storage
22

3-
import android.util.Log
43
import androidx.datastore.core.DataStore
54
import com.threegap.bitnagil.datastore.auth.model.AuthToken
65
import kotlinx.coroutines.flow.Flow
@@ -10,53 +9,43 @@ class AuthTokenDataStoreImpl(
109
) : AuthTokenDataStore {
1110
override val tokenFlow: Flow<AuthToken> = dataStore.data
1211

13-
override suspend fun updateAuthToken(authToken: AuthToken): AuthToken =
14-
runCatching {
15-
dataStore.updateData { authToken }
16-
}.fold(
17-
onSuccess = { it },
18-
onFailure = {
19-
Log.e(TAG, "updateAuthToken failed:", it)
20-
throw it
21-
},
22-
)
12+
override suspend fun updateAuthToken(accessToken: String, refreshToken: String) {
13+
try {
14+
dataStore.updateData {
15+
AuthToken(accessToken, refreshToken)
16+
}
17+
} catch (e: Exception) {
18+
throw e
19+
}
20+
}
2321

24-
override suspend fun updateAccessToken(accessToken: String): AuthToken =
25-
runCatching {
26-
dataStore.updateData { authToken ->
27-
authToken.copy(accessToken = accessToken)
22+
override suspend fun updateAccessToken(accessToken: String) {
23+
try {
24+
dataStore.updateData { currentToken ->
25+
currentToken.copy(accessToken = accessToken)
2826
}
29-
}.fold(
30-
onSuccess = { it },
31-
onFailure = {
32-
Log.e(TAG, "updateAccessToken failed:", it)
33-
throw it
34-
},
35-
)
27+
} catch (e: Exception) {
28+
throw e
29+
}
30+
}
3631

37-
override suspend fun updateRefreshToken(refreshToken: String): AuthToken =
38-
runCatching {
39-
dataStore.updateData { authToken ->
40-
authToken.copy(refreshToken = refreshToken)
32+
override suspend fun updateRefreshToken(refreshToken: String) {
33+
try {
34+
dataStore.updateData { currentToken ->
35+
currentToken.copy(refreshToken = refreshToken)
4136
}
42-
}.fold(
43-
onSuccess = { it },
44-
onFailure = {
45-
Log.e(TAG, "updateRefreshToken failed:", it)
46-
throw it
47-
},
48-
)
37+
} catch (e: Exception) {
38+
throw e
39+
}
40+
}
4941

50-
override suspend fun clearAuthToken(): AuthToken =
51-
runCatching {
42+
override suspend fun clearAuthToken() {
43+
try {
5244
dataStore.updateData { AuthToken() }
53-
}.fold(
54-
onSuccess = { it },
55-
onFailure = {
56-
Log.e(TAG, "clearAuthToken failed:", it)
57-
throw it
58-
},
59-
)
45+
} catch (e: Exception) {
46+
throw e
47+
}
48+
}
6049

6150
companion object {
6251
private const val TAG = "AuthTokenDataStore"

core/datastore/src/test/java/com/threegap/bitnagil/datastore/auth/storage/AuthTokenDataStoreImplTest.kt

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,19 @@ class AuthTokenDataStoreImplTest {
7070
fun `토큰 전체 업데이트가 성공하면 저장된 토큰을 반환해야 한다`() =
7171
runTest {
7272
// given
73+
val accessToken = "access"
74+
val refreshToken = "refresh"
7375
val token =
7476
AuthToken(
75-
accessToken = "access",
76-
refreshToken = "refresh",
77+
accessToken = accessToken,
78+
refreshToken = refreshToken,
7779
)
7880

7981
// when
80-
val result = authTokenDataStore.updateAuthToken(token)
82+
authTokenDataStore.updateAuthToken(accessToken, refreshToken)
8183

8284
// then
85+
val result = authTokenDataStore.tokenFlow.first()
8386
assertEquals(token, result)
8487
}
8588

@@ -88,54 +91,51 @@ class AuthTokenDataStoreImplTest {
8891
runTest {
8992
// given
9093
authTokenDataStore.updateAuthToken(
91-
AuthToken(
92-
accessToken = "oldAccess",
93-
refreshToken = "oldRefresh",
94-
),
94+
accessToken = "oldAccess",
95+
refreshToken = "oldRefresh",
9596
)
9697

9798
// when
98-
val updated = authTokenDataStore.updateAccessToken(accessToken = "newAccess")
99+
authTokenDataStore.updateAccessToken(accessToken = "newAccess")
99100

100101
// then
101-
assertEquals("newAccess", updated.accessToken)
102-
assertEquals("oldRefresh", updated.refreshToken)
102+
val result = authTokenDataStore.tokenFlow.first()
103+
assertEquals("newAccess", result.accessToken)
104+
assertEquals("oldRefresh", result.refreshToken)
103105
}
104106

105107
@Test
106108
fun `refreshToken만 업데이트하면 기존 accessToken은 유지되어야 한다`() =
107109
runTest {
108110
// given
109111
authTokenDataStore.updateAuthToken(
110-
AuthToken(
111-
accessToken = "oldAccess",
112-
refreshToken = "oldRefresh",
113-
),
112+
accessToken = "oldAccess",
113+
refreshToken = "oldRefresh",
114114
)
115115

116116
// when
117-
val updated = authTokenDataStore.updateRefreshToken(refreshToken = "newRefresh")
117+
authTokenDataStore.updateRefreshToken(refreshToken = "newRefresh")
118118

119119
// then
120-
assertEquals("oldAccess", updated.accessToken)
121-
assertEquals("newRefresh", updated.refreshToken)
120+
val result = authTokenDataStore.tokenFlow.first()
121+
assertEquals("oldAccess", result.accessToken)
122+
assertEquals("newRefresh", result.refreshToken)
122123
}
123124

124125
@Test
125126
fun `토큰을 클리어하면 기본값이 저장되어야 한다`() =
126127
runTest {
127128
// given
128129
authTokenDataStore.updateAuthToken(
129-
AuthToken(
130-
accessToken = "someAccess",
131-
refreshToken = "someRefresh",
132-
),
130+
accessToken = "someAccess",
131+
refreshToken = "someRefresh",
133132
)
134133

135134
// when
136-
val cleared = authTokenDataStore.clearAuthToken()
135+
authTokenDataStore.clearAuthToken()
137136

138137
// then
138+
val cleared = authTokenDataStore.tokenFlow.first()
139139
assertEquals(AuthToken(), cleared)
140140
}
141141

@@ -150,7 +150,7 @@ class AuthTokenDataStoreImplTest {
150150
)
151151

152152
// when
153-
authTokenDataStore.updateAuthToken(token)
153+
authTokenDataStore.updateAuthToken("flowAccess", "flowRefresh")
154154

155155
// then
156156
val flowValue = authTokenDataStore.tokenFlow.first()
@@ -172,7 +172,7 @@ class AuthTokenDataStoreImplTest {
172172
val failingDataStore = AuthTokenDataStoreImpl(brokenStore)
173173

174174
// when & then
175-
failingDataStore.updateAuthToken(AuthToken("access", "refresh"))
175+
failingDataStore.updateAuthToken("access", "refresh")
176176
}
177177

178178
@Test(expected = RuntimeException::class)

0 commit comments

Comments
 (0)