From 6bc6d9de3835005ed2d93e01e14d3eb160e0d084 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 16 Jul 2024 08:06:01 +0100 Subject: [PATCH 01/19] feat: create new worker to remove local file after upload file --- .../android/workers/RemoveLocalFileWorker.kt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt new file mode 100644 index 00000000000..a999d253e4a --- /dev/null +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt @@ -0,0 +1,74 @@ +/** + * ownCloud Android client application + * + * @author Aitor Ballesteros Pavón + * + * Copyright (C) 2024 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.workers + +import android.content.Context +import android.net.Uri +import androidx.core.net.toUri +import androidx.documentfile.provider.DocumentFile +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import com.owncloud.android.domain.camerauploads.model.UploadBehavior +import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.KEY_PARAM_BEHAVIOR +import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.KEY_PARAM_CONTENT_URI +import org.koin.core.component.KoinComponent +import timber.log.Timber + +class RemoveLocalFileWorker( + private val appContext: Context, + private val workerParameters: WorkerParameters +) : CoroutineWorker( + appContext, + workerParameters +), KoinComponent { + + private lateinit var behavior: UploadBehavior + private lateinit var contentUri: Uri + + override suspend fun doWork(): Result { + if (!areParametersValid()) return Result.failure() + return try { + // File is already uploaded, so the original one can be removed if the behaviour is MOVE + if (behavior == UploadBehavior.MOVE) { + removeLocalFile() + } + Result.success() + } catch (throwable: Throwable) { + Timber.e(throwable) + Result.failure() + } + } + + private fun areParametersValid(): Boolean { + val paramBehavior = workerParameters.inputData.getString(KEY_PARAM_BEHAVIOR) + val paramContentUri = workerParameters.inputData.getString(KEY_PARAM_CONTENT_URI) + + contentUri = paramContentUri?.toUri() ?: return false + behavior = paramBehavior?.let { UploadBehavior.fromString(it) } ?: return false + + return true + } + + private fun removeLocalFile() { + val documentFile = DocumentFile.fromSingleUri(appContext, contentUri) + documentFile?.delete() + } +} From de1b4ef10b4854565ebcf771da68123d2aa52ff1 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 16 Jul 2024 08:07:31 +0100 Subject: [PATCH 02/19] feat: added removeLocalFileWorker to UploadFileFromContentUriUseCase --- .../UploadFileFromContentUriUseCase.kt | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index 3d27c62a756..04e876fc4b1 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -3,8 +3,9 @@ * * @author Abel García de Prada * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2022 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -28,6 +29,7 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.workDataOf import com.owncloud.android.domain.BaseUseCase +import com.owncloud.android.workers.RemoveLocalFileWorker import com.owncloud.android.workers.UploadFileFromContentUriWorker import timber.log.Timber @@ -36,7 +38,7 @@ class UploadFileFromContentUriUseCase( ) : BaseUseCase() { override fun run(params: Params) { - val inputData = workDataOf( + val inputDataUploadFileFromContentUriWorker = workDataOf( UploadFileFromContentUriWorker.KEY_PARAM_ACCOUNT_NAME to params.accountName, UploadFileFromContentUriWorker.KEY_PARAM_BEHAVIOR to params.behavior, UploadFileFromContentUriWorker.KEY_PARAM_CONTENT_URI to params.contentUri.toString(), @@ -44,6 +46,10 @@ class UploadFileFromContentUriUseCase( UploadFileFromContentUriWorker.KEY_PARAM_UPLOAD_PATH to params.uploadPath, UploadFileFromContentUriWorker.KEY_PARAM_UPLOAD_ID to params.uploadIdInStorageManager ) + val inputDataRemoveLocalFileWorker = workDataOf( + UploadFileFromContentUriWorker.KEY_PARAM_BEHAVIOR to params.behavior, + UploadFileFromContentUriWorker.KEY_PARAM_CONTENT_URI to params.contentUri.toString(), + ) val networkRequired = if (params.wifiOnly) NetworkType.UNMETERED else NetworkType.CONNECTED val constraints = Constraints.Builder() @@ -52,13 +58,20 @@ class UploadFileFromContentUriUseCase( .build() val uploadFileFromContentUriWorker = OneTimeWorkRequestBuilder() - .setInputData(inputData) + .setInputData(inputDataUploadFileFromContentUriWorker) .setConstraints(constraints) .addTag(params.accountName) .addTag(params.uploadIdInStorageManager.toString()) .build() - workManager.enqueue(uploadFileFromContentUriWorker) + val removeLocalFileWorker = OneTimeWorkRequestBuilder() + .setInputData(inputDataRemoveLocalFileWorker) + .build() + + workManager.beginWith(uploadFileFromContentUriWorker) + .then(removeLocalFileWorker) + .enqueue() + Timber.i("Plain upload of ${params.contentUri.path} has been enqueued.") } From 8b1c648ad318357acb0edc8d0e1d50446f4e8912 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 16 Jul 2024 08:09:22 +0100 Subject: [PATCH 03/19] feat: remove code relate to removeLocalFile() in UploadFileFromContentUriWorker --- .../workers/UploadFileFromContentUriWorker.kt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt index 8e9dc12c5ce..7085082afcb 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt @@ -30,7 +30,6 @@ import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import androidx.work.workDataOf import com.owncloud.android.R -import com.owncloud.android.presentation.authentication.AccountUtils import com.owncloud.android.data.executeRemoteOperation import com.owncloud.android.data.providers.LocalStorageProvider import com.owncloud.android.domain.camerauploads.model.UploadBehavior @@ -57,6 +56,7 @@ import com.owncloud.android.lib.resources.files.UploadFileFromFileSystemOperatio import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSystemOperation import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSystemOperation.Companion.CHUNK_SIZE import com.owncloud.android.lib.resources.files.services.implementation.OCChunkService +import com.owncloud.android.presentation.authentication.AccountUtils import com.owncloud.android.utils.NotificationUtils import com.owncloud.android.utils.RemoteFileUtils.Companion.getAvailableRemotePath import com.owncloud.android.utils.SecurityUtils @@ -195,16 +195,6 @@ class UploadFileFromContentUriWorker( outputStream.close() transferRepository.updateTransferLocalPath(uploadIdInStorageManager, cachePath) - - // File is already in cache, so the original one can be removed if the behaviour is MOVE - if (behavior == UploadBehavior.MOVE) { - removeLocalFile() - } - } - - private fun removeLocalFile() { - val documentFile = DocumentFile.fromSingleUri(appContext, contentUri) - documentFile?.delete() } private fun getClientForThisUpload(): OwnCloudClient = From 197a1beeff571496fca7d55467eb222b82721dd6 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 16 Jul 2024 08:13:16 +0100 Subject: [PATCH 04/19] feat: changed comment place to UploadFileFromContentUriUseCase --- .../transfers/uploads/UploadFileFromContentUriUseCase.kt | 2 +- .../java/com/owncloud/android/workers/RemoveLocalFileWorker.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index 04e876fc4b1..d01b4097c50 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -69,7 +69,7 @@ class UploadFileFromContentUriUseCase( .build() workManager.beginWith(uploadFileFromContentUriWorker) - .then(removeLocalFileWorker) + .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE .enqueue() Timber.i("Plain upload of ${params.contentUri.path} has been enqueued.") diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt index a999d253e4a..4b3fc3d8efc 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt @@ -46,7 +46,6 @@ class RemoveLocalFileWorker( override suspend fun doWork(): Result { if (!areParametersValid()) return Result.failure() return try { - // File is already uploaded, so the original one can be removed if the behaviour is MOVE if (behavior == UploadBehavior.MOVE) { removeLocalFile() } From 7fba59c53504408354823b82dcea3bbf4b0ab1c3 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 16 Jul 2024 09:05:23 +0100 Subject: [PATCH 05/19] chore: added calens file --- changelog/unreleased/4437 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changelog/unreleased/4437 diff --git a/changelog/unreleased/4437 b/changelog/unreleased/4437 new file mode 100644 index 00000000000..e259e7c374b --- /dev/null +++ b/changelog/unreleased/4437 @@ -0,0 +1,6 @@ +Enhancement: Improved "Remove from original folder" option in auto-upload + +The file will be deleted locally after it has been uploaded to the server, avoiding the loss of the file if an error happens during the upload. + +https://github.com/owncloud/android/issues/4357 +https://github.com/owncloud/android/pull/4437 From ea0becd85f9604635fdba7c84f9288c48d6098a0 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 16 Jul 2024 08:06:06 +0000 Subject: [PATCH 06/19] docs: calens changelog updated --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe42c1b3d78..87df36c7898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ ownCloud admins and users. * Bugfix - Shares in non-root are updated correctly: [#4432](https://github.com/owncloud/android/issues/4432) * Enhancement - Improved accessibility of information and relationships: [#4362](https://github.com/owncloud/android/issues/4362) +* Enhancement - Improved "Remove from original folder" option in auto-upload: [#4357](https://github.com/owncloud/android/issues/4357) * Enhancement - Changed the color of some elements to improve accessibility: [#4364](https://github.com/owncloud/android/issues/4364) * Enhancement - Improved SearchView accessibility: [#4365](https://github.com/owncloud/android/issues/4365) * Enhancement - Hardware keyboard support: [#4438](https://github.com/owncloud/android/pull/4438) @@ -60,6 +61,14 @@ ownCloud admins and users. https://github.com/owncloud/android/issues/4371 https://github.com/owncloud/android/pull/4448 +* Enhancement - Improved "Remove from original folder" option in auto-upload: [#4357](https://github.com/owncloud/android/issues/4357) + + The file will be deleted locally after it has been uploaded to the server, + avoiding the loss of the file if an error happens during the upload. + + https://github.com/owncloud/android/issues/4357 + https://github.com/owncloud/android/pull/4437 + * Enhancement - Changed the color of some elements to improve accessibility: [#4364](https://github.com/owncloud/android/issues/4364) The color of some UI elements has been changed to meet minimum color contrast From 8c60e0725b5ea4c01075cde750b58b776e2a0235 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Mon, 22 Jul 2024 07:40:17 +0100 Subject: [PATCH 07/19] fix: moved behavior condition to UploadFileFromContentUriUseCase and some refactor --- .../uploads/UploadFileFromContentUriUseCase.kt | 18 ++++++++++-------- .../android/workers/RemoveLocalFileWorker.kt | 15 ++------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index d01b4097c50..0f12f3f7096 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -29,6 +29,7 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.workDataOf import com.owncloud.android.domain.BaseUseCase +import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.workers.RemoveLocalFileWorker import com.owncloud.android.workers.UploadFileFromContentUriWorker import timber.log.Timber @@ -47,7 +48,6 @@ class UploadFileFromContentUriUseCase( UploadFileFromContentUriWorker.KEY_PARAM_UPLOAD_ID to params.uploadIdInStorageManager ) val inputDataRemoveLocalFileWorker = workDataOf( - UploadFileFromContentUriWorker.KEY_PARAM_BEHAVIOR to params.behavior, UploadFileFromContentUriWorker.KEY_PARAM_CONTENT_URI to params.contentUri.toString(), ) @@ -64,13 +64,15 @@ class UploadFileFromContentUriUseCase( .addTag(params.uploadIdInStorageManager.toString()) .build() - val removeLocalFileWorker = OneTimeWorkRequestBuilder() - .setInputData(inputDataRemoveLocalFileWorker) - .build() - - workManager.beginWith(uploadFileFromContentUriWorker) - .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE - .enqueue() + var workContinuation = workManager.beginWith(uploadFileFromContentUriWorker) + val behavior = UploadBehavior.fromString(params.behavior) + if (behavior == UploadBehavior.MOVE) { + val removeLocalFileWorker = OneTimeWorkRequestBuilder() + .setInputData(inputDataRemoveLocalFileWorker) + .build() + workContinuation = workContinuation.then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE + } + workContinuation.enqueue() Timber.i("Plain upload of ${params.contentUri.path} has been enqueued.") } diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt index 4b3fc3d8efc..d365c144710 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt @@ -26,8 +26,6 @@ import androidx.core.net.toUri import androidx.documentfile.provider.DocumentFile import androidx.work.CoroutineWorker import androidx.work.WorkerParameters -import com.owncloud.android.domain.camerauploads.model.UploadBehavior -import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.KEY_PARAM_BEHAVIOR import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.KEY_PARAM_CONTENT_URI import org.koin.core.component.KoinComponent import timber.log.Timber @@ -40,15 +38,13 @@ class RemoveLocalFileWorker( workerParameters ), KoinComponent { - private lateinit var behavior: UploadBehavior private lateinit var contentUri: Uri override suspend fun doWork(): Result { if (!areParametersValid()) return Result.failure() return try { - if (behavior == UploadBehavior.MOVE) { - removeLocalFile() - } + val documentFile = DocumentFile.fromSingleUri(appContext, contentUri) + documentFile?.delete() Result.success() } catch (throwable: Throwable) { Timber.e(throwable) @@ -57,17 +53,10 @@ class RemoveLocalFileWorker( } private fun areParametersValid(): Boolean { - val paramBehavior = workerParameters.inputData.getString(KEY_PARAM_BEHAVIOR) val paramContentUri = workerParameters.inputData.getString(KEY_PARAM_CONTENT_URI) contentUri = paramContentUri?.toUri() ?: return false - behavior = paramBehavior?.let { UploadBehavior.fromString(it) } ?: return false return true } - - private fun removeLocalFile() { - val documentFile = DocumentFile.fromSingleUri(appContext, contentUri) - documentFile?.delete() - } } From 2f74054912a8b7493702ad191e3eda77c79fd4af Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Wed, 24 Jul 2024 08:04:22 +0100 Subject: [PATCH 08/19] fix: changed logic of worContinuation and added an else condition --- .../transfers/uploads/UploadFileFromContentUriUseCase.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index 0f12f3f7096..7070a55f4d0 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -64,15 +64,18 @@ class UploadFileFromContentUriUseCase( .addTag(params.uploadIdInStorageManager.toString()) .build() - var workContinuation = workManager.beginWith(uploadFileFromContentUriWorker) val behavior = UploadBehavior.fromString(params.behavior) if (behavior == UploadBehavior.MOVE) { val removeLocalFileWorker = OneTimeWorkRequestBuilder() .setInputData(inputDataRemoveLocalFileWorker) .build() - workContinuation = workContinuation.then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE + workManager.beginWith(uploadFileFromContentUriWorker) + .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE + .enqueue() + } else { + workManager.beginWith(uploadFileFromContentUriWorker) + .enqueue() } - workContinuation.enqueue() Timber.i("Plain upload of ${params.contentUri.path} has been enqueued.") } From 22858e7bdf08772cd63ec461194a7d6b02a422a5 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Mon, 29 Jul 2024 16:19:31 +0100 Subject: [PATCH 09/19] fix: removed beginWith when it is not necessary --- .../transfers/uploads/UploadFileFromContentUriUseCase.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index 7070a55f4d0..b576f7e10f9 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -73,8 +73,7 @@ class UploadFileFromContentUriUseCase( .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE .enqueue() } else { - workManager.beginWith(uploadFileFromContentUriWorker) - .enqueue() + workManager.enqueue(uploadFileFromContentUriWorker) } Timber.i("Plain upload of ${params.contentUri.path} has been enqueued.") From b723794bf746aff9b733cbb842f81ad0c2b0de60 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:26:33 +0100 Subject: [PATCH 10/19] fix: auto-migration room database with the new column sourcePath in Transfer table --- .../45.json | 1128 +++++++++++++++++ .../owncloud/android/data/OwncloudDatabase.kt | 1 + .../owncloud/android/data/ProviderMeta.java | 2 +- .../data/transfers/db/OCTransferEntity.kt | 4 +- .../domain/transfers/model/OCTransfer.kt | 4 +- 5 files changed, 1136 insertions(+), 3 deletions(-) create mode 100644 owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/45.json diff --git a/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/45.json b/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/45.json new file mode 100644 index 00000000000..4aca004c8b6 --- /dev/null +++ b/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/45.json @@ -0,0 +1,1128 @@ +{ + "formatVersion": 1, + "database": { + "version": 45, + "identityHash": "c31966355395e44a297570c614cd97d1", + "entities": [ + { + "tableName": "app_registry", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`account_name` TEXT NOT NULL, `mime_type` TEXT NOT NULL, `ext` TEXT, `app_providers` TEXT NOT NULL, `name` TEXT, `icon` TEXT, `description` TEXT, `allow_creation` INTEGER, `default_application` TEXT, PRIMARY KEY(`account_name`, `mime_type`))", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mimeType", + "columnName": "mime_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ext", + "columnName": "ext", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appProviders", + "columnName": "app_providers", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "icon", + "columnName": "icon", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "allowCreation", + "columnName": "allow_creation", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "defaultApplication", + "columnName": "default_application", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "account_name", + "mime_type" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "folder_backup", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountName` TEXT NOT NULL, `behavior` TEXT NOT NULL, `sourcePath` TEXT NOT NULL, `uploadPath` TEXT NOT NULL, `wifiOnly` INTEGER NOT NULL, `chargingOnly` INTEGER NOT NULL, `name` TEXT NOT NULL, `lastSyncTimestamp` INTEGER NOT NULL, `spaceId` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "behavior", + "columnName": "behavior", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sourcePath", + "columnName": "sourcePath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "uploadPath", + "columnName": "uploadPath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "wifiOnly", + "columnName": "wifiOnly", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "chargingOnly", + "columnName": "chargingOnly", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastSyncTimestamp", + "columnName": "lastSyncTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "spaceId", + "columnName": "spaceId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "capabilities", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`account` TEXT, `version_major` INTEGER NOT NULL, `version_minor` INTEGER NOT NULL, `version_micro` INTEGER NOT NULL, `version_string` TEXT, `version_edition` TEXT, `core_pollinterval` INTEGER NOT NULL, `dav_chunking_version` TEXT NOT NULL, `sharing_api_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_read_only` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_read_write` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_public_only` INTEGER NOT NULL DEFAULT -1, `sharing_public_expire_date_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_expire_date_days` INTEGER NOT NULL, `sharing_public_expire_date_enforced` INTEGER NOT NULL DEFAULT -1, `sharing_public_upload` INTEGER NOT NULL DEFAULT -1, `sharing_public_multiple` INTEGER NOT NULL DEFAULT -1, `supports_upload_only` INTEGER NOT NULL DEFAULT -1, `sharing_resharing` INTEGER NOT NULL DEFAULT -1, `sharing_federation_outgoing` INTEGER NOT NULL DEFAULT -1, `sharing_federation_incoming` INTEGER NOT NULL DEFAULT -1, `sharing_user_profile_picture` INTEGER NOT NULL DEFAULT -1, `files_bigfilechunking` INTEGER NOT NULL DEFAULT -1, `files_undelete` INTEGER NOT NULL DEFAULT -1, `files_versioning` INTEGER NOT NULL DEFAULT -1, `files_private_links` INTEGER NOT NULL DEFAULT -1, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `app_providers_enabled` INTEGER, `app_providers_version` TEXT, `app_providers_appsUrl` TEXT, `app_providers_openUrl` TEXT, `app_providers_openWebUrl` TEXT, `app_providers_newUrl` TEXT, `spaces_enabled` INTEGER, `spaces_projects` INTEGER, `spaces_shareJail` INTEGER, `password_policy_maxCharacters` INTEGER, `password_policy_minCharacters` INTEGER, `password_policy_minDigits` INTEGER, `password_policy_minLowercaseCharacters` INTEGER, `password_policy_minSpecialCharacters` INTEGER, `password_policy_minUppercaseCharacters` INTEGER)", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionMajor", + "columnName": "version_major", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionMinor", + "columnName": "version_minor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionMicro", + "columnName": "version_micro", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "versionString", + "columnName": "version_string", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionEdition", + "columnName": "version_edition", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "corePollInterval", + "columnName": "core_pollinterval", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "davChunkingVersion", + "columnName": "dav_chunking_version", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filesSharingApiEnabled", + "columnName": "sharing_api_enabled", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicEnabled", + "columnName": "sharing_public_enabled", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforced", + "columnName": "sharing_public_password_enforced", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforcedReadOnly", + "columnName": "sharing_public_password_enforced_read_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforcedReadWrite", + "columnName": "sharing_public_password_enforced_read_write", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicPasswordEnforcedUploadOnly", + "columnName": "sharing_public_password_enforced_public_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicExpireDateEnabled", + "columnName": "sharing_public_expire_date_enabled", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicExpireDateDays", + "columnName": "sharing_public_expire_date_days", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "filesSharingPublicExpireDateEnforced", + "columnName": "sharing_public_expire_date_enforced", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicUpload", + "columnName": "sharing_public_upload", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicMultiple", + "columnName": "sharing_public_multiple", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingPublicSupportsUploadOnly", + "columnName": "supports_upload_only", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingResharing", + "columnName": "sharing_resharing", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingFederationOutgoing", + "columnName": "sharing_federation_outgoing", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingFederationIncoming", + "columnName": "sharing_federation_incoming", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesSharingUserProfilePicture", + "columnName": "sharing_user_profile_picture", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesBigFileChunking", + "columnName": "files_bigfilechunking", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesUndelete", + "columnName": "files_undelete", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesVersioning", + "columnName": "files_versioning", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "filesPrivateLinks", + "columnName": "files_private_links", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appProviders.enabled", + "columnName": "app_providers_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "appProviders.version", + "columnName": "app_providers_version", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appProviders.appsUrl", + "columnName": "app_providers_appsUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appProviders.openUrl", + "columnName": "app_providers_openUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appProviders.openWebUrl", + "columnName": "app_providers_openWebUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "appProviders.newUrl", + "columnName": "app_providers_newUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "spaces.enabled", + "columnName": "spaces_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "spaces.projects", + "columnName": "spaces_projects", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "spaces.shareJail", + "columnName": "spaces_shareJail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "passwordPolicy.maxCharacters", + "columnName": "password_policy_maxCharacters", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "passwordPolicy.minCharacters", + "columnName": "password_policy_minCharacters", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "passwordPolicy.minDigits", + "columnName": "password_policy_minDigits", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "passwordPolicy.minLowercaseCharacters", + "columnName": "password_policy_minLowercaseCharacters", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "passwordPolicy.minSpecialCharacters", + "columnName": "password_policy_minSpecialCharacters", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "passwordPolicy.minUppercaseCharacters", + "columnName": "password_policy_minUppercaseCharacters", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "files", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`parentId` INTEGER, `owner` TEXT NOT NULL, `remotePath` TEXT NOT NULL, `remoteId` TEXT, `length` INTEGER NOT NULL, `creationTimestamp` INTEGER, `modificationTimestamp` INTEGER NOT NULL, `mimeType` TEXT NOT NULL, `etag` TEXT, `permissions` TEXT, `privateLink` TEXT, `storagePath` TEXT, `name` TEXT, `treeEtag` TEXT, `keepInSync` INTEGER, `lastSyncDateForData` INTEGER, `lastUsage` INTEGER, `fileShareViaLink` INTEGER, `needsToUpdateThumbnail` INTEGER NOT NULL, `modifiedAtLastSyncForData` INTEGER, `etagInConflict` TEXT, `fileIsDownloading` INTEGER, `sharedWithSharee` INTEGER, `sharedByLink` INTEGER NOT NULL, `spaceId` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`owner`, `spaceId`) REFERENCES `spaces`(`account_name`, `space_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "owner", + "columnName": "owner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "remotePath", + "columnName": "remotePath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "creationTimestamp", + "columnName": "creationTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "modificationTimestamp", + "columnName": "modificationTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mimeType", + "columnName": "mimeType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "privateLink", + "columnName": "privateLink", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "storagePath", + "columnName": "storagePath", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "treeEtag", + "columnName": "treeEtag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "availableOfflineStatus", + "columnName": "keepInSync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastSyncDateForData", + "columnName": "lastSyncDateForData", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastUsage", + "columnName": "lastUsage", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileShareViaLink", + "columnName": "fileShareViaLink", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "needsToUpdateThumbnail", + "columnName": "needsToUpdateThumbnail", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "modifiedAtLastSyncForData", + "columnName": "modifiedAtLastSyncForData", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etagInConflict", + "columnName": "etagInConflict", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileIsDownloading", + "columnName": "fileIsDownloading", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharedWithSharee", + "columnName": "sharedWithSharee", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharedByLink", + "columnName": "sharedByLink", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "spaceId", + "columnName": "spaceId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "spaces", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "owner", + "spaceId" + ], + "referencedColumns": [ + "account_name", + "space_id" + ] + } + ] + }, + { + "tableName": "files_sync", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fileId` INTEGER NOT NULL, `uploadWorkerUuid` BLOB, `downloadWorkerUuid` BLOB, `isSynchronizing` INTEGER NOT NULL, PRIMARY KEY(`fileId`), FOREIGN KEY(`fileId`) REFERENCES `files`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "fileId", + "columnName": "fileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "uploadWorkerUuid", + "columnName": "uploadWorkerUuid", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "downloadWorkerUuid", + "columnName": "downloadWorkerUuid", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "isSynchronizing", + "columnName": "isSynchronizing", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "fileId" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "files", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "fileId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "ocshares", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`share_type` INTEGER NOT NULL, `share_with` TEXT, `path` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `shared_date` INTEGER NOT NULL, `expiration_date` INTEGER NOT NULL, `token` TEXT, `shared_with_display_name` TEXT, `share_with_additional_info` TEXT, `is_directory` INTEGER NOT NULL, `id_remote_shared` TEXT NOT NULL, `owner_share` TEXT NOT NULL, `name` TEXT, `url` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "shareType", + "columnName": "share_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shareWith", + "columnName": "share_with", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sharedDate", + "columnName": "shared_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expirationDate", + "columnName": "expiration_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedWithDisplayName", + "columnName": "shared_with_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedWithAdditionalInfo", + "columnName": "share_with_additional_info", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isFolder", + "columnName": "is_directory", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "id_remote_shared", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountOwner", + "columnName": "owner_share", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shareLink", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transfers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localPath` TEXT NOT NULL, `remotePath` TEXT NOT NULL, `accountName` TEXT NOT NULL, `fileSize` INTEGER NOT NULL, `status` INTEGER NOT NULL, `localBehaviour` INTEGER NOT NULL, `forceOverwrite` INTEGER NOT NULL, `transferEndTimestamp` INTEGER, `lastResult` INTEGER, `createdBy` INTEGER NOT NULL, `transferId` TEXT, `spaceId` TEXT, `sourcePath` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "localPath", + "columnName": "localPath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "remotePath", + "columnName": "remotePath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fileSize", + "columnName": "fileSize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localBehaviour", + "columnName": "localBehaviour", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "forceOverwrite", + "columnName": "forceOverwrite", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "transferEndTimestamp", + "columnName": "transferEndTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastResult", + "columnName": "lastResult", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdBy", + "columnName": "createdBy", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "transferId", + "columnName": "transferId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "spaceId", + "columnName": "spaceId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sourcePath", + "columnName": "sourcePath", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "spaces", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`account_name` TEXT NOT NULL, `drive_alias` TEXT NOT NULL, `drive_type` TEXT NOT NULL, `space_id` TEXT NOT NULL, `last_modified_date_time` TEXT, `name` TEXT NOT NULL, `owner_id` TEXT, `web_url` TEXT NOT NULL, `description` TEXT, `quota_remaining` INTEGER, `quota_state` TEXT, `quota_total` INTEGER, `quota_used` INTEGER, `root_etag` TEXT, `root_id` TEXT NOT NULL, `root_web_dav_url` TEXT NOT NULL, `root_deleted_state` TEXT, PRIMARY KEY(`account_name`, `space_id`))", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "driveAlias", + "columnName": "drive_alias", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "driveType", + "columnName": "drive_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "space_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastModifiedDateTime", + "columnName": "last_modified_date_time", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ownerId", + "columnName": "owner_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "webUrl", + "columnName": "web_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "quota.remaining", + "columnName": "quota_remaining", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "quota.state", + "columnName": "quota_state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "quota.total", + "columnName": "quota_total", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "quota.used", + "columnName": "quota_used", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "root.eTag", + "columnName": "root_etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "root.id", + "columnName": "root_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "root.webDavUrl", + "columnName": "root_web_dav_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "root.deleteState", + "columnName": "root_deleted_state", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "account_name", + "space_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "spaces_special", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`spaces_special_account_name` TEXT NOT NULL, `spaces_special_space_id` TEXT NOT NULL, `spaces_special_etag` TEXT NOT NULL, `file_mime_type` TEXT NOT NULL, `special_id` TEXT NOT NULL, `last_modified_date_time` TEXT NOT NULL, `name` TEXT NOT NULL, `size` INTEGER NOT NULL, `special_folder_name` TEXT NOT NULL, `special_web_dav_url` TEXT NOT NULL, PRIMARY KEY(`spaces_special_space_id`, `special_id`), FOREIGN KEY(`spaces_special_account_name`, `spaces_special_space_id`) REFERENCES `spaces`(`account_name`, `space_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "spaces_special_account_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "spaceId", + "columnName": "spaces_special_space_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "eTag", + "columnName": "spaces_special_etag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fileMimeType", + "columnName": "file_mime_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "special_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastModifiedDateTime", + "columnName": "last_modified_date_time", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "specialFolderName", + "columnName": "special_folder_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "webDavUrl", + "columnName": "special_web_dav_url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "spaces_special_space_id", + "special_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "spaces", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "spaces_special_account_name", + "spaces_special_space_id" + ], + "referencedColumns": [ + "account_name", + "space_id" + ] + } + ] + }, + { + "tableName": "user_quotas", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountName` TEXT NOT NULL, `used` INTEGER NOT NULL, `available` INTEGER NOT NULL, PRIMARY KEY(`accountName`))", + "fields": [ + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "used", + "columnName": "used", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "available", + "columnName": "available", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "accountName" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c31966355395e44a297570c614cd97d1')" + ] + } +} \ No newline at end of file diff --git a/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt b/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt index 6613a7f20f7..b923e56a772 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt @@ -79,6 +79,7 @@ import com.owncloud.android.data.user.db.UserQuotaEntity AutoMigration(from = 39, to = 40, spec = AutoMigration39To40::class), AutoMigration(from = 40, to = 41), AutoMigration(from = 43, to = 44), + AutoMigration(from = 44, to = 45), ], version = ProviderMeta.DB_VERSION, exportSchema = true diff --git a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java index ace813be3e2..71f09044d5f 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java +++ b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java @@ -31,7 +31,7 @@ public class ProviderMeta { public static final String DB_NAME = "filelist"; public static final String NEW_DB_NAME = "owncloud_database"; - public static final int DB_VERSION = 44; + public static final int DB_VERSION = 45; private ProviderMeta() { } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt index 32d3da8f56e..96d9813e772 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/OCTransferEntity.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2023 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -54,6 +55,7 @@ data class OCTransferEntity( val createdBy: Int, val transferId: String? = null, val spaceId: String? = null, + val sourcePath: String? = null, ) { @PrimaryKey(autoGenerate = true) var id: Long = 0 diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt index b757d45c9e8..aa4733f6d8d 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/model/OCTransfer.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2023 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -40,6 +41,7 @@ data class OCTransfer( val createdBy: UploadEnqueuedBy, val transferId: String? = null, val spaceId: String? = null, + val sourcePath: String? = null, ) : Parcelable { init { if (!remotePath.startsWith(File.separator)) throw IllegalArgumentException("Remote path must be an absolute path in the local file system") From 02077f6d9f71084e56e162afde7e7ab5fa589597 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:28:06 +0100 Subject: [PATCH 11/19] fix: added updateTransferSourcePath func to dao, datasource and repository --- .../transfers/datasources/LocalTransferDataSource.kt | 4 +++- .../implementation/OCLocalTransferDataSource.kt | 9 ++++++++- .../android/data/transfers/db/TransferDao.kt | 12 ++++++++++-- .../transfers/repository/OCTransferRepository.kt | 7 ++++++- .../android/domain/transfers/TransferRepository.kt | 4 +++- 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt index 4662bb6c452..f46bcdaae49 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/LocalTransferDataSource.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2022 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -38,6 +39,7 @@ interface LocalTransferDataSource { ) fun updateTransferLocalPath(id: Long, localPath: String) + fun updateTransferSourcePath(id: Long, sourcePath: String) fun updateTransferStorageDirectoryInLocalPath( id: Long, oldDirectory: String, diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt index dfde793f7db..e149545590a 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSource.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2023 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -64,6 +65,10 @@ class OCLocalTransferDataSource( transferDao.updateTransferLocalPath(id, localPath) } + override fun updateTransferSourcePath(id: Long, sourcePath: String) { + transferDao.updateTransferSourcePath(id, sourcePath) + } + override fun updateTransferStorageDirectoryInLocalPath( id: Long, oldDirectory: String, @@ -163,6 +168,7 @@ class OCLocalTransferDataSource( createdBy = UploadEnqueuedBy.values()[createdBy], transferId = transferId, spaceId = spaceId, + sourcePath = sourcePath, ) @VisibleForTesting fun OCTransfer.toEntity() = OCTransferEntity( @@ -178,6 +184,7 @@ class OCLocalTransferDataSource( createdBy = createdBy.ordinal, transferId = transferId, spaceId = spaceId, + sourcePath = sourcePath, ).apply { this@toEntity.id?.let { this.id = it } } } } diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt index ce4b17e8bdc..56f358626ff 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/db/TransferDao.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2022 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -56,6 +57,9 @@ interface TransferDao { @Query(UPDATE_TRANSFER_LOCAL_PATH_WITH_ID) fun updateTransferLocalPath(id: Long, localPath: String) + @Query(UPDATE_TRANSFER_SOURCE_PATH_WITH_ID) + fun updateTransferSourcePath(id: Long, sourcePath: String) + @Query(UPDATE_TRANSFER_STORAGE_DIRECTORY) fun updateTransferStorageDirectoryInLocalPath(id: Long, oldDirectory: String, newDirectory: String) @@ -111,7 +115,11 @@ interface TransferDao { SET localPath = :localPath WHERE id = :id """ - + private const val UPDATE_TRANSFER_SOURCE_PATH_WITH_ID = """ + UPDATE $TRANSFERS_TABLE_NAME + SET sourcePath = :sourcePath + WHERE id = :id + """ private const val UPDATE_TRANSFER_STORAGE_DIRECTORY = """ UPDATE $TRANSFERS_TABLE_NAME SET localPath = `REPLACE`(localPath, :oldDirectory, :newDirectory) diff --git a/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt b/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt index 00f5e196fdc..7f3c07a9499 100644 --- a/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt +++ b/owncloudData/src/main/java/com/owncloud/android/data/transfers/repository/OCTransferRepository.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2022 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -48,6 +49,10 @@ class OCTransferRepository( localTransferDataSource.updateTransferLocalPath(id = id, localPath = localPath) } + override fun updateTransferSourcePath(id: Long, sourcePath: String) { + localTransferDataSource.updateTransferSourcePath(id = id, sourcePath = sourcePath) + } + override fun updateTransferWhenFinished( id: Long, status: TransferStatus, diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt index 23855a3a93c..5eea7df2daf 100644 --- a/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt +++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/transfers/TransferRepository.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2022 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -31,6 +32,7 @@ interface TransferRepository { fun updateTransferStatusToInProgressById(id: Long) fun updateTransferStatusToEnqueuedById(id: Long) fun updateTransferLocalPath(id: Long, localPath: String) + fun updateTransferSourcePath(id: Long, sourcePath: String) fun updateTransferWhenFinished( id: Long, status: TransferStatus, From e37c04f666d578e46deaa1f5b18116e6ad0879d6 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:29:35 +0100 Subject: [PATCH 12/19] fix: added sourcePath parameter to uploadFileFromSystemUseCase in RetryUploadFromSystemUseCase --- .../transfers/uploads/RetryUploadFromSystemUseCase.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt index 6b6fd06bcaa..b1dbd61b904 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/RetryUploadFromSystemUseCase.kt @@ -25,7 +25,6 @@ package com.owncloud.android.usecases.transfers.uploads import androidx.work.WorkInfo import androidx.work.WorkManager import com.owncloud.android.domain.BaseUseCase -import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.transfers.TransferRepository import com.owncloud.android.extensions.getWorkInfoByTags import com.owncloud.android.workers.UploadFileFromFileSystemWorker @@ -58,8 +57,9 @@ class RetryUploadFromSystemUseCase( accountName = uploadToRetry.accountName, localPath = uploadToRetry.localPath, lastModifiedInSeconds = (uploadToRetry.transferEndTimestamp?.div(1000)).toString(), - behavior = UploadBehavior.MOVE.name, + behavior = uploadToRetry.localBehaviour.name, uploadPath = uploadToRetry.remotePath, + sourcePath = uploadToRetry.sourcePath, uploadIdInStorageManager = params.uploadIdInStorageManager ) ) From 5b1ac773f2b585bd831ad5e290bcb2bacc5718dd Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:32:02 +0100 Subject: [PATCH 13/19] fix: updated sourcePath before uploading the file --- .../android/workers/UploadFileFromContentUriWorker.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt index 7085082afcb..120fc336caf 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromContentUriWorker.kt @@ -3,8 +3,9 @@ * * @author Abel García de Prada * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2023 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -194,6 +195,7 @@ class UploadFileFromContentUriWorker( inputStream?.close() outputStream.close() + transferRepository.updateTransferSourcePath(uploadIdInStorageManager, contentUri.toString()) transferRepository.updateTransferLocalPath(uploadIdInStorageManager, cachePath) } From 48cd37c48ccace4bf60a199a28bd3608847a9a2c Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:36:44 +0100 Subject: [PATCH 14/19] fix: Removed source file if the retry upload is successful --- .../uploads/UploadFileFromSystemUseCase.kt | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt index 6560b44b713..7bb3e00950b 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt @@ -2,8 +2,9 @@ * ownCloud Android client application * * @author Juan Carlos Garrote Gascón + * @author Aitor Ballesteros Pavón * - * Copyright (C) 2022 ownCloud GmbH. + * Copyright (C) 2024 ownCloud GmbH. *

* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -26,6 +27,9 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.workDataOf import com.owncloud.android.domain.BaseUseCase +import com.owncloud.android.domain.camerauploads.model.UploadBehavior +import com.owncloud.android.workers.RemoveLocalFileWorker +import com.owncloud.android.workers.UploadFileFromContentUriWorker import com.owncloud.android.workers.UploadFileFromFileSystemWorker import timber.log.Timber @@ -34,7 +38,7 @@ class UploadFileFromSystemUseCase( ) : BaseUseCase() { override fun run(params: Params) { - val inputData = workDataOf( + val inputDataUploadFileFromFileSystemWorker = workDataOf( UploadFileFromFileSystemWorker.KEY_PARAM_ACCOUNT_NAME to params.accountName, UploadFileFromFileSystemWorker.KEY_PARAM_BEHAVIOR to params.behavior, UploadFileFromFileSystemWorker.KEY_PARAM_LOCAL_PATH to params.localPath, @@ -42,19 +46,33 @@ class UploadFileFromSystemUseCase( UploadFileFromFileSystemWorker.KEY_PARAM_UPLOAD_PATH to params.uploadPath, UploadFileFromFileSystemWorker.KEY_PARAM_UPLOAD_ID to params.uploadIdInStorageManager ) + val inputDataRemoveLocalFileWorker = workDataOf( + UploadFileFromContentUriWorker.KEY_PARAM_CONTENT_URI to params.sourcePath, + ) val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() val uploadFileFromSystemWorker = OneTimeWorkRequestBuilder() - .setInputData(inputData) + .setInputData(inputDataUploadFileFromFileSystemWorker) .setConstraints(constraints) .addTag(params.accountName) .addTag(params.uploadIdInStorageManager.toString()) .build() - workManager.enqueue(uploadFileFromSystemWorker) + val behavior = UploadBehavior.fromString(params.behavior) + if (behavior == UploadBehavior.MOVE) { + val removeLocalFileWorker = OneTimeWorkRequestBuilder() + .setInputData(inputDataRemoveLocalFileWorker) + .build() + workManager.beginWith(uploadFileFromSystemWorker) + .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE + .enqueue() + } else { + workManager.enqueue(uploadFileFromSystemWorker) + } + Timber.i("Plain upload of ${params.localPath} has been enqueued.") } @@ -65,5 +83,6 @@ class UploadFileFromSystemUseCase( val behavior: String, val uploadPath: String, val uploadIdInStorageManager: Long, + val sourcePath: String? = null, ) } From 01db1a6b543b7556860f50c32b72f1d085479e08 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:40:25 +0100 Subject: [PATCH 15/19] fix: removed condition, the tmp file will be always removed --- .../android/workers/UploadFileFromFileSystemWorker.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromFileSystemWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromFileSystemWorker.kt index c0b4180ea24..1942d2674be 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromFileSystemWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/UploadFileFromFileSystemWorker.kt @@ -27,7 +27,6 @@ import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import androidx.work.workDataOf import com.owncloud.android.R -import com.owncloud.android.presentation.authentication.AccountUtils import com.owncloud.android.data.executeRemoteOperation import com.owncloud.android.domain.camerauploads.model.UploadBehavior import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase @@ -55,6 +54,7 @@ import com.owncloud.android.lib.resources.files.UploadFileFromFileSystemOperatio import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSystemOperation import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSystemOperation.Companion.CHUNK_SIZE import com.owncloud.android.lib.resources.files.services.implementation.OCChunkService +import com.owncloud.android.presentation.authentication.AccountUtils import com.owncloud.android.utils.NotificationUtils import com.owncloud.android.utils.RemoteFileUtils.Companion.getAvailableRemotePath import com.owncloud.android.utils.SecurityUtils @@ -250,8 +250,8 @@ class UploadFileFromFileSystemWorker( val result = executeRemoteOperation { uploadFileOperation.execute(client) } - if (result == Unit && behavior == UploadBehavior.MOVE) { - removeLocalFile() + if (result == Unit) { + removeLocalFile() // Removed file from tmp folder } } @@ -288,8 +288,8 @@ class UploadFileFromFileSystemWorker( fileLength = fileSize ) - // Step 4: Remove local file after uploading - if (result == Unit && behavior == UploadBehavior.MOVE) { + // Step 4: Remove tmp file folder after uploading + if (result == Unit) { removeLocalFile() } } From b6bda56e3ac1fe132f84aea6d49f32a321b5fdfe Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Tue, 6 Aug 2024 10:40:47 +0100 Subject: [PATCH 16/19] fix: added new func test in data source --- .../implementation/OCLocalTransferDataSourceTest.kt | 10 ++++++++++ .../java/com/owncloud/android/testutil/OCTransfer.kt | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/owncloudData/src/test/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSourceTest.kt b/owncloudData/src/test/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSourceTest.kt index ba092c8c330..df3bcca4496 100644 --- a/owncloudData/src/test/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSourceTest.kt +++ b/owncloudData/src/test/java/com/owncloud/android/data/transfers/datasources/implementation/OCLocalTransferDataSourceTest.kt @@ -122,6 +122,16 @@ class OCLocalTransferDataSourceTest { } } + @Test + fun `updateTransferSourcePath changes transfer source path correctly`() { + + ocLocalTransferDataSource.updateTransferSourcePath(OC_TRANSFER.id!!, OC_TRANSFER.sourcePath!!) + + verify(exactly = 1) { + transferDao.updateTransferSourcePath(OC_TRANSFER.id!!, OC_TRANSFER.sourcePath!!) + } + } + @Test fun `updateTransferStorageDirectoryInLocalPath changes directory correctly`() { val oldDirectory = "oldDirectory" diff --git a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCTransfer.kt b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCTransfer.kt index 8ed70060c45..e66031b5a78 100644 --- a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCTransfer.kt +++ b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCTransfer.kt @@ -34,5 +34,6 @@ val OC_TRANSFER = OCTransfer( status = TransferStatus.TRANSFER_IN_PROGRESS, localBehaviour = UploadBehavior.MOVE, forceOverwrite = true, - createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER + createdBy = UploadEnqueuedBy.ENQUEUED_BY_USER, + sourcePath = "/source/path", ) From 39a8cbe8325791b82bb5bd6a39292ca8e1552869 Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Mon, 12 Aug 2024 12:07:29 +0100 Subject: [PATCH 17/19] fix: renamed to RemoveSourceFileWorker --- .../uploads/UploadFileFromContentUriUseCase.kt | 10 +++++----- .../transfers/uploads/UploadFileFromSystemUseCase.kt | 10 +++++----- ...oveLocalFileWorker.kt => RemoveSourceFileWorker.kt} | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename owncloudApp/src/main/java/com/owncloud/android/workers/{RemoveLocalFileWorker.kt => RemoveSourceFileWorker.kt} (98%) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt index b576f7e10f9..ab4a0475000 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromContentUriUseCase.kt @@ -30,7 +30,7 @@ import androidx.work.WorkManager import androidx.work.workDataOf import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.camerauploads.model.UploadBehavior -import com.owncloud.android.workers.RemoveLocalFileWorker +import com.owncloud.android.workers.RemoveSourceFileWorker import com.owncloud.android.workers.UploadFileFromContentUriWorker import timber.log.Timber @@ -47,7 +47,7 @@ class UploadFileFromContentUriUseCase( UploadFileFromContentUriWorker.KEY_PARAM_UPLOAD_PATH to params.uploadPath, UploadFileFromContentUriWorker.KEY_PARAM_UPLOAD_ID to params.uploadIdInStorageManager ) - val inputDataRemoveLocalFileWorker = workDataOf( + val inputDataRemoveSourceFileWorker = workDataOf( UploadFileFromContentUriWorker.KEY_PARAM_CONTENT_URI to params.contentUri.toString(), ) @@ -66,11 +66,11 @@ class UploadFileFromContentUriUseCase( val behavior = UploadBehavior.fromString(params.behavior) if (behavior == UploadBehavior.MOVE) { - val removeLocalFileWorker = OneTimeWorkRequestBuilder() - .setInputData(inputDataRemoveLocalFileWorker) + val removeSourceFileWorker = OneTimeWorkRequestBuilder() + .setInputData(inputDataRemoveSourceFileWorker) .build() workManager.beginWith(uploadFileFromContentUriWorker) - .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE + .then(removeSourceFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE .enqueue() } else { workManager.enqueue(uploadFileFromContentUriWorker) diff --git a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt index 7bb3e00950b..6a219462de0 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/usecases/transfers/uploads/UploadFileFromSystemUseCase.kt @@ -28,7 +28,7 @@ import androidx.work.WorkManager import androidx.work.workDataOf import com.owncloud.android.domain.BaseUseCase import com.owncloud.android.domain.camerauploads.model.UploadBehavior -import com.owncloud.android.workers.RemoveLocalFileWorker +import com.owncloud.android.workers.RemoveSourceFileWorker import com.owncloud.android.workers.UploadFileFromContentUriWorker import com.owncloud.android.workers.UploadFileFromFileSystemWorker import timber.log.Timber @@ -46,7 +46,7 @@ class UploadFileFromSystemUseCase( UploadFileFromFileSystemWorker.KEY_PARAM_UPLOAD_PATH to params.uploadPath, UploadFileFromFileSystemWorker.KEY_PARAM_UPLOAD_ID to params.uploadIdInStorageManager ) - val inputDataRemoveLocalFileWorker = workDataOf( + val inputDataRemoveSourceFileWorker = workDataOf( UploadFileFromContentUriWorker.KEY_PARAM_CONTENT_URI to params.sourcePath, ) @@ -63,11 +63,11 @@ class UploadFileFromSystemUseCase( val behavior = UploadBehavior.fromString(params.behavior) if (behavior == UploadBehavior.MOVE) { - val removeLocalFileWorker = OneTimeWorkRequestBuilder() - .setInputData(inputDataRemoveLocalFileWorker) + val removeSourceFileWorker = OneTimeWorkRequestBuilder() + .setInputData(inputDataRemoveSourceFileWorker) .build() workManager.beginWith(uploadFileFromSystemWorker) - .then(removeLocalFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE + .then(removeSourceFileWorker) // File is already uploaded, so the original one can be removed if the behaviour is MOVE .enqueue() } else { workManager.enqueue(uploadFileFromSystemWorker) diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveSourceFileWorker.kt similarity index 98% rename from owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt rename to owncloudApp/src/main/java/com/owncloud/android/workers/RemoveSourceFileWorker.kt index d365c144710..c16b5b0f54e 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveLocalFileWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/RemoveSourceFileWorker.kt @@ -30,7 +30,7 @@ import com.owncloud.android.workers.UploadFileFromContentUriWorker.Companion.KEY import org.koin.core.component.KoinComponent import timber.log.Timber -class RemoveLocalFileWorker( +class RemoveSourceFileWorker( private val appContext: Context, private val workerParameters: WorkerParameters ) : CoroutineWorker( From 57a347679aba5a4c4416a0dbb0a50445808aa9da Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Wed, 14 Aug 2024 13:32:00 +0100 Subject: [PATCH 18/19] refactor: added comma --- .../java/com/owncloud/android/workers/DownloadFileWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owncloudApp/src/main/java/com/owncloud/android/workers/DownloadFileWorker.kt b/owncloudApp/src/main/java/com/owncloud/android/workers/DownloadFileWorker.kt index 585f8aaee5e..3d004608257 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/workers/DownloadFileWorker.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/workers/DownloadFileWorker.kt @@ -76,7 +76,7 @@ class DownloadFileWorker( private val workerParameters: WorkerParameters ) : CoroutineWorker( appContext, - workerParameters + workerParameters, ), KoinComponent, OnDatatransferProgressListener { private val getFileByIdUseCase: GetFileByIdUseCase by inject() From 048fd74b240e9dc0f0e7ca185ee2bc91fa58c21c Mon Sep 17 00:00:00 2001 From: Aitorbp Date: Wed, 14 Aug 2024 13:40:39 +0000 Subject: [PATCH 19/19] docs: calens changelog updated --- CHANGELOG.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87df36c7898..fbec3fac663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,8 @@ ownCloud admins and users. ## Summary * Bugfix - Shares in non-root are updated correctly: [#4432](https://github.com/owncloud/android/issues/4432) -* Enhancement - Improved accessibility of information and relationships: [#4362](https://github.com/owncloud/android/issues/4362) * Enhancement - Improved "Remove from original folder" option in auto-upload: [#4357](https://github.com/owncloud/android/issues/4357) +* Enhancement - Improved accessibility of information and relationships: [#4362](https://github.com/owncloud/android/issues/4362) * Enhancement - Changed the color of some elements to improve accessibility: [#4364](https://github.com/owncloud/android/issues/4364) * Enhancement - Improved SearchView accessibility: [#4365](https://github.com/owncloud/android/issues/4365) * Enhancement - Hardware keyboard support: [#4438](https://github.com/owncloud/android/pull/4438) @@ -49,6 +49,14 @@ ownCloud admins and users. https://github.com/owncloud/android/issues/4432 https://github.com/owncloud/android/pull/4435 +* Enhancement - Improved "Remove from original folder" option in auto-upload: [#4357](https://github.com/owncloud/android/issues/4357) + + The file will be deleted locally after it has been uploaded to the server, + avoiding the loss of the file if an error happens during the upload. + + https://github.com/owncloud/android/issues/4357 + https://github.com/owncloud/android/pull/4437 + * Enhancement - Improved accessibility of information and relationships: [#4362](https://github.com/owncloud/android/issues/4362) Headings have been added to the following views: Share, Edit/Create Share Link, @@ -61,14 +69,6 @@ ownCloud admins and users. https://github.com/owncloud/android/issues/4371 https://github.com/owncloud/android/pull/4448 -* Enhancement - Improved "Remove from original folder" option in auto-upload: [#4357](https://github.com/owncloud/android/issues/4357) - - The file will be deleted locally after it has been uploaded to the server, - avoiding the loss of the file if an error happens during the upload. - - https://github.com/owncloud/android/issues/4357 - https://github.com/owncloud/android/pull/4437 - * Enhancement - Changed the color of some elements to improve accessibility: [#4364](https://github.com/owncloud/android/issues/4364) The color of some UI elements has been changed to meet minimum color contrast