diff --git a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt index 819dc0122ac7..c97fe56641cc 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt @@ -19,19 +19,25 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker.Companion.currentUpload import com.nextcloud.client.network.Connectivity import com.nextcloud.client.network.ConnectivityService import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.datamodel.UploadsStorageManager.UploadStatus import com.owncloud.android.db.OCUpload import com.owncloud.android.db.UploadResult import com.owncloud.android.files.services.NameCollisionPolicy +import com.owncloud.android.lib.common.OwnCloudClient import com.owncloud.android.lib.common.network.OnDatatransferProgressListener import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation import com.owncloud.android.lib.resources.files.model.RemoteFile +import com.owncloud.android.operations.RemoveFileOperation import com.owncloud.android.operations.UploadFileOperation import com.owncloud.android.utils.FileUtil +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import java.io.File import java.util.concurrent.Semaphore import javax.inject.Inject @@ -48,6 +54,9 @@ class FileUploadHelper { @Inject lateinit var uploadsStorageManager: UploadsStorageManager + @Inject + lateinit var fileStorageManager: FileDataStorageManager + init { MainApp.getAppComponent().inject(this) } @@ -349,6 +358,41 @@ class FileUploadHelper { backgroundJobManager.startFilesUploadJob(user) } + /** + * Removes any existing file in the same directory that has the same name as the provided new file. + * + * This function checks the parent directory of the given `newFile` for any file with the same name. + * If such a file is found, it is removed using the `RemoveFileOperation`. + * + * @param duplicatedFile File to be deleted + * @param client Needed for executing RemoveFileOperation + * @param user Needed for creating client + */ + fun removeDuplicatedFile(duplicatedFile: OCFile, client: OwnCloudClient, user: User, onCompleted: () -> Unit) { + val job = CoroutineScope(Dispatchers.IO) + + job.launch { + val removeFileOperation = RemoveFileOperation( + duplicatedFile, + false, + user, + true, + MainApp.getAppContext(), + fileStorageManager + ) + + val result = removeFileOperation.execute(client) + + if (result.isSuccess) { + Log_OC.d(TAG, "Replaced file successfully removed") + + launch(Dispatchers.Main) { + onCompleted() + } + } + } + } + fun retryUpload(upload: OCUpload, user: User) { Log_OC.d(this, "retry upload") diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 63be12074521..31672084c093 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -45,6 +45,7 @@ import com.owncloud.android.lib.resources.files.model.GeoLocation; import com.owncloud.android.lib.resources.files.model.ImageDimension; import com.owncloud.android.lib.resources.files.model.RemoteFile; +import com.owncloud.android.lib.resources.files.model.ServerFileInterface; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareeUser; @@ -228,6 +229,23 @@ public List getFolderContent(OCFile ocFile, boolean onlyOnDevice) { } } + public OCFile findDuplicatedFile(OCFile parentFolder, ServerFileInterface newFile) { + List folderContent = getFolderContent(parentFolder, false); + if (folderContent == null || folderContent.isEmpty()) { + return null; + } + + OCFile duplicatedFile = null; + for (OCFile file : folderContent) { + if (file.getFileName().equals(newFile.getFileName())) { + duplicatedFile = file; + break; + } + } + + return duplicatedFile; + } + public List getFolderImages(OCFile folder, boolean onlyOnDevice) { List imageList = new ArrayList<>(); diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index a03a8f0b69f2..f3cb5197f9c5 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -19,6 +19,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.device.BatteryStatus; import com.nextcloud.client.device.PowerManagementService; +import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.jobs.upload.FileUploadWorker; import com.nextcloud.client.network.Connectivity; import com.nextcloud.client.network.ConnectivityService; @@ -162,6 +163,7 @@ public class UploadFileOperation extends SyncOperation { private final PowerManagementService powerManagementService; private boolean encryptedAncestor; + private OCFile duplicatedEncryptedFile; public static OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) { OCFile newFile = new OCFile(remotePath); @@ -492,7 +494,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare List fileNames = getCollidedFileNames(object); - RemoteOperationResult collisionResult = checkNameCollision(client, fileNames, parentFile.isEncrypted()); + RemoteOperationResult collisionResult = checkNameCollision(parentFile, client, fileNames, parentFile.isEncrypted()); if (collisionResult != null) { result = collisionResult; return collisionResult; @@ -849,9 +851,16 @@ private void completeE2EUpload(RemoteOperationResult result, E2EFiles e2eFiles, e2eFiles.deleteTemporalFile(); } + private void deleteDuplicatedFileAndSendRefreshFolderEvent(OwnCloudClient client) { + FileUploadHelper.Companion.instance().removeDuplicatedFile(duplicatedEncryptedFile, client, user, () -> { + duplicatedEncryptedFile = null; + sendRefreshFolderEventBroadcast(); + return null; + }); + } + private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, E2EFiles e2eFiles, RemoteOperationResult result, Object object, OwnCloudClient client, String token) { mUploadStarted.set(false); - sendRefreshFolderEventBroadcast(); if (fileLock != null) { try { @@ -881,6 +890,16 @@ private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, E2EFiles e2eFi result = unlockFolderResult; } + if (unlockFolderResult != null && unlockFolderResult.isSuccess()) { + Log_OC.d(TAG, "Folder successfully unlocked: " + e2eFiles.getParentFile().getFileName()); + + if (duplicatedEncryptedFile != null) { + deleteDuplicatedFileAndSendRefreshFolderEvent(client); + } else { + sendRefreshFolderEventBroadcast(); + } + } + e2eFiles.deleteEncryptedTempFile(); return result; @@ -948,7 +967,7 @@ private RemoteOperationResult normalUpload(OwnCloudClient client) { } // check name collision - RemoteOperationResult collisionResult = checkNameCollision(client, null, false); + RemoteOperationResult collisionResult = checkNameCollision(null, client, null, false); if (collisionResult != null) { result = collisionResult; return collisionResult; @@ -1135,7 +1154,8 @@ private RemoteOperationResult copyFile(File originalFile, String expectedPath) t } @CheckResult - private RemoteOperationResult checkNameCollision(OwnCloudClient client, + private RemoteOperationResult checkNameCollision(OCFile parentFile, + OwnCloudClient client, List fileNames, boolean encrypted) throws OperationCancelledException { @@ -1156,6 +1176,10 @@ private RemoteOperationResult checkNameCollision(OwnCloudClient client, } break; case OVERWRITE: + if (parentFile != null && encrypted) { + duplicatedEncryptedFile = getStorageManager().findDuplicatedFile(parentFile, mFile); + } + Log_OC.d(TAG, "Overwriting file"); break; case ASK_USER: