mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
PM-11154: Create basic Remove Master Password UI (#3782)
This commit is contained in:
parent
88b674f54c
commit
eac5516a94
20 changed files with 618 additions and 2 deletions
|
@ -1,12 +1,18 @@
|
||||||
package com.x8bit.bitwarden.data.auth.repository.model
|
package com.x8bit.bitwarden.data.auth.repository.model
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an organization a user may be a member of.
|
* Represents an organization a user may be a member of.
|
||||||
*
|
*
|
||||||
* @property id The ID of the organization.
|
* @property id The ID of the organization.
|
||||||
* @property name The name of the organization (if applicable).
|
* @property name The name of the organization (if applicable).
|
||||||
|
* @property shouldUseKeyConnector Indicates that the organization uses a key connector.
|
||||||
|
* @property role The user's role in the organization.
|
||||||
*/
|
*/
|
||||||
data class Organization(
|
data class Organization(
|
||||||
val id: String,
|
val id: String,
|
||||||
val name: String?,
|
val name: String?,
|
||||||
|
val shouldUseKeyConnector: Boolean,
|
||||||
|
val role: OrganizationType,
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,6 +14,8 @@ fun SyncResponseJson.Profile.Organization.toOrganization(): Organization =
|
||||||
Organization(
|
Organization(
|
||||||
id = this.id,
|
id = this.id,
|
||||||
name = this.name,
|
name = this.name,
|
||||||
|
shouldUseKeyConnector = this.shouldUseKeyConnector,
|
||||||
|
role = this.type,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -246,6 +246,9 @@ data class SyncResponseJson(
|
||||||
@SerialName("usePolicies")
|
@SerialName("usePolicies")
|
||||||
val shouldUsePolicies: Boolean,
|
val shouldUsePolicies: Boolean,
|
||||||
|
|
||||||
|
@SerialName("useKeyConnector")
|
||||||
|
val shouldUseKeyConnector: Boolean,
|
||||||
|
|
||||||
@SerialName("keyConnectorUrl")
|
@SerialName("keyConnectorUrl")
|
||||||
val keyConnectorUrl: String?,
|
val keyConnectorUrl: String?,
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.x8bit.bitwarden.ui.auth.feature.removepassword
|
||||||
|
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.NavOptions
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The route for navigating to the [RemovePasswordScreen].
|
||||||
|
*/
|
||||||
|
const val REMOVE_PASSWORD_ROUTE: String = "remove_password"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the Remove Password screen to the nav graph.
|
||||||
|
*/
|
||||||
|
fun NavGraphBuilder.removePasswordDestination() {
|
||||||
|
composable(
|
||||||
|
route = REMOVE_PASSWORD_ROUTE,
|
||||||
|
) {
|
||||||
|
RemovePasswordScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the Remove Password screen.
|
||||||
|
*/
|
||||||
|
fun NavController.navigateToRemovePassword(
|
||||||
|
navOptions: NavOptions? = null,
|
||||||
|
) {
|
||||||
|
this.navigate(REMOVE_PASSWORD_ROUTE, navOptions)
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package com.x8bit.bitwarden.ui.auth.feature.removepassword
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButton
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.dialog.BasicDialogState
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenPasswordField
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||||
|
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top level composable for the Remove Password screen.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun RemovePasswordScreen(
|
||||||
|
viewModel: RemovePasswordViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
|
RemovePasswordDialogs(
|
||||||
|
dialogState = state.dialogState,
|
||||||
|
onDismissRequest = remember(viewModel) {
|
||||||
|
{ viewModel.trySendAction(RemovePasswordAction.DialogDismiss) }
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
|
BitwardenScaffold(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
BitwardenTopAppBar(
|
||||||
|
title = stringResource(id = R.string.remove_master_password),
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
navigationIcon = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { innerPadding ->
|
||||||
|
RemovePasswordScreenContent(
|
||||||
|
state = state,
|
||||||
|
onContinueClick = remember(viewModel) {
|
||||||
|
{ viewModel.trySendAction(RemovePasswordAction.ContinueClick) }
|
||||||
|
},
|
||||||
|
onInputChanged = remember(viewModel) {
|
||||||
|
{ viewModel.trySendAction(RemovePasswordAction.InputChanged(it)) }
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(innerPadding)
|
||||||
|
.fillMaxSize(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RemovePasswordScreenContent(
|
||||||
|
state: RemovePasswordState,
|
||||||
|
onContinueClick: () -> Unit,
|
||||||
|
onInputChanged: (String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = state.description(),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier
|
||||||
|
.standardHorizontalMargin()
|
||||||
|
.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
BitwardenPasswordField(
|
||||||
|
label = stringResource(id = R.string.master_password),
|
||||||
|
value = state.input,
|
||||||
|
onValueChange = onInputChanged,
|
||||||
|
showPasswordTestTag = "PasswordVisibilityToggle",
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag(tag = "MasterPasswordEntry")
|
||||||
|
.standardHorizontalMargin()
|
||||||
|
.fillMaxWidth(),
|
||||||
|
autoFocus = true,
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
BitwardenFilledButton(
|
||||||
|
label = stringResource(id = R.string.continue_text),
|
||||||
|
onClick = onContinueClick,
|
||||||
|
isEnabled = state.input.isNotEmpty(),
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag(tag = "ContinueButton")
|
||||||
|
.standardHorizontalMargin()
|
||||||
|
.fillMaxWidth(),
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun RemovePasswordDialogs(
|
||||||
|
dialogState: RemovePasswordState.DialogState?,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
) {
|
||||||
|
when (dialogState) {
|
||||||
|
is RemovePasswordState.DialogState.Error -> {
|
||||||
|
BitwardenBasicDialog(
|
||||||
|
visibilityState = BasicDialogState.Shown(
|
||||||
|
title = dialogState.title,
|
||||||
|
message = dialogState.message,
|
||||||
|
),
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
private fun RemovePasswordScreen_preview() {
|
||||||
|
BitwardenTheme {
|
||||||
|
RemovePasswordScreenContent(
|
||||||
|
state = RemovePasswordState(
|
||||||
|
input = "",
|
||||||
|
description = "Organization is using SSO with a self-hosted key server.".asText(),
|
||||||
|
dialogState = null,
|
||||||
|
),
|
||||||
|
onContinueClick = { },
|
||||||
|
onInputChanged = { },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package com.x8bit.bitwarden.ui.auth.feature.removepassword
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val KEY_STATE = "state"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages application state for the Set Password screen.
|
||||||
|
*/
|
||||||
|
@HiltViewModel
|
||||||
|
class RemovePasswordViewModel @Inject constructor(
|
||||||
|
private val authRepository: AuthRepository,
|
||||||
|
savedStateHandle: SavedStateHandle,
|
||||||
|
) : BaseViewModel<RemovePasswordState, Unit, RemovePasswordAction>(
|
||||||
|
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||||
|
val orgName = authRepository.userStateFlow.value
|
||||||
|
?.activeAccount
|
||||||
|
?.organizations
|
||||||
|
?.firstOrNull { it.shouldUseKeyConnector }
|
||||||
|
?.name
|
||||||
|
.orEmpty()
|
||||||
|
RemovePasswordState(
|
||||||
|
input = "",
|
||||||
|
description = R.string
|
||||||
|
.organization_is_using_sso_with_a_self_hosted_key_server
|
||||||
|
.asText(orgName),
|
||||||
|
dialogState = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
override fun handleAction(action: RemovePasswordAction) {
|
||||||
|
when (action) {
|
||||||
|
RemovePasswordAction.ContinueClick -> handleContinueClick()
|
||||||
|
is RemovePasswordAction.InputChanged -> handleInputChanged(action)
|
||||||
|
RemovePasswordAction.DialogDismiss -> handleDialogDismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleContinueClick() {
|
||||||
|
// TODO: Process removing the password (PM-11155)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleInputChanged(action: RemovePasswordAction.InputChanged) {
|
||||||
|
mutableStateFlow.update { it.copy(input = action.input) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleDialogDismiss() {
|
||||||
|
mutableStateFlow.update { it.copy(dialogState = null) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models state of the Remove Password screen.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class RemovePasswordState(
|
||||||
|
val input: String,
|
||||||
|
val description: Text,
|
||||||
|
val dialogState: DialogState?,
|
||||||
|
) : Parcelable {
|
||||||
|
/**
|
||||||
|
* Represents the current state of any dialogs on the screen.
|
||||||
|
*/
|
||||||
|
sealed class DialogState : Parcelable {
|
||||||
|
/**
|
||||||
|
* Represents an error dialog with the given [message] and optional [title]. If no title
|
||||||
|
* is specified a default will be provided.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class Error(
|
||||||
|
val title: Text? = null,
|
||||||
|
val message: Text,
|
||||||
|
) : DialogState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models actions for the Remove Password screen.
|
||||||
|
*/
|
||||||
|
sealed class RemovePasswordAction {
|
||||||
|
/**
|
||||||
|
* Indicates that the user has clicked the continue button
|
||||||
|
*/
|
||||||
|
data object ContinueClick : RemovePasswordAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has modified the input.
|
||||||
|
*/
|
||||||
|
data class InputChanged(
|
||||||
|
val input: String,
|
||||||
|
) : RemovePasswordAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the dialog has been dismissed.
|
||||||
|
*/
|
||||||
|
data object DialogDismiss : RemovePasswordAction()
|
||||||
|
}
|
|
@ -615,6 +615,7 @@ Scanning will happen automatically.</string>
|
||||||
<string name="updating_password">Updating password</string>
|
<string name="updating_password">Updating password</string>
|
||||||
<string name="update_password_error">Currently unable to update password</string>
|
<string name="update_password_error">Currently unable to update password</string>
|
||||||
<string name="remove_master_password">Remove master password</string>
|
<string name="remove_master_password">Remove master password</string>
|
||||||
|
<string name="organization_is_using_sso_with_a_self_hosted_key_server">%1$s is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.</string>
|
||||||
<string name="remove_master_password_warning">%1$s is using SSO with customer-managed encryption. Continuing will remove your master password from your account and require SSO to login.</string>
|
<string name="remove_master_password_warning">%1$s is using SSO with customer-managed encryption. Continuing will remove your master password from your account and require SSO to login.</string>
|
||||||
<string name="remove_master_password_warning2">If you do not want to remove your master password, you may leave this organization.</string>
|
<string name="remove_master_password_warning2">If you do not want to remove your master password, you may leave this organization.</string>
|
||||||
<string name="leave_organization">Leave organization</string>
|
<string name="leave_organization">Leave organization</string>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserAccountTokens
|
import com.x8bit.bitwarden.data.auth.repository.model.UserAccountTokens
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
|
import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserSwitchingData
|
import com.x8bit.bitwarden.data.auth.repository.model.UserSwitchingData
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
@ -187,6 +188,8 @@ class AuthDiskSourceExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-1",
|
id = "mockId-1",
|
||||||
name = "mockName-1",
|
name = "mockName-1",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -196,6 +199,8 @@ class AuthDiskSourceExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-2",
|
id = "mockId-2",
|
||||||
name = "mockName-2",
|
name = "mockName-2",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -205,6 +210,8 @@ class AuthDiskSourceExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-3",
|
id = "mockId-3",
|
||||||
name = "mockName-3",
|
name = "mockName-3",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -241,6 +248,8 @@ class AuthDiskSourceExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-1",
|
id = "mockId-1",
|
||||||
name = "mockName-1",
|
name = "mockName-1",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -269,6 +278,8 @@ class AuthDiskSourceExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-1",
|
id = "mockId-1",
|
||||||
name = "mockName-1",
|
name = "mockName-1",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -278,6 +289,8 @@ class AuthDiskSourceExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-2",
|
id = "mockId-2",
|
||||||
name = "mockName-2",
|
name = "mockName-2",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.repository.util
|
||||||
|
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
||||||
|
@ -19,6 +20,8 @@ class SyncResponseJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-1",
|
id = "mockId-1",
|
||||||
name = "mockName-1",
|
name = "mockName-1",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
createMockOrganization(number = 1).toOrganization(),
|
createMockOrganization(number = 1).toOrganization(),
|
||||||
)
|
)
|
||||||
|
@ -31,15 +34,19 @@ class SyncResponseJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-1",
|
id = "mockId-1",
|
||||||
name = "mockName-1",
|
name = "mockName-1",
|
||||||
|
shouldUseKeyConnector = true,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockId-2",
|
id = "mockId-2",
|
||||||
name = "mockName-2",
|
name = "mockName-2",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.USER,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
listOf(
|
listOf(
|
||||||
createMockOrganization(number = 1),
|
createMockOrganization(number = 1).copy(shouldUseKeyConnector = true),
|
||||||
createMockOrganization(number = 2),
|
createMockOrganization(number = 2).copy(type = OrganizationType.USER),
|
||||||
)
|
)
|
||||||
.toOrganizations(),
|
.toOrganizations(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
@ -229,6 +230,8 @@ class UserStateJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBiometricsEnabled = false,
|
isBiometricsEnabled = false,
|
||||||
|
@ -287,6 +290,8 @@ class UserStateJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -320,6 +325,8 @@ class UserStateJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBiometricsEnabled = true,
|
isBiometricsEnabled = true,
|
||||||
|
@ -374,6 +381,8 @@ class UserStateJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -408,6 +417,8 @@ class UserStateJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBiometricsEnabled = false,
|
isBiometricsEnabled = false,
|
||||||
|
@ -470,6 +481,8 @@ class UserStateJsonExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -37,6 +37,7 @@ fun createMockOrganization(
|
||||||
): SyncResponseJson.Profile.Organization =
|
): SyncResponseJson.Profile.Organization =
|
||||||
SyncResponseJson.Profile.Organization(
|
SyncResponseJson.Profile.Organization(
|
||||||
shouldUsePolicies = shouldUsePolicies,
|
shouldUsePolicies = shouldUsePolicies,
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
keyConnectorUrl = "mockKeyConnectorUrl-$number",
|
keyConnectorUrl = "mockKeyConnectorUrl-$number",
|
||||||
type = OrganizationType.ADMIN,
|
type = OrganizationType.ADMIN,
|
||||||
seats = 1,
|
seats = 1,
|
||||||
|
|
|
@ -58,6 +58,7 @@ private const val SYNC_SUCCESS_JSON = """
|
||||||
"organizations": [
|
"organizations": [
|
||||||
{
|
{
|
||||||
"usePolicies": false,
|
"usePolicies": false,
|
||||||
|
"useKeyConnector": false,
|
||||||
"keyConnectorUrl": "mockKeyConnectorUrl-1",
|
"keyConnectorUrl": "mockKeyConnectorUrl-1",
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"seats": 1,
|
"seats": 1,
|
||||||
|
@ -132,6 +133,7 @@ private const val SYNC_SUCCESS_JSON = """
|
||||||
"providerOrganizations": [
|
"providerOrganizations": [
|
||||||
{
|
{
|
||||||
"usePolicies": false,
|
"usePolicies": false,
|
||||||
|
"useKeyConnector": false,
|
||||||
"keyConnectorUrl": "mockKeyConnectorUrl-1",
|
"keyConnectorUrl": "mockKeyConnectorUrl-1",
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"seats": 1,
|
"seats": 1,
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.x8bit.bitwarden.ui.auth.feature.removepassword
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.assert
|
||||||
|
import androidx.compose.ui.test.assertIsEnabled
|
||||||
|
import androidx.compose.ui.test.assertIsNotEnabled
|
||||||
|
import androidx.compose.ui.test.hasAnyAncestor
|
||||||
|
import androidx.compose.ui.test.isDialog
|
||||||
|
import androidx.compose.ui.test.isDisplayed
|
||||||
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
|
import androidx.compose.ui.test.performClick
|
||||||
|
import androidx.compose.ui.test.performScrollTo
|
||||||
|
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class RemovePasswordScreenTest : BaseComposeTest() {
|
||||||
|
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||||
|
val viewModel = mockk<RemovePasswordViewModel>(relaxed = true) {
|
||||||
|
every { eventFlow } returns bufferedMutableSharedFlow()
|
||||||
|
every { stateFlow } returns mutableStateFlow
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
composeTestRule.setContent {
|
||||||
|
RemovePasswordScreen(
|
||||||
|
viewModel = viewModel,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `dialog should update according to state`() {
|
||||||
|
val errorTitle = "message title"
|
||||||
|
val errorMessage = "Error message"
|
||||||
|
composeTestRule.assertNoDialogExists()
|
||||||
|
composeTestRule.onNodeWithText(text = errorTitle).assertDoesNotExist()
|
||||||
|
composeTestRule.onNodeWithText(text = errorMessage).assertDoesNotExist()
|
||||||
|
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(
|
||||||
|
dialogState = RemovePasswordState.DialogState.Error(
|
||||||
|
title = errorTitle.asText(),
|
||||||
|
message = errorMessage.asText(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText(text = errorTitle)
|
||||||
|
.assert(hasAnyAncestor(isDialog()))
|
||||||
|
.isDisplayed()
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText(text = errorMessage)
|
||||||
|
.assert(hasAnyAncestor(isDialog()))
|
||||||
|
.isDisplayed()
|
||||||
|
|
||||||
|
mutableStateFlow.update { it.copy(dialogState = null) }
|
||||||
|
|
||||||
|
composeTestRule.onNode(isDialog()).assertDoesNotExist()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `description should update according to state`() {
|
||||||
|
val description = "description"
|
||||||
|
composeTestRule.onNodeWithText(text = description).assertDoesNotExist()
|
||||||
|
|
||||||
|
mutableStateFlow.update { it.copy(description = description.asText()) }
|
||||||
|
|
||||||
|
composeTestRule.onNodeWithText(text = description).isDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `continue button should update according to state`() {
|
||||||
|
composeTestRule.onNodeWithText(text = "Continue").performScrollTo().assertIsNotEnabled()
|
||||||
|
mutableStateFlow.update { it.copy(input = "a") }
|
||||||
|
composeTestRule.onNodeWithText(text = "Continue").performScrollTo().assertIsEnabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `continue button click should emit ContinueClick`() {
|
||||||
|
mutableStateFlow.update { it.copy(input = "a") }
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText(text = "Continue")
|
||||||
|
.performScrollTo()
|
||||||
|
.performClick()
|
||||||
|
|
||||||
|
verify(exactly = 1) {
|
||||||
|
viewModel.trySendAction(RemovePasswordAction.ContinueClick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DEFAULT_STATE = RemovePasswordState(
|
||||||
|
input = "",
|
||||||
|
dialogState = null,
|
||||||
|
description = "My org".asText(),
|
||||||
|
)
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.x8bit.bitwarden.ui.auth.feature.removepassword
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import app.cash.turbine.test
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
|
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class RemovePasswordViewModelTest : BaseViewModelTest() {
|
||||||
|
private val mutableUserStateFlow = MutableStateFlow<UserState?>(DEFAULT_USER_STATE)
|
||||||
|
private val authRepository: AuthRepository = mockk {
|
||||||
|
every { userStateFlow } returns mutableUserStateFlow
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ContinueClick calls does nothing`() = runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
viewModel.trySendAction(RemovePasswordAction.ContinueClick)
|
||||||
|
expectNoEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `InputChanged updates the state`() {
|
||||||
|
val input = "123"
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
viewModel.trySendAction(RemovePasswordAction.InputChanged(input = input))
|
||||||
|
assertEquals(DEFAULT_STATE.copy(input = input), viewModel.stateFlow.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `DialogDismiss calls clears the dialog state`() = runTest {
|
||||||
|
val initialState = DEFAULT_STATE.copy(
|
||||||
|
dialogState = RemovePasswordState.DialogState.Error(
|
||||||
|
title = "title".asText(),
|
||||||
|
message = "message".asText(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val viewModel = createViewModel(initialState)
|
||||||
|
|
||||||
|
viewModel.stateFlow.test {
|
||||||
|
assertEquals(initialState, awaitItem())
|
||||||
|
viewModel.trySendAction(RemovePasswordAction.DialogDismiss)
|
||||||
|
assertEquals(DEFAULT_STATE, awaitItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createViewModel(
|
||||||
|
state: RemovePasswordState? = null,
|
||||||
|
): RemovePasswordViewModel =
|
||||||
|
RemovePasswordViewModel(
|
||||||
|
authRepository = authRepository,
|
||||||
|
savedStateHandle = SavedStateHandle(mapOf("state" to state)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ORGANIZATION_NAME: String = "My org"
|
||||||
|
private val DEFAULT_STATE = RemovePasswordState(
|
||||||
|
input = "",
|
||||||
|
dialogState = null,
|
||||||
|
description = R.string
|
||||||
|
.organization_is_using_sso_with_a_self_hosted_key_server
|
||||||
|
.asText(ORGANIZATION_NAME),
|
||||||
|
)
|
||||||
|
|
||||||
|
private const val USER_ID: String = "user_id"
|
||||||
|
private val DEFAULT_ACCOUNT = UserState.Account(
|
||||||
|
userId = USER_ID,
|
||||||
|
name = "Active User",
|
||||||
|
email = "active@bitwarden.com",
|
||||||
|
environment = Environment.Us,
|
||||||
|
avatarColorHex = "#aa00aa",
|
||||||
|
isPremium = true,
|
||||||
|
isLoggedIn = true,
|
||||||
|
isVaultUnlocked = true,
|
||||||
|
needsPasswordReset = false,
|
||||||
|
isBiometricsEnabled = false,
|
||||||
|
organizations = listOf(
|
||||||
|
Organization(
|
||||||
|
id = "orgId",
|
||||||
|
name = ORGANIZATION_NAME,
|
||||||
|
shouldUseKeyConnector = true,
|
||||||
|
role = OrganizationType.USER,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
needsMasterPassword = false,
|
||||||
|
trustedDevice = null,
|
||||||
|
hasMasterPassword = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val DEFAULT_USER_STATE = UserState(
|
||||||
|
activeUserId = USER_ID,
|
||||||
|
accounts = listOf(DEFAULT_ACCOUNT),
|
||||||
|
)
|
|
@ -37,6 +37,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||||
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
|
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
|
||||||
import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRepository
|
import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRepository
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||||
|
@ -3878,6 +3879,8 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBiometricsEnabled = true,
|
isBiometricsEnabled = true,
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
import com.x8bit.bitwarden.data.auth.repository.model.VaultUnlockType
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockFolderView
|
||||||
|
@ -434,6 +435,8 @@ class CipherViewExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-1",
|
id = "mockOrganizationId-1",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
isBiometricsEnabled = true,
|
isBiometricsEnabled = true,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
||||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||||
|
@ -490,14 +491,20 @@ private val DEFAULT_USER_STATE = UserState(
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-1",
|
id = "mockOrganizationId-1",
|
||||||
name = "mockOrganizationName-1",
|
name = "mockOrganizationName-1",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-2",
|
id = "mockOrganizationId-2",
|
||||||
name = "mockOrganizationName-2",
|
name = "mockOrganizationName-2",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-3",
|
id = "mockOrganizationId-3",
|
||||||
name = "mockOrganizationName-3",
|
name = "mockOrganizationName-3",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.x8bit.bitwarden.R
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
@ -102,14 +103,20 @@ private fun createMockUserState(hasOrganizations: Boolean = true): UserState =
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-1",
|
id = "mockOrganizationId-1",
|
||||||
name = "mockOrganizationName-1",
|
name = "mockOrganizationName-1",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-2",
|
id = "mockOrganizationId-2",
|
||||||
name = "mockOrganizationName-2",
|
name = "mockOrganizationName-2",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "mockOrganizationId-3",
|
id = "mockOrganizationId-3",
|
||||||
name = "mockOrganizationName-3",
|
name = "mockOrganizationName-3",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl
|
import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.PolicyTypeJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||||
|
@ -187,6 +188,8 @@ class VaultViewModelTest : BaseViewModelTest() {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organiationId",
|
id = "organiationId",
|
||||||
name = "Test Organization",
|
name = "Test Organization",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -267,6 +270,8 @@ class VaultViewModelTest : BaseViewModelTest() {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "Test Organization",
|
name = "Test Organization",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -471,6 +476,8 @@ class VaultViewModelTest : BaseViewModelTest() {
|
||||||
Organization(
|
Organization(
|
||||||
id = "testOrganizationId",
|
id = "testOrganizationId",
|
||||||
name = "Test Organization",
|
name = "Test Organization",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJso
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
import com.x8bit.bitwarden.data.vault.datasource.network.model.OrganizationType
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterData
|
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterData
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||||
|
@ -76,6 +77,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -97,6 +100,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -122,6 +127,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -147,6 +154,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -187,6 +196,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -225,6 +236,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -267,6 +280,8 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId",
|
id = "organizationId",
|
||||||
name = "organizationName",
|
name = "organizationName",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -336,10 +351,14 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId-B",
|
id = "organizationId-B",
|
||||||
name = "Organization B",
|
name = "Organization B",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId-A",
|
id = "organizationId-A",
|
||||||
name = "Organization A",
|
name = "Organization A",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
@ -385,10 +404,14 @@ class UserStateExtensionsTest {
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId-B",
|
id = "organizationId-B",
|
||||||
name = "Organization B",
|
name = "Organization B",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
Organization(
|
Organization(
|
||||||
id = "organizationId-A",
|
id = "organizationId-A",
|
||||||
name = "Organization A",
|
name = "Organization A",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
role = OrganizationType.ADMIN,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trustedDevice = null,
|
trustedDevice = null,
|
||||||
|
|
Loading…
Reference in a new issue