Skip to content

Commit bad1d31

Browse files
Merge pull request #8156 from woocommerce/issue/8110-user-role
[REST API] Check user role
2 parents dcdb972 + 186808f commit bad1d31

File tree

6 files changed

+65
-94
lines changed

6 files changed

+65
-94
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/AppInitializer.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,15 @@ class AppInitializer @Inject constructor() : ApplicationLifecycleListener {
192192
}
193193

194194
override fun onFirstActivityResumed() {
195-
// Update the WP.com account details, settings, and site list every time the app is completely restarted,
196-
// only if the logged in
197-
if (networkStatus.isConnected() && accountStore.hasAccessToken()) {
198-
dispatcher.dispatch(AccountActionBuilder.newFetchAccountAction())
199-
dispatcher.dispatch(AccountActionBuilder.newFetchSettingsAction())
195+
// App is completely restarted
196+
if (networkStatus.isConnected()) {
197+
if (accountStore.hasAccessToken()) {
198+
// Update the WPCom account if the user is signed in using a WPCom account
199+
dispatcher.dispatch(AccountActionBuilder.newFetchAccountAction())
200+
dispatcher.dispatch(AccountActionBuilder.newFetchSettingsAction())
201+
}
202+
203+
// Update the list of sites
200204
appCoroutineScope.launch {
201205
wooCommerceStore.fetchWooCommerceSites()
202206

@@ -212,7 +216,7 @@ class AppInitializer @Inject constructor() : ApplicationLifecycleListener {
212216
}
213217
}
214218

215-
// Update the user info for the currently logged in user
219+
// Update the user info
216220
if (selectedSite.exists()) {
217221
userEligibilityFetcher.fetchUserEligibility()
218222
}

WooCommerce/src/main/kotlin/com/woocommerce/android/model/User.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ data class User(
1414
val roles: List<String>
1515
) : Parcelable {
1616
fun getUserNameForDisplay(): String {
17-
val name = "$firstName $lastName"
17+
val name = "$firstName $lastName".trim()
1818
return when {
19-
name.isEmpty() && username.isEmpty() -> email
20-
name.isEmpty() && username.isNotEmpty() -> username
21-
else -> name
19+
name.isNotEmpty() -> name
20+
username.isNotEmpty() -> username
21+
else -> email
2222
}
2323
}
2424
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/common/UserEligibilityErrorViewModel.kt

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import com.woocommerce.android.AppPrefs
66
import com.woocommerce.android.R.string
77
import com.woocommerce.android.model.User
88
import com.woocommerce.android.model.toAppModel
9-
import com.woocommerce.android.util.WooLog
10-
import com.woocommerce.android.util.WooLog.T
9+
import com.woocommerce.android.ui.login.AccountRepository
1110
import com.woocommerce.android.viewmodel.LiveDataDelegate
1211
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
1312
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Logout
@@ -16,46 +15,32 @@ import com.woocommerce.android.viewmodel.ScopedViewModel
1615
import dagger.hilt.android.lifecycle.HiltViewModel
1716
import kotlinx.coroutines.launch
1817
import kotlinx.parcelize.Parcelize
19-
import org.greenrobot.eventbus.Subscribe
20-
import org.greenrobot.eventbus.ThreadMode
21-
import org.wordpress.android.fluxc.Dispatcher
22-
import org.wordpress.android.fluxc.generated.AccountActionBuilder
23-
import org.wordpress.android.fluxc.generated.SiteActionBuilder
24-
import org.wordpress.android.fluxc.store.AccountStore
25-
import org.wordpress.android.fluxc.store.AccountStore.OnAccountChanged
2618
import javax.inject.Inject
2719

2820
@HiltViewModel
2921
class UserEligibilityErrorViewModel @Inject constructor(
3022
savedState: SavedStateHandle,
3123
private val appPrefs: AppPrefs,
32-
private val dispatcher: Dispatcher,
33-
private val accountStore: AccountStore,
24+
private val accountRepository: AccountRepository,
3425
private val userEligibilityFetcher: UserEligibilityFetcher
3526
) : ScopedViewModel(savedState) {
3627
final val viewStateData = LiveDataDelegate(savedState, ViewState())
3728
private var viewState by viewStateData
3829

39-
init {
40-
dispatcher.register(this)
41-
}
42-
43-
override fun onCleared() {
44-
super.onCleared()
45-
dispatcher.unregister(this)
46-
}
47-
48-
final fun start() {
30+
fun start() {
4931
val email = appPrefs.getUserEmail()
5032
if (email.isNotEmpty()) {
5133
val user = userEligibilityFetcher.getUserByEmail(email)
5234
viewState = viewState.copy(user = user?.toAppModel())
5335
}
5436
}
5537

56-
fun onLogoutButtonClicked() {
57-
dispatcher.dispatch(AccountActionBuilder.newSignOutAction())
58-
dispatcher.dispatch(SiteActionBuilder.newRemoveWpcomAndJetpackSitesAction())
38+
fun onLogoutButtonClicked() = launch {
39+
accountRepository.logout().let {
40+
if (it) {
41+
triggerEvent(Logout)
42+
}
43+
}
5944
}
6045

6146
fun onRetryButtonClicked() {
@@ -80,18 +65,4 @@ class UserEligibilityErrorViewModel @Inject constructor(
8065
val user: User? = null,
8166
val isProgressDialogShown: Boolean? = null
8267
) : Parcelable
83-
84-
@Suppress("unused")
85-
@Subscribe(threadMode = ThreadMode.MAIN)
86-
fun onAccountChanged(event: OnAccountChanged) {
87-
if (event.isError) {
88-
WooLog.e(
89-
T.LOGIN,
90-
"Account error [type = ${event.causeOfChange}] : " +
91-
"${event.error.type} > ${event.error.message}"
92-
)
93-
} else if (!accountStore.hasAccessToken()) {
94-
triggerEvent(Logout)
95-
}
96-
}
9768
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.woocommerce.android.applicationpasswords.ApplicationPasswordsNotifier
1111
import com.woocommerce.android.model.UiString.UiStringRes
1212
import com.woocommerce.android.model.UiString.UiStringText
1313
import com.woocommerce.android.tools.SelectedSite
14+
import com.woocommerce.android.ui.common.UserEligibilityFetcher
1415
import com.woocommerce.android.ui.login.WPApiSiteRepository
1516
import com.woocommerce.android.viewmodel.MultiLiveEvent
1617
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
@@ -50,7 +51,8 @@ class LoginSiteCredentialsViewModel @Inject constructor(
5051
private val selectedSite: SelectedSite,
5152
private val loginAnalyticsListener: LoginAnalyticsListener,
5253
private val resourceProvider: ResourceProvider,
53-
applicationPasswordsNotifier: ApplicationPasswordsNotifier
54+
applicationPasswordsNotifier: ApplicationPasswordsNotifier,
55+
private val userEligibilityFetcher: UserEligibilityFetcher
5456
) : ScopedViewModel(savedStateHandle) {
5557
companion object {
5658
const val SITE_ADDRESS_KEY = "site-address"
@@ -100,8 +102,17 @@ class LoginSiteCredentialsViewModel @Inject constructor(
100102

101103
fun onContinueClick() = launch {
102104
loginAnalyticsListener.trackSubmitClicked()
103-
isLoading.value = true
105+
if (selectedSite.exists()) {
106+
// The login already succeeded, proceed to fetching user info
107+
fetchUserInfo()
108+
} else {
109+
login()
110+
}
111+
}
112+
113+
private suspend fun login() {
104114
val state = requireNotNull(this@LoginSiteCredentialsViewModel.state.value)
115+
isLoading.value = true
105116
wpApiSiteRepository.login(
106117
url = siteAddress,
107118
username = state.username,
@@ -111,7 +122,6 @@ class LoginSiteCredentialsViewModel @Inject constructor(
111122
checkWooStatus(it)
112123
},
113124
onFailure = { exception ->
114-
isLoading.value = false
115125
var errorMessage: Int? = null
116126
if (exception is OnChangedException && exception.error is AuthenticationError) {
117127
errorMessage = exception.error.toErrorMessage()
@@ -137,6 +147,7 @@ class LoginSiteCredentialsViewModel @Inject constructor(
137147
)
138148
}
139149
)
150+
isLoading.value = false
140151
}
141152

142153
private suspend fun checkWooStatus(site: SiteModel) {
@@ -146,7 +157,7 @@ class LoginSiteCredentialsViewModel @Inject constructor(
146157
if (isWooInstalled) {
147158
loginAnalyticsListener.trackAnalyticsSignIn(false)
148159
selectedSite.set(site)
149-
triggerEvent(LoggedIn(site.id))
160+
fetchUserInfo()
150161
} else {
151162
triggerEvent(ShowNonWooErrorScreen(siteAddress))
152163
}
@@ -158,6 +169,18 @@ class LoginSiteCredentialsViewModel @Inject constructor(
158169
isLoading.value = false
159170
}
160171

172+
private suspend fun fetchUserInfo() {
173+
isLoading.value = true
174+
val userInfo = userEligibilityFetcher.fetchUserInfo()
175+
if (userInfo != null) {
176+
userEligibilityFetcher.updateUserInfo(userInfo)
177+
triggerEvent(LoggedIn(selectedSite.getSelectedSiteId()))
178+
} else {
179+
triggerEvent(ShowSnackbar(R.string.error_generic))
180+
}
181+
isLoading.value = false
182+
}
183+
161184
fun onResetPasswordClick() {
162185
triggerEvent(ShowResetPasswordScreen(siteAddress))
163186
}

WooCommerce/src/test/kotlin/com/woocommerce/android/ui/common/UserEligibilityErrorViewModelTest.kt

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,32 @@ import com.woocommerce.android.R.string
66
import com.woocommerce.android.extensions.takeIfNotEqualTo
77
import com.woocommerce.android.model.toAppModel
88
import com.woocommerce.android.ui.common.UserEligibilityErrorViewModel.ViewState
9+
import com.woocommerce.android.ui.login.AccountRepository
910
import com.woocommerce.android.viewmodel.BaseUnitTest
10-
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.*
11+
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
12+
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Logout
13+
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar
1114
import kotlinx.coroutines.ExperimentalCoroutinesApi
1215
import org.assertj.core.api.Assertions.assertThat
1316
import org.junit.Before
1417
import org.junit.Test
15-
import org.mockito.kotlin.KArgumentCaptor
1618
import org.mockito.kotlin.any
17-
import org.mockito.kotlin.argumentCaptor
18-
import org.mockito.kotlin.clearInvocations
1919
import org.mockito.kotlin.doReturn
2020
import org.mockito.kotlin.mock
21-
import org.mockito.kotlin.spy
2221
import org.mockito.kotlin.times
2322
import org.mockito.kotlin.verify
2423
import org.mockito.kotlin.whenever
25-
import org.wordpress.android.fluxc.Dispatcher
26-
import org.wordpress.android.fluxc.action.AccountAction.SIGN_OUT
27-
import org.wordpress.android.fluxc.action.SiteAction
28-
import org.wordpress.android.fluxc.annotations.action.Action
2924
import org.wordpress.android.fluxc.model.user.WCUserModel
30-
import org.wordpress.android.fluxc.store.AccountStore
31-
import org.wordpress.android.fluxc.store.AccountStore.OnAccountChanged
32-
import kotlin.test.assertEquals
3325
import kotlin.test.assertFalse
3426
import kotlin.test.assertTrue
3527

3628
@ExperimentalCoroutinesApi
3729
class UserEligibilityErrorViewModelTest : BaseUnitTest() {
3830
private val appPrefsWrapper: AppPrefs = mock()
39-
private val dispatcher: Dispatcher = mock()
40-
private val accountStore: AccountStore = mock()
31+
private val accountRepository: AccountRepository = mock()
4132
private val userEligibilityFetcher: UserEligibilityFetcher = mock()
4233

4334
private lateinit var viewModel: UserEligibilityErrorViewModel
44-
private lateinit var actionCaptor: KArgumentCaptor<Action<*>>
4535

4636
private val testUser = WCUserModel().apply {
4737
remoteUserId = 1L
@@ -56,22 +46,11 @@ class UserEligibilityErrorViewModelTest : BaseUnitTest() {
5646

5747
@Before
5848
fun setup() {
59-
actionCaptor = argumentCaptor()
60-
61-
viewModel = spy(
62-
UserEligibilityErrorViewModel(
63-
SavedStateHandle(),
64-
appPrefsWrapper,
65-
dispatcher,
66-
accountStore,
67-
userEligibilityFetcher
68-
)
69-
)
70-
71-
clearInvocations(
72-
viewModel,
73-
userEligibilityFetcher,
74-
appPrefsWrapper
49+
viewModel = UserEligibilityErrorViewModel(
50+
SavedStateHandle(),
51+
appPrefsWrapper,
52+
accountRepository,
53+
userEligibilityFetcher
7554
)
7655
}
7756

@@ -149,23 +128,17 @@ class UserEligibilityErrorViewModelTest : BaseUnitTest() {
149128
}
150129

151130
@Test
152-
fun `Handles logout button click correctly`() {
153-
doReturn(false).whenever(accountStore).hasAccessToken()
131+
fun `Handles logout button click correctly`() = testBlocking {
132+
doReturn(true).whenever(accountRepository).logout()
154133

155134
var logoutEvent: Logout? = null
156135
viewModel.event.observeForever {
157-
if (it is Logout) logoutEvent = it
136+
logoutEvent = it as? Logout
158137
}
159138

160139
viewModel.onLogoutButtonClicked()
161140

162-
// note that we expect two dispatches because there's one to sign out the user and
163-
// the other to remove WPcom and Jetpack sites from local db
164-
verify(dispatcher, times(2)).dispatch(actionCaptor.capture())
165-
assertEquals(SIGN_OUT, actionCaptor.firstValue.type)
166-
assertEquals(SiteAction.REMOVE_WPCOM_AND_JETPACK_SITES, actionCaptor.secondValue.type)
167-
168-
viewModel.onAccountChanged(OnAccountChanged())
141+
verify(accountRepository).logout()
169142
assertThat(logoutEvent).isNotNull
170143
}
171144
}

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ tasks.register("installGitHooks", Copy) {
9999
}
100100

101101
ext {
102-
fluxCVersion = '2.10.0'
102+
fluxCVersion = 'trunk-463c753ae48797fd0543f237f668b322345eb69b'
103103
glideVersion = '4.13.2'
104104
coilVersion = '2.1.0'
105105
constraintLayoutVersion = '1.2.0'

0 commit comments

Comments
 (0)