Extract Base URL from authentication
This commit is contained in:
@@ -2,7 +2,7 @@ package gq.kirmanak.mealient.data.auth
|
||||
|
||||
interface AuthDataSource {
|
||||
/**
|
||||
* Tries to acquire authentication token using the provided credentials on specified server.
|
||||
* Tries to acquire authentication token using the provided credentials
|
||||
*/
|
||||
suspend fun authenticate(username: String, password: String, baseUrl: String): String
|
||||
suspend fun authenticate(username: String, password: String): String
|
||||
}
|
||||
@@ -3,11 +3,8 @@ package gq.kirmanak.mealient.data.auth
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AuthRepo {
|
||||
suspend fun authenticate(username: String, password: String, baseUrl: String)
|
||||
|
||||
suspend fun getBaseUrl(): String?
|
||||
|
||||
suspend fun requireBaseUrl(): String
|
||||
suspend fun authenticate(username: String, password: String)
|
||||
|
||||
suspend fun getAuthHeader(): String?
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ package gq.kirmanak.mealient.data.auth
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AuthStorage {
|
||||
suspend fun storeAuthData(authHeader: String, baseUrl: String)
|
||||
|
||||
suspend fun getBaseUrl(): String?
|
||||
suspend fun storeAuthData(authHeader: String)
|
||||
|
||||
suspend fun getAuthHeader(): String?
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package gq.kirmanak.mealient.data.auth.impl
|
||||
|
||||
import gq.kirmanak.mealient.data.auth.AuthDataSource
|
||||
import gq.kirmanak.mealient.data.auth.impl.AuthenticationError.*
|
||||
import gq.kirmanak.mealient.data.network.ErrorDetail
|
||||
import gq.kirmanak.mealient.data.network.NetworkError.*
|
||||
import gq.kirmanak.mealient.data.network.ServiceFactory
|
||||
import gq.kirmanak.mealient.extensions.decodeErrorBodyOrNull
|
||||
import kotlinx.coroutines.CancellationException
|
||||
@@ -20,13 +20,14 @@ class AuthDataSourceImpl @Inject constructor(
|
||||
private val json: Json,
|
||||
) : AuthDataSource {
|
||||
|
||||
override suspend fun authenticate(
|
||||
username: String,
|
||||
password: String,
|
||||
baseUrl: String
|
||||
): String {
|
||||
Timber.v("authenticate() called with: username = $username, password = $password, baseUrl = $baseUrl")
|
||||
val authService = authServiceFactory.provideService(baseUrl)
|
||||
override suspend fun authenticate(username: String, password: String): String {
|
||||
Timber.v("authenticate() called with: username = $username, password = $password")
|
||||
val authService = try {
|
||||
authServiceFactory.provideService()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "authenticate: can't create Retrofit service")
|
||||
throw MalformedUrl(e)
|
||||
}
|
||||
val response = sendRequest(authService, username, password)
|
||||
val accessToken = parseToken(response)
|
||||
Timber.v("authenticate() returned: $accessToken")
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package gq.kirmanak.mealient.data.auth.impl
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import gq.kirmanak.mealient.data.auth.AuthDataSource
|
||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||
import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||
import gq.kirmanak.mealient.data.auth.impl.AuthenticationError.MalformedUrl
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@@ -19,23 +15,13 @@ class AuthRepoImpl @Inject constructor(
|
||||
private val storage: AuthStorage,
|
||||
) : AuthRepo {
|
||||
|
||||
override suspend fun authenticate(
|
||||
username: String,
|
||||
password: String,
|
||||
baseUrl: String
|
||||
) {
|
||||
Timber.v("authenticate() called with: username = $username, password = $password, baseUrl = $baseUrl")
|
||||
val url = parseBaseUrl(baseUrl)
|
||||
val accessToken = dataSource.authenticate(username, password, url)
|
||||
override suspend fun authenticate(username: String, password: String) {
|
||||
Timber.v("authenticate() called with: username = $username, password = $password")
|
||||
val accessToken = dataSource.authenticate(username, password)
|
||||
Timber.d("authenticate result is \"$accessToken\"")
|
||||
storage.storeAuthData(AUTH_HEADER_FORMAT.format(accessToken), url)
|
||||
storage.storeAuthData(AUTH_HEADER_FORMAT.format(accessToken))
|
||||
}
|
||||
|
||||
override suspend fun getBaseUrl(): String? = storage.getBaseUrl()
|
||||
|
||||
override suspend fun requireBaseUrl(): String =
|
||||
checkNotNull(getBaseUrl()) { "Base URL is null when it was required" }
|
||||
|
||||
override suspend fun getAuthHeader(): String? = storage.getAuthHeader()
|
||||
|
||||
override suspend fun requireAuthHeader(): String =
|
||||
@@ -51,18 +37,6 @@ class AuthRepoImpl @Inject constructor(
|
||||
storage.clearAuthData()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun parseBaseUrl(baseUrl: String): String = try {
|
||||
val withScheme = Uri.parse(baseUrl).let {
|
||||
if (it.scheme == null) it.buildUpon().scheme("https").build()
|
||||
else it
|
||||
}.toString()
|
||||
withScheme.toHttpUrl().toString()
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "authenticate: can't parse base url $baseUrl")
|
||||
throw MalformedUrl(e)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val AUTH_HEADER_FORMAT = "Bearer %s"
|
||||
}
|
||||
|
||||
@@ -13,20 +13,10 @@ class AuthStorageImpl @Inject constructor(
|
||||
) : AuthStorage {
|
||||
|
||||
private val authHeaderKey by preferencesStorage::authHeaderKey
|
||||
private val baseUrlKey by preferencesStorage::baseUrlKey
|
||||
|
||||
override suspend fun storeAuthData(authHeader: String, baseUrl: String) {
|
||||
Timber.v("storeAuthData() called with: authHeader = $authHeader, baseUrl = $baseUrl")
|
||||
preferencesStorage.storeValues(
|
||||
Pair(authHeaderKey, authHeader),
|
||||
Pair(baseUrlKey, baseUrl),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getBaseUrl(): String? {
|
||||
val baseUrl = preferencesStorage.getValue(baseUrlKey)
|
||||
Timber.d("getBaseUrl: base url is $baseUrl")
|
||||
return baseUrl
|
||||
override suspend fun storeAuthData(authHeader: String) {
|
||||
Timber.v("storeAuthData() called with: authHeader = $authHeader")
|
||||
preferencesStorage.storeValues(Pair(authHeaderKey, authHeader))
|
||||
}
|
||||
|
||||
override suspend fun getAuthHeader(): String? {
|
||||
@@ -43,6 +33,6 @@ class AuthStorageImpl @Inject constructor(
|
||||
|
||||
override suspend fun clearAuthData() {
|
||||
Timber.v("clearAuthData() called")
|
||||
preferencesStorage.removeValues(authHeaderKey, baseUrlKey)
|
||||
preferencesStorage.removeValues(authHeaderKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package gq.kirmanak.mealient.data.auth.impl
|
||||
|
||||
sealed class AuthenticationError(cause: Throwable) : RuntimeException(cause) {
|
||||
class Unauthorized(cause: Throwable) : AuthenticationError(cause)
|
||||
class NoServerConnection(cause: Throwable) : AuthenticationError(cause)
|
||||
class NotMealie(cause: Throwable) : AuthenticationError(cause)
|
||||
class MalformedUrl(cause: Throwable) : AuthenticationError(cause)
|
||||
}
|
||||
Reference in New Issue
Block a user