Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jetpack Setup] Update magic link handling to work with the Connection API integration #13686

Open
wants to merge 4 commits into
base: issue/13665-jetpack-connection-api-cookies
Choose a base branch
from
Open
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
@@ -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