|
|
|
@ -2,11 +2,12 @@ package bou.amine.apps.readerforselfossv2.rest
|
|
|
|
|
|
|
|
|
|
import bou.amine.apps.readerforselfossv2.model.*
|
|
|
|
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
|
|
|
|
import io.github.aakira.napier.Napier
|
|
|
|
|
import io.ktor.client.*
|
|
|
|
|
import io.ktor.client.call.*
|
|
|
|
|
import io.ktor.client.plugins.*
|
|
|
|
|
import io.ktor.client.plugins.cache.*
|
|
|
|
|
import io.ktor.client.plugins.contentnegotiation.*
|
|
|
|
|
import io.ktor.client.plugins.cookies.*
|
|
|
|
|
import io.ktor.client.plugins.logging.*
|
|
|
|
|
import io.ktor.client.request.*
|
|
|
|
|
import io.ktor.client.request.forms.*
|
|
|
|
@ -20,7 +21,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
var client = createHttpClient()
|
|
|
|
|
|
|
|
|
|
private fun createHttpClient(): HttpClient {
|
|
|
|
|
return HttpClient {
|
|
|
|
|
val client = HttpClient {
|
|
|
|
|
install(ContentNegotiation) {
|
|
|
|
|
install(HttpCache)
|
|
|
|
|
json(Json {
|
|
|
|
@ -32,7 +33,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
install(Logging) {
|
|
|
|
|
logger = object : Logger {
|
|
|
|
|
override fun log(message: String) {
|
|
|
|
|
appSettingsService.logApiCalls(message)
|
|
|
|
|
Napier.d(message, tag = "LogApiCalls")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
level = LogLevel.INFO
|
|
|
|
@ -40,22 +41,26 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
install(HttpTimeout) {
|
|
|
|
|
requestTimeoutMillis = appSettingsService.getApiTimeout()
|
|
|
|
|
}
|
|
|
|
|
/* TODO: Auth as basic
|
|
|
|
|
if (apiDetailsService.getUserName().isNotEmpty() && apiDetailsService.getPassword().isNotEmpty()) {
|
|
|
|
|
|
|
|
|
|
install(Auth) {
|
|
|
|
|
basic {
|
|
|
|
|
credentials {
|
|
|
|
|
BasicAuthCredentials(username = apiDetailsService.getUserName(), password = apiDetailsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
sendWithoutRequest {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
install(HttpCookies)
|
|
|
|
|
expectSuccess = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client.plugin(HttpSend).intercept { request ->
|
|
|
|
|
val originalCall = execute(request)
|
|
|
|
|
if (originalCall.response.status == HttpStatusCode.Forbidden && shouldHavePostLogin() && hasLoginInfo()) {
|
|
|
|
|
Napier.i("Forbidden action, will try to login and retry", tag = "HttpSend")
|
|
|
|
|
|
|
|
|
|
if (login().isSuccess) {
|
|
|
|
|
Napier.i("Logged in worked", tag = "HttpSend")
|
|
|
|
|
execute(request)
|
|
|
|
|
}
|
|
|
|
|
originalCall
|
|
|
|
|
} else {
|
|
|
|
|
originalCall
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return client
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun url(path: String) =
|
|
|
|
@ -66,11 +71,38 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
client = createHttpClient()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Api version was introduces after the POST login, so when there is a version, it should be available
|
|
|
|
|
private fun shouldHavePostLogin() = appSettingsService.getApiVersion() != -1
|
|
|
|
|
private fun hasLoginInfo() = appSettingsService.getUserName() != null && appSettingsService.getPassword() != null
|
|
|
|
|
|
|
|
|
|
suspend fun login(): SuccessResponse =
|
|
|
|
|
maybeResponse(client.get(url("/login")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
if (shouldHavePostLogin()) {
|
|
|
|
|
postLogin()
|
|
|
|
|
} else {
|
|
|
|
|
getLogin()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private suspend fun getLogin() = maybeResponse(client.get(url("/login")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
private suspend fun postLogin() = maybeResponse(client.post(url("/login")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
private fun shouldHaveNewLogout() = appSettingsService.getApiVersion() >= 5 // We are missing 4.1.0
|
|
|
|
|
suspend fun logout(): SuccessResponse =
|
|
|
|
|
if (shouldHaveNewLogout()) {
|
|
|
|
|
doLogout()
|
|
|
|
|
} else {
|
|
|
|
|
maybeLogoutIfAvailable()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private suspend fun maybeLogoutIfAvailable() = responseOrSuccessIf404(client.get(url("/logout")))
|
|
|
|
|
|
|
|
|
|
private suspend fun doLogout() = maybeResponse(client.delete(url("/api/session/current")))
|
|
|
|
|
|
|
|
|
|
suspend fun getItems(
|
|
|
|
|
type: String,
|
|
|
|
@ -82,80 +114,102 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
items: Int? = null
|
|
|
|
|
): StatusAndData<List<SelfossModel.Item>> =
|
|
|
|
|
bodyOrFailure(client.get(url("/items")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
parameter("type", type)
|
|
|
|
|
parameter("tag", tag)
|
|
|
|
|
parameter("source", source)
|
|
|
|
|
parameter("search", search)
|
|
|
|
|
parameter("updatedsince", updatedSince)
|
|
|
|
|
parameter("items", items ?: appSettingsService.getItemsNumber())
|
|
|
|
|
parameter("offset", offset)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
parameter("type", type)
|
|
|
|
|
parameter("tag", tag)
|
|
|
|
|
parameter("source", source)
|
|
|
|
|
parameter("search", search)
|
|
|
|
|
parameter("updatedsince", updatedSince)
|
|
|
|
|
parameter("items", items ?: appSettingsService.getItemsNumber())
|
|
|
|
|
parameter("offset", offset)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun stats(): StatusAndData<SelfossModel.Stats> =
|
|
|
|
|
bodyOrFailure(client.get(url("/stats")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun tags(): StatusAndData<List<SelfossModel.Tag>> =
|
|
|
|
|
bodyOrFailure(client.get(url("/tags")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun update(): StatusAndData<String> =
|
|
|
|
|
bodyOrFailure(client.get(url("/update")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun spouts(): StatusAndData<Map<String, SelfossModel.Spout>> =
|
|
|
|
|
bodyOrFailure(client.get(url("/sources/spouts")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun sources(): StatusAndData<ArrayList<SelfossModel.Source>> =
|
|
|
|
|
bodyOrFailure(client.get(url("/sources/list")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun version(): StatusAndData<SelfossModel.ApiVersion> =
|
|
|
|
|
bodyOrFailure(client.get(url("/api/about")))
|
|
|
|
|
|
|
|
|
|
suspend fun markAsRead(id: String): SuccessResponse =
|
|
|
|
|
maybeResponse(client.post(url("/mark/$id")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun unmarkAsRead(id: String): SuccessResponse =
|
|
|
|
|
maybeResponse(client.post(url("/unmark/$id")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun starr(id: String): SuccessResponse =
|
|
|
|
|
maybeResponse(client.post(url("/starr/$id")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun unstarr(id: String): SuccessResponse =
|
|
|
|
|
maybeResponse(client.post(url("/unstarr/$id")) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
suspend fun markAllAsRead(ids: List<String>): SuccessResponse =
|
|
|
|
|
maybeResponse(client.submitForm(
|
|
|
|
|
url = url("/mark"),
|
|
|
|
|
formParameters = Parameters.build {
|
|
|
|
|
append("username", appSettingsService.getUserName())
|
|
|
|
|
append("password", appSettingsService.getPassword())
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
append("username", appSettingsService.getUserName())
|
|
|
|
|
append("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
ids.map { append("ids[]", it) }
|
|
|
|
|
}
|
|
|
|
|
))
|
|
|
|
@ -165,18 +219,17 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
url: String,
|
|
|
|
|
spout: String,
|
|
|
|
|
tags: String,
|
|
|
|
|
filter: String,
|
|
|
|
|
version: Int
|
|
|
|
|
filter: String
|
|
|
|
|
): SuccessResponse =
|
|
|
|
|
maybeResponse(
|
|
|
|
|
if (version > 1) {
|
|
|
|
|
if (appSettingsService.getApiVersion() > 1) {
|
|
|
|
|
createSource2(title, url, spout, tags, filter)
|
|
|
|
|
} else {
|
|
|
|
|
createSource(title, url, spout, tags, filter)
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun createSource(
|
|
|
|
|
private suspend fun createSource(
|
|
|
|
|
title: String,
|
|
|
|
|
url: String,
|
|
|
|
|
spout: String,
|
|
|
|
@ -184,8 +237,13 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
filter: String
|
|
|
|
|
): HttpResponse =
|
|
|
|
|
client.submitForm(
|
|
|
|
|
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
|
|
|
|
url = url("/source"),
|
|
|
|
|
formParameters = Parameters.build {
|
|
|
|
|
// TODO: test this
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
append("username", appSettingsService.getUserName())
|
|
|
|
|
append("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
append("title", title)
|
|
|
|
|
append("url", url)
|
|
|
|
|
append("spout", spout)
|
|
|
|
@ -194,7 +252,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
suspend fun createSource2(
|
|
|
|
|
private suspend fun createSource2(
|
|
|
|
|
title: String,
|
|
|
|
|
url: String,
|
|
|
|
|
spout: String,
|
|
|
|
@ -202,8 +260,12 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
filter: String
|
|
|
|
|
): HttpResponse =
|
|
|
|
|
client.submitForm(
|
|
|
|
|
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
|
|
|
|
url = url("/source"),
|
|
|
|
|
formParameters = Parameters.build {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
append("username", appSettingsService.getUserName())
|
|
|
|
|
append("password", appSettingsService.getPassword())
|
|
|
|
|
}
|
|
|
|
|
append("title", title)
|
|
|
|
|
append("url", url)
|
|
|
|
|
append("spout", spout)
|
|
|
|
@ -214,7 +276,9 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|
|
|
|
|
|
|
|
|
suspend fun deleteSource(id: Int): SuccessResponse =
|
|
|
|
|
maybeResponse(client.delete(url("/source/$id")) {
|
|
|
|
|
if (!shouldHavePostLogin()) {
|
|
|
|
|
parameter("username", appSettingsService.getUserName())
|
|
|
|
|
parameter("password", appSettingsService.getPassword())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|