Skip to content

Commit 8a2e270

Browse files
committed
fix(auto-upload): clean stale upload entities when user delete auto upload folder
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
1 parent f2d01a8 commit 8a2e270

File tree

5 files changed

+61
-25
lines changed

5 files changed

+61
-25
lines changed

app/src/main/java/com/nextcloud/client/database/dao/SyncedFolderDao.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,14 @@ interface SyncedFolderDao {
2727

2828
@Query("SELECT * FROM ${ProviderMeta.ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME}")
2929
fun getAllAsFlow(): Flow<List<SyncedFolderEntity>>
30+
31+
@Query(
32+
"""
33+
SELECT * FROM ${ProviderMeta.ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME}
34+
WHERE ${ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_REMOTE_PATH} = :remotePath
35+
AND ${ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT} = :account
36+
LIMIT 1
37+
"""
38+
)
39+
suspend fun findByRemotePathAndAccount(remotePath: String, account: String): SyncedFolderEntity?
3040
}

app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadHelper.kt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import android.content.Context
1313
import android.content.Intent
1414
import com.nextcloud.client.account.User
1515
import com.nextcloud.client.account.UserAccountManager
16+
import com.nextcloud.client.database.entity.SyncedFolderEntity
1617
import com.nextcloud.client.database.entity.UploadEntity
1718
import com.nextcloud.client.database.entity.toOCUpload
1819
import com.nextcloud.client.database.entity.toUploadEntity
@@ -39,9 +40,11 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult
3940
import com.owncloud.android.lib.common.utils.Log_OC
4041
import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation
4142
import com.owncloud.android.lib.resources.files.model.RemoteFile
43+
import com.owncloud.android.lib.resources.files.model.ServerFileInterface
4244
import com.owncloud.android.lib.resources.status.OCCapability
4345
import com.owncloud.android.operations.RemoveFileOperation
4446
import com.owncloud.android.operations.UploadFileOperation
47+
import com.owncloud.android.ui.activity.SyncedFoldersActivity
4548
import com.owncloud.android.utils.DisplayUtils
4649
import com.owncloud.android.utils.FileUtil
4750
import kotlinx.coroutines.CoroutineScope
@@ -615,4 +618,33 @@ class FileUploadHelper {
615618
}
616619
}
617620
}
621+
622+
/**
623+
* When a synced folder is disabled or deleted, its associated OCUpload entries in the uploads
624+
* table must be cleaned up. Without this, stale upload entries outlive the folder config that
625+
* created them, causing FileUploadWorker to keep retrying uploads for a folder that no longer
626+
* exists or is intentionally turned off, and AutoUploadWorker to re-queue already handled files
627+
* on its next scan via FileSystemRepository.getFilePathsWithIds.
628+
*/
629+
suspend fun removeEntityFromUploadEntities(id: Long) {
630+
uploadsStorageManager.fileSystemDao.getBySyncedFolderId(id.toString())
631+
.filter { it.localPath != null && it.remotePath != null }
632+
.forEach {
633+
Log_OC.d(
634+
TAG,
635+
"deleting upload entity localPath: ${it.localPath}, " + "remotePath: ${it.remotePath}"
636+
)
637+
uploadsStorageManager.uploadDao.deleteByLocalRemotePath(
638+
localPath = it.localPath!!,
639+
remotePath = it.remotePath!!
640+
)
641+
}
642+
}
643+
644+
suspend fun getAutoUploadFolderEntity(file: ServerFileInterface, user: User): SyncedFolderEntity? {
645+
val dao = uploadsStorageManager.syncedFolderDao
646+
val normalizedRemotePath = file.remotePath.trimEnd()
647+
if (normalizedRemotePath.isEmpty()) return null
648+
return dao.findByRemotePathAndAccount(normalizedRemotePath, user.accountName)
649+
}
618650
}

app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.nextcloud.client.account.User;
2424
import com.nextcloud.client.database.NextcloudDatabase;
2525
import com.nextcloud.client.database.dao.FileSystemDao;
26+
import com.nextcloud.client.database.dao.SyncedFolderDao;
2627
import com.nextcloud.client.database.dao.UploadDao;
2728
import com.nextcloud.client.database.entity.UploadEntity;
2829
import com.nextcloud.client.database.entity.UploadEntityKt;
@@ -72,6 +73,7 @@ public class UploadsStorageManager extends Observable {
7273
private OCCapability capability;
7374
public final UploadDao uploadDao = NextcloudDatabase.instance().uploadDao();
7475
public final FileSystemDao fileSystemDao = NextcloudDatabase.instance().fileSystemDao();
76+
public final SyncedFolderDao syncedFolderDao = NextcloudDatabase.instance().syncedFolderDao();
7577

7678
public UploadsStorageManager(
7779
CurrentAccountProvider currentAccountProvider,

app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,6 +2185,21 @@ class FileDisplayActivity :
21852185
}
21862186
supportInvalidateOptionsMenu()
21872187
fetchRecommendedFilesIfNeeded(ignoreETag = true, currentDir)
2188+
2189+
// clean stale upload entities for auto upload folder
2190+
if (removedFile.isFolder) {
2191+
lifecycleScope.launch(Dispatchers.IO) {
2192+
val optionalUser = user
2193+
if (user.isEmpty) {
2194+
return@launch
2195+
}
2196+
2197+
val autoUploadFolder = fileUploadHelper
2198+
.getAutoUploadFolderEntity(removedFile, optionalUser.get()) ?: return@launch
2199+
2200+
autoUploadFolder.id?.toLong()?.let { fileUploadHelper.removeEntityFromUploadEntities(it) }
2201+
}
2202+
}
21882203
} else {
21892204
if (result.isSslRecoverableException) {
21902205
mLastSslUntrustedServerResult = result

app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -778,33 +778,10 @@ class SyncedFoldersActivity :
778778
Log_OC.d(TAG, "auto-upload configuration sync status is disabled: " + item.remotePath)
779779

780780
lifecycleScope.launch(Dispatchers.IO) {
781-
removeEntityFromUploadEntities(item.id)
781+
fileUploadHelper.removeEntityFromUploadEntities(item.id)
782782
}
783783
}
784784

785-
/**
786-
* When a synced folder is disabled or deleted, its associated OCUpload entries in the uploads
787-
* table must be cleaned up. Without this, stale upload entries outlive the folder config that
788-
* created them, causing FileUploadWorker to keep retrying uploads for a folder that no longer
789-
* exists or is intentionally turned off, and AutoUploadWorker to re-queue already handled files
790-
* on its next scan via FileSystemRepository.getFilePathsWithIds.
791-
*/
792-
private suspend fun removeEntityFromUploadEntities(id: Long) {
793-
val storageManager = fileUploadHelper.uploadsStorageManager
794-
storageManager.fileSystemDao.getBySyncedFolderId(id.toString())
795-
.filter { it.localPath != null && it.remotePath != null }
796-
.forEach {
797-
Log_OC.d(
798-
TAG,
799-
"deleting upload entity localPath: ${it.localPath}, " + "remotePath: ${it.remotePath}"
800-
)
801-
storageManager.uploadDao.deleteByLocalRemotePath(
802-
localPath = it.localPath!!,
803-
remotePath = it.remotePath!!
804-
)
805-
}
806-
}
807-
808785
override fun onDeleteSyncedFolderPreference(syncedFolder: SyncedFolderParcelable?) {
809786
if (syncedFolder == null) {
810787
return
@@ -813,7 +790,7 @@ class SyncedFoldersActivity :
813790
Log_OC.d(TAG, "deleting auto upload configuration: " + syncedFolder.remotePath)
814791

815792
lifecycleScope.launch(Dispatchers.IO) {
816-
removeEntityFromUploadEntities(syncedFolder.id)
793+
fileUploadHelper.removeEntityFromUploadEntities(syncedFolder.id)
817794
syncedFolderProvider.deleteSyncedFolder(syncedFolder.id)
818795
withContext(Dispatchers.Main) {
819796
adapter.removeItem(syncedFolder.section)

0 commit comments

Comments
 (0)