diff --git a/changelog/unreleased/4938 b/changelog/unreleased/4938 new file mode 100644 index 00000000000..ce917d70c73 --- /dev/null +++ b/changelog/unreleased/4938 @@ -0,0 +1,6 @@ +Bugfix: Refresh share badges when the folder etag is unchanged + +Share badges have been refreshed on pull-to-refresh when a folder etag is unchanged +after the folder is shared or unshared on ownCloud 10. + +https://github.com/owncloud/android/issues/4938 diff --git a/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt index e272d465cfc..60f7280b4b3 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/files/repository/OCFileRepository.kt @@ -404,6 +404,9 @@ class OCFileRepository( } // Fix: What about renames? Need to fix storage path }) + } else if (shareMetadataChanged(localChildToSync, remoteChild)) { + // oC10 does not change the etag when only share metadata changes. + folderContentUpdated.add(childWithRefreshedShareMetadata(remoteChild, localChildToSync, remoteFolder)) } } @@ -609,6 +612,26 @@ class OCFileRepository( deleteOrResetFileFromDatabase(ocFile, onlyFromLocalStorage) } + private fun shareMetadataChanged(localChild: OCFile, remoteChild: OCFile): Boolean = + localChild.sharedByLink != remoteChild.sharedByLink || + (localChild.sharedWithSharee == true) != (remoteChild.sharedWithSharee == true) || + localChild.permissions != remoteChild.permissions + + private fun childWithRefreshedShareMetadata( + remoteChild: OCFile, + localChild: OCFile, + remoteFolder: OCFile, + ): OCFile = + remoteChild.apply { + copyLocalPropertiesFrom(localChild) + // DO NOT update etag till contents are synced. Share fields stay on the remote child. + etag = localChild.etag + needsToUpdateThumbnail = localChild.needsToUpdateThumbnail + if (remoteFolder.isAvailableOffline) { + availableOfflineStatus = AVAILABLE_OFFLINE_PARENT + } + } + private fun deleteOrResetFileFromDatabase(ocFile: OCFile, onlyFromLocalStorage: Boolean) { if (onlyFromLocalStorage) { localFileDataSource.saveFile(ocFile.copy(storagePath = null, etagInConflict = null, lastUsage = null, etag = null)) diff --git a/owncloudData/src/test/java/com/owncloud/android/data/files/repository/OCFileRepositoryTest.kt b/owncloudData/src/test/java/com/owncloud/android/data/files/repository/OCFileRepositoryTest.kt index 70929cc9cb6..fc57d5cf5a1 100644 --- a/owncloudData/src/test/java/com/owncloud/android/data/files/repository/OCFileRepositoryTest.kt +++ b/owncloudData/src/test/java/com/owncloud/android/data/files/repository/OCFileRepositoryTest.kt @@ -1685,6 +1685,71 @@ class OCFileRepositoryTest { } } + @Suppress("MaxLineLength") + @Test + fun `refreshFolder saves a folder child when the etag matches but share badges changed`() { + val ocParentFolderWithoutSpaceId = OC_PARENT_FOLDER_WITH_SPACE_ID.copy(spaceId = null) + val remoteFolderChild = OC_FOLDER_WITH_SPACE_ID.copy(spaceId = null, sharedByLink = true) + val expectedFolderChild = OC_FOLDER_WITH_SPACE_ID.copy(sharedByLink = true) + every { + remoteFileDataSource.refreshFolder( + remotePath = OC_PARENT_FOLDER_WITH_SPACE_ID.remotePath, + accountName = OC_PARENT_FOLDER_WITH_SPACE_ID.owner, + spaceWebDavUrl = OC_SPACE_PERSONAL.root.webDavUrl + ) + } returns listOf(ocParentFolderWithoutSpaceId, remoteFolderChild) + every { + localFileDataSource.getFileByRemotePath( + remotePath = OC_PARENT_FOLDER_WITH_SPACE_ID.remotePath, + owner = OC_PARENT_FOLDER_WITH_SPACE_ID.owner, + spaceId = OC_PARENT_FOLDER_WITH_SPACE_ID.spaceId + ) + } returns OC_PARENT_FOLDER_WITH_SPACE_ID + every { + localFileDataSource.getFolderContent( + folderId = OC_PARENT_FOLDER_WITH_SPACE_ID.id!! + ) + } returns listOf(OC_FOLDER_WITH_SPACE_ID) + every { + localFileDataSource.saveFilesInFolderAndReturnTheFilesThatChanged( + listOfFiles = listOf(expectedFolderChild), + folder = OC_PARENT_FOLDER_WITH_SPACE_ID, + ) + } returns listOf(expectedFolderChild) + + val listOfFiles = ocFileRepository.refreshFolder( + OC_PARENT_FOLDER_WITH_SPACE_ID.remotePath, + OC_PARENT_FOLDER_WITH_SPACE_ID.owner, + OC_PARENT_FOLDER_WITH_SPACE_ID.spaceId, + false + ) + assertEquals(listOf(expectedFolderChild), listOfFiles) + + verify(exactly = 1) { + localSpacesDataSource.getWebDavUrlForSpace( + spaceId = OC_PARENT_FOLDER_WITH_SPACE_ID.spaceId, + accountName = OC_PARENT_FOLDER_WITH_SPACE_ID.owner + ) + remoteFileDataSource.refreshFolder( + remotePath = OC_PARENT_FOLDER_WITH_SPACE_ID.remotePath, + accountName = OC_PARENT_FOLDER_WITH_SPACE_ID.owner, + spaceWebDavUrl = OC_SPACE_PERSONAL.root.webDavUrl + ) + localFileDataSource.getFileByRemotePath( + remotePath = OC_PARENT_FOLDER_WITH_SPACE_ID.remotePath, + owner = OC_PARENT_FOLDER_WITH_SPACE_ID.owner, + spaceId = OC_PARENT_FOLDER_WITH_SPACE_ID.spaceId + ) + localFileDataSource.getFolderContent( + folderId = OC_PARENT_FOLDER_WITH_SPACE_ID.id!! + ) + localFileDataSource.saveFilesInFolderAndReturnTheFilesThatChanged( + listOfFiles = listOf(expectedFolderChild), + folder = OC_PARENT_FOLDER_WITH_SPACE_ID, + ) + } + } + @Suppress("MaxLineLength") @Test fun `refreshFolder returns an empty list of OCFiles when folder and its content already exists in database but there are additional files in conflict in local to be removed`() {