Skip to content

Commit

Permalink
Merge pull request #13686 from woocommerce/issue/13666-jetpack-connec…
Browse files Browse the repository at this point in the history
…tion-api-magic-link

[Jetpack Setup] Update magic link handling to work with the Connection API integration
  • Loading branch information
hichamboushaba authored Mar 11, 2025
2 parents b673397 + 1719817 commit 7db1f4d
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.woocommerce.android.ui.login

import org.wordpress.android.fluxc.store.AccountStore.AuthEmailFlow

enum class MagicLinkFlow(private val value: String) : AuthEmailFlow {
JetpackConnection("jetpack-connection");

override fun getName(): String = value

companion object {
fun fromString(value: String): MagicLinkFlow? {
return MagicLinkFlow.values().firstOrNull { it.value == value }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.google.android.material.snackbar.Snackbar
import com.woocommerce.android.R
import com.woocommerce.android.analytics.AnalyticsEvent
import com.woocommerce.android.analytics.AnalyticsTracker
import com.woocommerce.android.ui.login.MagicLinkInterceptViewModel.CancelJetpackActivation
import com.woocommerce.android.ui.login.MagicLinkInterceptViewModel.ContinueJetpackActivation
import com.woocommerce.android.ui.login.MagicLinkInterceptViewModel.OpenLogin
import com.woocommerce.android.ui.login.MagicLinkInterceptViewModel.OpenSitePicker
Expand All @@ -35,7 +36,6 @@ import javax.inject.Inject
class MagicLinkInterceptActivity : AppCompatActivity() {
companion object {
private const val TOKEN_PARAMETER = "token"
private const val SOURCE_PARAMETER = "source"
private const val FLOW_PARAMETER = "flow"
}

Expand Down Expand Up @@ -74,14 +74,11 @@ class MagicLinkInterceptActivity : AppCompatActivity() {

val uri = requireNotNull(intent.data)
val authToken = uri.getQueryParameter(TOKEN_PARAMETER)
val source = uri.getQueryParameter(SOURCE_PARAMETER)?.let {
MagicLinkSource.fromString(it)
}
val flow = uri.getQueryParameter(FLOW_PARAMETER)?.let {
MagicLinkFlow.fromString(it)
}

authToken?.let { viewModel.handleMagicLink(it, flow, source) }
authToken?.let { viewModel.handleMagicLink(authToken = it, flow = flow) }
}

private fun setupObservers() {
Expand All @@ -91,7 +88,7 @@ class MagicLinkInterceptActivity : AppCompatActivity() {

viewModel.event.observe(this) { event ->
when (event) {
OpenSitePicker -> showSitePickerScreen()
OpenSitePicker, CancelJetpackActivation -> openMainActivity()
OpenLogin -> showLoginScreen()
is ContinueJetpackActivation -> continueJetpackActivation(event)
is ShowSnackbar -> showSnackBar(event.message)
Expand Down Expand Up @@ -138,7 +135,7 @@ class MagicLinkInterceptActivity : AppCompatActivity() {
retryContainer?.isVisible = show
}

private fun showSitePickerScreen() {
private fun openMainActivity() {
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.R
import com.woocommerce.android.R.string
import com.woocommerce.android.model.JetpackConnectionStatus
import com.woocommerce.android.model.JetpackSiteRegistrationStatus
import com.woocommerce.android.model.JetpackStatus
import com.woocommerce.android.model.RequestResult
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.tools.SiteConnectionType
import com.woocommerce.android.ui.jetpack.FetchJetpackStatus
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar
import com.woocommerce.android.viewmodel.ScopedViewModel
Expand All @@ -24,7 +24,7 @@ class MagicLinkInterceptViewModel @Inject constructor(
savedState: SavedStateHandle,
private val magicLinkInterceptRepository: MagicLinkInterceptRepository,
private val selectedSite: SelectedSite,
private val accountRepository: AccountRepository
private val fetchJetpackStatus: FetchJetpackStatus
) : ScopedViewModel(savedState) {
private val _isLoading = MutableLiveData<Boolean>()
val isLoading: LiveData<Boolean> = _isLoading
Expand All @@ -33,11 +33,9 @@ class MagicLinkInterceptViewModel @Inject constructor(
val showRetryOption: LiveData<Boolean> = _showRetryOption

private var flow: MagicLinkFlow? = null
private var source: MagicLinkSource? = null

fun handleMagicLink(authToken: String, flow: MagicLinkFlow?, source: MagicLinkSource?) {
fun handleMagicLink(authToken: String, flow: MagicLinkFlow?) {
this.flow = flow
this.source = source
launch {
_isLoading.value = true
handleRequestResultResponse(
Expand All @@ -56,19 +54,12 @@ class MagicLinkInterceptViewModel @Inject constructor(

private fun handleRequestResultResponse(requestResult: RequestResult) {
_isLoading.value = false
val source = this.source
when (requestResult) {
RequestResult.SUCCESS -> {
if (flow == MagicLinkFlow.SiteCredentialsToWPCom &&
source != null &&
if (flow == MagicLinkFlow.JetpackConnection &&
selectedSite.connectionType == SiteConnectionType.ApplicationPasswords
) {
triggerEvent(
ContinueJetpackActivation(
jetpackStatus = source.inferJetpackStatus(),
siteUrl = selectedSite.get().url
)
)
handleJetpackConnectionFlow()
} else {
triggerEvent(OpenSitePicker)
}
Expand All @@ -78,7 +69,7 @@ class MagicLinkInterceptViewModel @Inject constructor(
// or if the user is not logged in
// Either way, display error message and redirect user to login screen
RequestResult.ERROR -> {
triggerEvent(ShowSnackbar(string.magic_link_update_error))
triggerEvent(ShowSnackbar(R.string.magic_link_update_error))
triggerEvent(OpenLogin)
}

Expand All @@ -94,31 +85,42 @@ class MagicLinkInterceptViewModel @Inject constructor(
}
}

override fun onCleared() {
super.onCleared()
magicLinkInterceptRepository.onCleanup()
}
private fun handleJetpackConnectionFlow() {
_isLoading.value = true
launch {
fetchJetpackStatus(selectedSite.get(), useApplicationPasswords = true).fold(
onSuccess = { result ->
_isLoading.value = false
val jetpackStatus = when (result) {
is FetchJetpackStatus.JetpackStatusFetchResponse.Success -> result.status

private fun MagicLinkSource.inferJetpackStatus(): JetpackStatus {
val isJetpackInstalled = this != MagicLinkSource.JetpackInstallation
val isJetpackConnected = this == MagicLinkSource.WPComAuthentication
val wpComEmail = if (isJetpackConnected) {
accountRepository.getUserAccount()?.email
} else {
null
FetchJetpackStatus.JetpackStatusFetchResponse.ConnectionForbidden -> {
// Shouldn't happen unless the user changed their account's role after starting the setup.
// If this occurs, we'll just use a default value, and then the next screens
// will show an error message.
JetpackStatus(
isJetpackInstalled = false,
jetpackConnectionStatus = JetpackConnectionStatus.AccountNotConnected(
siteRegistrationStatus = JetpackSiteRegistrationStatus.NOT_REGISTERED,
blogId = null
)
)
}
}
triggerEvent(ContinueJetpackActivation(jetpackStatus, selectedSite.get().url))
},
onFailure = {
triggerEvent(ShowSnackbar(R.string.magic_link_fetch_account_error))
_isLoading.value = false
_showRetryOption.value = true
}
)
}
}

return JetpackStatus(
isJetpackInstalled = isJetpackInstalled,
jetpackConnectionStatus = if (isJetpackConnected) {
JetpackConnectionStatus.AccountConnected(wpComEmail.orEmpty())
} else {
JetpackConnectionStatus.AccountNotConnected(
siteRegistrationStatus = JetpackSiteRegistrationStatus.UNKNOWN,
blogId = null
)
}
)
override fun onCleared() {
super.onCleared()
magicLinkInterceptRepository.onCleanup()
}

object OpenSitePicker : MultiLiveEvent.Event()
Expand All @@ -127,4 +129,5 @@ class MagicLinkInterceptViewModel @Inject constructor(
val jetpackStatus: JetpackStatus,
val siteUrl: String
) : MultiLiveEvent.Event()
data object CancelJetpackActivation : MultiLiveEvent.Event()
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ class WPComLoginRepository @Inject constructor(
suspend fun requestMagicLink(
emailOrUsername: String,
flow: MagicLinkFlow,
source: MagicLinkSource,
isSignup: Boolean
): Result<Unit> {
WooLog.i(WooLog.T.LOGIN, "Submitting a Magic Link request")
Expand All @@ -89,7 +88,7 @@ class WPComLoginRepository @Inject constructor(
emailOrUsername,
isSignup,
flow,
source,
null,
AuthEmailPayloadScheme.WOOCOMMERCE
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import com.woocommerce.android.analytics.AnalyticsTracker
import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
import com.woocommerce.android.model.JetpackStatus
import com.woocommerce.android.ui.login.MagicLinkFlow
import com.woocommerce.android.ui.login.MagicLinkSource
import com.woocommerce.android.ui.login.WPComLoginRepository
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
Expand Down Expand Up @@ -108,15 +107,9 @@ class JetpackActivationMagicLinkRequestViewModel @Inject constructor(
magicLinkFallbackButton = navArgs.fallbackButton,
isLoadingDialogShown = true
)
val source = when {
!navArgs.jetpackStatus.isJetpackInstalled -> MagicLinkSource.JetpackInstallation
!navArgs.jetpackStatus.isCurrentUserConnected -> MagicLinkSource.JetpackConnection
else -> MagicLinkSource.WPComAuthentication
}
wpComLoginRepository.requestMagicLink(
emailOrUsername = navArgs.emailOrUsername,
flow = MagicLinkFlow.SiteCredentialsToWPCom,
source = source,
flow = MagicLinkFlow.JetpackConnection,
isSignup = navArgs.isNewWpComAccount
).fold(
onSuccess = {
Expand Down
Loading

0 comments on commit 7db1f4d

Please sign in to comment.