Skip to content

Commit f969975

Browse files
Merge pull request #15548 from nextcloud/backport/15449/stable-3.33
[stable-3.33] fix: correct query to fetch uploads by IDs and account name
2 parents c4680f0 + 7f5fb92 commit f969975

File tree

5 files changed

+106
-93
lines changed

5 files changed

+106
-93
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package com.nextcloud.client.database.dao
99

1010
import androidx.room.Dao
1111
import androidx.room.Query
12+
import com.nextcloud.client.database.entity.UploadEntity
1213
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta
1314

1415
@Dao
@@ -19,4 +20,11 @@ interface UploadDao {
1920
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + " = :accountName AND _id IS NOT NULL"
2021
)
2122
fun getAllIds(status: Int, accountName: String): List<Int>
23+
24+
@Query(
25+
"SELECT * FROM " + ProviderTableMeta.UPLOADS_TABLE_NAME +
26+
" WHERE " + ProviderTableMeta._ID + " IN (:ids) AND " +
27+
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + " = :accountName"
28+
)
29+
fun getUploadsByIds(ids: LongArray, accountName: String): List<UploadEntity>
2230
}

app/src/main/java/com/nextcloud/client/database/entity/UploadEntity.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ package com.nextcloud.client.database.entity
1010
import androidx.room.ColumnInfo
1111
import androidx.room.Entity
1212
import androidx.room.PrimaryKey
13+
import com.nextcloud.utils.autoRename.AutoRename
14+
import com.owncloud.android.datamodel.UploadsStorageManager
15+
import com.owncloud.android.db.OCUpload
1316
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta
17+
import com.owncloud.android.db.UploadResult
18+
import com.owncloud.android.files.services.NameCollisionPolicy
19+
import com.owncloud.android.lib.resources.status.OCCapability
1420

1521
@Entity(tableName = ProviderTableMeta.UPLOADS_TABLE_NAME)
1622
data class UploadEntity(
@@ -48,3 +54,27 @@ data class UploadEntity(
4854
@ColumnInfo(name = ProviderTableMeta.UPLOADS_FOLDER_UNLOCK_TOKEN)
4955
val folderUnlockToken: String?
5056
)
57+
58+
fun UploadEntity.toOCUpload(capability: OCCapability? = null): OCUpload {
59+
val localPath = localPath
60+
var remotePath = remotePath
61+
if (capability != null && remotePath != null) {
62+
remotePath = AutoRename.rename(remotePath, capability)
63+
}
64+
val upload = OCUpload(localPath, remotePath, accountName)
65+
66+
fileSize?.let { upload.fileSize = it }
67+
id?.let { upload.uploadId = it.toLong() }
68+
status?.let { upload.uploadStatus = UploadsStorageManager.UploadStatus.fromValue(it) }
69+
localBehaviour?.let { upload.localAction = it }
70+
nameCollisionPolicy?.let { upload.nameCollisionPolicy = NameCollisionPolicy.deserialize(it) }
71+
isCreateRemoteFolder?.let { upload.isCreateRemoteFolder = it == 1 }
72+
uploadEndTimestamp?.let { upload.uploadEndTimestamp = it.toLong() }
73+
lastResult?.let { upload.lastResult = UploadResult.fromValue(it) }
74+
createdBy?.let { upload.createdBy = it }
75+
isWifiOnly?.let { upload.isUseWifiOnly = it == 1 }
76+
isWhileChargingOnly?.let { upload.isWhileChargingOnly = it == 1 }
77+
folderUnlockToken?.let { upload.folderUnlockToken = it }
78+
79+
return upload
80+
}

app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -610,13 +610,15 @@ internal class BackgroundJobManagerImpl(
610610
.setRequiredNetworkType(NetworkType.CONNECTED)
611611
.build()
612612

613+
val dataBuilder = Data.Builder()
614+
.putBoolean(FileUploadWorker.IS_AUTO_UPLOAD, isAutoUpload)
615+
.putString(FileUploadWorker.ACCOUNT, user.accountName)
616+
.putInt(FileUploadWorker.TOTAL_UPLOAD_SIZE, uploadIds.size)
617+
613618
val workRequests = batches.mapIndexed { index, batch ->
614-
val dataBuilder = Data.Builder()
615-
.putBoolean(FileUploadWorker.IS_AUTO_UPLOAD, isAutoUpload)
616-
.putString(FileUploadWorker.ACCOUNT, user.accountName)
619+
dataBuilder
617620
.putLongArray(FileUploadWorker.UPLOAD_IDS, batch.toLongArray())
618621
.putInt(FileUploadWorker.CURRENT_BATCH_INDEX, index)
619-
.putInt(FileUploadWorker.TOTAL_UPLOAD_SIZE, uploadIds.size)
620622

621623
oneTimeRequestBuilder(FileUploadWorker::class, JOB_FILES_UPLOAD, user)
622624
.addTag(tag)

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager
2727
import com.owncloud.android.datamodel.UploadsStorageManager
2828
import com.owncloud.android.db.OCUpload
2929
import com.owncloud.android.lib.common.OwnCloudAccount
30+
import com.owncloud.android.lib.common.OwnCloudClient
3031
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
3132
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
3233
import com.owncloud.android.lib.common.operations.RemoteOperationResult
@@ -157,9 +158,18 @@ class FileUploadWorker(
157158
return Result.failure()
158159
}
159160

160-
val previouslyUploadedFileSize = currentBatchIndex * FileUploadHelper.MAX_FILE_COUNT
161+
// since worker's policy is append or replace and account name comes from there no need check in the loop
162+
val optionalUser = userAccountManager.getUser(accountName)
163+
if (!optionalUser.isPresent) {
164+
Log_OC.e(TAG, "User not found for account: $accountName")
165+
return Result.failure()
166+
}
161167

162-
val uploads = uploadIds.map { id -> uploadsStorageManager.getUploadById(id) }.filterNotNull()
168+
val user = optionalUser.get()
169+
val previouslyUploadedFileSize = currentBatchIndex * FileUploadHelper.MAX_FILE_COUNT
170+
val uploads = uploadsStorageManager.getUploadsByIds(uploadIds, accountName)
171+
val ocAccount = OwnCloudAccount(user.toPlatformAccount(), context)
172+
val client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context)
163173

164174
for ((index, upload) in uploads.withIndex()) {
165175
if (preferences.isGlobalUploadPaused) {
@@ -175,19 +185,12 @@ class FileUploadWorker(
175185
return Result.failure()
176186
}
177187

178-
val user = userAccountManager.getUser(accountName)
179-
if (!user.isPresent) {
180-
uploadsStorageManager.removeUpload(upload.uploadId)
181-
continue
182-
}
183-
184188
if (isStopped) {
185189
continue
186190
}
187191

188-
setWorkerState(user.get())
189-
190-
val operation = createUploadFileOperation(upload, user.get())
192+
setWorkerState(user)
193+
val operation = createUploadFileOperation(upload, user)
191194
currentUploadFileOperation = operation
192195

193196
val currentIndex = (index + 1)
@@ -200,7 +203,7 @@ class FileUploadWorker(
200203
totalUploadSize = totalUploadSize
201204
)
202205

203-
val result = upload(operation, user.get())
206+
val result = upload(operation, user, client)
204207
currentUploadFileOperation = null
205208
sendUploadFinishEvent(totalUploadSize, currentUploadIndex, operation, result)
206209
}
@@ -262,15 +265,16 @@ class FileUploadWorker(
262265
}
263266

264267
@Suppress("TooGenericExceptionCaught", "DEPRECATION")
265-
private fun upload(uploadFileOperation: UploadFileOperation, user: User): RemoteOperationResult<Any?> {
268+
private fun upload(
269+
uploadFileOperation: UploadFileOperation,
270+
user: User,
271+
client: OwnCloudClient
272+
): RemoteOperationResult<Any?> {
266273
lateinit var result: RemoteOperationResult<Any?>
267274

268275
try {
269276
val storageManager = uploadFileOperation.storageManager
270-
val ocAccount = OwnCloudAccount(user.toPlatformAccount(), context)
271-
val uploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context)
272-
result = uploadFileOperation.execute(uploadClient)
273-
277+
result = uploadFileOperation.execute(client)
274278
val task = ThumbnailsCacheManager.ThumbnailGenerationTask(storageManager, user)
275279
val file = File(uploadFileOperation.originalStoragePath)
276280
val remoteId: String? = uploadFileOperation.file.remoteId

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

Lines changed: 41 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import com.nextcloud.client.account.User;
2828
import com.nextcloud.client.database.NextcloudDatabase;
2929
import com.nextcloud.client.database.dao.UploadDao;
30+
import com.nextcloud.client.database.entity.UploadEntity;
31+
import com.nextcloud.client.database.entity.UploadEntityKt;
3032
import com.nextcloud.client.jobs.upload.FileUploadHelper;
3133
import com.nextcloud.client.jobs.upload.FileUploadWorker;
3234
import com.nextcloud.utils.autoRename.AutoRename;
@@ -189,9 +191,22 @@ private ContentValues getContentValues(OCUpload ocUpload) {
189191
* @param ocUpload Upload object with state to update
190192
* @return num of updated uploads.
191193
*/
192-
public int updateUpload(OCUpload ocUpload) {
194+
public synchronized int updateUpload(OCUpload ocUpload) {
193195
Log_OC.v(TAG, "Updating " + ocUpload.getLocalPath() + " with status=" + ocUpload.getUploadStatus());
194196

197+
OCUpload existingUpload = getUploadById(ocUpload.getUploadId());
198+
if (existingUpload == null) {
199+
Log_OC.e(TAG, "Upload not found for ID: " + ocUpload.getUploadId());
200+
return 0;
201+
}
202+
203+
if (!existingUpload.getAccountName().equals(ocUpload.getAccountName())) {
204+
Log_OC.e(TAG, "Account mismatch for upload ID " + ocUpload.getUploadId() +
205+
": expected " + existingUpload.getAccountName() +
206+
", got " + ocUpload.getAccountName());
207+
return 0;
208+
}
209+
195210
ContentValues cv = new ContentValues();
196211
cv.put(ProviderTableMeta.UPLOADS_LOCAL_PATH, ocUpload.getLocalPath());
197212
cv.put(ProviderTableMeta.UPLOADS_REMOTE_PATH, ocUpload.getRemotePath());
@@ -204,8 +219,8 @@ public int updateUpload(OCUpload ocUpload) {
204219

205220
int result = getDB().update(ProviderTableMeta.CONTENT_URI_UPLOADS,
206221
cv,
207-
ProviderTableMeta._ID + "=?",
208-
new String[]{String.valueOf(ocUpload.getUploadId())}
222+
ProviderTableMeta._ID + "=? AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=?",
223+
new String[]{String.valueOf(ocUpload.getUploadId()), ocUpload.getAccountName()}
209224
);
210225

211226
Log_OC.d(TAG, "updateUpload returns with: " + result + " for file: " + ocUpload.getLocalPath());
@@ -437,6 +452,20 @@ OCUpload getUploadById(long id) {
437452
return result;
438453
}
439454

455+
public List<OCUpload> getUploadsByIds(long[] uploadIds, String accountName) {
456+
final List<OCUpload> result = new ArrayList<>();
457+
458+
final List<UploadEntity> entities = uploadDao.getUploadsByIds(uploadIds, accountName);
459+
entities.forEach(uploadEntity -> {
460+
OCUpload ocUpload = createOCUploadFromEntity(uploadEntity);
461+
if (ocUpload != null) {
462+
result.add(ocUpload);
463+
}
464+
});
465+
466+
return result;
467+
}
468+
440469
private OCUpload[] getUploads(@Nullable String selection, @Nullable String... selectionArgs) {
441470
final List<OCUpload> uploads = new ArrayList<>();
442471
long page = 0;
@@ -555,6 +584,15 @@ private List<OCUpload> getUploadPage(long limit, final long afterId, final boole
555584
return uploads;
556585
}
557586

587+
@Nullable
588+
private OCUpload createOCUploadFromEntity(UploadEntity entity) {
589+
if (entity == null) {
590+
return null;
591+
}
592+
initOCCapability();
593+
return UploadEntityKt.toOCUpload(entity, capability);
594+
}
595+
558596
private OCUpload createOCUploadFromCursor(Cursor c) {
559597
initOCCapability();
560598

@@ -610,16 +648,6 @@ public long[] getCurrentUploadIds(final @NonNull String accountName) {
610648
.toArray();
611649
}
612650

613-
/**
614-
* Gets a page of uploads after <code>afterId</code>, where uploads are sorted by ascending upload id.
615-
* <p>
616-
* If <code>afterId</code> is -1, returns the first page
617-
*/
618-
public List<OCUpload> getCurrentAndPendingUploadsForAccountPageAscById(final long afterId, final @NonNull String accountName) {
619-
final String selection = getInProgressAndDelayedUploadsSelection();
620-
return getUploadPage(QUERY_PAGE_SIZE, afterId, false, selection, accountName);
621-
}
622-
623651
/**
624652
* Get all failed uploads.
625653
*/
@@ -656,13 +684,6 @@ public OCUpload[] getCancelledUploadsForCurrentAccount() {
656684
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, user.getAccountName());
657685
}
658686

659-
/**
660-
* Get all uploads which where successfully completed.
661-
*/
662-
public OCUpload[] getFinishedUploads() {
663-
return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_SUCCEEDED.value, (String[]) null);
664-
}
665-
666687
public OCUpload[] getFailedButNotDelayedUploadsForCurrentAccount() {
667688
User user = currentAccountProvider.getUser();
668689

@@ -679,25 +700,6 @@ public OCUpload[] getFailedButNotDelayedUploadsForCurrentAccount() {
679700
user.getAccountName());
680701
}
681702

682-
/**
683-
* Get all failed uploads, except for those that were not performed due to lack of Wifi connection.
684-
*
685-
* @return Array of failed uploads, except for those that were not performed due to lack of Wifi connection.
686-
*/
687-
public OCUpload[] getFailedButNotDelayedUploads() {
688-
689-
return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_FAILED.value + AND +
690-
ProviderTableMeta.UPLOADS_LAST_RESULT + ANGLE_BRACKETS + UploadResult.LOCK_FAILED.getValue() +
691-
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
692-
ANGLE_BRACKETS + UploadResult.DELAYED_FOR_WIFI.getValue() +
693-
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
694-
ANGLE_BRACKETS + UploadResult.DELAYED_FOR_CHARGING.getValue() +
695-
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
696-
ANGLE_BRACKETS + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue(),
697-
(String[]) null
698-
);
699-
}
700-
701703
private ContentResolver getDB() {
702704
return contentResolver;
703705
}
@@ -823,39 +825,6 @@ public void updateDatabaseUploadStart(UploadFileOperation upload) {
823825
);
824826
}
825827

826-
/**
827-
* Changes the status of any in progress upload from UploadStatus.UPLOAD_IN_PROGRESS to UploadStatus.UPLOAD_FAILED
828-
*
829-
* @return Number of uploads which status was changed.
830-
*/
831-
public int failInProgressUploads(UploadResult fail) {
832-
Log_OC.v(TAG, "Updating state of any killed upload");
833-
834-
ContentValues cv = new ContentValues();
835-
cv.put(ProviderTableMeta.UPLOADS_STATUS, UploadStatus.UPLOAD_FAILED.getValue());
836-
cv.put(
837-
ProviderTableMeta.UPLOADS_LAST_RESULT,
838-
fail != null ? fail.getValue() : UploadResult.UNKNOWN.getValue()
839-
);
840-
cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, Calendar.getInstance().getTimeInMillis());
841-
842-
int result = getDB().update(
843-
ProviderTableMeta.CONTENT_URI_UPLOADS,
844-
cv,
845-
ProviderTableMeta.UPLOADS_STATUS + "=?",
846-
new String[]{String.valueOf(UploadStatus.UPLOAD_IN_PROGRESS.getValue())}
847-
);
848-
849-
if (result == 0) {
850-
Log_OC.v(TAG, "No upload was killed");
851-
} else {
852-
Log_OC.w(TAG, Integer.toString(result) + " uploads where abruptly interrupted");
853-
notifyObserversNow();
854-
}
855-
856-
return result;
857-
}
858-
859828
@VisibleForTesting
860829
public void removeAllUploads() {
861830
Log_OC.v(TAG, "Delete all uploads!");

0 commit comments

Comments
 (0)