From f7150d33cbb467ac510bcd7b9d2d078cd6a4582a Mon Sep 17 00:00:00 2001 From: Ramsey Smith <142836716+ramsey-livefront@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:52:39 -0700 Subject: [PATCH] BIT-1704: Edit items in collection bug (#977) --- .../vault/repository/VaultRepositoryImpl.kt | 6 +- .../addedit/util/CipherViewExtensions.kt | 6 +- .../vault/repository/VaultRepositoryTest.kt | 2 +- .../addedit/util/CipherViewExtensionsTest.kt | 171 ++++++++++++++++++ 4 files changed, 182 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index b92784a79..0563915aa 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -744,7 +744,11 @@ class VaultRepositoryImpl( } is UpdateCipherResponseJson.Success -> { - vaultDiskSource.saveCipher(userId = userId, cipher = response.cipher) + vaultDiskSource.saveCipher( + userId = userId, + cipher = response.cipher + .copy(collectionIds = cipherView.collectionIds), + ) UpdateCipherResult.Success } } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index 240ce1dca..a2dd91b08 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -114,6 +114,7 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( ), availableOwners = activeAccount.toAvailableOwners( collectionViewList = collectionViewList, + cipherView = currentContentState.common.originalCipher, isIndividualVaultDisabled = isIndividualVaultDisabled, ), ), @@ -165,6 +166,7 @@ private fun UserState.Account.toSelectedOwnerId(cipherView: CipherView?): String private fun UserState.Account.toAvailableOwners( collectionViewList: List<CollectionView>, + cipherView: CipherView?, isIndividualVaultDisabled: Boolean, ): List<VaultAddEditState.Owner> = listOfNotNull( @@ -188,7 +190,9 @@ private fun UserState.Account.toAvailableOwners( VaultCollection( id = collection.id.orEmpty(), name = collection.name, - isSelected = false, + isSelected = cipherView + ?.collectionIds + ?.contains(collection.id) == true, ) }, ) diff --git a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index 110635804..5d8314b47 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -2021,7 +2021,7 @@ class VaultRepositoryTest { coEvery { vaultDiskSource.saveCipher( userId = userId, - cipher = mockCipher, + cipher = mockCipher.copy(collectionIds = mockCipherView.collectionIds), ) } just runs diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt index 5fab1bd0c..7ee17644e 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt @@ -13,10 +13,20 @@ import com.bitwarden.core.PasswordHistoryView import com.bitwarden.core.SecureNoteType import com.bitwarden.core.SecureNoteView import com.x8bit.bitwarden.R +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.VaultUnlockType +import com.x8bit.bitwarden.data.platform.repository.model.Environment +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.createMockFolderView +import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.manager.resource.ResourceManager import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditState import com.x8bit.bitwarden.ui.vault.feature.addedit.model.UriItem +import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand +import com.x8bit.bitwarden.ui.vault.model.VaultCollection import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType import io.mockk.every import io.mockk.mockk @@ -33,6 +43,7 @@ class CipherViewExtensionsTest { private val resourceManager: ResourceManager = mockk { every { getString(R.string.clone) } returns "Clone" + every { getString(R.string.folder_none) } returns "No Folder" } @BeforeEach @@ -248,6 +259,166 @@ class CipherViewExtensionsTest { result, ) } + + @Test + fun `validateCipherOrReturnErrorState with valid cipher should return provided state`() { + val providedState = VaultAddEditState.ViewState.Loading + + val result = createMockCipherView(number = 1) + .validateCipherOrReturnErrorState( + currentAccount = createAccount(), + vaultAddEditType = VaultAddEditType.AddItem, + ) { _, _ -> providedState } + + assertEquals(providedState, result) + } + + @Test + fun `validateCipherOrReturnErrorState with EditItem null cipher type should return Error`() { + val providedState = VaultAddEditState.ViewState.Loading + + val result = null + .validateCipherOrReturnErrorState( + currentAccount = createAccount(), + vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "mockId-1"), + ) { _, _ -> providedState } + + assertEquals( + VaultAddEditState.ViewState.Error(R.string.generic_error_message.asText()), + result, + ) + } + + @Test + fun `validateCipherOrReturnErrorState with null account type should return Error`() { + val providedState = VaultAddEditState.ViewState.Loading + + val result = createMockCipherView(number = 1) + .validateCipherOrReturnErrorState( + currentAccount = null, + vaultAddEditType = VaultAddEditType.AddItem, + ) { _, _ -> providedState } + + assertEquals( + VaultAddEditState.ViewState.Error(R.string.generic_error_message.asText()), + result, + ) + } + + @Test + fun `appendFolderAndOwnerData should append folder and owner data`() { + val viewState = createSecureNoteViewState(withFolderAndOwnerData = false) + val account = createAccount() + val folderView = listOf(createMockFolderView(number = 1)) + val collectionList = listOf(createMockCollectionView(number = 1)) + + val result = viewState.appendFolderAndOwnerData( + folderViewList = folderView, + collectionViewList = collectionList, + activeAccount = account, + isIndividualVaultDisabled = false, + resourceManager = resourceManager, + ) + + assertEquals( + createSecureNoteViewState(withFolderAndOwnerData = true), + result, + ) + } + + private fun createSecureNoteViewState( + cipherView: CipherView = createMockCipherView(number = 1), + withFolderAndOwnerData: Boolean, + ): VaultAddEditState.ViewState.Content = + VaultAddEditState.ViewState.Content( + common = VaultAddEditState.ViewState.Content.Common( + originalCipher = cipherView, + name = "cipher", + favorite = false, + masterPasswordReprompt = true, + notes = "Lots of notes", + customFieldData = listOf( + VaultAddEditState.Custom.BooleanField( + itemId = TEST_ID, + name = "TestBoolean", + value = false, + ), + VaultAddEditState.Custom.TextField( + itemId = TEST_ID, + name = "TestText", + value = "TestText", + ), + VaultAddEditState.Custom.HiddenField( + itemId = TEST_ID, + name = "TestHidden", + value = "TestHidden", + ), + ), + availableFolders = emptyList(), + availableOwners = emptyList(), + ) + .let { + if (withFolderAndOwnerData) { + it.copy( + selectedFolderId = "mockId-1", + selectedOwnerId = "mockOrganizationId-1", + availableFolders = listOf( + VaultAddEditState.Folder( + id = null, + name = "No Folder", + ), + VaultAddEditState.Folder( + id = "mockId-1", + name = "mockName-1", + ), + ), + availableOwners = listOf( + VaultAddEditState.Owner( + id = null, + name = "activeEmail", + collections = emptyList(), + ), + VaultAddEditState.Owner( + id = "mockOrganizationId-1", + name = "organizationName", + collections = listOf( + VaultCollection( + id = "mockId-1", + name = "mockName-1", + isSelected = true, + ), + ), + ), + ), + ) + } else { + it + } + }, + isIndividualVaultDisabled = true, + type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, + ) + + private fun createAccount(): UserState.Account = + UserState.Account( + userId = "activeUserId", + name = "activeName", + email = "activeEmail", + avatarColorHex = "#ffecbc49", + environment = Environment.Eu, + isPremium = true, + isLoggedIn = false, + isVaultUnlocked = false, + needsPasswordReset = false, + organizations = listOf( + Organization( + id = "mockOrganizationId-1", + name = "organizationName", + ), + ), + isBiometricsEnabled = true, + vaultUnlockType = VaultUnlockType.MASTER_PASSWORD, + ) } private val DEFAULT_BASE_CIPHER_VIEW: CipherView = CipherView(