Extract Authorization header to an interceptor
This commit is contained in:
@@ -3,6 +3,7 @@ package gq.kirmanak.mealient.data.auth.impl
|
|||||||
import gq.kirmanak.mealient.data.auth.AuthDataSource
|
import gq.kirmanak.mealient.data.auth.AuthDataSource
|
||||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||||
import gq.kirmanak.mealient.data.auth.AuthStorage
|
import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||||
|
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
||||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -15,7 +16,7 @@ class AuthRepoImpl @Inject constructor(
|
|||||||
private val authStorage: AuthStorage,
|
private val authStorage: AuthStorage,
|
||||||
private val authDataSource: AuthDataSource,
|
private val authDataSource: AuthDataSource,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
) : AuthRepo {
|
) : AuthRepo, AuthenticationProvider {
|
||||||
|
|
||||||
override val isAuthorizedFlow: Flow<Boolean>
|
override val isAuthorizedFlow: Flow<Boolean>
|
||||||
get() = authStorage.authHeaderFlow.map { it != null }
|
get() = authStorage.authHeaderFlow.map { it != null }
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ class MealieDataSourceWrapper @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun addRecipe(
|
override suspend fun addRecipe(
|
||||||
recipe: AddRecipeInfo,
|
recipe: AddRecipeInfo,
|
||||||
): String = makeCall { token, url, version ->
|
): String = makeCall { url, version ->
|
||||||
when (version) {
|
when (version) {
|
||||||
ServerVersion.V0 -> v0Source.addRecipe(url, token, recipe.toV0Request())
|
ServerVersion.V0 -> v0Source.addRecipe(url, recipe.toV0Request())
|
||||||
ServerVersion.V1 -> {
|
ServerVersion.V1 -> {
|
||||||
val slug = v1Source.createRecipe(url, token, recipe.toV1CreateRequest())
|
val slug = v1Source.createRecipe(url, recipe.toV1CreateRequest())
|
||||||
v1Source.updateRecipe(url, token, slug, recipe.toV1UpdateRequest())
|
v1Source.updateRecipe(url, slug, recipe.toV1UpdateRequest())
|
||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,53 +49,53 @@ class MealieDataSourceWrapper @Inject constructor(
|
|||||||
override suspend fun requestRecipes(
|
override suspend fun requestRecipes(
|
||||||
start: Int,
|
start: Int,
|
||||||
limit: Int,
|
limit: Int,
|
||||||
): List<RecipeSummaryInfo> = makeCall { token, url, version ->
|
): List<RecipeSummaryInfo> = makeCall { url, version ->
|
||||||
when (version) {
|
when (version) {
|
||||||
ServerVersion.V0 -> {
|
ServerVersion.V0 -> {
|
||||||
v0Source.requestRecipes(url, token, start, limit).map { it.toRecipeSummaryInfo() }
|
v0Source.requestRecipes(url, start, limit).map { it.toRecipeSummaryInfo() }
|
||||||
}
|
}
|
||||||
ServerVersion.V1 -> {
|
ServerVersion.V1 -> {
|
||||||
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
|
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
|
||||||
val page = start / limit + 1
|
val page = start / limit + 1
|
||||||
v1Source.requestRecipes(url, token, page, limit).map { it.toRecipeSummaryInfo() }
|
v1Source.requestRecipes(url, page, limit).map { it.toRecipeSummaryInfo() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(
|
override suspend fun requestRecipeInfo(
|
||||||
slug: String,
|
slug: String,
|
||||||
): FullRecipeInfo = makeCall { token, url, version ->
|
): FullRecipeInfo = makeCall { url, version ->
|
||||||
when (version) {
|
when (version) {
|
||||||
ServerVersion.V0 -> v0Source.requestRecipeInfo(url, token, slug).toFullRecipeInfo()
|
ServerVersion.V0 -> v0Source.requestRecipeInfo(url, slug).toFullRecipeInfo()
|
||||||
ServerVersion.V1 -> v1Source.requestRecipeInfo(url, token, slug).toFullRecipeInfo()
|
ServerVersion.V1 -> v1Source.requestRecipeInfo(url, slug).toFullRecipeInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun parseRecipeFromURL(
|
override suspend fun parseRecipeFromURL(
|
||||||
parseRecipeURLInfo: ParseRecipeURLInfo,
|
parseRecipeURLInfo: ParseRecipeURLInfo,
|
||||||
): String = makeCall { token, url, version ->
|
): String = makeCall { url, version ->
|
||||||
when (version) {
|
when (version) {
|
||||||
ServerVersion.V0 -> {
|
ServerVersion.V0 -> {
|
||||||
v0Source.parseRecipeFromURL(url, token, parseRecipeURLInfo.toV0Request())
|
v0Source.parseRecipeFromURL(url, parseRecipeURLInfo.toV0Request())
|
||||||
}
|
}
|
||||||
ServerVersion.V1 -> {
|
ServerVersion.V1 -> {
|
||||||
v1Source.parseRecipeFromURL(url, token, parseRecipeURLInfo.toV1Request())
|
v1Source.parseRecipeFromURL(url, parseRecipeURLInfo.toV1Request())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun <T> makeCall(block: (String?, String, ServerVersion) -> T): T {
|
private suspend inline fun <T> makeCall(block: (String, ServerVersion) -> T): T {
|
||||||
val authHeader = authRepo.getAuthHeader()
|
val authHeader = authRepo.getAuthHeader()
|
||||||
val url = serverInfoRepo.requireUrl()
|
val url = serverInfoRepo.requireUrl()
|
||||||
val version = serverInfoRepo.getVersion()
|
val version = serverInfoRepo.getVersion()
|
||||||
return runCatchingExceptCancel { block(authHeader, url, version) }.getOrElse {
|
return runCatchingExceptCancel { block(url, version) }.getOrElse {
|
||||||
if (it is NetworkError.Unauthorized) {
|
if (it is NetworkError.Unauthorized) {
|
||||||
logger.e { "Unauthorized, trying to invalidate token" }
|
logger.e { "Unauthorized, trying to invalidate token" }
|
||||||
authRepo.invalidateAuthHeader()
|
authRepo.invalidateAuthHeader()
|
||||||
// Trying again with new authentication header
|
// Trying again with new authentication header
|
||||||
val newHeader = authRepo.getAuthHeader()
|
val newHeader = authRepo.getAuthHeader()
|
||||||
logger.e { "New token ${if (newHeader == authHeader) "matches" else "doesn't match"} old token" }
|
logger.e { "New token ${if (newHeader == authHeader) "matches" else "doesn't match"} old token" }
|
||||||
if (newHeader == authHeader) throw it else block(newHeader, url, version)
|
if (newHeader == authHeader) throw it else block(url, version)
|
||||||
} else {
|
} else {
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import gq.kirmanak.mealient.data.auth.AuthStorage
|
|||||||
import gq.kirmanak.mealient.data.auth.impl.AuthDataSourceImpl
|
import gq.kirmanak.mealient.data.auth.impl.AuthDataSourceImpl
|
||||||
import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl
|
import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl
|
||||||
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
|
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
|
||||||
|
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -37,6 +38,10 @@ interface AuthModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo
|
fun bindAuthRepo(authRepo: AuthRepoImpl): AuthRepo
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindAuthProvider(authRepo: AuthRepoImpl): AuthenticationProvider
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
|
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package gq.kirmanak.mealient.ui.recipes.images
|
package gq.kirmanak.mealient.ui.recipes.images
|
||||||
|
|
||||||
import com.bumptech.glide.load.Options
|
import com.bumptech.glide.load.Options
|
||||||
import com.bumptech.glide.load.model.*
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
import com.bumptech.glide.load.model.ModelCache
|
||||||
|
import com.bumptech.glide.load.model.ModelLoader
|
||||||
import com.bumptech.glide.load.model.stream.BaseGlideUrlLoader
|
import com.bumptech.glide.load.model.stream.BaseGlideUrlLoader
|
||||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.impl.RecipeImageUrlProvider
|
import gq.kirmanak.mealient.data.recipes.impl.RecipeImageUrlProvider
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME
|
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@@ -16,7 +16,6 @@ import javax.inject.Singleton
|
|||||||
class RecipeModelLoader private constructor(
|
class RecipeModelLoader private constructor(
|
||||||
private val recipeImageUrlProvider: RecipeImageUrlProvider,
|
private val recipeImageUrlProvider: RecipeImageUrlProvider,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
private val authRepo: AuthRepo,
|
|
||||||
concreteLoader: ModelLoader<GlideUrl, InputStream>,
|
concreteLoader: ModelLoader<GlideUrl, InputStream>,
|
||||||
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
|
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
|
||||||
) : BaseGlideUrlLoader<RecipeSummaryEntity>(concreteLoader, cache) {
|
) : BaseGlideUrlLoader<RecipeSummaryEntity>(concreteLoader, cache) {
|
||||||
@@ -25,13 +24,12 @@ class RecipeModelLoader private constructor(
|
|||||||
class Factory @Inject constructor(
|
class Factory @Inject constructor(
|
||||||
private val recipeImageUrlProvider: RecipeImageUrlProvider,
|
private val recipeImageUrlProvider: RecipeImageUrlProvider,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
private val authRepo: AuthRepo,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun build(
|
fun build(
|
||||||
concreteLoader: ModelLoader<GlideUrl, InputStream>,
|
concreteLoader: ModelLoader<GlideUrl, InputStream>,
|
||||||
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
|
cache: ModelCache<RecipeSummaryEntity, GlideUrl>,
|
||||||
) = RecipeModelLoader(recipeImageUrlProvider, logger, authRepo, concreteLoader, cache)
|
) = RecipeModelLoader(recipeImageUrlProvider, logger, concreteLoader, cache)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,20 +44,4 @@ class RecipeModelLoader private constructor(
|
|||||||
logger.v { "getUrl() called with: model = $model, width = $width, height = $height, options = $options" }
|
logger.v { "getUrl() called with: model = $model, width = $width, height = $height, options = $options" }
|
||||||
return runBlocking { recipeImageUrlProvider.generateImageUrl(model?.imageId) }
|
return runBlocking { recipeImageUrlProvider.generateImageUrl(model?.imageId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getHeaders(
|
|
||||||
model: RecipeSummaryEntity?,
|
|
||||||
width: Int,
|
|
||||||
height: Int,
|
|
||||||
options: Options?
|
|
||||||
): Headers? {
|
|
||||||
val authorization = runBlocking { authRepo.getAuthHeader() }
|
|
||||||
return if (authorization.isNullOrBlank()) {
|
|
||||||
super.getHeaders(model, width, height, options)
|
|
||||||
} else {
|
|
||||||
LazyHeaders.Builder()
|
|
||||||
.setHeader(AUTHORIZATION_HEADER_NAME, authorization)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -57,11 +57,8 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
fun `when makeCall fails with Unauthorized expect it to invalidate token`() = runTest {
|
fun `when makeCall fails with Unauthorized expect it to invalidate token`() = runTest {
|
||||||
val slug = "porridge"
|
val slug = "porridge"
|
||||||
coEvery {
|
coEvery {
|
||||||
v0Source.requestRecipeInfo(any(), isNull(), any())
|
v0Source.requestRecipeInfo(any(), any())
|
||||||
} throws NetworkError.Unauthorized(IOException())
|
} throws NetworkError.Unauthorized(IOException()) andThen PORRIDGE_RECIPE_RESPONSE_V0
|
||||||
coEvery {
|
|
||||||
v0Source.requestRecipeInfo(any(), eq(TEST_AUTH_HEADER), any())
|
|
||||||
} returns PORRIDGE_RECIPE_RESPONSE_V0
|
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
coEvery { authRepo.getAuthHeader() } returns null andThen TEST_AUTH_HEADER
|
coEvery { authRepo.getAuthHeader() } returns null andThen TEST_AUTH_HEADER
|
||||||
@@ -79,7 +76,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
fun `when server version v1 expect requestRecipeInfo to call v1`() = runTest {
|
fun `when server version v1 expect requestRecipeInfo to call v1`() = runTest {
|
||||||
val slug = "porridge"
|
val slug = "porridge"
|
||||||
coEvery {
|
coEvery {
|
||||||
v1Source.requestRecipeInfo(eq(TEST_BASE_URL), eq(TEST_AUTH_HEADER), eq(slug))
|
v1Source.requestRecipeInfo(eq(TEST_BASE_URL), eq(slug))
|
||||||
} returns PORRIDGE_RECIPE_RESPONSE_V1
|
} returns PORRIDGE_RECIPE_RESPONSE_V1
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
@@ -87,7 +84,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
|
|
||||||
val actual = subject.requestRecipeInfo(slug)
|
val actual = subject.requestRecipeInfo(slug)
|
||||||
|
|
||||||
coVerify { v1Source.requestRecipeInfo(eq(TEST_BASE_URL), eq(TEST_AUTH_HEADER), eq(slug)) }
|
coVerify { v1Source.requestRecipeInfo(eq(TEST_BASE_URL), eq(slug)) }
|
||||||
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_FULL_RECIPE_INFO)
|
assertThat(actual).isEqualTo(PORRIDGE_FULL_RECIPE_INFO)
|
||||||
}
|
}
|
||||||
@@ -95,7 +92,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `when server version v1 expect requestRecipes to call v1`() = runTest {
|
fun `when server version v1 expect requestRecipes to call v1`() = runTest {
|
||||||
coEvery {
|
coEvery {
|
||||||
v1Source.requestRecipes(any(), any(), any(), any())
|
v1Source.requestRecipes(any(), any(), any())
|
||||||
} returns listOf(PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1)
|
} returns listOf(PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1)
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
@@ -106,7 +103,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
val page = 5 // 0-9 (1), 10-19 (2), 20-29 (3), 30-39 (4), 40-49 (5)
|
val page = 5 // 0-9 (1), 10-19 (2), 20-29 (3), 30-39 (4), 40-49 (5)
|
||||||
val perPage = 10
|
val perPage = 10
|
||||||
coVerify {
|
coVerify {
|
||||||
v1Source.requestRecipes(eq(TEST_BASE_URL), eq(TEST_AUTH_HEADER), eq(page), eq(perPage))
|
v1Source.requestRecipes(eq(TEST_BASE_URL), eq(page), eq(perPage))
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(actual).isEqualTo(listOf(RECIPE_SUMMARY_PORRIDGE_V1))
|
assertThat(actual).isEqualTo(listOf(RECIPE_SUMMARY_PORRIDGE_V1))
|
||||||
@@ -115,7 +112,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `when server version v0 expect requestRecipes to call v0`() = runTest {
|
fun `when server version v0 expect requestRecipes to call v0`() = runTest {
|
||||||
coEvery {
|
coEvery {
|
||||||
v0Source.requestRecipes(any(), any(), any(), any())
|
v0Source.requestRecipes(any(), any(), any())
|
||||||
} returns listOf(PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0)
|
} returns listOf(PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0)
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
@@ -126,7 +123,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
val actual = subject.requestRecipes(start, limit)
|
val actual = subject.requestRecipes(start, limit)
|
||||||
|
|
||||||
coVerify {
|
coVerify {
|
||||||
v0Source.requestRecipes(eq(TEST_BASE_URL), eq(TEST_AUTH_HEADER), eq(start), eq(limit))
|
v0Source.requestRecipes(eq(TEST_BASE_URL), eq(start), eq(limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(actual).isEqualTo(listOf(RECIPE_SUMMARY_PORRIDGE_V0))
|
assertThat(actual).isEqualTo(listOf(RECIPE_SUMMARY_PORRIDGE_V0))
|
||||||
@@ -134,7 +131,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
|
|
||||||
@Test(expected = IOException::class)
|
@Test(expected = IOException::class)
|
||||||
fun `when request fails expect addRecipe to rethrow`() = runTest {
|
fun `when request fails expect addRecipe to rethrow`() = runTest {
|
||||||
coEvery { v0Source.addRecipe(any(), any(), any()) } throws IOException()
|
coEvery { v0Source.addRecipe(any(), any()) } throws IOException()
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
|
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
|
||||||
@@ -145,7 +142,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
fun `when server version v0 expect addRecipe to call v0`() = runTest {
|
fun `when server version v0 expect addRecipe to call v0`() = runTest {
|
||||||
val slug = "porridge"
|
val slug = "porridge"
|
||||||
|
|
||||||
coEvery { v0Source.addRecipe(any(), any(), any()) } returns slug
|
coEvery { v0Source.addRecipe(any(), any()) } returns slug
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
|
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
|
||||||
@@ -155,7 +152,6 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
coVerify {
|
coVerify {
|
||||||
v0Source.addRecipe(
|
v0Source.addRecipe(
|
||||||
eq(TEST_BASE_URL),
|
eq(TEST_BASE_URL),
|
||||||
eq(TEST_AUTH_HEADER),
|
|
||||||
eq(PORRIDGE_ADD_RECIPE_REQUEST_V0),
|
eq(PORRIDGE_ADD_RECIPE_REQUEST_V0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -167,9 +163,9 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
fun `when server version v1 expect addRecipe to call v1`() = runTest {
|
fun `when server version v1 expect addRecipe to call v1`() = runTest {
|
||||||
val slug = "porridge"
|
val slug = "porridge"
|
||||||
|
|
||||||
coEvery { v1Source.createRecipe(any(), any(), any()) } returns slug
|
coEvery { v1Source.createRecipe(any(), any()) } returns slug
|
||||||
coEvery {
|
coEvery {
|
||||||
v1Source.updateRecipe(any(), any(), any(), any())
|
v1Source.updateRecipe(any(), any(), any())
|
||||||
} returns PORRIDGE_RECIPE_RESPONSE_V1
|
} returns PORRIDGE_RECIPE_RESPONSE_V1
|
||||||
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
|
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
|
||||||
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
|
||||||
@@ -180,13 +176,11 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
coVerifySequence {
|
coVerifySequence {
|
||||||
v1Source.createRecipe(
|
v1Source.createRecipe(
|
||||||
eq(TEST_BASE_URL),
|
eq(TEST_BASE_URL),
|
||||||
eq(TEST_AUTH_HEADER),
|
|
||||||
eq(PORRIDGE_CREATE_RECIPE_REQUEST_V1),
|
eq(PORRIDGE_CREATE_RECIPE_REQUEST_V1),
|
||||||
)
|
)
|
||||||
|
|
||||||
v1Source.updateRecipe(
|
v1Source.updateRecipe(
|
||||||
eq(TEST_BASE_URL),
|
eq(TEST_BASE_URL),
|
||||||
eq(TEST_AUTH_HEADER),
|
|
||||||
eq(slug),
|
eq(slug),
|
||||||
eq(PORRIDGE_UPDATE_RECIPE_REQUEST_V1),
|
eq(PORRIDGE_UPDATE_RECIPE_REQUEST_V1),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource
|
||||||
|
|
||||||
|
interface AuthenticationProvider {
|
||||||
|
|
||||||
|
suspend fun getAuthHeader(): String?
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ import dagger.Module
|
|||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import dagger.multibindings.IntoSet
|
||||||
|
import gq.kirmanak.mealient.datasource.impl.AuthInterceptor
|
||||||
import gq.kirmanak.mealient.datasource.impl.CacheBuilderImpl
|
import gq.kirmanak.mealient.datasource.impl.CacheBuilderImpl
|
||||||
import gq.kirmanak.mealient.datasource.impl.NetworkRequestWrapperImpl
|
import gq.kirmanak.mealient.datasource.impl.NetworkRequestWrapperImpl
|
||||||
import gq.kirmanak.mealient.datasource.impl.OkHttpBuilderImpl
|
import gq.kirmanak.mealient.datasource.impl.OkHttpBuilderImpl
|
||||||
@@ -18,6 +20,7 @@ import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1Impl
|
|||||||
import gq.kirmanak.mealient.datasource.v1.MealieServiceV1
|
import gq.kirmanak.mealient.datasource.v1.MealieServiceV1
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Interceptor
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import retrofit2.Converter
|
import retrofit2.Converter
|
||||||
@@ -31,8 +34,6 @@ interface DataSourceModule {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val AUTHORIZATION_HEADER_NAME = "Authorization"
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideJson(): Json = Json {
|
fun provideJson(): Json = Json {
|
||||||
@@ -87,4 +88,9 @@ interface DataSourceModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun bindNetworkRequestWrapper(networkRequestWrapperImpl: NetworkRequestWrapperImpl): NetworkRequestWrapper
|
fun bindNetworkRequestWrapper(networkRequestWrapperImpl: NetworkRequestWrapperImpl): NetworkRequestWrapper
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
@IntoSet
|
||||||
|
fun bindAuthInterceptor(authInterceptor: AuthInterceptor): Interceptor
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.impl
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class AuthInterceptor @Inject constructor(
|
||||||
|
private val authenticationProvider: Provider<AuthenticationProvider>,
|
||||||
|
) : Interceptor {
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val token = runBlocking { authenticationProvider.get().getAuthHeader() }
|
||||||
|
val request = if (token == null) {
|
||||||
|
chain.request()
|
||||||
|
} else {
|
||||||
|
chain.request()
|
||||||
|
.newBuilder()
|
||||||
|
.header(HEADER_NAME, token)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
return chain.proceed(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val HEADER_NAME = "Authorization"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ interface MealieDataSourceV0 {
|
|||||||
|
|
||||||
suspend fun addRecipe(
|
suspend fun addRecipe(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
recipe: AddRecipeRequestV0,
|
recipe: AddRecipeRequestV0,
|
||||||
): String
|
): String
|
||||||
|
|
||||||
@@ -29,20 +28,17 @@ interface MealieDataSourceV0 {
|
|||||||
|
|
||||||
suspend fun requestRecipes(
|
suspend fun requestRecipes(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
start: Int,
|
start: Int,
|
||||||
limit: Int,
|
limit: Int,
|
||||||
): List<GetRecipeSummaryResponseV0>
|
): List<GetRecipeSummaryResponseV0>
|
||||||
|
|
||||||
suspend fun requestRecipeInfo(
|
suspend fun requestRecipeInfo(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
slug: String,
|
slug: String,
|
||||||
): GetRecipeResponseV0
|
): GetRecipeResponseV0
|
||||||
|
|
||||||
suspend fun parseRecipeFromURL(
|
suspend fun parseRecipeFromURL(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
request: ParseRecipeURLRequestV0,
|
request: ParseRecipeURLRequestV0,
|
||||||
): String
|
): String
|
||||||
}
|
}
|
||||||
@@ -26,12 +26,11 @@ class MealieDataSourceV0Impl @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun addRecipe(
|
override suspend fun addRecipe(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
recipe: AddRecipeRequestV0,
|
recipe: AddRecipeRequestV0,
|
||||||
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.addRecipe("$baseUrl/api/recipes/create", token, recipe) },
|
block = { service.addRecipe("$baseUrl/api/recipes/create", recipe) },
|
||||||
logMethod = { "addRecipe" },
|
logMethod = { "addRecipe" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, recipe = $recipe" }
|
logParameters = { "baseUrl = $baseUrl, recipe = $recipe" }
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun authenticate(
|
override suspend fun authenticate(
|
||||||
@@ -64,33 +63,30 @@ class MealieDataSourceV0Impl @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun requestRecipes(
|
override suspend fun requestRecipes(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
start: Int,
|
start: Int,
|
||||||
limit: Int,
|
limit: Int,
|
||||||
): List<GetRecipeSummaryResponseV0> = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): List<GetRecipeSummaryResponseV0> = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.getRecipeSummary("$baseUrl/api/recipes/summary", token, start, limit) },
|
block = { service.getRecipeSummary("$baseUrl/api/recipes/summary", start, limit) },
|
||||||
logMethod = { "requestRecipes" },
|
logMethod = { "requestRecipes" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, start = $start, limit = $limit" }
|
logParameters = { "baseUrl = $baseUrl, start = $start, limit = $limit" }
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(
|
override suspend fun requestRecipeInfo(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
slug: String,
|
slug: String,
|
||||||
): GetRecipeResponseV0 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): GetRecipeResponseV0 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.getRecipe("$baseUrl/api/recipes/$slug", token) },
|
block = { service.getRecipe("$baseUrl/api/recipes/$slug") },
|
||||||
logMethod = { "requestRecipeInfo" },
|
logMethod = { "requestRecipeInfo" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, slug = $slug" }
|
logParameters = { "baseUrl = $baseUrl, slug = $slug" }
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun parseRecipeFromURL(
|
override suspend fun parseRecipeFromURL(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
request: ParseRecipeURLRequestV0
|
request: ParseRecipeURLRequestV0
|
||||||
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.createRecipeFromURL("$baseUrl/api/recipes/create-url", token, request) },
|
block = { service.createRecipeFromURL("$baseUrl/api/recipes/create-url", request) },
|
||||||
logMethod = { "parseRecipeFromURL" },
|
logMethod = { "parseRecipeFromURL" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, request = $request" }
|
logParameters = { "baseUrl = $baseUrl, request = $request" }
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package gq.kirmanak.mealient.datasource.v0
|
package gq.kirmanak.mealient.datasource.v0
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.*
|
import gq.kirmanak.mealient.datasource.v0.models.*
|
||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
|
|
||||||
@@ -17,7 +16,6 @@ interface MealieServiceV0 {
|
|||||||
@POST
|
@POST
|
||||||
suspend fun addRecipe(
|
suspend fun addRecipe(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Body addRecipeRequestV0: AddRecipeRequestV0,
|
@Body addRecipeRequestV0: AddRecipeRequestV0,
|
||||||
): String
|
): String
|
||||||
|
|
||||||
@@ -29,7 +27,6 @@ interface MealieServiceV0 {
|
|||||||
@GET
|
@GET
|
||||||
suspend fun getRecipeSummary(
|
suspend fun getRecipeSummary(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Query("start") start: Int,
|
@Query("start") start: Int,
|
||||||
@Query("limit") limit: Int,
|
@Query("limit") limit: Int,
|
||||||
): List<GetRecipeSummaryResponseV0>
|
): List<GetRecipeSummaryResponseV0>
|
||||||
@@ -37,13 +34,11 @@ interface MealieServiceV0 {
|
|||||||
@GET
|
@GET
|
||||||
suspend fun getRecipe(
|
suspend fun getRecipe(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
): GetRecipeResponseV0
|
): GetRecipeResponseV0
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
suspend fun createRecipeFromURL(
|
suspend fun createRecipeFromURL(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Body request: ParseRecipeURLRequestV0,
|
@Body request: ParseRecipeURLRequestV0,
|
||||||
): String
|
): String
|
||||||
}
|
}
|
||||||
@@ -11,13 +11,11 @@ interface MealieDataSourceV1 {
|
|||||||
|
|
||||||
suspend fun createRecipe(
|
suspend fun createRecipe(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
recipe: CreateRecipeRequestV1,
|
recipe: CreateRecipeRequestV1,
|
||||||
): String
|
): String
|
||||||
|
|
||||||
suspend fun updateRecipe(
|
suspend fun updateRecipe(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
slug: String,
|
slug: String,
|
||||||
recipe: UpdateRecipeRequestV1,
|
recipe: UpdateRecipeRequestV1,
|
||||||
): GetRecipeResponseV1
|
): GetRecipeResponseV1
|
||||||
@@ -37,20 +35,17 @@ interface MealieDataSourceV1 {
|
|||||||
|
|
||||||
suspend fun requestRecipes(
|
suspend fun requestRecipes(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
page: Int,
|
page: Int,
|
||||||
perPage: Int,
|
perPage: Int,
|
||||||
): List<GetRecipeSummaryResponseV1>
|
): List<GetRecipeSummaryResponseV1>
|
||||||
|
|
||||||
suspend fun requestRecipeInfo(
|
suspend fun requestRecipeInfo(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
slug: String,
|
slug: String,
|
||||||
): GetRecipeResponseV1
|
): GetRecipeResponseV1
|
||||||
|
|
||||||
suspend fun parseRecipeFromURL(
|
suspend fun parseRecipeFromURL(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
request: ParseRecipeURLRequestV1,
|
request: ParseRecipeURLRequestV1,
|
||||||
): String
|
): String
|
||||||
}
|
}
|
||||||
@@ -27,23 +27,21 @@ class MealieDataSourceV1Impl @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun createRecipe(
|
override suspend fun createRecipe(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
recipe: CreateRecipeRequestV1
|
recipe: CreateRecipeRequestV1
|
||||||
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.createRecipe("$baseUrl/api/recipes", token, recipe) },
|
block = { service.createRecipe("$baseUrl/api/recipes", recipe) },
|
||||||
logMethod = { "createRecipe" },
|
logMethod = { "createRecipe" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, recipe = $recipe" }
|
logParameters = { "baseUrl = $baseUrl, recipe = $recipe" }
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun updateRecipe(
|
override suspend fun updateRecipe(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
slug: String,
|
slug: String,
|
||||||
recipe: UpdateRecipeRequestV1
|
recipe: UpdateRecipeRequestV1
|
||||||
): GetRecipeResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): GetRecipeResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.updateRecipe("$baseUrl/api/recipes/$slug", token, recipe) },
|
block = { service.updateRecipe("$baseUrl/api/recipes/$slug", recipe) },
|
||||||
logMethod = { "updateRecipe" },
|
logMethod = { "updateRecipe" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, slug = $slug, recipe = $recipe" }
|
logParameters = { "baseUrl = $baseUrl, slug = $slug, recipe = $recipe" }
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun authenticate(
|
override suspend fun authenticate(
|
||||||
@@ -76,33 +74,30 @@ class MealieDataSourceV1Impl @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun requestRecipes(
|
override suspend fun requestRecipes(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
page: Int,
|
page: Int,
|
||||||
perPage: Int
|
perPage: Int
|
||||||
): List<GetRecipeSummaryResponseV1> = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): List<GetRecipeSummaryResponseV1> = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.getRecipeSummary("$baseUrl/api/recipes", token, page, perPage) },
|
block = { service.getRecipeSummary("$baseUrl/api/recipes", page, perPage) },
|
||||||
logMethod = { "requestRecipes" },
|
logMethod = { "requestRecipes" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, page = $page, perPage = $perPage" }
|
logParameters = { "baseUrl = $baseUrl, page = $page, perPage = $perPage" }
|
||||||
).items
|
).items
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(
|
override suspend fun requestRecipeInfo(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
slug: String
|
slug: String
|
||||||
): GetRecipeResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): GetRecipeResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.getRecipe("$baseUrl/api/recipes/$slug", token) },
|
block = { service.getRecipe("$baseUrl/api/recipes/$slug") },
|
||||||
logMethod = { "requestRecipeInfo" },
|
logMethod = { "requestRecipeInfo" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, slug = $slug" }
|
logParameters = { "baseUrl = $baseUrl, slug = $slug" }
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun parseRecipeFromURL(
|
override suspend fun parseRecipeFromURL(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
token: String?,
|
|
||||||
request: ParseRecipeURLRequestV1
|
request: ParseRecipeURLRequestV1
|
||||||
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
): String = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
block = { service.createRecipeFromURL("$baseUrl/api/recipes/create-url", token, request) },
|
block = { service.createRecipeFromURL("$baseUrl/api/recipes/create-url", request) },
|
||||||
logMethod = { "parseRecipeFromURL" },
|
logMethod = { "parseRecipeFromURL" },
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, request = $request" }
|
logParameters = { "baseUrl = $baseUrl, request = $request" }
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package gq.kirmanak.mealient.datasource.v1
|
package gq.kirmanak.mealient.datasource.v1
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.*
|
import gq.kirmanak.mealient.datasource.v1.models.*
|
||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
|
|
||||||
@@ -17,14 +16,12 @@ interface MealieServiceV1 {
|
|||||||
@POST
|
@POST
|
||||||
suspend fun createRecipe(
|
suspend fun createRecipe(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Body addRecipeRequest: CreateRecipeRequestV1,
|
@Body addRecipeRequest: CreateRecipeRequestV1,
|
||||||
): String
|
): String
|
||||||
|
|
||||||
@PATCH
|
@PATCH
|
||||||
suspend fun updateRecipe(
|
suspend fun updateRecipe(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Body addRecipeRequest: UpdateRecipeRequestV1,
|
@Body addRecipeRequest: UpdateRecipeRequestV1,
|
||||||
): GetRecipeResponseV1
|
): GetRecipeResponseV1
|
||||||
|
|
||||||
@@ -36,7 +33,6 @@ interface MealieServiceV1 {
|
|||||||
@GET
|
@GET
|
||||||
suspend fun getRecipeSummary(
|
suspend fun getRecipeSummary(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Query("page") page: Int,
|
@Query("page") page: Int,
|
||||||
@Query("perPage") perPage: Int,
|
@Query("perPage") perPage: Int,
|
||||||
): GetRecipesResponseV1
|
): GetRecipesResponseV1
|
||||||
@@ -44,13 +40,11 @@ interface MealieServiceV1 {
|
|||||||
@GET
|
@GET
|
||||||
suspend fun getRecipe(
|
suspend fun getRecipe(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
): GetRecipeResponseV1
|
): GetRecipeResponseV1
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
suspend fun createRecipeFromURL(
|
suspend fun createRecipeFromURL(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Body request: ParseRecipeURLRequestV1,
|
@Body request: ParseRecipeURLRequestV1,
|
||||||
): String
|
): String
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user