From 8a0848d2529c946d20ab5b7047e0e26616cd782a Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Thu, 30 Jun 2022 20:49:48 +0200 Subject: [PATCH] fix data loss when re-adding existing account (#2601) --- .../tusky/components/login/LoginActivity.kt | 53 ++++++++++++------ .../keylesspalace/tusky/db/AccountManager.kt | 54 ++++++++++--------- .../tusky/network/MastodonApi.kt | 5 +- app/src/main/res/values/strings.xml | 1 + 4 files changed, 71 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt index e55bbd71f..68fc5233d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt @@ -34,6 +34,7 @@ import com.keylesspalace.tusky.MainActivity import com.keylesspalace.tusky.R import com.keylesspalace.tusky.databinding.ActivityLoginBinding import com.keylesspalace.tusky.di.Injectable +import com.keylesspalace.tusky.entity.AccessToken import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.util.getNonNullString import com.keylesspalace.tusky.util.rickRoll @@ -236,32 +237,50 @@ class LoginActivity : BaseActivity(), Injectable { domain, clientId, clientSecret, oauthRedirectUri, code, "authorization_code" ).fold( { accessToken -> - accountManager.addAccount( - accessToken = accessToken.accessToken, - domain = domain, - clientId = clientId, - clientSecret = clientSecret, - oauthScopes = OAUTH_SCOPES - ) - - val intent = Intent(this, MainActivity::class.java) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - startActivity(intent) - finish() - overridePendingTransition(R.anim.explode, R.anim.explode) + fetchAccountDetails(accessToken, domain, clientId, clientSecret) }, { e -> setLoading(false) binding.domainTextInputLayout.error = getString(R.string.error_retrieving_oauth_token) - Log.e( - TAG, - "%s %s".format(getString(R.string.error_retrieving_oauth_token), e.message), - ) + Log.e(TAG, getString(R.string.error_retrieving_oauth_token), e) } ) } + private suspend fun fetchAccountDetails( + accessToken: AccessToken, + domain: String, + clientId: String, + clientSecret: String + ) { + + mastodonApi.accountVerifyCredentials( + domain = domain, + auth = "Bearer ${accessToken.accessToken}" + ).fold({ newAccount -> + accountManager.addAccount( + accessToken = accessToken.accessToken, + domain = domain, + clientId = clientId, + clientSecret = clientSecret, + oauthScopes = OAUTH_SCOPES, + newAccount = newAccount + ) + + val intent = Intent(this, MainActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + startActivity(intent) + finish() + overridePendingTransition(R.anim.explode, R.anim.explode) + }, { e -> + setLoading(false) + binding.domainTextInputLayout.error = + getString(R.string.error_loading_account_details) + Log.e(TAG, getString(R.string.error_loading_account_details), e) + }) + } + private fun setLoading(loadingState: Boolean) { if (loadingState) { binding.loginLoadingLayout.visibility = View.VISIBLE diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt index 6048c855e..04f8e6f56 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt @@ -48,18 +48,21 @@ class AccountManager @Inject constructor(db: AppDatabase) { } /** - * Adds a new empty account and makes it the active account. - * More account information has to be added later with [updateActiveAccount] - * or the account wont be saved to the database. + * Adds a new account and makes it the active account. * @param accessToken the access token for the new account * @param domain the domain of the accounts Mastodon instance + * @param clientId the oauth client id used to sign in the account + * @param clientSecret the oauth client secret used to sign in the account + * @param oauthScopes the oauth scopes granted to the account + * @param newAccount the [Account] as returned by the Mastodon Api */ fun addAccount( accessToken: String, domain: String, clientId: String, clientSecret: String, - oauthScopes: String + oauthScopes: String, + newAccount: Account ) { activeAccount?.let { @@ -68,18 +71,31 @@ class AccountManager @Inject constructor(db: AppDatabase) { accountDao.insertOrReplace(it) } - - val maxAccountId = accounts.maxByOrNull { it.id }?.id ?: 0 - val newAccountId = maxAccountId + 1 - activeAccount = AccountEntity( - id = newAccountId, - domain = domain.lowercase(Locale.ROOT), + // check if this is a relogin with an existing account, if yes update it, otherwise create a new one + val newAccountEntity = accounts.find { account -> + domain == account.domain && newAccount.id == account.accountId + }?.copy( accessToken = accessToken, clientId = clientId, clientSecret = clientSecret, - oauthScopes = oauthScopes, - isActive = true - ) + oauthScopes = oauthScopes + ) ?: run { + val maxAccountId = accounts.maxByOrNull { it.id }?.id ?: 0 + val newAccountId = maxAccountId + 1 + AccountEntity( + id = newAccountId, + domain = domain.lowercase(Locale.ROOT), + accessToken = accessToken, + clientId = clientId, + clientSecret = clientSecret, + oauthScopes = oauthScopes, + isActive = true, + accountId = newAccount.id + ).also { accounts.add(it) } + } + + activeAccount = newAccountEntity + updateActiveAccount(newAccount) } /** @@ -135,17 +151,7 @@ class AccountManager @Inject constructor(db: AppDatabase) { it.emojis = account.emojis ?: emptyList() Log.d(TAG, "updateActiveAccount: saving account with id " + it.id) - it.id = accountDao.insertOrReplace(it) - - val accountIndex = accounts.indexOf(it) - - if (accountIndex != -1) { - // in case the user was already logged in with this account, remove the old information - accounts.removeAt(accountIndex) - accounts.add(accountIndex, it) - } else { - accounts.add(it) - } + accountDao.insertOrReplace(it) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt index b8834a54b..e1d18e9f6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt +++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt @@ -250,7 +250,10 @@ interface MastodonApi { ): NetworkResult @GET("api/v1/accounts/verify_credentials") - suspend fun accountVerifyCredentials(): NetworkResult + suspend fun accountVerifyCredentials( + @Header(DOMAIN_HEADER) domain: String? = null, + @Header("Authorization") auth: String? = null, + ): NetworkResult @FormUrlEncoded @PATCH("api/v1/accounts/update_credentials") diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7a9d1b20d..1a7ef2983 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,6 +9,7 @@ An unidentified authorization error occurred. Authorization was denied. Failed getting a login token. + Failed loading account details Could not load the login page. The post is too long! The file must be less than 8MB.