Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nextcloud.client.jobs.autoUpload

import com.nextcloud.client.database.entity.UploadEntity
import com.owncloud.android.db.OCUpload

sealed class AutoUploadEntityResult {
data object NonRetryable : AutoUploadEntityResult()
data object CreationError : AutoUploadEntityResult()
data object Uploaded : AutoUploadEntityResult()
data class Success(val data: Pair<UploadEntity, OCUpload>) : AutoUploadEntityResult()
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import com.nextcloud.client.account.User
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.database.entity.UploadEntity
import com.nextcloud.client.database.entity.toOCUpload
import com.nextcloud.client.database.entity.toUploadEntity
import com.nextcloud.client.device.PowerManagementService
Expand All @@ -25,6 +24,7 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.jobs.utils.UploadErrorNotificationManager
import com.nextcloud.client.network.ConnectivityService
import com.nextcloud.client.preferences.SubFolderRule
import com.nextcloud.utils.extensions.isNonRetryable
import com.nextcloud.utils.extensions.updateStatus
import com.owncloud.android.R
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
Expand All @@ -35,6 +35,7 @@ import com.owncloud.android.datamodel.SyncedFolderProvider
import com.owncloud.android.datamodel.UploadsStorageManager
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.OwnCloudAccount
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
import com.owncloud.android.lib.common.operations.RemoteOperationResult
Expand Down Expand Up @@ -304,14 +305,14 @@ class AutoUploadWorker(
)

try {
val result = createEntityAndUpload(user, localPath, remotePath)
if (result == null) {
val entityResult = getEntityResult(user, localPath, remotePath)
if (entityResult !is AutoUploadEntityResult.Success) {
repository.markFileAsHandled(localPath, syncedFolder)
Log_OC.d(TAG, "Marked file as handled due to existing conflict: $localPath")
Log_OC.d(TAG, "marked file as handled: $localPath")
continue
}

var (uploadEntity, upload) = result
var (uploadEntity, upload) = entityResult.data

// if local file deleted, upload process cannot be started or retriable thus needs to be removed
if (path.isEmpty() || !file.exists()) {
Expand Down Expand Up @@ -391,11 +392,7 @@ class AutoUploadWorker(
}

@Suppress("ReturnCount")
private fun createEntityAndUpload(
user: User,
localPath: String,
remotePath: String
): Pair<UploadEntity, OCUpload>? {
private fun getEntityResult(user: User, localPath: String, remotePath: String): AutoUploadEntityResult {
val (needsCharging, needsWifi, uploadAction) = getUploadSettings(syncedFolder)
Log_OC.d(TAG, "creating oc upload for ${user.accountName}")

Expand All @@ -407,16 +404,27 @@ class AutoUploadWorker(
)

val lastUploadResult = uploadEntity?.lastResult?.let { UploadResult.fromValue(it) }
if (lastUploadResult == UploadResult.SYNC_CONFLICT) {
Log_OC.w(TAG, "Conflict already exists, skipping auto-upload: $localPath")
return null
if (lastUploadResult?.isNonRetryable() == true) {
Log_OC.w(
TAG,
"last upload failed with ${lastUploadResult.value}, skipping auto-upload: $localPath"
)
return AutoUploadEntityResult.NonRetryable
}

val upload = try {
uploadEntity?.toOCUpload(null) ?: OCUpload(localPath, remotePath, user.accountName)
} catch (_: IllegalArgumentException) {
Log_OC.e(TAG, "cannot construct oc upload")
return null
return AutoUploadEntityResult.CreationError
}

// only valid for skip collision policy other scenarios will be handled in UploadFileOperation.java
if (upload.lastResult == UploadResult.UPLOADED &&
syncedFolder.nameCollisionPolicy == NameCollisionPolicy.SKIP
) {
Log_OC.d(TAG, "no need to create and process this entity file is already uploaded")
return AutoUploadEntityResult.Uploaded
}

upload.apply {
Expand All @@ -433,7 +441,7 @@ class AutoUploadWorker(
}
}

return upload.toUploadEntity() to upload
return AutoUploadEntityResult.Success(upload.toUploadEntity() to upload)
}

private fun createUploadFileOperation(upload: OCUpload, user: User): UploadFileOperation = UploadFileOperation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ package com.nextcloud.utils.extensions

import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
import com.owncloud.android.lib.resources.files.model.RemoteFile
import com.owncloud.android.utils.ErrorMessageAdapter
import com.owncloud.android.utils.FileStorageUtils

@Suppress("ReturnCount")
fun Pair<RemoteOperationResult<*>?, RemoteOperation<*>?>?.getErrorMessage(): String {
Expand Down Expand Up @@ -45,20 +42,3 @@ fun ResultCode.isFileSpecificError(): Boolean {

return !errorCodes.contains(this)
}

@Suppress("Deprecation")
fun RemoteOperationResult<*>?.toOCFile(): List<OCFile>? = if (this?.isSuccess == true) {
data?.toOCFileList()
} else {
null
}

private fun ArrayList<Any>.toOCFileList(): List<OCFile> = this.mapNotNull {
val remoteFile = (it as? RemoteFile)

remoteFile?.let {
remoteFile.toOCFile()
}
}

private fun RemoteFile?.toOCFile(): OCFile = FileStorageUtils.fillOCFile(this)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.nextcloud.utils.extensions

import com.owncloud.android.db.UploadResult

fun UploadResult.isNonRetryable(): Boolean = when (this) {
UploadResult.FILE_NOT_FOUND,
UploadResult.FILE_ERROR,
UploadResult.FOLDER_ERROR,
UploadResult.CANNOT_CREATE_FILE,
UploadResult.SYNC_CONFLICT,
UploadResult.LOCAL_STORAGE_NOT_COPIED,
UploadResult.VIRUS_DETECTED,
UploadResult.QUOTA_EXCEEDED,
UploadResult.SAME_FILE_CONFLICT,
UploadResult.PRIVILEGES_ERROR,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UploadResult.PRIVILEGES_ERROR, UploadResult.CREDENTIAL_ERROR, UploadResult.LOCAL_STORAGE_NOT_COPIED, I'm not sure about these lets decide together. @tobiasKaminsky

UploadResult.CREDENTIAL_ERROR,

// most cases covered and mapped from RemoteOperationResult. Most likely UploadResult.UNKNOWN this error will
// occur again
UploadResult.UNKNOWN,

// user's choice
UploadResult.CANCELLED -> true

// everything else may succeed after retry
else -> false
}
Loading