diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/disk/AuthDiskSourceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/disk/AuthDiskSourceImpl.kt index 767f8a86c..48f33483e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/disk/AuthDiskSourceImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/disk/AuthDiskSourceImpl.kt @@ -23,16 +23,14 @@ private const val ORGANIZATION_KEYS_KEY = "$BASE_KEY:encOrgKeys" /** * Primary implementation of [AuthDiskSource]. */ +@Suppress("TooManyFunctions") class AuthDiskSourceImpl( sharedPreferences: SharedPreferences, private val json: Json, ) : BaseDiskSource(sharedPreferences = sharedPreferences), AuthDiskSource { - private val mutableOrganizationsFlow = - MutableSharedFlow<List<SyncResponseJson.Profile.Organization>?>( - replay = 1, - extraBufferCapacity = Int.MAX_VALUE, - ) + private val mutableOrganizationsFlowMap = + mutableMapOf<String, MutableSharedFlow<List<SyncResponseJson.Profile.Organization>?>>() override val uniqueAppId: String get() = getString(key = UNIQUE_APP_ID_KEY) ?: generateAndStoreUniqueAppId() @@ -108,7 +106,7 @@ class AuthDiskSourceImpl( override fun getOrganizationsFlow( userId: String, ): Flow<List<SyncResponseJson.Profile.Organization>?> = - mutableOrganizationsFlow + getMutableOrganizationsFlow(userId = userId) .onSubscription { emit(getOrganizations(userId = userId)) } override fun storeOrganizations( @@ -119,7 +117,7 @@ class AuthDiskSourceImpl( key = "${ORGANIZATIONS_KEY}_$userId", value = organizations?.let { json.encodeToString(it) }, ) - mutableOrganizationsFlow.tryEmit(organizations) + getMutableOrganizationsFlow(userId = userId).tryEmit(organizations) } private fun generateAndStoreUniqueAppId(): String = @@ -129,4 +127,14 @@ class AuthDiskSourceImpl( .also { putString(key = UNIQUE_APP_ID_KEY, value = it) } + + private fun getMutableOrganizationsFlow( + userId: String, + ): MutableSharedFlow<List<SyncResponseJson.Profile.Organization>?> = + mutableOrganizationsFlowMap.getOrPut(userId) { + MutableSharedFlow( + replay = 1, + extraBufferCapacity = Int.MAX_VALUE, + ) + } } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index c6d126a5d..51229721c 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -27,6 +27,8 @@ import com.x8bit.bitwarden.data.auth.repository.util.CaptchaCallbackTokenResult import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams import com.x8bit.bitwarden.data.auth.repository.util.toUserState import com.x8bit.bitwarden.data.auth.repository.util.toUserStateJson +import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsList +import com.x8bit.bitwarden.data.auth.repository.util.userOrganizationsListFlow import com.x8bit.bitwarden.data.auth.util.KdfParamsConstants.DEFAULT_PBKDF2_ITERATIONS import com.x8bit.bitwarden.data.auth.util.toSdkParams import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager @@ -36,6 +38,7 @@ import com.x8bit.bitwarden.data.platform.util.flatMap import com.x8bit.bitwarden.data.vault.repository.VaultRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -94,14 +97,17 @@ class AuthRepositoryImpl constructor( initialValue = AuthState.Uninitialized, ) + @OptIn(ExperimentalCoroutinesApi::class) override val userStateFlow: StateFlow<UserState?> = combine( authDiskSource.userStateFlow, + authDiskSource.userOrganizationsListFlow, vaultRepository.vaultStateFlow, mutableSpecialCircumstanceStateFlow, - ) { userStateJson, vaultState, specialCircumstance -> + ) { userStateJson, userOrganizationsList, vaultState, specialCircumstance -> userStateJson ?.toUserState( vaultState = vaultState, + userOrganizationsList = userOrganizationsList, specialCircumstance = specialCircumstance, ) } @@ -112,6 +118,7 @@ class AuthRepositoryImpl constructor( .userState ?.toUserState( vaultState = vaultRepository.vaultStateFlow.value, + userOrganizationsList = authDiskSource.userOrganizationsList, specialCircumstance = mutableSpecialCircumstanceStateFlow.value, ), ) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/Organization.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/Organization.kt new file mode 100644 index 000000000..a0c61a9b4 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/Organization.kt @@ -0,0 +1,12 @@ +package com.x8bit.bitwarden.data.auth.repository.model + +/** + * Represents an organization a user may be a member of. + * + * @property id The ID of the organization. + * @property name The name of the organization (if applicable). + */ +data class Organization( + val id: String, + val name: String?, +) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserOrganizations.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserOrganizations.kt new file mode 100644 index 000000000..c57afeb92 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserOrganizations.kt @@ -0,0 +1,9 @@ +package com.x8bit.bitwarden.data.auth.repository.model + +/** + * Associates a list of [organizations] with the given [userId]. + */ +data class UserOrganizations( + val userId: String, + val organizations: List<Organization>, +) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt index f14de951b..4a8d9ed41 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/model/UserState.kt @@ -43,6 +43,7 @@ data class UserState( * @property environment The [Environment] associated with the user's account. * @property isPremium `true` if the account has a premium membership. * @property isVaultUnlocked Whether or not the user's vault is currently unlocked. + * @property organizations List of [Organization]s the user is associated with, if any. */ data class Account( val userId: String, @@ -52,6 +53,7 @@ data class UserState( val environment: Environment, val isPremium: Boolean, val isVaultUnlocked: Boolean, + val organizations: List<Organization>, ) /** diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/AuthDiskSourceExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/AuthDiskSourceExtensions.kt new file mode 100644 index 000000000..5eaba051e --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/AuthDiskSourceExtensions.kt @@ -0,0 +1,55 @@ +package com.x8bit.bitwarden.data.auth.repository.util + +import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource +import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map + +/** + * Returns the current list of [UserOrganizations]. + */ +val AuthDiskSource.userOrganizationsList: List<UserOrganizations> + get() = this + .userState + ?.accounts + .orEmpty() + .map { (userId, _) -> + UserOrganizations( + userId = userId, + organizations = this + .getOrganizations(userId = userId) + .orEmpty() + .toOrganizations(), + ) + } + +/** + * Returns a [Flow] that emits distinct updates to [UserOrganizations]. + */ +@OptIn(ExperimentalCoroutinesApi::class) +val AuthDiskSource.userOrganizationsListFlow: Flow<List<UserOrganizations>> + get() = + this + .userStateFlow + .flatMapLatest { userStateJson -> + combine( + userStateJson + ?.accounts + .orEmpty() + .map { (userId, _) -> + this + .getOrganizationsFlow(userId = userId) + .map { + UserOrganizations( + userId = userId, + organizations = it.orEmpty().toOrganizations(), + ) + } + }, + ) { values -> values.toList() } + } + .distinctUntilChanged() diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt new file mode 100644 index 000000000..019009580 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt @@ -0,0 +1,20 @@ +package com.x8bit.bitwarden.data.auth.repository.util + +import com.x8bit.bitwarden.data.auth.repository.model.Organization +import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson + +/** + * Maps the given [SyncResponseJson.Profile.Organization] to an [Organization]. + */ +fun SyncResponseJson.Profile.Organization.toOrganization(): Organization = + Organization( + id = this.id, + name = this.name, + ) + +/** + * Maps the given list of [SyncResponseJson.Profile.Organization] to a list of + * [Organization]s. + */ +fun List<SyncResponseJson.Profile.Organization>.toOrganizations(): List<Organization> = + this.map { it.toOrganization() } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt index e9509faaa..5b873451c 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensions.kt @@ -1,6 +1,7 @@ package com.x8bit.bitwarden.data.auth.repository.util import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson +import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.platform.repository.util.toEnvironmentUrlsOrDefault import com.x8bit.bitwarden.data.vault.datasource.network.model.SyncResponseJson @@ -42,6 +43,7 @@ fun UserStateJson.toUpdatedUserStateJson( */ fun UserStateJson.toUserState( vaultState: VaultState, + userOrganizationsList: List<UserOrganizations>, specialCircumstance: UserState.SpecialCircumstance?, ): UserState = UserState( @@ -63,6 +65,10 @@ fun UserStateJson.toUserState( .toEnvironmentUrlsOrDefault(), isPremium = accountJson.profile.hasPremium == true, isVaultUnlocked = userId in vaultState.unlockedVaultUserIds, + organizations = userOrganizationsList + .find { it.userId == userId } + ?.organizations + .orEmpty(), ) }, specialCircumstance = specialCircumstance, diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt index 6d41aacd0..1a85d4409 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt @@ -32,8 +32,10 @@ import com.x8bit.bitwarden.data.auth.repository.model.LoginResult import com.x8bit.bitwarden.data.auth.repository.model.PasswordStrengthResult import com.x8bit.bitwarden.data.auth.repository.model.RegisterResult import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult +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.util.CaptchaCallbackTokenResult +import com.x8bit.bitwarden.data.auth.repository.util.toOrganizations import com.x8bit.bitwarden.data.auth.repository.util.toSdkParams import com.x8bit.bitwarden.data.auth.repository.util.toUserState import com.x8bit.bitwarden.data.auth.repository.util.toUserStateJson @@ -143,7 +145,7 @@ class AuthRepositoryTest { } @Test - fun `userStateFlow should update with changes to the UserStateJson and VaultState data`() { + fun `userStateFlow should update according to changes in its underyling data sources`() { fakeAuthDiskSource.userState = null assertEquals( null, @@ -155,6 +157,7 @@ class AuthRepositoryTest { assertEquals( SINGLE_USER_STATE_1.toUserState( vaultState = VAULT_STATE, + userOrganizationsList = emptyList(), specialCircumstance = null, ), repository.userStateFlow.value, @@ -164,6 +167,7 @@ class AuthRepositoryTest { assertEquals( MULTI_USER_STATE.toUserState( vaultState = VAULT_STATE, + userOrganizationsList = emptyList(), specialCircumstance = null, ), repository.userStateFlow.value, @@ -174,6 +178,20 @@ class AuthRepositoryTest { assertEquals( MULTI_USER_STATE.toUserState( vaultState = emptyVaultState, + userOrganizationsList = emptyList(), + specialCircumstance = null, + ), + repository.userStateFlow.value, + ) + + fakeAuthDiskSource.storeOrganizations( + userId = USER_ID_1, + organizations = ORGANIZATIONS, + ) + assertEquals( + MULTI_USER_STATE.toUserState( + vaultState = emptyVaultState, + userOrganizationsList = USER_ORGANIZATIONS, specialCircumstance = null, ), repository.userStateFlow.value, @@ -201,6 +219,7 @@ class AuthRepositoryTest { assertNull(repository.specialCircumstance) val initialUserState = SINGLE_USER_STATE_1.toUserState( vaultState = VAULT_STATE, + userOrganizationsList = emptyList(), specialCircumstance = null, ) mutableVaultStateFlow.value = VAULT_STATE @@ -1173,6 +1192,7 @@ class AuthRepositoryTest { val originalUserId = USER_ID_1 val originalUserState = SINGLE_USER_STATE_1.toUserState( vaultState = VAULT_STATE, + userOrganizationsList = emptyList(), specialCircumstance = null, ) fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 @@ -1203,6 +1223,7 @@ class AuthRepositoryTest { val invalidId = "invalidId" val originalUserState = SINGLE_USER_STATE_1.toUserState( vaultState = VAULT_STATE, + userOrganizationsList = emptyList(), specialCircumstance = null, ) fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 @@ -1231,6 +1252,7 @@ class AuthRepositoryTest { val updatedUserId = USER_ID_2 val originalUserState = MULTI_USER_STATE.toUserState( vaultState = VAULT_STATE, + userOrganizationsList = emptyList(), specialCircumstance = null, ) fakeAuthDiskSource.userState = MULTI_USER_STATE @@ -1494,6 +1516,12 @@ class AuthRepositoryTest { USER_ID_3 to ACCOUNT_3, ), ) + private val USER_ORGANIZATIONS = listOf( + UserOrganizations( + userId = USER_ID_1, + organizations = ORGANIZATIONS.toOrganizations(), + ), + ) private val VAULT_STATE = VaultState( unlockedVaultUserIds = setOf(USER_ID_1), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/AuthDiskSourceExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/AuthDiskSourceExtensionsTest.kt new file mode 100644 index 000000000..38de9f80f --- /dev/null +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/AuthDiskSourceExtensionsTest.kt @@ -0,0 +1,157 @@ +package com.x8bit.bitwarden.data.auth.repository.util + +import app.cash.turbine.test +import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource +import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson +import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson +import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource +import com.x8bit.bitwarden.data.auth.repository.model.Organization +import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations +import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class AuthDiskSourceExtensionsTest { + private val authDiskSource: AuthDiskSource = FakeAuthDiskSource() + + @Test + fun `userOrganizationsList should return data for all available users`() { + val mockAccounts = mapOf( + "userId1" to mockk<AccountJson>(), + "userId2" to mockk<AccountJson>(), + "userId3" to mockk<AccountJson>(), + ) + val userStateJson = mockk<UserStateJson>() { + every { accounts } returns mockAccounts + } + authDiskSource.apply { + userState = userStateJson + storeOrganizations( + userId = "userId1", + organizations = listOf(createMockOrganization(number = 1)), + ) + storeOrganizations( + userId = "userId2", + organizations = listOf(createMockOrganization(number = 2)), + ) + storeOrganizations( + userId = "userId3", + organizations = listOf(createMockOrganization(number = 3)), + ) + } + + assertEquals( + listOf( + UserOrganizations( + userId = "userId1", + organizations = listOf( + Organization( + id = "mockId-1", + name = "mockName-1", + ), + ), + ), + UserOrganizations( + userId = "userId2", + organizations = listOf( + Organization( + id = "mockId-2", + name = "mockName-2", + ), + ), + ), + UserOrganizations( + userId = "userId3", + organizations = listOf( + Organization( + id = "mockId-3", + name = "mockName-3", + ), + ), + ), + ), + authDiskSource.userOrganizationsList, + ) + } + + @Test + fun `userOrganizationsListFlow should emit whenever there are changes to organization data`() = + runTest { + val mockAccounts = mapOf( + "userId1" to mockk<AccountJson>(), + "userId2" to mockk<AccountJson>(), + "userId3" to mockk<AccountJson>(), + ) + val userStateJson = mockk<UserStateJson>() { + every { accounts } returns mockAccounts + } + authDiskSource.apply { + userState = userStateJson + storeOrganizations( + userId = "userId1", + organizations = listOf(createMockOrganization(number = 1)), + ) + } + + authDiskSource.userOrganizationsListFlow.test { + assertEquals( + listOf( + UserOrganizations( + userId = "userId1", + organizations = listOf( + Organization( + id = "mockId-1", + name = "mockName-1", + ), + ), + ), + UserOrganizations( + userId = "userId2", + organizations = emptyList(), + ), + UserOrganizations( + userId = "userId3", + organizations = emptyList(), + ), + ), + awaitItem(), + ) + + authDiskSource.storeOrganizations( + userId = "userId2", + organizations = listOf(createMockOrganization(number = 2)), + ) + + assertEquals( + listOf( + UserOrganizations( + userId = "userId1", + organizations = listOf( + Organization( + id = "mockId-1", + name = "mockName-1", + ), + ), + ), + UserOrganizations( + userId = "userId2", + organizations = listOf( + Organization( + id = "mockId-2", + name = "mockName-2", + ), + ), + ), + UserOrganizations( + userId = "userId3", + organizations = emptyList(), + ), + ), + awaitItem(), + ) + } + } +} diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt new file mode 100644 index 000000000..d3a53d624 --- /dev/null +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt @@ -0,0 +1,40 @@ +package com.x8bit.bitwarden.data.auth.repository.util + +import com.x8bit.bitwarden.data.auth.repository.model.Organization +import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockOrganization +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class SyncResponseJsonExtensionsTest { + @Test + fun `toOrganization should output the correct organization`() { + assertEquals( + Organization( + id = "mockId-1", + name = "mockName-1", + ), + createMockOrganization(number = 1).toOrganization(), + ) + } + + @Test + fun `toOrganizations should output the correct list of organizations`() { + assertEquals( + listOf( + Organization( + id = "mockId-1", + name = "mockName-1", + ), + Organization( + id = "mockId-2", + name = "mockName-2", + ), + ), + listOf( + createMockOrganization(number = 1), + createMockOrganization(number = 2), + ) + .toOrganizations(), + ) + } +} diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt index aa48d1b23..76d9d2115 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/repository/util/UserStateJsonExtensionsTest.kt @@ -4,6 +4,8 @@ import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.UserStateJson import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson +import com.x8bit.bitwarden.data.auth.repository.model.Organization +import com.x8bit.bitwarden.data.auth.repository.model.UserOrganizations import com.x8bit.bitwarden.data.auth.repository.model.UserState import com.x8bit.bitwarden.data.platform.repository.model.Environment import com.x8bit.bitwarden.data.vault.repository.model.VaultState @@ -101,6 +103,12 @@ class UserStateJsonExtensionsTest { environment = Environment.Eu, isPremium = false, isVaultUnlocked = true, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ), ), ), @@ -126,6 +134,17 @@ class UserStateJsonExtensionsTest { vaultState = VaultState( unlockedVaultUserIds = setOf("activeUserId"), ), + userOrganizationsList = listOf( + UserOrganizations( + userId = "activeUserId", + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), + ), + ), specialCircumstance = null, ), ) @@ -146,6 +165,12 @@ class UserStateJsonExtensionsTest { environment = Environment.Eu, isPremium = true, isVaultUnlocked = false, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ), ), specialCircumstance = UserState.SpecialCircumstance.PendingAccountAddition, @@ -172,6 +197,17 @@ class UserStateJsonExtensionsTest { vaultState = VaultState( unlockedVaultUserIds = emptySet(), ), + userOrganizationsList = listOf( + UserOrganizations( + userId = "activeUserId", + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), + ), + ), specialCircumstance = UserState.SpecialCircumstance.PendingAccountAddition, ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt index affe0004c..61f48aaf1 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/landing/LandingViewModelTest.kt @@ -70,6 +70,7 @@ class LandingViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ) @@ -198,6 +199,7 @@ class LandingViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ) val userState = UserState( activeUserId = "activeUserId", diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt index 3e8868c1a..288e05744 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/login/LoginViewModelTest.kt @@ -123,6 +123,7 @@ class LoginViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt index db492600e..2d148f23b 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/auth/feature/vaultunlock/VaultUnlockViewModelTest.kt @@ -106,6 +106,7 @@ class VaultUnlockViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ) @@ -341,6 +342,7 @@ private val DEFAULT_USER_STATE = UserState( avatarColorHex = "#aa00aa", isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt index 51eb2de36..5727b711d 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavViewModelTest.kt @@ -37,6 +37,7 @@ class RootNavViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ), @@ -59,6 +60,7 @@ class RootNavViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = false, + organizations = emptyList(), ), ), ), diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt index fad950a9e..327207cb5 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt @@ -598,6 +598,7 @@ private val DEFAULT_USER_STATE: UserState = UserState( environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt index f7a8e72d4..004188311 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultViewModelTest.kt @@ -126,6 +126,7 @@ class VaultViewModelTest : BaseViewModelTest() { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), ), ) @@ -773,6 +774,7 @@ private val DEFAULT_USER_STATE = UserState( environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = emptyList(), ), UserState.Account( userId = "lockedUserId", @@ -782,6 +784,7 @@ private val DEFAULT_USER_STATE = UserState( environment = Environment.Us, isPremium = false, isVaultUnlocked = false, + organizations = emptyList(), ), ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt index 8b93a3f96..d3cceb61c 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/vault/util/UserStateExtensionsTest.kt @@ -1,6 +1,7 @@ package com.x8bit.bitwarden.ui.vault.feature.vault.util import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson +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.ui.platform.components.model.AccountSummary @@ -51,6 +52,12 @@ class UserStateExtensionsTest { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ), UserState.Account( userId = "lockedUserId", @@ -60,6 +67,12 @@ class UserStateExtensionsTest { environment = Environment.Eu, isPremium = false, isVaultUnlocked = false, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ), UserState.Account( userId = "unlockedUserId", @@ -73,6 +86,12 @@ class UserStateExtensionsTest { ), isPremium = true, isVaultUnlocked = true, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ), ), ) @@ -100,6 +119,12 @@ class UserStateExtensionsTest { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ) .toAccountSummary(isActive = true), ) @@ -125,6 +150,12 @@ class UserStateExtensionsTest { environment = Environment.Us, isPremium = false, isVaultUnlocked = false, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ) .toAccountSummary(isActive = false), ) @@ -154,6 +185,12 @@ class UserStateExtensionsTest { environment = Environment.Us, isPremium = true, isVaultUnlocked = true, + organizations = listOf( + Organization( + id = "organizationId", + name = "organizationName", + ), + ), ), ), )