Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.greenrobot.eventbus.ThreadMode
import org.wordpress.android.fluxc.Dispatcher
import org.wordpress.android.fluxc.generated.SiteActionBuilder
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder
import org.wordpress.android.fluxc.store.SiteStore
import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged
Expand All @@ -21,6 +22,8 @@
import org.wordpress.android.ui.accounts.login.ApplicationPasswordLoginHelper.UriLogin
import org.wordpress.android.util.AppLog
import org.wordpress.android.util.UrlUtils
import com.automattic.android.tracks.crashlogging.CrashLogging
import org.wordpress.android.util.crashlogging.sendReportWithTag
import javax.inject.Inject
import javax.inject.Named

Expand All @@ -32,6 +35,7 @@
private val selfHostedEndpointFinder: SelfHostedEndpointFinder,
private val siteStore: SiteStore,
private val appLogWrapper: AppLogWrapper,
private val crashLogging: CrashLogging,
) : ViewModel() {
private val _onFinishedEvent = MutableSharedFlow<NavigationActionData>()
/**
Expand Down Expand Up @@ -60,15 +64,12 @@
fun setupSite(rawData: String) {
viewModelScope.launch {
if (rawData.isEmpty()) {
appLogWrapper.e(AppLog.T.MAIN, "A_P: Cannot store credentials: rawData is empty")
_onFinishedEvent.emit(
NavigationActionData(
showSiteSelector = false,
siteUrl = "",
oldSitesIDs = oldSitesIDs,
isError = true
)
appLogWrapper.e(
AppLog.T.MAIN,
"A_P: Cannot store credentials: rawData is empty"
)
applicationPasswordLoginHelper.trackStoringFailed("", "empty_raw_data")
emitError(siteUrl = "", errorMessage = "empty_raw_data")
return@launch
}
val urlLogin = applicationPasswordLoginHelper.getSiteUrlLoginFromRawData(rawData)
Expand Down Expand Up @@ -96,6 +97,10 @@
AppLog.T.DB,
"A_P: Error storing credentials: ${e.stackTraceToString()}"
)
applicationPasswordLoginHelper.trackStoringFailed(
urlLogin.siteUrl, "store_credentials_exception"
)
crashLogging.sendReportWithTag(e, AppLog.T.DB)
false
}
}
Expand All @@ -117,7 +122,13 @@
", siteUrl isEmpty=${siteUrl.isEmpty()}" +
", apiRootUrl isEmpty=${apiRootUrl.isEmpty()}"
)
emitErrorFetching(siteUrl)
applicationPasswordLoginHelper.trackStoringFailed(
siteUrl, "empty_fetch_params"
)
emitError(
siteUrl = siteUrl,
errorMessage = "empty_fetch_params"
)
} else {
val xmlRpcEndpoint =
selfHostedEndpointFinder.verifyOrDiscoverXMLRPCEndpoint(siteUrl)
Expand All @@ -137,67 +148,153 @@
AppLog.T.API,
"A_P: Error fetching sites: ${e.stackTraceToString()}"
)
emitErrorFetching(siteUrl)
applicationPasswordLoginHelper.trackStoringFailed(
siteUrl, "fetch_sites_exception"
)
emitError(siteUrl = siteUrl, errorMessage = e.message, cause = e)
}
}

private suspend fun emitErrorFetching(siteUrl: String) = _onFinishedEvent.emit(
NavigationActionData(
showSiteSelector = false,
siteUrl = siteUrl,
oldSitesIDs = oldSitesIDs,
isError = true
private suspend fun emitError(
siteUrl: String,
errorMessage: String? = null,
cause: Throwable? = null
) {
val exception = cause
?: Exception("Application password login failed: $errorMessage")
crashLogging.sendReportWithTag(exception, AppLog.T.MAIN)
_onFinishedEvent.emit(
NavigationActionData(
showSiteSelector = false,
siteUrl = siteUrl,
oldSitesIDs = oldSitesIDs,
isError = true,
errorMessage = errorMessage
)
)
)
}

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.BACKGROUND)
fun onSiteChanged(event: OnSiteChanged) {
viewModelScope.launch {
val currentNormalizedUrl = UrlUtils.normalizeUrl(currentUrlLogin?.siteUrl)
val site = siteStore.sites.firstOrNull { UrlUtils.normalizeUrl(it.url) == currentNormalizedUrl }
if (event.rowsAffected < 1 || site == null || applicationPasswordLoginHelper.siteHasBadCredentials(site)) {
appLogWrapper.e(
AppLog.T.MAIN,
"A_P: onSiteChanged failed" +
" for: ${currentUrlLogin?.siteUrl}" +
" - rowsAffected=${event.rowsAffected}" +
", siteFound=${site != null}" +
", badCredentials=${
site?.let {
applicationPasswordLoginHelper
.siteHasBadCredentials(it)
}
}"
)
_onFinishedEvent.emit(
NavigationActionData(
showSiteSelector = false,
siteUrl = currentUrlLogin?.siteUrl,
oldSitesIDs = oldSitesIDs,
isError = true
)
)
if (event.isError) {
handleSiteChangedError(event)
} else {
_onFinishedEvent.emit(
NavigationActionData(
showSiteSelector = siteStore.hasSite() &&
oldSitesIDs?.contains(site.id) != true, // null or false
siteUrl = currentUrlLogin?.siteUrl,
oldSitesIDs = oldSitesIDs,
isError = false,
newSiteLocalId = site.id
)
)
handleSiteChangedSuccess(event)
}
}
}

private suspend fun handleSiteChangedError(event: OnSiteChanged) {
val error = event.error
appLogWrapper.e(
AppLog.T.MAIN,
"A_P: onSiteChanged failed: " +
"SiteStore error ${error?.type}: ${error?.message}"
)
applicationPasswordLoginHelper.trackStoringFailed(
currentUrlLogin?.siteUrl,
"site_changed_failed"
)
emitError(
siteUrl = currentUrlLogin?.siteUrl.orEmpty(),
errorMessage = "site_store_error"
)
}

@Suppress("TooGenericExceptionCaught")
private suspend fun handleSiteChangedSuccess(event: OnSiteChanged) {
val normalizedUrl =
UrlUtils.normalizeUrl(currentUrlLogin?.siteUrl)

val site = try {
siteStore.sites.firstOrNull {
UrlUtils.normalizeUrl(it.url) == normalizedUrl
}
} catch (e: Exception) {
logAndEmitSiteChangedError(
logMessage = "exception reading sites from DB: " +
e.stackTraceToString(),
errorCode = "db_read_exception",
cause = e
)
return
}

val validationError = validateSiteChanged(event, site)
if (validationError != null) {
logAndEmitSiteChangedError(
logMessage = validationError.logMessage,
errorCode = validationError.errorCode
)
} else {
val resolvedSite = site ?: return

Check warning on line 232 in WordPress/src/main/java/org/wordpress/android/ui/accounts/applicationpassword/ApplicationPasswordLoginViewModel.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless elvis operation ?:, it always succeeds.

See more on https://sonarcloud.io/project/issues?id=wordpress-mobile_WordPress-Android&issues=AZ0BiFfaAluW8AsDOSw2&open=AZ0BiFfaAluW8AsDOSw2&pullRequest=22702
_onFinishedEvent.emit(
NavigationActionData(
showSiteSelector = siteStore.hasSite() &&
oldSitesIDs?.contains(resolvedSite.id) != true,
siteUrl = currentUrlLogin?.siteUrl,
oldSitesIDs = oldSitesIDs,
isError = false,
newSiteLocalId = resolvedSite.id
)
)
}
}

private fun validateSiteChanged(
event: OnSiteChanged,
site: SiteModel?
): SiteChangedValidationError? = when {
event.rowsAffected < 1 -> SiteChangedValidationError(
logMessage = "No rows affected " +
"(rowsAffected=${event.rowsAffected})",
errorCode = "no_rows_affected"
)
site == null -> SiteChangedValidationError(
logMessage = "Site not found after update",
errorCode = "site_not_found"
)
applicationPasswordLoginHelper
.siteHasBadCredentials(site) -> SiteChangedValidationError(
logMessage = "Credentials are empty after store",
errorCode = "empty_credentials"
)
else -> null
}

private data class SiteChangedValidationError(
val logMessage: String,
val errorCode: String
)

private suspend fun logAndEmitSiteChangedError(
logMessage: String,
errorCode: String,
cause: Throwable? = null
) {
appLogWrapper.e(
AppLog.T.MAIN,
"A_P: onSiteChanged failed: $logMessage"
)
applicationPasswordLoginHelper.trackStoringFailed(
currentUrlLogin?.siteUrl,
"site_changed_failed"
)
emitError(
siteUrl = currentUrlLogin?.siteUrl.orEmpty(),
errorMessage = errorCode,
cause = cause
)
}

data class NavigationActionData(
val showSiteSelector: Boolean,
val siteUrl: String?,
val oldSitesIDs: ArrayList<Int>?,
val isError: Boolean,
val newSiteLocalId: Int? = null
val newSiteLocalId: Int? = null,
val errorMessage: String? = null
)
}
Loading
Loading