Skip to content

Commit a49e6cf

Browse files
Merge pull request #14538 from woocommerce/issue/WOOMOB-1181-fetch-app-passwords-on-launch
[Jetpack Performance] Fetch app passwords support on app launch
2 parents 08f37d4 + 2fbd59c commit a49e6cf

File tree

8 files changed

+334
-397
lines changed

8 files changed

+334
-397
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/jetpack/JetpackActivationRepository.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,9 @@ class JetpackActivationRepository @Inject constructor(
165165
WooLog.d(WooLog.T.LOGIN, "Jetpack Activation: Site $siteUrl is missing from account sites")
166166
Result.failure(IllegalStateException("Site missing"))
167167
} else {
168-
if (!site.hasWooCommerce) {
169-
// If the site doesn't have WooCommerce, let's do one additional fetch using `fetchSite`,
170-
// this function will make sure to fetch data from the remote site, which might result in more
171-
// accurate result
172-
siteStore.fetchSite(site)
173-
}
168+
// Fetch full site details from the remote site, this will also allow us to fetch the
169+
// Applications Passwords support on the site
170+
siteStore.fetchSite(site)
174171
Result.success(site)
175172
}
176173
}

libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/system/WooSystemRestClient.kt

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,13 @@ import com.google.gson.annotations.SerializedName
55
import org.wordpress.android.fluxc.generated.endpoint.WOOCOMMERCE
66
import org.wordpress.android.fluxc.generated.endpoint.WPAPI
77
import org.wordpress.android.fluxc.model.SiteModel
8-
import org.wordpress.android.fluxc.network.rest.wpapi.WPAPIResponse
98
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooNetwork
109
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload
11-
import org.wordpress.android.fluxc.network.rest.wpcom.wc.toWooError
1210
import org.wordpress.android.fluxc.utils.toWooPayload
1311
import javax.inject.Inject
1412

1513
class WooSystemRestClient @Inject constructor(private val wooNetwork: WooNetwork) {
1614
companion object {
17-
private const val NOT_FOUND = 404
18-
private const val FORBIDDEN = 403
1915
private const val SAVE_SITE_TITLE_RESPONSE_FIELD = "title"
2016
}
2117

@@ -44,51 +40,6 @@ class WooSystemRestClient @Inject constructor(private val wooNetwork: WooNetwork
4440
return response.toWooPayload()
4541
}
4642

47-
/**
48-
* Test the settings endpoint of WooCommerce to confirm if the plugin is available or not.
49-
* We pass an empty _fields just to reduce the response payload size, as we don't care about the contents
50-
*
51-
* @return JetpackSuccess(true) if WooCommerce is installed, JetpackSuccess(false) is we get a 404,
52-
* and JetpackError otherwise
53-
*/
54-
suspend fun checkIfWooCommerceIsAvailable(site: SiteModel): WooPayload<Boolean> {
55-
val url = WOOCOMMERCE.settings.pathV3
56-
57-
val response = wooNetwork.executeGetGsonRequest(
58-
site = site,
59-
path = url,
60-
params = mapOf("_fields" to ""),
61-
clazz = Any::class.java
62-
)
63-
64-
return when (response) {
65-
is WPAPIResponse.Success -> WooPayload(true)
66-
is WPAPIResponse.Error -> {
67-
when (response.error.volleyError?.networkResponse?.statusCode) {
68-
NOT_FOUND -> WooPayload(false)
69-
FORBIDDEN -> {
70-
// If we get a 403 status code, we can infer that Woo is installed,
71-
// the user just doesn't have permission to access the Woo API
72-
WooPayload(true)
73-
}
74-
else -> WooPayload(response.error.toWooError())
75-
}
76-
}
77-
}
78-
}
79-
80-
suspend fun fetchSiteSettings(site: SiteModel): WooPayload<WPSiteSettingsResponse> {
81-
val url = WPAPI.settings.urlV2
82-
83-
val response = wooNetwork.executeGetGsonRequest(
84-
site = site,
85-
path = url,
86-
clazz = WPSiteSettingsResponse::class.java
87-
)
88-
89-
return response.toWooPayload()
90-
}
91-
9243
suspend fun saveSiteTitle(site: SiteModel, siteTitle: String): WooPayload<SaveSiteTitleResponse> {
9344
val url = WPAPI.settings.urlV2
9445

@@ -139,12 +90,4 @@ class WooSystemRestClient @Inject constructor(private val wooNetwork: WooNetwork
13990
val security: JsonElement? = null,
14091
val pages: JsonElement? = null
14192
)
142-
143-
data class WPSiteSettingsResponse(
144-
@SerializedName("title") val title: String? = null,
145-
@SerializedName("description") val description: String? = null,
146-
@SerializedName("url") val url: String? = null,
147-
@SerializedName("show_on_front") val showOnFront: String? = null,
148-
@SerializedName("page_on_front") val pageOnFront: Long? = null
149-
)
15093
}

libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WooCommerceStore.kt

Lines changed: 7 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ package org.wordpress.android.fluxc.store
33
import android.content.Context
44
import com.wellsql.generated.SiteModelTable
55
import kotlinx.coroutines.Dispatchers
6-
import kotlinx.coroutines.async
7-
import kotlinx.coroutines.awaitAll
8-
import kotlinx.coroutines.coroutineScope
96
import kotlinx.coroutines.flow.Flow
107
import kotlinx.coroutines.flow.map
118
import kotlinx.coroutines.runBlocking
@@ -92,9 +89,6 @@ open class WooCommerceStore @Inject internal constructor(
9289
const val WOO_API_NAMESPACE_V3 = "wc/v3"
9390
}
9491

95-
private val SiteModel.needsAdditionalCheckForWooInstallation
96-
get() = origin == SiteModel.ORIGIN_XMLRPC || (origin == SiteModel.ORIGIN_WPCOM_REST && isJetpackCPConnected)
97-
9892
override fun onRegister() = AppLog.d(T.API, "WooCommerceStore onRegister")
9993

10094
@Subscribe(threadMode = ThreadMode.ASYNC)
@@ -108,33 +102,7 @@ open class WooCommerceStore @Inject internal constructor(
108102
OnSiteChanged()
109103
}
110104

111-
if (fetchResult.isError) {
112-
emitChange(fetchResult)
113-
114-
return WooResult(
115-
WooError(
116-
type = GENERIC_ERROR,
117-
message = fetchResult.error.message,
118-
original = UNKNOWN
119-
)
120-
)
121-
}
122-
123-
// Fetch WooCommerce availability for non-Jetpack sites
124-
val updatedSites = siteStore.sites
125-
.filter { it.needsAdditionalCheckForWooInstallation }
126-
.pmap { site ->
127-
val isResultUpdated = fetchAndUpdateNonJetpackSite(site)
128-
if (isResultUpdated.model == true && !fetchResult.updatedSites.contains(site)) {
129-
1
130-
} else {
131-
0
132-
}
133-
}.sum()
134-
135-
val rowsAffected = fetchResult.rowsAffected + updatedSites
136-
137-
emitChange(OnSiteChanged(rowsAffected, fetchResult.updatedSites))
105+
emitChange(fetchResult)
138106

139107
return withContext(Dispatchers.IO) { WooResult(getWooCommerceSites()) }
140108
}
@@ -158,28 +126,7 @@ open class WooCommerceStore @Inject internal constructor(
158126
}
159127
}
160128

161-
if (!site.isJetpackCPConnected) {
162-
// The endpoint used by siteStore to fetch a single site is broken for Jetpack CP sites, so skip it for them
163-
siteStore.fetchSite(site).let {
164-
if (it.isError) {
165-
return WooResult(
166-
WooError(
167-
type = GENERIC_ERROR,
168-
message = it.error.message,
169-
original = UNKNOWN
170-
)
171-
)
172-
}
173-
}
174-
}
175-
176-
val isSiteUpdated = if (site.needsAdditionalCheckForWooInstallation) {
177-
fetchAndUpdateNonJetpackSite(site).let {
178-
if (it.isError) return WooResult(it.error)
179-
180-
it.model!!
181-
}
182-
} else false
129+
val fetchResult = siteStore.fetchSite(site)
183130

184131
val updatedSite = withContext(Dispatchers.IO) {
185132
siteStore.getSiteByLocalId(site.id)
@@ -191,7 +138,7 @@ open class WooCommerceStore @Inject internal constructor(
191138
)
192139
)
193140

194-
if (isSiteUpdated) {
141+
if (fetchResult.rowsAffected > 0) {
195142
emitChange(OnSiteChanged(1, listOf(updatedSite)))
196143
}
197144

@@ -330,83 +277,6 @@ open class WooCommerceStore @Inject internal constructor(
330277
}
331278
}
332279

333-
/**
334-
* Fetch additional data about non-Jetpack connected sites, and here we mean two types:
335-
* 1. Jetpack CP connected sites.
336-
* 2. Self-hosted sites accessed using site credentials.
337-
*
338-
* @return [WooResult] representing whether the result succeeded and whether the site was updated
339-
*/
340-
@Suppress("ReturnCount")
341-
private suspend fun fetchAndUpdateNonJetpackSite(site: SiteModel): WooResult<Boolean> {
342-
// Fetch site metadata for Jetpack CP sites
343-
val isMetadataUpdated = if (site.isJetpackCPConnected) {
344-
fetchAndUpdateMetaDataFromSiteSettings(site).let {
345-
if (it.isError) {
346-
return it
347-
}
348-
it.model!!
349-
}
350-
} else false
351-
352-
// Check Woo installation status for Jetpack CP sites and non-Jetpack sites
353-
val isWooStatusUpdated = fetchAndUpdateWooCommerceAvailability(site).let {
354-
if (it.isError) {
355-
return it
356-
}
357-
it.model!!
358-
}
359-
360-
return WooResult(isMetadataUpdated || isWooStatusUpdated)
361-
}
362-
363-
private suspend fun fetchAndUpdateMetaDataFromSiteSettings(site: SiteModel): WooResult<Boolean> {
364-
fun SiteModel.updateFromSiteSettings(response: WooSystemRestClient.WPSiteSettingsResponse) = apply {
365-
name = response.title ?: name
366-
description = response.description ?: description
367-
url = response.url ?: url
368-
showOnFront = response.showOnFront ?: showOnFront
369-
pageOnFront = response.pageOnFront ?: pageOnFront
370-
}
371-
372-
return coroutineEngine.withDefaultContext(T.API, this, "fetchAndUpdateMetaDataFromSiteSettings") {
373-
val response = systemRestClient.fetchSiteSettings(site)
374-
return@withDefaultContext when {
375-
response.isError -> {
376-
AppLog.w(T.API, "fetching site settings site ${site.siteId}")
377-
WooResult(response.error)
378-
}
379-
380-
else -> {
381-
WooResult(response.result?.let {
382-
siteSqlUtils.insertOrUpdateSite(site.updateFromSiteSettings(it)) == 1
383-
} ?: false)
384-
}
385-
}
386-
}
387-
}
388-
389-
private suspend fun fetchAndUpdateWooCommerceAvailability(site: SiteModel): WooResult<Boolean> {
390-
return coroutineEngine.withDefaultContext(T.API, this, "fetchAndUpdateWooCommerceAvailability") {
391-
val response = systemRestClient.checkIfWooCommerceIsAvailable(site)
392-
return@withDefaultContext when {
393-
response.isError -> {
394-
AppLog.w(T.API, "Checking WooCommerce availability failed for site ${site.siteId}")
395-
WooResult(response.error)
396-
}
397-
398-
else -> {
399-
val updated = response.result?.takeIf { it != site.hasWooCommerce }?.let {
400-
site.hasWooCommerce = it
401-
siteSqlUtils.insertOrUpdateSite(site)
402-
true
403-
} ?: false
404-
WooResult(updated)
405-
}
406-
}
407-
}
408-
}
409-
410280
suspend fun fetchSupportedApiVersion(
411281
site: SiteModel,
412282
overrideRetryPolicy: Boolean = false
@@ -531,11 +401,13 @@ open class WooCommerceStore @Inject internal constructor(
531401
)
532402
WooResult(response.error)
533403
}
404+
534405
response.result != null -> {
535406
val settings = settingsMapper.mapTaxBasedOnSettings(response.result, site.localId())
536407
taxBasedOnDao.insertOrUpdate(settings)
537408
WooResult(settings)
538409
}
410+
539411
else -> {
540412
WooResult(WooError(GENERIC_ERROR, UNKNOWN))
541413
}
@@ -554,12 +426,14 @@ open class WooCommerceStore @Inject internal constructor(
554426
)
555427
WooResult(response.error)
556428
}
429+
557430
response.result != null -> {
558431
val settingsMap = response.result.associate { setting ->
559432
setting.id to (setting.value ?: setting.default ?: "")
560433
}
561434
WooResult(settingsMap)
562435
}
436+
563437
else -> {
564438
WooResult(WooError(GENERIC_ERROR, UNKNOWN))
565439
}
@@ -648,8 +522,4 @@ open class WooCommerceStore @Inject internal constructor(
648522
): String {
649523
return formatCurrencyForDisplay(amount.toString(), site, currencyCode, applyDecimalFormatting)
650524
}
651-
652-
private suspend fun <A, B> Iterable<A>.pmap(f: suspend (A) -> B): List<B> = coroutineScope {
653-
map { async { f(it) } }.awaitAll()
654-
}
655525
}

0 commit comments

Comments
 (0)