diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt index 142f04f630..a73bf51cba 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt @@ -227,9 +227,14 @@ class PushManagerImpl @Inject constructor( .decodeFromString( string = notification.payload, ) - .takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) } - ?.folderId - ?.let { mutableSyncFolderDeleteSharedFlow.tryEmit(SyncFolderDeleteData(it)) } + .takeIf { it.userId != null && it.folderId != null } + ?.let { + SyncFolderDeleteData( + userId = requireNotNull(it.userId), + folderId = requireNotNull(it.folderId), + ) + } + ?.let { mutableSyncFolderDeleteSharedFlow.tryEmit(it) } } NotificationType.SYNC_ORG_KEYS -> { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/SyncFolderDeleteData.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/SyncFolderDeleteData.kt index 8f3d7fba36..dac884c591 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/SyncFolderDeleteData.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/manager/model/SyncFolderDeleteData.kt @@ -2,9 +2,8 @@ package com.x8bit.bitwarden.data.platform.manager.model /** * Required data for sync folder delete operations. - * - * @property folderId The folder ID. */ data class SyncFolderDeleteData( + val userId: String, val folderId: String, ) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index 9467c6f504..2ad983a869 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -929,11 +929,9 @@ class VaultRepositoryImpl( } private suspend fun clearFolderIdFromCiphers(folderId: String, userId: String) { - vaultDiskSource.getCiphersFlow(userId).firstOrNull()?.forEach { + vaultDiskSource.getCiphers(userId = userId).forEach { if (it.folderId == folderId) { - vaultDiskSource.saveCipher( - userId, it.copy(folderId = null), - ) + vaultDiskSource.saveCipher(userId = userId, cipher = it.copy(folderId = null)) } } } @@ -1433,16 +1431,13 @@ class VaultRepositoryImpl( * Deletes the folder specified by [syncFolderDeleteData] from disk. */ private suspend fun deleteFolder(syncFolderDeleteData: SyncFolderDeleteData) { - val userId = activeUserId ?: return - - val folderId = syncFolderDeleteData.folderId clearFolderIdFromCiphers( - folderId = folderId, - userId = userId, + folderId = syncFolderDeleteData.folderId, + userId = syncFolderDeleteData.userId, ) vaultDiskSource.deleteFolder( - folderId = folderId, - userId = userId, + folderId = syncFolderDeleteData.folderId, + userId = syncFolderDeleteData.userId, ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt index bc00af6cd9..1a53a56052 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt @@ -285,6 +285,7 @@ class PushManagerTest { pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP) assertEquals( SyncFolderDeleteData( + userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", ), awaitItem(), @@ -425,12 +426,19 @@ class PushManagerTest { } @Test - fun `onMessageReceived with sync folder delete does nothing`() = runTest { - pushManager.syncFolderDeleteFlow.test { - pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP) - expectNoEvents() + fun `onMessageReceived with sync folder delete emits to syncFolderDeleteFlow`() = + runTest { + pushManager.syncFolderDeleteFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP) + assertEquals( + SyncFolderDeleteData( + userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", + folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + ), + awaitItem(), + ) + } } - } @Test fun `onMessageReceived with sync folder update does nothing`() = runTest { diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index e61001b4a0..40bcf2d8b4 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -2834,46 +2834,26 @@ class VaultRepositoryTest { fun `DeleteFolder with folderService Delete success should return DeleteFolderResult Success and update ciphers`() = runTest { fakeAuthDiskSource.userState = MOCK_USER_STATE + val userId = MOCK_USER_STATE.activeUserId val folderId = "mockFolderId-1" + val mockCipher = createMockCipher(number = 1) + val ciphers = listOf(mockCipher, createMockCipher(number = 2)) coEvery { folderService.deleteFolder(folderId) } returns Unit.asSuccess() - coEvery { - vaultDiskSource.deleteFolder( - MOCK_USER_STATE.activeUserId, - folderId, - ) - } just runs - - val mockCipher = createMockCipher(1) - - val mutableCiphersStateFlow = - MutableStateFlow( - listOf( - mockCipher, - createMockCipher(2), - ), - ) - - coEvery { - vaultDiskSource.getCiphersFlow(MOCK_USER_STATE.activeUserId) - } returns mutableCiphersStateFlow - + coEvery { vaultDiskSource.deleteFolder(userId = userId, folderId = folderId) } just runs + coEvery { vaultDiskSource.getCiphers(userId = userId) } returns ciphers coEvery { vaultDiskSource.saveCipher( - MOCK_USER_STATE.activeUserId, - mockCipher.copy( - folderId = null, - ), + userId = userId, + cipher = mockCipher.copy(folderId = null), ) } just runs - val result = vaultRepository.deleteFolder(folderId) + val result = vaultRepository.deleteFolder(folderId = folderId) coVerify(exactly = 1) { vaultDiskSource.saveCipher( - MOCK_USER_STATE.activeUserId, - mockCipher.copy( - folderId = null, - ), + userId = userId, + cipher = mockCipher.copy(folderId = null), ) } @@ -4020,20 +4000,21 @@ class VaultRepositoryTest { fun `syncFolderDeleteFlow should delete folder from disk and update ciphers`() { val userId = "mockId-1" val folderId = "mockId-1" + val cipher = createMockCipher(number = 1, folderId = folderId) + val updatedCipher = createMockCipher(number = 1, folderId = null) - fakeAuthDiskSource.userState = MOCK_USER_STATE coEvery { vaultDiskSource.deleteFolder(userId = userId, folderId = folderId) } just runs - coEvery { - vaultDiskSource.getCiphersFlow(userId) - } returns flowOf() + coEvery { vaultDiskSource.getCiphers(userId = userId) } returns listOf(cipher) + coEvery { vaultDiskSource.saveCipher(userId = userId, cipher = updatedCipher) } just runs mutableSyncFolderDeleteFlow.tryEmit( - SyncFolderDeleteData(folderId = folderId), + SyncFolderDeleteData(userId = userId, folderId = folderId), ) - coVerify { + coVerify(exactly = 1) { vaultDiskSource.deleteFolder(userId = userId, folderId = folderId) - vaultDiskSource.getCiphersFlow(userId) + vaultDiskSource.getCiphers(userId = userId) + vaultDiskSource.saveCipher(userId = userId, cipher = updatedCipher) } }