From 2e92b70a0887684d411f5432107c4c4640d93640 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Fri, 13 Nov 2026 16:12:05 +0800 Subject: [PATCH] fix(upload): refresh lock metadata after uploading files Read ordinary file lock metadata from the final remote properties together with the remote file ID. Clear obsolete cached locks when the server reports an unlocked file and retain current remote lock ownership. Assisted-by: Codex:GPT-6 Signed-off-by: Li Wei --- .../operations/upload/UploadFileResolver.kt | 8 ++ .../upload/UploadFileLockStateTest.kt | 93 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 app/src/test/java/com/owncloud/android/operations/upload/UploadFileLockStateTest.kt diff --git a/app/src/main/java/com/owncloud/android/operations/upload/UploadFileResolver.kt b/app/src/main/java/com/owncloud/android/operations/upload/UploadFileResolver.kt index 8a3df939cdc1..cd0f03c789ed 100644 --- a/app/src/main/java/com/owncloud/android/operations/upload/UploadFileResolver.kt +++ b/app/src/main/java/com/owncloud/android/operations/upload/UploadFileResolver.kt @@ -87,6 +87,14 @@ class UploadFileResolver(private val operation: UploadFileOperation) { etag = remoteFile.etag etagOnServer = remoteFile.etag remoteId = remoteFile.remoteId + isLocked = remoteFile.isLocked + lockType = remoteFile.lockType + lockOwnerId = remoteFile.lockOwner + lockOwnerDisplayName = remoteFile.lockOwnerDisplayName + lockOwnerEditor = remoteFile.lockOwnerEditor + lockTimestamp = remoteFile.lockTimestamp + lockTimeout = remoteFile.lockTimeout + lockToken = remoteFile.lockToken permissions = remoteFile.permissions uploadTimestamp = remoteFile.uploadTimestamp isPreviewAvailable = remoteFile.isHasPreview diff --git a/app/src/test/java/com/owncloud/android/operations/upload/UploadFileLockStateTest.kt b/app/src/test/java/com/owncloud/android/operations/upload/UploadFileLockStateTest.kt new file mode 100644 index 000000000000..331b4b471738 --- /dev/null +++ b/app/src/test/java/com/owncloud/android/operations/upload/UploadFileLockStateTest.kt @@ -0,0 +1,93 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.operations.upload + +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.resources.files.model.FileLockType +import com.owncloud.android.lib.resources.files.model.RemoteFile +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.mockito.kotlin.mock + +@Suppress("MagicNumber") +class UploadFileLockStateTest { + private val resolver = UploadFileResolver(mock()) + + @Test + fun uploadedFileUsesCurrentRemoteLockForTheSameAndReplacedIdentity() { + for (remoteId in listOf("old-id", "new-id")) { + val file = previouslyLockedFile() + val remoteFile = RemoteFile("/document.docx").apply { + this.remoteId = remoteId + isLocked = true + lockType = FileLockType.fromValue(0) + lockOwner = "current-owner" + lockOwnerDisplayName = "Current owner" + lockOwnerEditor = "current-editor" + lockTimestamp = 200 + lockTimeout = 600 + lockToken = "current-token" + } + + resolver.updateOCFile(file, remoteFile) + + assertEquals(remoteId, file.remoteId) + assertTrue(file.isLocked) + assertEquals(remoteFile.lockType, file.lockType) + assertEquals("current-owner", file.lockOwnerId) + assertEquals("Current owner", file.lockOwnerDisplayName) + assertEquals("current-editor", file.lockOwnerEditor) + assertEquals(200L, file.lockTimestamp) + assertEquals(600L, file.lockTimeout) + assertEquals("current-token", file.lockToken) + assertEquals(7L, file.fileId) + assertEquals(3L, file.parentId) + assertEquals("/local/document.docx", file.storagePath) + } + } + + @Test + fun unlockedRemoteFileClearsEveryCachedLockFieldForTheSameAndReplacedIdentity() { + for (remoteId in listOf("old-id", "new-id")) { + val file = previouslyLockedFile() + val remoteFile = RemoteFile("/document.docx").apply { + this.remoteId = remoteId + } + + resolver.updateOCFile(file, remoteFile) + + assertEquals(remoteId, file.remoteId) + assertFalse(file.isLocked) + assertNull(file.lockType) + assertNull(file.lockOwnerId) + assertNull(file.lockOwnerDisplayName) + assertNull(file.lockOwnerEditor) + assertEquals(0L, file.lockTimestamp) + assertEquals(0L, file.lockTimeout) + assertNull(file.lockToken) + } + } + + private fun previouslyLockedFile() = OCFile("/document.docx").apply { + fileId = 7 + parentId = 3 + storagePath = "/local/document.docx" + remoteId = "old-id" + isLocked = true + lockType = FileLockType.fromValue(2) + lockOwnerId = "old-owner" + lockOwnerDisplayName = "Old owner" + lockOwnerEditor = "old-editor" + lockTimestamp = 100 + lockTimeout = 300 + lockToken = "old-token" + } +}