Create API token when signing in

This commit is contained in:
Kirill Kamakin
2022-12-11 11:57:13 +01:00
parent a560db8bb6
commit c99f9fea88
21 changed files with 130 additions and 124 deletions

View File

@@ -4,4 +4,6 @@ interface AuthenticationProvider {
suspend fun getAuthHeader(): String?
suspend fun logout()
}

View File

@@ -12,21 +12,30 @@ import javax.inject.Provider
import javax.inject.Singleton
@Singleton
// TODO has to be interceptor, otherwise only public recipes are visible
class MealieAuthenticator @Inject constructor(
private val authenticationProvider: Provider<AuthenticationProvider>,
private val authenticationProviderProvider: Provider<AuthenticationProvider>,
) : Authenticator {
private val authenticationProvider: AuthenticationProvider
get() = authenticationProviderProvider.get()
override fun authenticate(route: Route?, response: Response): Request? {
val supportsBearer = response.challenges().any { it.scheme == BEARER_SCHEME }
val request = response.request
return if (supportsBearer && request.header(HEADER_NAME) == null) {
getAuthHeader()?.let { request.copyWithHeader(HEADER_NAME, it) }
} else {
null // Either Bearer is not supported or we've already tried to authenticate
return when {
request.header(HEADER_NAME) != null -> {
logout()
null
}
supportsBearer -> getAuthHeader()?.let { request.copyWithHeader(HEADER_NAME, it) }
else -> null
}
}
private fun getAuthHeader() = runBlocking { authenticationProvider.get().getAuthHeader() }
private fun getAuthHeader() = runBlocking { authenticationProvider.getAuthHeader() }
private fun logout() = runBlocking { authenticationProvider.logout() }
companion object {
@VisibleForTesting

View File

@@ -1,6 +1,7 @@
package gq.kirmanak.mealient.datasource.v0
import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0
import gq.kirmanak.mealient.datasource.v0.models.CreateApiTokenRequestV0
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeResponseV0
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeSummaryResponseV0
import gq.kirmanak.mealient.datasource.v0.models.ParseRecipeURLRequestV0
@@ -41,4 +42,9 @@ interface MealieDataSourceV0 {
baseUrl: String,
request: ParseRecipeURLRequestV0,
): String
suspend fun createApiToken(
baseUrl: String,
request: CreateApiTokenRequestV0,
): String
}

View File

@@ -4,6 +4,7 @@ import gq.kirmanak.mealient.datasource.NetworkError
import gq.kirmanak.mealient.datasource.NetworkRequestWrapper
import gq.kirmanak.mealient.datasource.decode
import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0
import gq.kirmanak.mealient.datasource.v0.models.CreateApiTokenRequestV0
import gq.kirmanak.mealient.datasource.v0.models.ErrorDetailV0
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeResponseV0
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeSummaryResponseV0
@@ -86,7 +87,15 @@ class MealieDataSourceV0Impl @Inject constructor(
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
block = { service.createRecipeFromURL("$baseUrl/api/recipes/create-url", request) },
logMethod = { "parseRecipeFromURL" },
logParameters = { "baseUrl = $baseUrl, request = $request" }
logParameters = { "baseUrl = $baseUrl, request = $request" },
)
override suspend fun createApiToken(
baseUrl: String,
request: CreateApiTokenRequestV0,
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
block = { service.createApiToken("$baseUrl/api/users/api-tokens", request) },
logMethod = { "createApiToken" },
logParameters = { "baseUrl = $baseUrl, request = $request" }
)
}

View File

@@ -41,4 +41,10 @@ interface MealieServiceV0 {
@Url url: String,
@Body request: ParseRecipeURLRequestV0,
): String
@POST
suspend fun createApiToken(
@Url url: String,
@Body request: CreateApiTokenRequestV0,
): String
}

View File

@@ -0,0 +1,9 @@
package gq.kirmanak.mealient.datasource.v0.models
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class CreateApiTokenRequestV0(
@SerialName("name") val name: String,
)

View File

@@ -1,5 +1,7 @@
package gq.kirmanak.mealient.datasource.v1
import gq.kirmanak.mealient.datasource.v1.models.CreateApiTokenRequestV1
import gq.kirmanak.mealient.datasource.v1.models.CreateApiTokenResponseV1
import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
@@ -48,4 +50,9 @@ interface MealieDataSourceV1 {
baseUrl: String,
request: ParseRecipeURLRequestV1,
): String
suspend fun createApiToken(
baseUrl: String,
request: CreateApiTokenRequestV1,
): CreateApiTokenResponseV1
}

View File

@@ -3,6 +3,8 @@ package gq.kirmanak.mealient.datasource.v1
import gq.kirmanak.mealient.datasource.NetworkError
import gq.kirmanak.mealient.datasource.NetworkRequestWrapper
import gq.kirmanak.mealient.datasource.decode
import gq.kirmanak.mealient.datasource.v1.models.CreateApiTokenRequestV1
import gq.kirmanak.mealient.datasource.v1.models.CreateApiTokenResponseV1
import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
import gq.kirmanak.mealient.datasource.v1.models.ErrorDetailV1
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
@@ -98,8 +100,15 @@ class MealieDataSourceV1Impl @Inject constructor(
block = { service.createRecipeFromURL("$baseUrl/api/recipes/create-url", request) },
logMethod = { "parseRecipeFromURL" },
logParameters = { "baseUrl = $baseUrl, request = $request" }
)
override suspend fun createApiToken(
baseUrl: String,
request: CreateApiTokenRequestV1
): CreateApiTokenResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
block = { service.createApiToken("$baseUrl/api/users/api-tokens", request) },
logMethod = { "createApiToken" },
logParameters = { "baseUrl = $baseUrl, request = $request" }
)
}

View File

@@ -47,4 +47,10 @@ interface MealieServiceV1 {
@Url url: String,
@Body request: ParseRecipeURLRequestV1,
): String
@POST
suspend fun createApiToken(
@Url url: String,
@Body request: CreateApiTokenRequestV1,
): CreateApiTokenResponseV1
}

View File

@@ -0,0 +1,9 @@
package gq.kirmanak.mealient.datasource.v1.models
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class CreateApiTokenRequestV1(
@SerialName("name") val name: String,
)

View File

@@ -0,0 +1,9 @@
package gq.kirmanak.mealient.datasource.v1.models
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class CreateApiTokenResponseV1(
@SerialName("token") val token: String,
)