diff --git a/.editorconfig b/.editorconfig
index e5586d73..77c75f79 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,4 +1,4 @@
[*.{kt,kts}]
-ij_kotlin_allow_trailing_comma=true
-ij_kotlin_allow_trailing_comma_on_call_site=true
-ktlint_function_naming_ignore_when_annotated_with=Composable, Test
+ij_kotlin_allow_trailing_comma = true
+ij_kotlin_allow_trailing_comma_on_call_site = true
+ktlint_function_naming_ignore_when_annotated_with = Composable, Test
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index ca22c10d..f7a94a9f 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,8 +1,11 @@
## 관련 이슈번호
+
close #
## 작업 사항
+
## 기타 사항
+
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index dee1cb1e..af241e66 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -7,7 +7,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
-
+
steps:
- uses: actions/checkout@v3
- name: set up JDK 17
@@ -45,3 +45,4 @@ jobs:
- name: Run ktlint
run: ./gradlew ktlintCheck
+
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index e402d08e..724be0a1 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -20,5 +20,10 @@ android {
dependencies {
implementation(project(":feature:login"))
+ implementation(project(":core:interceptor"))
+ implementation(project(":core:data"))
+ implementation(project(":core:network"))
+ implementation(project(":core:datastore"))
+ implementation(project(":core:domain"))
implementation(project(":core:designsystem"))
}
diff --git a/app/src/androidTest/java/com/withpeace/withpeace/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/withpeace/withpeace/ExampleInstrumentedTest.kt
index a855b0aa..fabc1c37 100644
--- a/app/src/androidTest/java/com/withpeace/withpeace/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/com/withpeace/withpeace/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package com.withpeace.withpeace
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 33e48a87..ab29bc8c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,6 +11,7 @@
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
+ android:usesCleartextTraffic="true"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
diff --git a/app/src/main/java/com/withpeace/withpeace/WithPeaceApplication.kt b/app/src/main/java/com/withpeace/withpeace/WithPeaceApplication.kt
index cd59d3f1..8390979d 100644
--- a/app/src/main/java/com/withpeace/withpeace/WithPeaceApplication.kt
+++ b/app/src/main/java/com/withpeace/withpeace/WithPeaceApplication.kt
@@ -4,5 +4,5 @@ import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
-class WithPeaceApplication: Application() {
+class WithPeaceApplication : Application() {
}
\ No newline at end of file
diff --git a/app/src/test/java/com/withpeace/withpeace/ExampleUnitTest.kt b/app/src/test/java/com/withpeace/withpeace/ExampleUnitTest.kt
index 7386af31..944b793d 100644
--- a/app/src/test/java/com/withpeace/withpeace/ExampleUnitTest.kt
+++ b/app/src/test/java/com/withpeace/withpeace/ExampleUnitTest.kt
@@ -1,9 +1,8 @@
package com.withpeace.withpeace
+import org.junit.Assert.assertEquals
import org.junit.Test
-import org.junit.Assert.*
-
/**
* Example local unit test, which will execute on the development machine (host).
*
diff --git a/build-logic/src/main/kotlin/convention.feature.gradle.kts b/build-logic/src/main/kotlin/convention.feature.gradle.kts
index 559cfcb4..756f561f 100644
--- a/build-logic/src/main/kotlin/convention.feature.gradle.kts
+++ b/build-logic/src/main/kotlin/convention.feature.gradle.kts
@@ -6,6 +6,9 @@ plugins {
id("convention.android.compose")
id("convention.android.hilt")
}
-dependencies {
+
+dependencies{
+ implementation(project(":core:data"))
+ implementation(project(":core:domain"))
implementation(project(":core:designsystem"))
-}
+}
\ No newline at end of file
diff --git a/core/data/src/androidTest/java/com/withpeace/withpeace/core/data/ExampleInstrumentedTest.kt b/core/data/src/androidTest/java/com/withpeace/withpeace/core/data/ExampleInstrumentedTest.kt
index b3b26a3a..410df2d5 100644
--- a/core/data/src/androidTest/java/com/withpeace/withpeace/core/data/ExampleInstrumentedTest.kt
+++ b/core/data/src/androidTest/java/com/withpeace/withpeace/core/data/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package com.withpeace.withpeace.core.data
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
diff --git a/core/data/src/main/AndroidManifest.xml b/core/data/src/main/AndroidManifest.xml
index a5918e68..44008a43 100644
--- a/core/data/src/main/AndroidManifest.xml
+++ b/core/data/src/main/AndroidManifest.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/RepositoryModule.kt b/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/RepositoryModule.kt
new file mode 100644
index 00000000..9d9305a0
--- /dev/null
+++ b/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/RepositoryModule.kt
@@ -0,0 +1,18 @@
+package com.withpeace.withpeace.core.data.di
+
+import com.withpeace.withpeace.core.data.repository.DefaultTokenRepository
+import com.withpeace.withpeace.core.domain.repository.TokenRepository
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+interface RepositoryModule {
+
+ @Binds
+ @Singleton
+ fun bindsTokenRepository(defaultTokenRepository: DefaultTokenRepository): TokenRepository
+}
\ No newline at end of file
diff --git a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/mapper/TokenMapper.kt b/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/mapper/TokenMapper.kt
index e7d7c9c2..b95516fa 100644
--- a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/mapper/TokenMapper.kt
+++ b/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/mapper/TokenMapper.kt
@@ -6,6 +6,6 @@ import com.withpeace.withpeace.core.network.di.response.TokenResponse
fun TokenResponse.toDomain(): Token {
return Token(
accessToken = accessToken,
- refreshToken = refreshToken
+ refreshToken = refreshToken,
)
}
\ No newline at end of file
diff --git a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/repository/DefaultTokenRepository.kt b/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/repository/DefaultTokenRepository.kt
index c725e557..e853f8b3 100644
--- a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/repository/DefaultTokenRepository.kt
+++ b/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/repository/DefaultTokenRepository.kt
@@ -1,49 +1,74 @@
package com.withpeace.withpeace.core.data.repository
-import com.skydoves.sandwich.message
+import com.skydoves.sandwich.messageOrNull
import com.skydoves.sandwich.suspendMapSuccess
-import com.skydoves.sandwich.suspendOnError
+import com.skydoves.sandwich.suspendOnFailure
import com.withpeace.withpeace.core.data.mapper.toDomain
import com.withpeace.withpeace.core.datastore.dataStore.TokenPreferenceDataSource
import com.withpeace.withpeace.core.domain.model.Token
import com.withpeace.withpeace.core.domain.repository.TokenRepository
+import com.withpeace.withpeace.core.network.di.request.SignUpRequest
import com.withpeace.withpeace.core.network.di.service.AuthService
+import com.withpeace.withpeace.core.network.di.service.LoginService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import javax.inject.Inject
+class DefaultTokenRepository
+ @Inject
+ constructor(
+ private val tokenPreferenceDataSource: TokenPreferenceDataSource,
+ private val loginService: LoginService,
+ private val authService: AuthService,
+ ) : TokenRepository {
+ override fun getAccessToken(): Flow {
+ return tokenPreferenceDataSource.accessToken
+ }
-class DefaultTokenRepository @Inject constructor(
- private val tokenPreferenceDataSource: TokenPreferenceDataSource,
- private val authService: AuthService
-) : TokenRepository {
+ override fun getRefreshToken(): Flow {
+ return tokenPreferenceDataSource.refreshToken
+ }
- override fun getAccessToken(): Flow {
- return tokenPreferenceDataSource.accessToken
- }
+ override suspend fun updateAccessToken(accessToken: String) {
+ tokenPreferenceDataSource.updateAccessToken(accessToken)
+ }
- override fun getRefreshToken(): Flow {
- return tokenPreferenceDataSource.refreshToken
- }
+ override suspend fun updateRefreshToken(refreshToken: String) {
+ tokenPreferenceDataSource.updateRefreshToken(refreshToken)
+ }
- override suspend fun updateAccessToken(accessToken: String) {
- tokenPreferenceDataSource.updateAccessToken(accessToken)
- }
+ override suspend fun signUp(
+ email: String,
+ nickname: String,
+ deviceToken: String?,
+ ) {
+ authService.signUp(
+ SignUpRequest(
+ email = email,
+ nickname = nickname,
+ deviceToken = deviceToken,
+ ),
+ )
+ }
- override suspend fun updateRefreshToken(refreshToken: String) {
- tokenPreferenceDataSource.updateRefreshToken(refreshToken)
- }
+ override fun googleLogin(
+ idToken: String,
+ onError: (String?) -> Unit,
+ ): Flow =
+ flow {
+ loginService.googleLogin(AUTHORIZATION_FORMAT.format(idToken))
+ .suspendMapSuccess {
+ emit(data.toDomain())
+ updateAccessToken(data.accessToken)
+ updateRefreshToken(data.refreshToken)
+ }.suspendOnFailure {
+ onError(messageOrNull)
+ }
+ }.flowOn(Dispatchers.IO)
- override fun googleLogin(onError: (String?) -> Unit): Flow = flow {
- authService.googleLogin()
- .suspendMapSuccess {
- emit(data.toDomain())
- updateAccessToken(data.accessToken)
- updateRefreshToken(data.refreshToken)
- }.suspendOnError {
- onError(message())
- }
- }.flowOn(Dispatchers.IO)
-}
\ No newline at end of file
+ companion object {
+ private const val AUTHORIZATION_FORMAT = "Bearer %s"
+ }
+ }
diff --git a/core/data/src/test/java/com/withpeace/withpeace/core/data/ExampleUnitTest.kt b/core/data/src/test/java/com/withpeace/withpeace/core/data/ExampleUnitTest.kt
index 61be3bed..2dce1955 100644
--- a/core/data/src/test/java/com/withpeace/withpeace/core/data/ExampleUnitTest.kt
+++ b/core/data/src/test/java/com/withpeace/withpeace/core/data/ExampleUnitTest.kt
@@ -1,9 +1,8 @@
package com.withpeace.withpeace.core.data
+import org.junit.Assert.assertEquals
import org.junit.Test
-import org.junit.Assert.*
-
/**
* Example local unit test, which will execute on the development machine (host).
*
diff --git a/core/datastore/src/androidTest/java/com/withpeace/withpeace/core/datastore/ExampleInstrumentedTest.kt b/core/datastore/src/androidTest/java/com/withpeace/withpeace/core/datastore/ExampleInstrumentedTest.kt
index 70ef8ee6..1e831671 100644
--- a/core/datastore/src/androidTest/java/com/withpeace/withpeace/core/datastore/ExampleInstrumentedTest.kt
+++ b/core/datastore/src/androidTest/java/com/withpeace/withpeace/core/datastore/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package com.withpeace.withpeace.core.datastore
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
diff --git a/core/datastore/src/main/AndroidManifest.xml b/core/datastore/src/main/AndroidManifest.xml
index a5918e68..44008a43 100644
--- a/core/datastore/src/main/AndroidManifest.xml
+++ b/core/datastore/src/main/AndroidManifest.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/dataStore/DefaultTokenPreferenceDataSource.kt b/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/dataStore/DefaultTokenPreferenceDataSource.kt
index a1f7b504..6b5cca17 100644
--- a/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/dataStore/DefaultTokenPreferenceDataSource.kt
+++ b/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/dataStore/DefaultTokenPreferenceDataSource.kt
@@ -10,31 +10,31 @@ import javax.inject.Inject
import javax.inject.Named
class DefaultTokenPreferenceDataSource @Inject constructor(
- @Named("auth") private val dataStore: DataStore
-): TokenPreferenceDataSource {
+ @Named("auth") private val dataStore: DataStore,
+) : TokenPreferenceDataSource {
- override val accessToken: Flow = dataStore.data.map{ preferences ->
+ override val accessToken: Flow = dataStore.data.map { preferences ->
preferences[ACCESS_TOKEN]
}
- override val refreshToken: Flow = dataStore.data.map{preferences ->
+ override val refreshToken: Flow = dataStore.data.map { preferences ->
preferences[REFRESH_TOKEN]
}
- override suspend fun updateAccessToken(accessToken: String) {
- dataStore.edit{preferences->
+ override suspend fun updateAccessToken(accessToken: String) {
+ dataStore.edit { preferences ->
preferences[ACCESS_TOKEN] = accessToken
}
}
override suspend fun updateRefreshToken(refreshToken: String) {
- dataStore.edit{preferences->
+ dataStore.edit { preferences ->
preferences[REFRESH_TOKEN] = refreshToken
}
}
- companion object{
- private val ACCESS_TOKEN= stringPreferencesKey("ACCESS_TOKEN")
- private val REFRESH_TOKEN= stringPreferencesKey("REFRESH_TOKEN")
+ companion object {
+ private val ACCESS_TOKEN = stringPreferencesKey("ACCESS_TOKEN")
+ private val REFRESH_TOKEN = stringPreferencesKey("REFRESH_TOKEN")
}
}
\ No newline at end of file
diff --git a/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/DataStoreModule.kt b/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/DataStoreModule.kt
index d670e80e..8215224f 100644
--- a/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/DataStoreModule.kt
+++ b/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/DataStoreModule.kt
@@ -24,6 +24,6 @@ object DataStoreModule {
@Singleton
@Named("auth")
fun providesTokenDataStore(
- @ApplicationContext context: Context
+ @ApplicationContext context: Context,
): DataStore = context.authDataStore
}
\ No newline at end of file
diff --git a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/DataSourceModule.kt b/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/PreferenceDataSourceModule.kt
similarity index 62%
rename from core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/DataSourceModule.kt
rename to core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/PreferenceDataSourceModule.kt
index c2816b1e..e0beaa82 100644
--- a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/DataSourceModule.kt
+++ b/core/datastore/src/main/java/com/withpeace/withpeace/core/datastore/di/PreferenceDataSourceModule.kt
@@ -1,4 +1,4 @@
-package com.withpeace.withpeace.core.data.di
+package com.withpeace.withpeace.core.datastore.di
import com.withpeace.withpeace.core.datastore.dataStore.DefaultTokenPreferenceDataSource
import com.withpeace.withpeace.core.datastore.dataStore.TokenPreferenceDataSource
@@ -10,9 +10,11 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
-abstract class DataSourceModule {
+interface PreferenceDataSourceModule {
@Binds
@Singleton
- abstract fun bindsTokenDataSource(tokenPreferenceDataSource: DefaultTokenPreferenceDataSource): TokenPreferenceDataSource
+ fun bindsTokenPreferenceDataSource(
+ defaultTokenPreferenceDataSource: DefaultTokenPreferenceDataSource,
+ ): TokenPreferenceDataSource
}
\ No newline at end of file
diff --git a/core/datastore/src/test/java/com/withpeace/withpeace/core/datastore/ExampleUnitTest.kt b/core/datastore/src/test/java/com/withpeace/withpeace/core/datastore/ExampleUnitTest.kt
index ca1f94c0..c98a0772 100644
--- a/core/datastore/src/test/java/com/withpeace/withpeace/core/datastore/ExampleUnitTest.kt
+++ b/core/datastore/src/test/java/com/withpeace/withpeace/core/datastore/ExampleUnitTest.kt
@@ -1,9 +1,8 @@
package com.withpeace.withpeace.core.datastore
+import org.junit.Assert.assertEquals
import org.junit.Test
-import org.junit.Assert.*
-
/**
* Example local unit test, which will execute on the development machine (host).
*
diff --git a/core/domain/src/main/java/com/withpeace/withpeace/core/domain/model/Token.kt b/core/domain/src/main/java/com/withpeace/withpeace/core/domain/model/Token.kt
index 8fddfc8b..f8ca3553 100644
--- a/core/domain/src/main/java/com/withpeace/withpeace/core/domain/model/Token.kt
+++ b/core/domain/src/main/java/com/withpeace/withpeace/core/domain/model/Token.kt
@@ -2,5 +2,5 @@ package com.withpeace.withpeace.core.domain.model
data class Token(
val accessToken: String,
- val refreshToken: String
+ val refreshToken: String,
)
\ No newline at end of file
diff --git a/core/domain/src/main/java/com/withpeace/withpeace/core/domain/repository/TokenRepository.kt b/core/domain/src/main/java/com/withpeace/withpeace/core/domain/repository/TokenRepository.kt
index 56f6c7f0..893b0953 100644
--- a/core/domain/src/main/java/com/withpeace/withpeace/core/domain/repository/TokenRepository.kt
+++ b/core/domain/src/main/java/com/withpeace/withpeace/core/domain/repository/TokenRepository.kt
@@ -13,5 +13,7 @@ interface TokenRepository {
suspend fun updateRefreshToken(refreshToken: String)
- fun googleLogin(onError: (message: String?) -> Unit): Flow
+ suspend fun signUp(email: String, nickname: String, deviceToken: String?)
+
+ fun googleLogin(idToken: String, onError: (message: String?) -> Unit): Flow
}
\ No newline at end of file
diff --git a/core/interceptor/.gitignore b/core/interceptor/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/core/interceptor/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/core/interceptor/build.gradle.kts b/core/interceptor/build.gradle.kts
new file mode 100644
index 00000000..1967e9b0
--- /dev/null
+++ b/core/interceptor/build.gradle.kts
@@ -0,0 +1,17 @@
+plugins {
+ id("com.android.library")
+ id("convention.android.base")
+ id("convention.android.hilt")
+}
+
+android {
+ namespace = "com.withpeace.withpeace.core.interceptor"
+}
+
+dependencies {
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.retrofit.core)
+ implementation(libs.okhttp.logging)
+ implementation(project(":core:datastore"))
+ implementation(project(":core:network"))
+}
\ No newline at end of file
diff --git a/core/interceptor/consumer-rules.pro b/core/interceptor/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/core/interceptor/proguard-rules.pro b/core/interceptor/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/core/interceptor/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/core/interceptor/src/androidTest/java/com/withpeace/withpeace/core/interceptor/ExampleInstrumentedTest.kt b/core/interceptor/src/androidTest/java/com/withpeace/withpeace/core/interceptor/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..5d4149a9
--- /dev/null
+++ b/core/interceptor/src/androidTest/java/com/withpeace/withpeace/core/interceptor/ExampleInstrumentedTest.kt
@@ -0,0 +1,22 @@
+package com.withpeace.withpeace.core.interceptor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.*
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.withpeace.withpeace.core.interceptor.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/core/interceptor/src/main/AndroidManifest.xml b/core/interceptor/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..44008a43
--- /dev/null
+++ b/core/interceptor/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/core/interceptor/src/main/java/com/withpeace/withpeace/core/interceptor/AuthInterceptor.kt b/core/interceptor/src/main/java/com/withpeace/withpeace/core/interceptor/AuthInterceptor.kt
new file mode 100644
index 00000000..cb211e25
--- /dev/null
+++ b/core/interceptor/src/main/java/com/withpeace/withpeace/core/interceptor/AuthInterceptor.kt
@@ -0,0 +1,100 @@
+package com.withpeace.withpeace.core.interceptor
+
+import android.content.Context
+import com.withpeace.withpeace.core.datastore.dataStore.TokenPreferenceDataSource
+import com.withpeace.withpeace.core.network.di.response.TokenResponse
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import dagger.hilt.android.EntryPointAccessors
+import dagger.hilt.components.SingletonComponent
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import kotlinx.serialization.json.Json
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+
+class AuthInterceptor(context: Context) : Interceptor {
+ private val tokenPreferenceDataSource =
+ EntryPointAccessors
+ .fromApplication(context)
+ .getTokenPreferenceDataSource()
+
+ private val client = OkHttpClient.Builder().build()
+
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val accessToken = runBlocking { tokenPreferenceDataSource.accessToken.firstOrNull() }
+ val tokenAddedRequest =
+ chain.request()
+ .newBuilder()
+ .addHeader(
+ ACCESS_TOKEN_HEADER,
+ TOKEN_FORMAT.format(accessToken),
+ ).build()
+ var response = chain.proceed(tokenAddedRequest)
+
+ if (response.code == 401) {
+ val refreshToken = runBlocking { tokenPreferenceDataSource.refreshToken.firstOrNull() }
+ if (refreshToken != null) {
+ runCatching {
+ refreshAccessToken(refreshToken)
+ }.onSuccess { tokenResponse ->
+ runBlocking {
+ tokenPreferenceDataSource.updateAccessToken(tokenResponse.accessToken)
+ tokenPreferenceDataSource.updateRefreshToken(tokenResponse.refreshToken)
+ }
+ response =
+ chain.proceed(
+ chain.request().newBuilder().addHeader(
+ ACCESS_TOKEN_HEADER,
+ TOKEN_FORMAT.format(tokenResponse.accessToken),
+ ).build(),
+ )
+ }
+ }
+ }
+ return response
+ }
+
+ private fun refreshAccessToken(refreshToken: String): TokenResponse {
+ val response: Response =
+ runBlocking {
+ withContext(Dispatchers.IO) {
+ client.newCall(createAccessTokenRefreshRequest(refreshToken)).execute()
+ }
+ }
+ if (response.isSuccessful) {
+ return response.toDto()
+ }
+ throw IllegalArgumentException()
+ }
+
+ private fun createAccessTokenRefreshRequest(refreshToken: String): Request {
+ return Request.Builder()
+ .url(REFRESH_URL)
+ .addHeader(REFRESH_TOKEN_FORMAT, TOKEN_FORMAT.format(refreshToken))
+ .build()
+ }
+
+ private inline fun Response.toDto(): T {
+ body?.let {
+ return Json.decodeFromString(it.string())
+ } ?: throw IllegalArgumentException()
+ }
+
+ @EntryPoint
+ @InstallIn(SingletonComponent::class)
+ interface AuthInterceptorEntryPoint {
+ fun getTokenPreferenceDataSource(): TokenPreferenceDataSource
+ }
+
+ companion object {
+ private const val REFRESH_URL = "http://49.50.160.170:8080/api/v1/auth/refresh"
+ private const val REFRESH_TOKEN_FORMAT = "ReAuthorization"
+ private const val ACCESS_TOKEN_HEADER = "Authorization"
+ private const val TOKEN_FORMAT = "Bearer %s"
+ }
+}
diff --git a/core/interceptor/src/main/java/com/withpeace/withpeace/core/interceptor/InterceptorModule.kt b/core/interceptor/src/main/java/com/withpeace/withpeace/core/interceptor/InterceptorModule.kt
new file mode 100644
index 00000000..71b74afa
--- /dev/null
+++ b/core/interceptor/src/main/java/com/withpeace/withpeace/core/interceptor/InterceptorModule.kt
@@ -0,0 +1,20 @@
+package com.withpeace.withpeace.core.interceptor
+
+import android.content.Context
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import okhttp3.Interceptor
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object InterceptorModule {
+
+ @Provides
+ @Singleton
+ fun provideHeaderInterceptor(@ApplicationContext context: Context): Interceptor =
+ AuthInterceptor(context)
+}
\ No newline at end of file
diff --git a/core/interceptor/src/test/java/com/withpeace/withpeace/core/interceptor/ExampleUnitTest.kt b/core/interceptor/src/test/java/com/withpeace/withpeace/core/interceptor/ExampleUnitTest.kt
new file mode 100644
index 00000000..03abd607
--- /dev/null
+++ b/core/interceptor/src/test/java/com/withpeace/withpeace/core/interceptor/ExampleUnitTest.kt
@@ -0,0 +1,16 @@
+package com.withpeace.withpeace.core.interceptor
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/core/network/src/androidTest/java/com/withpeace/withpeace/core/network/ExampleInstrumentedTest.kt b/core/network/src/androidTest/java/com/withpeace/withpeace/core/network/ExampleInstrumentedTest.kt
index 75fdeedb..dd396ff4 100644
--- a/core/network/src/androidTest/java/com/withpeace/withpeace/core/network/ExampleInstrumentedTest.kt
+++ b/core/network/src/androidTest/java/com/withpeace/withpeace/core/network/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package com.withpeace.withpeace.core.network
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
diff --git a/core/network/src/main/AndroidManifest.xml b/core/network/src/main/AndroidManifest.xml
index a5918e68..44008a43 100644
--- a/core/network/src/main/AndroidManifest.xml
+++ b/core/network/src/main/AndroidManifest.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/AuthInterceptor.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/AuthInterceptor.kt
new file mode 100644
index 00000000..e69de29b
diff --git a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/NetworkModule.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/di/NetworkModule.kt
similarity index 66%
rename from core/network/src/main/java/com/withpeace/withpeace/core/network/di/NetworkModule.kt
rename to core/network/src/main/java/com/withpeace/withpeace/core/network/di/di/NetworkModule.kt
index e84b59a3..dae7fe46 100644
--- a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/NetworkModule.kt
+++ b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/di/NetworkModule.kt
@@ -1,4 +1,4 @@
-package com.withpeace.withpeace.core.network.di
+package com.withpeace.withpeace.core.network.di.di
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.skydoves.sandwich.adapters.ApiResponseCallAdapterFactory
@@ -7,11 +7,13 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.json.Json
+import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Converter
import retrofit2.Retrofit
+import javax.inject.Named
import javax.inject.Singleton
@Module
@@ -39,34 +41,45 @@ object NetworkModule {
}
}
-// @Provides
-// @Singleton
-// fun provideHeaderInterceptor(chain: Interceptor.Chain) {
-// val requestBuilder = chain.request().newBuilder()
-// var apiKey = BuildConfig.X_RIOT_TOKEN
-// requestBuilder.addHeader("X-Riot-Token", apiKey)
-// chain.proceed(requestBuilder.build())
-// }
-
@Singleton
@Provides
- fun provideOkhttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
+ fun provideOkhttpClient(
+ authInterceptor: Interceptor,
+ httpLoggingInterceptor: HttpLoggingInterceptor,
+ ): OkHttpClient {
return OkHttpClient.Builder().apply {
- // addInterceptor(AccessTokenInterceptor) TODO("토큰 인터셉터 할당")
+ addInterceptor(authInterceptor)
addInterceptor(httpLoggingInterceptor)
}.build()
}
-
+ @Named("general")
@Provides
@Singleton
- fun provideRetrofitClient(
+ fun provideTokenRetrofitClient(
okHttpClient: OkHttpClient,
- converterFactory: Converter.Factory
+ converterFactory: Converter.Factory,
): Retrofit {
return Retrofit.Builder()
.client(okHttpClient)
- .baseUrl("https://asia.api.riotgames.com/") // TODO("BaseUrl 수정")
+ .baseUrl("http://49.50.160.170:8080/")
+ .addConverterFactory(converterFactory)
+ .addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
+ .build()
+ }
+
+
+ /**
+ * todo: 네이밍 수정
+ */
+ @Named("initial")
+ @Provides
+ @Singleton
+ fun provideRetrofitClient(
+ converterFactory: Converter.Factory,
+ ): Retrofit {
+ return Retrofit.Builder()
+ .baseUrl("http://49.50.160.170:8080/")
.addConverterFactory(converterFactory)
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
.build()
diff --git a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/ServiceModule.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/di/ServiceModule.kt
similarity index 50%
rename from core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/ServiceModule.kt
rename to core/network/src/main/java/com/withpeace/withpeace/core/network/di/di/ServiceModule.kt
index 1b2f6fb1..4c598414 100644
--- a/core/data/src/main/kotlin/com/withpeace/withpeace/core/data/di/ServiceModule.kt
+++ b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/di/ServiceModule.kt
@@ -1,11 +1,13 @@
-package com.withpeace.withpeace.core.data.di
+package com.withpeace.withpeace.core.network.di.di
import com.withpeace.withpeace.core.network.di.service.AuthService
+import com.withpeace.withpeace.core.network.di.service.LoginService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
+import javax.inject.Named
import javax.inject.Singleton
@Module
@@ -14,6 +16,11 @@ object ServiceModule {
@Provides
@Singleton
- fun providesAuthService(retrofit: Retrofit): AuthService =
+ fun providesAuthService(@Named("general") retrofit: Retrofit): AuthService =
retrofit.create(AuthService::class.java)
+
+ @Provides
+ @Singleton
+ fun providesLoginService(@Named("initial") retrofit: Retrofit): LoginService =
+ retrofit.create(LoginService::class.java)
}
\ No newline at end of file
diff --git a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/request/SignUpRequest.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/request/SignUpRequest.kt
index af72b92d..d69487fb 100644
--- a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/request/SignUpRequest.kt
+++ b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/request/SignUpRequest.kt
@@ -1,5 +1,8 @@
package com.withpeace.withpeace.core.network.di.request
+import kotlinx.serialization.Serializable
+
+@Serializable
data class SignUpRequest(
val email: String,
val nickname: String,
diff --git a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/response/TokenResponse.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/response/TokenResponse.kt
index 26350bd7..7f0c414f 100644
--- a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/response/TokenResponse.kt
+++ b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/response/TokenResponse.kt
@@ -1,5 +1,8 @@
package com.withpeace.withpeace.core.network.di.response
+import kotlinx.serialization.Serializable
+
+@Serializable
data class TokenResponse(
val accessToken: String,
val refreshToken: String,
diff --git a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/AuthService.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/AuthService.kt
index 546e1ed0..fffa79ad 100644
--- a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/AuthService.kt
+++ b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/AuthService.kt
@@ -5,18 +5,18 @@ import com.withpeace.withpeace.core.network.di.request.SignUpRequest
import com.withpeace.withpeace.core.network.di.response.BaseResponse
import com.withpeace.withpeace.core.network.di.response.TokenResponse
import retrofit2.http.Body
+import retrofit2.http.Header
import retrofit2.http.POST
interface AuthService {
- @POST("/api/v1/auth/google")
- fun googleLogin(): ApiResponse>
-
@POST("/api/v1/auth/register")
- fun signUp(@Body signUpRequest: SignUpRequest): ApiResponse>
+ suspend fun signUp(
+ @Body signUpRequest: SignUpRequest,
+ ): ApiResponse>
@POST("/api/v1/auth/refresh")
- fun refreshAccessToken(): ApiResponse>
+ suspend fun refreshAccessToken(): ApiResponse>
@POST("/api/v1/auth/logout")
- fun logout(): ApiResponse>
+ suspend fun logout(): ApiResponse>
}
\ No newline at end of file
diff --git a/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/LoginService.kt b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/LoginService.kt
new file mode 100644
index 00000000..deee313d
--- /dev/null
+++ b/core/network/src/main/java/com/withpeace/withpeace/core/network/di/service/LoginService.kt
@@ -0,0 +1,16 @@
+package com.withpeace.withpeace.core.network.di.service
+
+import com.skydoves.sandwich.ApiResponse
+import com.withpeace.withpeace.core.network.di.response.BaseResponse
+import com.withpeace.withpeace.core.network.di.response.TokenResponse
+import retrofit2.http.Header
+import retrofit2.http.POST
+
+interface LoginService {
+
+ @POST("/api/v1/auth/google")
+ suspend fun googleLogin(
+ @Header("Authorization")
+ idToken: String,
+ ): ApiResponse>
+}
\ No newline at end of file
diff --git a/core/network/src/test/java/com/withpeace/withpeace/core/network/ExampleUnitTest.kt b/core/network/src/test/java/com/withpeace/withpeace/core/network/ExampleUnitTest.kt
index 9b8a7dd4..3a01bec8 100644
--- a/core/network/src/test/java/com/withpeace/withpeace/core/network/ExampleUnitTest.kt
+++ b/core/network/src/test/java/com/withpeace/withpeace/core/network/ExampleUnitTest.kt
@@ -1,9 +1,8 @@
package com.withpeace.withpeace.core.network
+import org.junit.Assert.assertEquals
import org.junit.Test
-import org.junit.Assert.*
-
/**
* Example local unit test, which will execute on the development machine (host).
*
diff --git a/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginScreen.kt b/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginScreen.kt
index 71a1a148..8cc21785 100644
--- a/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginScreen.kt
+++ b/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginScreen.kt
@@ -2,6 +2,8 @@ package com.withpeace.withpeace.feature.login
import android.util.Log
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Surface
@@ -11,30 +13,37 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
-import com.withpeace.withpeace.core.designsystem.theme.WithpeaceTheme
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.viewmodel.compose.viewModel
import com.withpeace.withpeace.googlelogin.GoogleLoginManager
+import kotlinx.coroutines.launch
@Composable
fun LoginScreen() {
+ val viewModel: LoginViewModel = viewModel()
val coroutineScope = rememberCoroutineScope()
val googleLoginManager = GoogleLoginManager(LocalContext.current)
- Surface(modifier = Modifier.fillMaxSize()) {
- Box {
- Button(
- onClick = {
- googleLoginManager.startLogin(
- coroutineScope,
- onSuccessLogin = { Log.d("Wooseok", it) },
- onFailLogin = { Log.d("wooseok", it.toString()) },
- )
- },
- ) {
- Text(
- text = "Login",
- style = WithpeaceTheme.typography.body,
- color = WithpeaceTheme.colors.MainPink,
+ Row(modifier = Modifier.fillMaxSize()) {
+ Button(
+ onClick = {
+ googleLoginManager.startLogin(
+ coroutineScope,
+ onSuccessLogin = {
+ Log.d("woogi", "idToken: $it")
+ viewModel.googleLogin(it)
+ },
+ onFailLogin = { Log.d("wooseok", it.toString()) },
)
- }
+ },
+ ) {
+ Text(text = "Login")
+ }
+ Button(
+ onClick = {
+ viewModel.signUp()
+ },
+ ) {
+ Text(text = "signup")
}
}
}
diff --git a/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginViewModel.kt b/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginViewModel.kt
new file mode 100644
index 00000000..d88918d3
--- /dev/null
+++ b/feature/login/src/main/java/com/withpeace/withpeace/feature/login/LoginViewModel.kt
@@ -0,0 +1,37 @@
+package com.withpeace.withpeace.feature.login
+
+import android.util.Log
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.withpeace.withpeace.core.domain.repository.TokenRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class LoginViewModel
+ @Inject
+ constructor(
+ private val tokenRepository: TokenRepository,
+ ) : ViewModel() {
+ fun googleLogin(idToken: String) {
+ viewModelScope.launch {
+ tokenRepository.googleLogin(idToken) {
+ Log.e("woogi", it ?: "메시지 없음")
+ }.collect { token ->
+ tokenRepository.updateAccessToken(token.accessToken)
+ tokenRepository.updateRefreshToken(token.refreshToken)
+ }
+ }
+ }
+
+ fun signUp() {
+ viewModelScope.launch {
+ tokenRepository.signUp(
+ email = "wooseok",
+ nickname = "haha",
+ deviceToken = null,
+ )
+ }
+ }
+ }
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index a183a317..b620c3c7 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -139,7 +139,7 @@ mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
multidex = { group = "androidx.multidex", name = "multidex", version.ref = "multidex" }
-google-login = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "google-login"}
+google-login = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "google-login" }
# verify
verify-detektFormatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index e13144e1..f73b4e73 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -23,3 +23,4 @@ include(":core:data")
include(":core:domain")
include(":core:datastore")
include(":core:designsystem")
+include(":core:interceptor")