fix data loss when re-adding existing account (#2601)
This commit is contained in:
parent
9dcb1b666c
commit
8a0848d252
4 changed files with 71 additions and 42 deletions
|
@ -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,32 +237,50 @@ class LoginActivity : BaseActivity(), Injectable {
|
||||||
domain, clientId, clientSecret, oauthRedirectUri, code, "authorization_code"
|
domain, clientId, clientSecret, oauthRedirectUri, code, "authorization_code"
|
||||||
).fold(
|
).fold(
|
||||||
{ accessToken ->
|
{ accessToken ->
|
||||||
accountManager.addAccount(
|
fetchAccountDetails(accessToken, domain, clientId, clientSecret)
|
||||||
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)
|
|
||||||
},
|
},
|
||||||
{ e ->
|
{ e ->
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
binding.domainTextInputLayout.error =
|
binding.domainTextInputLayout.error =
|
||||||
getString(R.string.error_retrieving_oauth_token)
|
getString(R.string.error_retrieving_oauth_token)
|
||||||
Log.e(
|
Log.e(TAG, getString(R.string.error_retrieving_oauth_token), e)
|
||||||
TAG,
|
|
||||||
"%s %s".format(getString(R.string.error_retrieving_oauth_token), e.message),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private fun setLoading(loadingState: Boolean) {
|
||||||
if (loadingState) {
|
if (loadingState) {
|
||||||
binding.loginLoadingLayout.visibility = View.VISIBLE
|
binding.loginLoadingLayout.visibility = View.VISIBLE
|
||||||
|
|
|
@ -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 maxAccountId = accounts.maxByOrNull { it.id }?.id ?: 0
|
val newAccountEntity = accounts.find { account ->
|
||||||
val newAccountId = maxAccountId + 1
|
domain == account.domain && newAccount.id == account.accountId
|
||||||
activeAccount = AccountEntity(
|
}?.copy(
|
||||||
id = newAccountId,
|
|
||||||
domain = domain.lowercase(Locale.ROOT),
|
|
||||||
accessToken = accessToken,
|
accessToken = accessToken,
|
||||||
clientId = clientId,
|
clientId = clientId,
|
||||||
clientSecret = clientSecret,
|
clientSecret = clientSecret,
|
||||||
oauthScopes = oauthScopes,
|
oauthScopes = oauthScopes
|
||||||
isActive = true
|
) ?: 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()
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue