From 732ae4efa43ce282d483f9ccd40dc515d1d3da14 Mon Sep 17 00:00:00 2001 From: Shinokuni Date: Tue, 6 Aug 2024 22:09:23 +0200 Subject: [PATCH] Make FeverRepository compile again and Fever auth work --- .../com/readrops/api/services/Credentials.kt | 3 +- .../api/services/fever/FeverDataSource.kt | 82 +++---- .../api/services/fever/FeverService.kt | 4 + .../fever/adapters/FeverAPIAdapter.kt | 20 +- .../java/com/readrops/api/utils/ApiUtils.kt | 4 - .../api/utils/exceptions/LoginException.kt | 4 - .../utils/exceptions/LoginFailedException.kt | 3 + .../fever/adapters/FeverAPIAdapterTest.kt | 11 +- .../fever/adapters/FeverDataSourceTest.kt | 13 +- .../services/fever/unsuccessful_auth.json | 4 + .../main/java/com/readrops/app/AppModule.kt | 21 +- .../credentials/AccountCredentialsScreen.kt | 3 +- .../app/repositories/FeverRepository.kt | 203 +++++++++--------- .../db/entities/account/AccountType.kt | 2 +- .../db/queries/FeedUnreadCountQueryBuilder.kt | 2 +- 15 files changed, 208 insertions(+), 171 deletions(-) delete mode 100644 api/src/main/java/com/readrops/api/utils/exceptions/LoginException.kt create mode 100644 api/src/main/java/com/readrops/api/utils/exceptions/LoginFailedException.kt create mode 100644 api/src/test/resources/services/fever/unsuccessful_auth.json diff --git a/api/src/main/java/com/readrops/api/services/Credentials.kt b/api/src/main/java/com/readrops/api/services/Credentials.kt index 0fc421a9..0559a506 100644 --- a/api/src/main/java/com/readrops/api/services/Credentials.kt +++ b/api/src/main/java/com/readrops/api/services/Credentials.kt @@ -1,6 +1,7 @@ package com.readrops.api.services import com.readrops.api.services.fever.FeverCredentials +import com.readrops.api.services.fever.FeverService import com.readrops.api.services.freshrss.FreshRSSCredentials import com.readrops.api.services.freshrss.FreshRSSService import com.readrops.api.services.nextcloudnews.NextcloudNewsCredentials @@ -27,7 +28,7 @@ abstract class Credentials(val authorization: String?, val url: String) { return when (accountType) { AccountType.FRESHRSS -> FreshRSSService.END_POINT AccountType.NEXTCLOUD_NEWS -> NextcloudNewsService.END_POINT - AccountType.FEVER -> "" + AccountType.FEVER -> FeverService.END_POINT else -> throw IllegalArgumentException("Unknown account type") } } diff --git a/api/src/main/java/com/readrops/api/services/fever/FeverDataSource.kt b/api/src/main/java/com/readrops/api/services/fever/FeverDataSource.kt index 2fd60972..dadc52fc 100644 --- a/api/src/main/java/com/readrops/api/services/fever/FeverDataSource.kt +++ b/api/src/main/java/com/readrops/api/services/fever/FeverDataSource.kt @@ -2,35 +2,33 @@ package com.readrops.api.services.fever import com.readrops.api.services.SyncType import com.readrops.api.services.fever.adapters.FeverAPIAdapter -import com.readrops.api.utils.exceptions.LoginException +import com.readrops.api.utils.ApiUtils import com.readrops.db.entities.Item import com.squareup.moshi.Moshi import okhttp3.MultipartBody class FeverDataSource(private val service: FeverService) { - suspend fun login(body: MultipartBody) { - val response = service.login(body) + suspend fun login(login: String, password: String): Boolean { + val response = service.login(getFeverRequestBody(login, password)) val adapter = Moshi.Builder() - .add(Boolean::class.java, FeverAPIAdapter()) - .build() - .adapter(Boolean::class.java) + .add(Boolean::class.java, FeverAPIAdapter()) + .build() + .adapter(Boolean::class.java) - val authenticated = adapter.fromJson(response.source())!! - - // Error handling is shit, but it will stay like that until the UI - // and the other data sources/repositories are rewritten in Kotlin - if (!authenticated) { - throw LoginException("Login failed. Please check your credentials") - } + return adapter.fromJson(response.source())!! } - suspend fun sync(syncType: SyncType, syncData: FeverSyncData, body: MultipartBody): FeverSyncResult { + suspend fun synchronize( + syncType: SyncType, + syncData: FeverSyncData, + body: MultipartBody + ): FeverSyncResult { if (syncType == SyncType.INITIAL_SYNC) { val unreadIds = service.getUnreadItemsIds(body) - .reversed() - .subList(0, MAX_ITEMS_IDS) + .reversed() + .subList(0, MAX_ITEMS_IDS) var lastId = unreadIds.first() val items = arrayListOf() @@ -42,13 +40,13 @@ class FeverDataSource(private val service: FeverService) { } return FeverSyncResult( - feverFeeds = service.getFeeds(body), - folders = service.getFolders(body), - items = items, - unreadIds = unreadIds, - starredIds = service.getStarredItemsIds(body), - favicons = listOf(), - sinceId = unreadIds.first().toLong(), + feverFeeds = service.getFeeds(body), + folders = service.getFolders(body), + items = items, + unreadIds = unreadIds, + starredIds = service.getStarredItemsIds(body), + favicons = listOf(), + sinceId = unreadIds.first().toLong(), ) } else { val items = arrayListOf() @@ -63,19 +61,31 @@ class FeverDataSource(private val service: FeverService) { } return FeverSyncResult( - feverFeeds = service.getFeeds(body), - folders = service.getFolders(body), - items = items, - unreadIds = service.getUnreadItemsIds(body), - starredIds = service.getStarredItemsIds(body), - favicons = listOf(), - sinceId = if (items.isNotEmpty()) items.first().remoteId!!.toLong() else sinceId.toLong(), + feverFeeds = service.getFeeds(body), + folders = service.getFolders(body), + items = items, + unreadIds = service.getUnreadItemsIds(body), + starredIds = service.getStarredItemsIds(body), + favicons = listOf(), + sinceId = if (items.isNotEmpty()) items.first().remoteId!!.toLong() else sinceId.toLong(), ) } } - suspend fun setItemState(body: MultipartBody, action: String, id: String) = - service.updateItemState(body, action, id) + suspend fun setItemState(login: String, password: String, action: String, id: String) { + val body = getFeverRequestBody(login, password) + + service.updateItemState(body, action, id) + } + + private fun getFeverRequestBody(login: String, password: String): MultipartBody { + val credentials = ApiUtils.md5hash("$login:$password") + + return MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("api_key", credentials) + .build() + } companion object { private const val MAX_ITEMS_IDS = 5000 @@ -85,12 +95,12 @@ class FeverDataSource(private val service: FeverService) { sealed class ItemAction(val value: String) { sealed class ReadStateAction(value: String) : ItemAction(value) { - object ReadAction : ReadStateAction("read") - object UnreadAction : ReadStateAction("unread") + data object ReadAction : ReadStateAction("read") + data object UnreadAction : ReadStateAction("unread") } sealed class StarStateAction(value: String) : ItemAction(value) { - object StarAction : StarStateAction("saved") - object UnstarAction : StarStateAction("unsaved") + data object StarAction : StarStateAction("saved") + data object UnstarAction : StarStateAction("unsaved") } } \ No newline at end of file diff --git a/api/src/main/java/com/readrops/api/services/fever/FeverService.kt b/api/src/main/java/com/readrops/api/services/fever/FeverService.kt index 4262286b..fd4ad3ed 100644 --- a/api/src/main/java/com/readrops/api/services/fever/FeverService.kt +++ b/api/src/main/java/com/readrops/api/services/fever/FeverService.kt @@ -38,4 +38,8 @@ interface FeverService { suspend fun updateItemState(@Body body: MultipartBody, @Query("as") action: String, @Query("id") id: String) + companion object { + const val END_POINT = "/api/fever.php/" + } + } \ No newline at end of file diff --git a/api/src/main/java/com/readrops/api/services/fever/adapters/FeverAPIAdapter.kt b/api/src/main/java/com/readrops/api/services/fever/adapters/FeverAPIAdapter.kt index 1c31413a..e41ca60a 100644 --- a/api/src/main/java/com/readrops/api/services/fever/adapters/FeverAPIAdapter.kt +++ b/api/src/main/java/com/readrops/api/services/fever/adapters/FeverAPIAdapter.kt @@ -2,7 +2,13 @@ package com.readrops.api.services.fever.adapters import com.readrops.api.utils.exceptions.ParseException import com.readrops.api.utils.extensions.skipField -import com.squareup.moshi.* +import com.readrops.api.utils.extensions.toBoolean +import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonReader.Token +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson class FeverAPIAdapter : JsonAdapter() { @@ -15,19 +21,21 @@ class FeverAPIAdapter : JsonAdapter() { override fun fromJson(reader: JsonReader): Boolean = with(reader) { return try { beginObject() - skipField() var authenticated = 0 if (nextName() == "auth") { authenticated = nextInt() + } else { + skipValue() + } + + while (peek() == Token.NAME) { + skipField() } - skipField() endObject() - - - authenticated == 1 + authenticated.toBoolean() } catch (e: Exception) { throw ParseException(e.message) } diff --git a/api/src/main/java/com/readrops/api/utils/ApiUtils.kt b/api/src/main/java/com/readrops/api/utils/ApiUtils.kt index a09dfb3d..2305323c 100644 --- a/api/src/main/java/com/readrops/api/utils/ApiUtils.kt +++ b/api/src/main/java/com/readrops/api/utils/ApiUtils.kt @@ -14,10 +14,6 @@ object ApiUtils { const val LAST_MODIFIED_HEADER = "Last-Modified" const val IF_MODIFIED_HEADER = "If-Modified-Since" - const val HTTP_UNPROCESSABLE = 422 - const val HTTP_NOT_FOUND = 404 - const val HTTP_CONFLICT = 409 - val OPML_MIMETYPES = listOf("application/xml", "text/xml", "text/x-opml") private const val RSS_CONTENT_TYPE_REGEX = "([^;]+)" diff --git a/api/src/main/java/com/readrops/api/utils/exceptions/LoginException.kt b/api/src/main/java/com/readrops/api/utils/exceptions/LoginException.kt deleted file mode 100644 index 61ca4eff..00000000 --- a/api/src/main/java/com/readrops/api/utils/exceptions/LoginException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.readrops.api.utils.exceptions - -class LoginException(override val message: String?) : Exception() { -} \ No newline at end of file diff --git a/api/src/main/java/com/readrops/api/utils/exceptions/LoginFailedException.kt b/api/src/main/java/com/readrops/api/utils/exceptions/LoginFailedException.kt new file mode 100644 index 00000000..14024d47 --- /dev/null +++ b/api/src/main/java/com/readrops/api/utils/exceptions/LoginFailedException.kt @@ -0,0 +1,3 @@ +package com.readrops.api.utils.exceptions + +class LoginFailedException(override val message: String? = null) : Exception() \ No newline at end of file diff --git a/api/src/test/java/com/readrops/api/services/fever/adapters/FeverAPIAdapterTest.kt b/api/src/test/java/com/readrops/api/services/fever/adapters/FeverAPIAdapterTest.kt index ac9cb356..11e15b17 100644 --- a/api/src/test/java/com/readrops/api/services/fever/adapters/FeverAPIAdapterTest.kt +++ b/api/src/test/java/com/readrops/api/services/fever/adapters/FeverAPIAdapterTest.kt @@ -3,8 +3,9 @@ package com.readrops.api.services.fever.adapters import com.readrops.api.TestUtils import com.squareup.moshi.Moshi import okio.Buffer -import kotlin.test.Test +import org.junit.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse class FeverAPIAdapterTest { @@ -20,4 +21,12 @@ class FeverAPIAdapterTest { val value = adapter.fromJson(Buffer().readFrom(stream))!! assertEquals(value, true) } + + @Test + fun unauthenticatedTest() { + val stream = TestUtils.loadResource("services/fever/unsuccessful_auth.json") + + val value = adapter.fromJson(Buffer().readFrom(stream))!! + assertFalse { value } + } } \ No newline at end of file diff --git a/api/src/test/java/com/readrops/api/services/fever/adapters/FeverDataSourceTest.kt b/api/src/test/java/com/readrops/api/services/fever/adapters/FeverDataSourceTest.kt index 7ffe59e6..92c07fa2 100644 --- a/api/src/test/java/com/readrops/api/services/fever/adapters/FeverDataSourceTest.kt +++ b/api/src/test/java/com/readrops/api/services/fever/adapters/FeverDataSourceTest.kt @@ -6,9 +6,8 @@ import com.readrops.api.services.fever.FeverCredentials import com.readrops.api.services.fever.FeverDataSource import com.readrops.api.utils.ApiUtils import com.readrops.api.utils.AuthInterceptor -import com.readrops.api.utils.exceptions.LoginException +import com.readrops.api.utils.exceptions.LoginFailedException import kotlinx.coroutines.runBlocking -import okhttp3.MultipartBody import okhttp3.OkHttpClient import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -68,9 +67,7 @@ class FeverDataSourceTest : KoinTest { .setBody(Buffer().readFrom(stream))) runBlocking { - dataSource.login(MultipartBody.Builder() - .addFormDataPart("api_key", "value") - .build()) + dataSource.login("","") } } @@ -82,11 +79,9 @@ class FeverDataSourceTest : KoinTest { .addHeader(ApiUtils.CONTENT_TYPE_HEADER, "application/json") .setBody(Buffer().readFrom(stream))) - assertThrows(LoginException::class.java) { + assertThrows(LoginFailedException::class.java) { runBlocking { - dataSource.login(MultipartBody.Builder() - .addFormDataPart("api_key", "value") - .build()) + dataSource.login("","") } } } diff --git a/api/src/test/resources/services/fever/unsuccessful_auth.json b/api/src/test/resources/services/fever/unsuccessful_auth.json new file mode 100644 index 00000000..e8ddf189 --- /dev/null +++ b/api/src/test/resources/services/fever/unsuccessful_auth.json @@ -0,0 +1,4 @@ +{ + "api_version": 3, + "auth": 0 +} \ No newline at end of file diff --git a/app/src/main/java/com/readrops/app/AppModule.kt b/app/src/main/java/com/readrops/app/AppModule.kt index 7f8394e4..1cd2a362 100644 --- a/app/src/main/java/com/readrops/app/AppModule.kt +++ b/app/src/main/java/com/readrops/app/AppModule.kt @@ -19,6 +19,7 @@ import com.readrops.app.item.ItemScreenModel import com.readrops.app.more.preferences.PreferencesScreenModel import com.readrops.app.notifications.NotificationsScreenModel import com.readrops.app.repositories.BaseRepository +import com.readrops.app.repositories.FeverRepository import com.readrops.app.repositories.FreshRSSRepository import com.readrops.app.repositories.GetFoldersWithFeeds import com.readrops.app.repositories.LocalRSSRepository @@ -61,13 +62,23 @@ val appModule = module { when (account.accountType) { AccountType.LOCAL -> LocalRSSRepository(get(), get(), account) AccountType.FRESHRSS -> FreshRSSRepository( - get(), account, - get(parameters = { parametersOf(Credentials.toCredentials(account)) }) + database = get(), + account = account, + dataSource = get(parameters = { parametersOf(Credentials.toCredentials(account)) }) ) + AccountType.NEXTCLOUD_NEWS -> NextcloudNewsRepository( - get(), account, - get(parameters = { parametersOf(Credentials.toCredentials(account)) }) + database = get(), + account = account, + dataSource = get(parameters = { parametersOf(Credentials.toCredentials(account)) }) ) + + AccountType.FEVER -> FeverRepository( + database = get(), + account = account, + feverDataSource = get(parameters = { parametersOf(Credentials.toCredentials(account)) }) + ) + else -> throw IllegalArgumentException("Unknown account type") } } @@ -91,7 +102,7 @@ val appModule = module { corruptionHandler = ReplaceFileCorruptionHandler( produceNewData = { emptyPreferences() } ), - migrations = listOf(SharedPreferencesMigration(get(),"settings")), + migrations = listOf(SharedPreferencesMigration(get(), "settings")), scope = CoroutineScope(Dispatchers.IO + SupervisorJob()), produceFile = { get().preferencesDataStoreFile("settings") } ) diff --git a/app/src/main/java/com/readrops/app/account/credentials/AccountCredentialsScreen.kt b/app/src/main/java/com/readrops/app/account/credentials/AccountCredentialsScreen.kt index 5e30b7fb..98fe0cd8 100644 --- a/app/src/main/java/com/readrops/app/account/credentials/AccountCredentialsScreen.kt +++ b/app/src/main/java/com/readrops/app/account/credentials/AccountCredentialsScreen.kt @@ -41,6 +41,7 @@ import cafe.adriel.voyager.koin.getScreenModel import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow import com.readrops.app.R +import com.readrops.app.account.selection.adaptiveIconPainterResource import com.readrops.app.home.HomeScreen import com.readrops.app.util.ErrorMessage import com.readrops.app.util.components.AndroidScreen @@ -115,7 +116,7 @@ class AccountCredentialsScreen( .verticalScroll(rememberScrollState()) ) { Image( - painter = painterResource(id = account.accountType!!.iconRes), + painter = adaptiveIconPainterResource(id = account.accountType!!.iconRes), contentDescription = null, modifier = Modifier.size(48.dp) ) diff --git a/app/src/main/java/com/readrops/app/repositories/FeverRepository.kt b/app/src/main/java/com/readrops/app/repositories/FeverRepository.kt index c22f46d4..fef40121 100644 --- a/app/src/main/java/com/readrops/app/repositories/FeverRepository.kt +++ b/app/src/main/java/com/readrops/app/repositories/FeverRepository.kt @@ -1,7 +1,5 @@ package com.readrops.app.repositories -/* -import android.content.Context import android.util.Log import com.readrops.api.services.SyncType import com.readrops.api.services.fever.FeverDataSource @@ -9,107 +7,103 @@ import com.readrops.api.services.fever.FeverSyncData import com.readrops.api.services.fever.ItemAction import com.readrops.api.services.fever.adapters.FeverFeeds import com.readrops.api.utils.ApiUtils -import com.readrops.app.addfeed.FeedInsertionResult -import com.readrops.app.addfeed.ParsingResult -import com.readrops.app.utils.Utils +import com.readrops.api.utils.exceptions.LoginFailedException +import com.readrops.app.util.Utils import com.readrops.db.Database import com.readrops.db.entities.Feed import com.readrops.db.entities.Folder import com.readrops.db.entities.Item import com.readrops.db.entities.ItemState import com.readrops.db.entities.account.Account -import io.reactivex.Completable -import io.reactivex.Single -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.rx2.await -import kotlinx.coroutines.rx2.rxCompletable import okhttp3.MultipartBody class FeverRepository( - private val feverDataSource: FeverDataSource, - private val dispatcher: CoroutineDispatcher, - database: Database, - context: Context, - account: Account?, -) : BaseRepository(database, context, account) { + database: Database, + account: Account, + private val feverDataSource: FeverDataSource +) : BaseRepository(database, account) { - override fun login(account: Account, insert: Boolean): Completable = - rxCompletable(context = dispatcher) { - try { - feverDataSource.login(getFeverRequestBody()) - account.displayedName = account.accountType!!.name + override suspend fun login(account: Account) { + val authenticated = feverDataSource.login(account.login!!, account.password!!) - database.accountDao().insert(account) - .doOnSuccess { account.id = it.toInt() } - .await() - } catch (e: Exception) { - Log.e(TAG, "login: ${e.message}") - error(e.message!!) - } - } + if (authenticated) { + account.displayedName = account.accountType!!.name + } else { + throw LoginFailedException() + } + } - override fun sync(feeds: List?, update: FeedUpdate?): Completable = - rxCompletable(context = dispatcher) { - try { - val syncType = if (account.lastModified != 0L) { - SyncType.CLASSIC_SYNC - } else { - SyncType.INITIAL_SYNC - } + override suspend fun synchronize(): SyncResult { + val syncType = if (account.lastModified != 0L) { + SyncType.CLASSIC_SYNC + } else { + SyncType.INITIAL_SYNC + } - val syncResult = feverDataSource.sync(syncType, - FeverSyncData(account.lastModified.toString()), getFeverRequestBody()) + return feverDataSource.synchronize( + syncType, + FeverSyncData(account.lastModified.toString()), + getFeverRequestBody() + ).run { + insertFolders(folders) + insertFeeds(feverFeeds) - insertFolders(syncResult.folders) - insertFeeds(syncResult.feverFeeds) + insertItems(items) + insertItemsIds(unreadIds, starredIds.toMutableList()) - insertItems(syncResult.items) - insertItemsIds(syncResult.unreadIds, syncResult.starredIds.toMutableList()) + // We store the id to use for the next synchronisation even if it's not a timestamp + database.accountDao().updateLastModified(sinceId, account.id) - // We store the id to use for the next synchronisation even if it's not a timestamp - database.accountDao().updateLastModified(account.id, syncResult.sinceId) - } catch (e: Exception) { - Log.e(TAG, "sync: ${e.message}") - error(e.message!!) - } - } + SyncResult() + } + } + + override suspend fun synchronize( + selectedFeeds: List, + onUpdate: suspend (Feed) -> Unit + ): Pair = throw NotImplementedError("This method can't be called here") // Not supported by Fever API - override fun addFeeds(results: List?): Single> = Single.just(listOf()) + override suspend fun insertNewFeeds( + newFeeds: List, + onUpdate: (Feed) -> Unit + ): ErrorResult = throw CloneNotSupportedException() // Not supported by Fever API - override fun updateFeed(feed: Feed?): Completable = Completable.complete() + override suspend fun updateFeed(feed: Feed) {} // Not supported by Fever API - override fun deleteFeed(feed: Feed?): Completable = Completable.complete() + override suspend fun deleteFeed(feed: Feed) {} // Not supported by Fever API - override fun addFolder(folder: Folder?): Single = Single.just(0) + override suspend fun addFolder(folder: Folder) {} // Not supported by Fever API - override fun updateFolder(folder: Folder?): Completable = Completable.complete() + override suspend fun updateFolder(folder: Folder) {} // Not supported by Fever API - override fun deleteFolder(folder: Folder?): Completable = Completable.complete() + override suspend fun deleteFolder(folder: Folder) {} - override fun setItemReadState(item: Item): Completable { - val action = if (item.isRead) ItemAction.ReadStateAction.ReadAction else ItemAction.ReadStateAction.UnreadAction + override suspend fun setItemReadState(item: Item) { + val action = + if (item.isRead) ItemAction.ReadStateAction.ReadAction else ItemAction.ReadStateAction.UnreadAction return setItemState(item, action) } - override fun setItemStarState(item: Item): Completable { - val action = if (item.isStarred) ItemAction.StarStateAction.StarAction else ItemAction.StarStateAction.UnstarAction + override suspend fun setItemStarState(item: Item) { + val action = + if (item.isStarred) ItemAction.StarStateAction.StarAction else ItemAction.StarStateAction.UnstarAction return setItemState(item, action) } - private fun setItemState(item: Item, action: ItemAction): Completable = rxCompletable(context = dispatcher) { + private suspend fun setItemState(item: Item, action: ItemAction) { try { - feverDataSource.setItemState(getFeverRequestBody(), action.value, item.remoteId!!) + feverDataSource.setItemState(account.login!!, account.password!!, action.value, item.remoteId!!) val itemState = ItemState( - read = item.isRead, - starred = item.isStarred, - remoteId = item.remoteId!!, - accountId = account.id, + read = item.isRead, + starred = item.isStarred, + remoteId = item.remoteId!!, + accountId = account.id, ) val completable = if (action is ItemAction.ReadStateAction) { @@ -118,7 +112,6 @@ class FeverRepository( database.itemStateDao().upsertItemStarState(itemState) } - completable.await() } catch (e: Exception) { val completable = if (action is ItemAction.ReadStateAction) { super.setItemReadState(item) @@ -126,14 +119,14 @@ class FeverRepository( super.setItemStarState(item) } - completable.await() Log.e(TAG, "setItemStarState: ${e.message}") error(e.message!!) } } private suspend fun sendPreviousItemStateChanges() { - val stateChanges = database.itemStateChangesDao().getItemStateChanges(account.id) + val stateChanges = database.itemStateChangeDao() + .selectItemStateChanges(account.id) for (stateChange in stateChanges) { val action = if (stateChange.readChange) { @@ -142,28 +135,30 @@ class FeverRepository( if (stateChange.starred) ItemAction.StarStateAction.StarAction else ItemAction.StarStateAction.UnstarAction } - feverDataSource.setItemState(getFeverRequestBody(), action.value, stateChange.remoteId) + feverDataSource.setItemState(account.login!!, account.password!!, action.value, stateChange.remoteId) } } - private fun insertFolders(folders: List) { + private suspend fun insertFolders(folders: List) { folders.forEach { it.accountId = account.id } - database.folderDao().foldersUpsert(folders, account) + database.folderDao().upsertFolders(folders, account) } - private fun insertFeeds(feverFeeds: FeverFeeds) = with(feverFeeds) { + private suspend fun insertFeeds(feverFeeds: FeverFeeds) = with(feverFeeds) { for (feed in feeds) { for ((folderId, feedsIds) in feedsGroups) { - if (feedsIds.contains(feed.remoteId!!.toInt())) feed.remoteFolderId = folderId.toString() + if (feedsIds.contains(feed.remoteId!!.toInt())) { + feed.remoteFolderId = folderId.toString() + } } } feeds.forEach { it.accountId = account.id } - database.feedDao().feedsUpsert(feeds, account) + database.feedDao().upsertFeeds(feeds, account) } - private fun insertItems(items: List) { - val itemsToInsert = arrayListOf() + private suspend fun insertItems(items: List): List { + val newItems = arrayListOf() val itemsFeedsIds = mutableMapOf() for (item in items) { @@ -171,46 +166,50 @@ class FeverRepository( if (itemsFeedsIds.containsKey(item.feedRemoteId)) { feedId = itemsFeedsIds[item.feedRemoteId] } else { - feedId = database.feedDao().getFeedIdByRemoteId(item.feedRemoteId!!, account.id) - itemsFeedsIds[item.feedRemoteId!!] = feedId + //feedId = database.feedDao().getFeedIdByRemoteId(item.feedRemoteId!!, account.id) + // itemsFeedsIds[item.feedRemoteId!!] = feedId } - item.feedId = feedId!! + //item.feedId = feedId!! item.text?.let { item.readTime = Utils.readTimeFromString(it) } - itemsToInsert += item + newItems += item } - if (itemsToInsert.isNotEmpty()) { - itemsToInsert.sortWith(Item::compareTo) - database.itemDao().insert(itemsToInsert) + if (newItems.isNotEmpty()) { + newItems.sortWith(Item::compareTo) + database.itemDao().insert(newItems) + .zip(newItems) + .forEach { (id, item) -> item.id = id.toInt() } } + + return newItems } - private fun insertItemsIds(unreadIds: List, starredIds: MutableList) { - database.itemStateDao().deleteItemsStates(account.id) + private suspend fun insertItemsIds(unreadIds: List, starredIds: MutableList) { + database.itemStateDao().deleteItemStates(account.id) - database.itemStateDao().insertItemStates(unreadIds.map { unreadId -> + database.itemStateDao().insert(unreadIds.map { unreadId -> val starred = starredIds.any { starredId -> starredId == unreadId } if (starred) starredIds.remove(unreadId) ItemState( - id = 0, - read = false, - starred = starred, - remoteId = unreadId, - accountId = account.id, + id = 0, + read = false, + starred = starred, + remoteId = unreadId, + accountId = account.id, ) }) if (starredIds.isNotEmpty()) { - database.itemStateDao().insertItemStates(starredIds.map { starredId -> + database.itemStateDao().insert(starredIds.map { starredId -> ItemState( - id = 0, - read = true, // if this id wasn't in the unread ids list, it is considered a read - starred = true, - remoteId = starredId, - accountId = account.id, + id = 0, + read = true, // if this id wasn't in the unread ids list, it is considered a read + starred = true, + remoteId = starredId, + accountId = account.id, ) }) } @@ -219,12 +218,12 @@ class FeverRepository( private fun getFeverRequestBody(): MultipartBody { val credentials = ApiUtils.md5hash("${account.login}:${account.password}") return MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart("api_key", credentials) - .build() + .setType(MultipartBody.FORM) + .addFormDataPart("api_key", credentials) + .build() } companion object { val TAG: String = FeverRepository::class.java.simpleName } -}*/ +} diff --git a/db/src/main/java/com/readrops/db/entities/account/AccountType.kt b/db/src/main/java/com/readrops/db/entities/account/AccountType.kt index f4f32101..f8860cfd 100644 --- a/db/src/main/java/com/readrops/db/entities/account/AccountType.kt +++ b/db/src/main/java/com/readrops/db/entities/account/AccountType.kt @@ -9,7 +9,7 @@ enum class AccountType(@DrawableRes val iconRes: Int, val accountConfig: AccountConfig?) { LOCAL(R.mipmap.ic_launcher, R.string.local_account, AccountConfig.LOCAL), NEXTCLOUD_NEWS(R.drawable.ic_nextcloud_news, R.string.nextcloud_news, AccountConfig.NEXTCLOUD_NEWS), - FEEDLY(R.drawable.ic_feedly, R.string.feedly, null), + //FEEDLY(R.drawable.ic_feedly, R.string.feedly, null), FRESHRSS(R.drawable.ic_freshrss, R.string.freshrss, AccountConfig.FRESHRSS), FEVER(R.mipmap.ic_launcher, R.string.fever, AccountConfig.FEVER) } \ No newline at end of file diff --git a/db/src/main/java/com/readrops/db/queries/FeedUnreadCountQueryBuilder.kt b/db/src/main/java/com/readrops/db/queries/FeedUnreadCountQueryBuilder.kt index 65956db4..ed903b83 100644 --- a/db/src/main/java/com/readrops/db/queries/FeedUnreadCountQueryBuilder.kt +++ b/db/src/main/java/com/readrops/db/queries/FeedUnreadCountQueryBuilder.kt @@ -27,7 +27,7 @@ object FeedUnreadCountQueryBuilder { ) } else { SimpleSQLiteQuery( - """Select feed_id, count(*) AS item_count From ItemState Inner Join Item On ItemState.remote_id = Item.remoteId + """Select feed_id, count(*) AS item_count From ItemState Inner Join Item On ItemState.remote_id = Item.remote_id Where ItemState.read = 0 And account_id = $accountId $filter Group By feed_id""".trimIndent()) }