fix data loss when re-adding existing account (#2601)

This commit is contained in:
Konrad Pozniak 2022-06-30 20:49:48 +02:00 committed by GitHub
parent 9dcb1b666c
commit 8a0848d252
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 42 deletions

View file

@ -34,6 +34,7 @@ import com.keylesspalace.tusky.MainActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ActivityLoginBinding import com.keylesspalace.tusky.databinding.ActivityLoginBinding
import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.AccessToken
import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.getNonNullString import com.keylesspalace.tusky.util.getNonNullString
import com.keylesspalace.tusky.util.rickRoll import com.keylesspalace.tusky.util.rickRoll
@ -236,12 +237,35 @@ class LoginActivity : BaseActivity(), Injectable {
domain, clientId, clientSecret, oauthRedirectUri, code, "authorization_code" domain, clientId, clientSecret, oauthRedirectUri, code, "authorization_code"
).fold( ).fold(
{ accessToken -> { accessToken ->
fetchAccountDetails(accessToken, domain, clientId, clientSecret)
},
{ e ->
setLoading(false)
binding.domainTextInputLayout.error =
getString(R.string.error_retrieving_oauth_token)
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( accountManager.addAccount(
accessToken = accessToken.accessToken, accessToken = accessToken.accessToken,
domain = domain, domain = domain,
clientId = clientId, clientId = clientId,
clientSecret = clientSecret, clientSecret = clientSecret,
oauthScopes = OAUTH_SCOPES oauthScopes = OAUTH_SCOPES,
newAccount = newAccount
) )
val intent = Intent(this, MainActivity::class.java) val intent = Intent(this, MainActivity::class.java)
@ -249,17 +273,12 @@ class LoginActivity : BaseActivity(), Injectable {
startActivity(intent) startActivity(intent)
finish() finish()
overridePendingTransition(R.anim.explode, R.anim.explode) overridePendingTransition(R.anim.explode, R.anim.explode)
}, }, { e ->
{ e ->
setLoading(false) setLoading(false)
binding.domainTextInputLayout.error = binding.domainTextInputLayout.error =
getString(R.string.error_retrieving_oauth_token) getString(R.string.error_loading_account_details)
Log.e( Log.e(TAG, getString(R.string.error_loading_account_details), e)
TAG, })
"%s %s".format(getString(R.string.error_retrieving_oauth_token), e.message),
)
}
)
} }
private fun setLoading(loadingState: Boolean) { private fun setLoading(loadingState: Boolean) {

View file

@ -48,18 +48,21 @@ class AccountManager @Inject constructor(db: AppDatabase) {
} }
/** /**
* Adds a new empty account and makes it the active account. * Adds a new 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.
* @param accessToken the access token for the new account * @param accessToken the access token for the new account
* @param domain the domain of the accounts Mastodon instance * @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( fun addAccount(
accessToken: String, accessToken: String,
domain: String, domain: String,
clientId: String, clientId: String,
clientSecret: String, clientSecret: String,
oauthScopes: String oauthScopes: String,
newAccount: Account
) { ) {
activeAccount?.let { activeAccount?.let {
@ -68,18 +71,31 @@ class AccountManager @Inject constructor(db: AppDatabase) {
accountDao.insertOrReplace(it) accountDao.insertOrReplace(it)
} }
// 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
) ?: run {
val maxAccountId = accounts.maxByOrNull { it.id }?.id ?: 0 val maxAccountId = accounts.maxByOrNull { it.id }?.id ?: 0
val newAccountId = maxAccountId + 1 val newAccountId = maxAccountId + 1
activeAccount = AccountEntity( AccountEntity(
id = newAccountId, id = newAccountId,
domain = domain.lowercase(Locale.ROOT), domain = domain.lowercase(Locale.ROOT),
accessToken = accessToken, accessToken = accessToken,
clientId = clientId, clientId = clientId,
clientSecret = clientSecret, clientSecret = clientSecret,
oauthScopes = oauthScopes, oauthScopes = oauthScopes,
isActive = true 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() it.emojis = account.emojis ?: emptyList()
Log.d(TAG, "updateActiveAccount: saving account with id " + it.id) Log.d(TAG, "updateActiveAccount: saving account with id " + it.id)
it.id = accountDao.insertOrReplace(it) 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)
}
} }
} }

View file

@ -250,7 +250,10 @@ interface MastodonApi {
): NetworkResult<ResponseBody> ): NetworkResult<ResponseBody>
@GET("api/v1/accounts/verify_credentials") @GET("api/v1/accounts/verify_credentials")
suspend fun accountVerifyCredentials(): NetworkResult<Account> suspend fun accountVerifyCredentials(
@Header(DOMAIN_HEADER) domain: String? = null,
@Header("Authorization") auth: String? = null,
): NetworkResult<Account>
@FormUrlEncoded @FormUrlEncoded
@PATCH("api/v1/accounts/update_credentials") @PATCH("api/v1/accounts/update_credentials")

View file

@ -9,6 +9,7 @@
<string name="error_authorization_unknown">An unidentified authorization error occurred.</string> <string name="error_authorization_unknown">An unidentified authorization error occurred.</string>
<string name="error_authorization_denied">Authorization was denied.</string> <string name="error_authorization_denied">Authorization was denied.</string>
<string name="error_retrieving_oauth_token">Failed getting a login token.</string> <string name="error_retrieving_oauth_token">Failed getting a login token.</string>
<string name="error_loading_account_details">Failed loading account details</string>
<string name="error_could_not_load_login_page">Could not load the login page.</string> <string name="error_could_not_load_login_page">Could not load the login page.</string>
<string name="error_compose_character_limit">The post is too long!</string> <string name="error_compose_character_limit">The post is too long!</string>
<string name="error_image_upload_size">The file must be less than 8MB.</string> <string name="error_image_upload_size">The file must be less than 8MB.</string>