fix: Ensure logging out accounts completes (#515)
The account logout process could fail due to API exceptions; network errors for example, or if the user had already revoked the app's token for that account. This would prevent the rest of the logout process (cleaning database, etc) from completing. Fix this by ignoring network errors during the logout process, and always cleaning up account content in the database. Fix a related issue where a deleted account might be recreated in a partial state if the account's visible position was saved after it was deleted. The recreated account couldn't do anything as it had no tokens, but is very confusing.
This commit is contained in:
parent
0105a8179c
commit
0445e187df
|
@ -14,6 +14,7 @@ import app.pachli.core.network.retrofit.MastodonApi
|
||||||
import app.pachli.util.removeShortcut
|
import app.pachli.util.removeShortcut
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
class LogoutUsecase @Inject constructor(
|
class LogoutUsecase @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
|
@ -37,11 +38,15 @@ class LogoutUsecase @Inject constructor(
|
||||||
val clientId = activeAccount.clientId
|
val clientId = activeAccount.clientId
|
||||||
val clientSecret = activeAccount.clientSecret
|
val clientSecret = activeAccount.clientSecret
|
||||||
if (clientId != null && clientSecret != null) {
|
if (clientId != null && clientSecret != null) {
|
||||||
api.revokeOAuthToken(
|
try {
|
||||||
clientId = clientId,
|
api.revokeOAuthToken(
|
||||||
clientSecret = clientSecret,
|
clientId = clientId,
|
||||||
token = activeAccount.accessToken,
|
clientSecret = clientSecret,
|
||||||
)
|
token = activeAccount.accessToken,
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e, "Could not revoke OAuth token, continuing")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable push notifications
|
// disable push notifications
|
||||||
|
|
|
@ -130,10 +130,25 @@ class AccountManager @Inject constructor(
|
||||||
* @param account the account to save
|
* @param account the account to save
|
||||||
*/
|
*/
|
||||||
fun saveAccount(account: AccountEntity) {
|
fun saveAccount(account: AccountEntity) {
|
||||||
if (account.id != 0L) {
|
if (account.id == 0L) {
|
||||||
Timber.d("saveAccount: saving account with id %d", account.id)
|
Timber.e("Trying to save account with ID = 0, ignoring")
|
||||||
accountDao.insertOrReplace(account)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Work around saveAccount() being called after account deletion
|
||||||
|
// For example:
|
||||||
|
// - Have two accounts, A and B, signed in with A, looking at home timeline for A
|
||||||
|
// - Log out of A. This triggers deletion of account A from the database
|
||||||
|
// - Shortly afterwards the timeline activity/fragment ends, and it tries to save
|
||||||
|
// the visible ID back to the database, which creates the AccountEntity record
|
||||||
|
// that was just deleted, but in a partial state.
|
||||||
|
if (accounts.find { it.id == account.id } == null) {
|
||||||
|
Timber.e("Trying to save account with ID = %d which does not exist, ignoring", account.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Timber.d("saveAccount: saving account with id %d", account.id)
|
||||||
|
accountDao.insertOrReplace(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue