From 6c4d4d8bc4abc3f1b3d794da9d90906ccac12607 Mon Sep 17 00:00:00 2001
From: Vincent Petry <vincent@nextcloud.com>
Date: Wed, 12 Jan 2022 11:42:10 +0100
Subject: [PATCH 1/2] Properly abort uploads

Add a new approach for flagging an upload as aborted because we can't
rely on the browser fully cancelling the request as we now seem to
receive an error response from the server instead of a jQuery "abort"
message.

Signed-off-by: Vincent Petry <vincent@nextcloud.com>
---
 apps/files/js/file-upload.js | 45 ++++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index 9f51f05d56117..df43135789d0d 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -322,26 +322,34 @@ OC.FileUpload.prototype = {
 		);
 	},
 
+	_delete: function() {
+		var self = this;
+		if (this.data.isChunked) {
+			this._deleteChunkFolder()
+		}
+		this.deleteUpload();
+	},
+
 	/**
 	 * Abort the upload
 	 */
 	abort: function() {
-		if (this.data.isChunked) {
-			this._deleteChunkFolder();
+		var self = this;
+		if (this.aborted) {
+			return
 		}
-		this.data.abort();
-		this.deleteUpload();
 		this.aborted = true;
+		this._delete();
 	},
 
 	/**
 	 * Fail the upload
 	 */
 	fail: function() {
-		this.deleteUpload();
-		if (this.data.isChunked) {
-			this._deleteChunkFolder();
+		if (this.aborted) {
+			return
 		}
+		this._delete();
 	},
 
 	/**
@@ -679,7 +687,13 @@ OC.Uploader.prototype = _.extend({
 			return;
 		}
 
-		delete this._uploads[upload.data.uploadId];
+		// defer as some calls/chunks might still be busy failing, so we need
+		// the upload info there still
+		var self = this;
+		var uploadId = upload.data.uploadId;
+		window.setTimeout(function() {
+			delete self._uploads[uploadId];
+		}, 5000)
 	},
 
 	showUploadCancelMessage: _.debounce(function() {
@@ -905,6 +919,7 @@ OC.Uploader.prototype = _.extend({
 		if ($uploadEl.exists()) {
 			this.progressBar.on('cancel', function() {
 				self.cancelUploads();
+				self.showUploadCancelMessage();
 			});
 
 			this.fileUploadParam = {
@@ -1075,6 +1090,10 @@ OC.Uploader.prototype = _.extend({
 					var upload = self.getUpload(data);
 					var status = null;
 					if (upload) {
+						if (upload.aborted) {
+							// uploads might fail with errors from the server when aborted
+							return
+						}
 						status = upload.getResponseStatus();
 					}
 					self.log('fail', e, upload);
@@ -1082,7 +1101,7 @@ OC.Uploader.prototype = _.extend({
 					self.removeUpload(upload);
 
 					if (data.textStatus === 'abort' || data.errorThrown === 'abort') {
-						self.showUploadCancelMessage();
+						return
 					} else if (status === 412) {
 						// file already exists
 						self.showConflict(upload);
@@ -1283,6 +1302,10 @@ OC.Uploader.prototype = _.extend({
 				fileupload.on('fileuploadchunksend', function(e, data) {
 					// modify the request to adjust it to our own chunking
 					var upload = self.getUpload(data);
+					if (!upload) {
+						// likely cancelled
+						return
+					}
 					var range = data.contentRange.split(' ')[1];
 					var chunkId = range.split('/')[0].split('-')[0];
 					data.url = OC.getRootPath() +
@@ -1317,6 +1340,10 @@ OC.Uploader.prototype = _.extend({
 
 						self.trigger('done', e, upload);
 					}).fail(function(status, response) {
+						if (upload.aborted) {
+							return
+						}
+
 						var message = response.message;
 						if (status === 507) {
 							// not enough space

From 11c7e100ae4e4bd42218c3f3fbc106546e1c19b4 Mon Sep 17 00:00:00 2001
From: Vincent Petry <vincent@nextcloud.com>
Date: Wed, 12 Jan 2022 16:39:45 +0100
Subject: [PATCH 2/2] Properly hide progress bar after error

Whenever an error occurs, also hide the progress bar.

The logic was also adjusted to properly detect uploads that are pending
deletion, in which case the progress bar can already be hidden.

Signed-off-by: Vincent Petry <vincent@nextcloud.com>
---
 apps/files/js/file-upload.js | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index df43135789d0d..793c9672c3f66 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -323,7 +323,6 @@ OC.FileUpload.prototype = {
 	},
 
 	_delete: function() {
-		var self = this;
 		if (this.data.isChunked) {
 			this._deleteChunkFolder()
 		}
@@ -334,7 +333,6 @@ OC.FileUpload.prototype = {
 	 * Abort the upload
 	 */
 	abort: function() {
-		var self = this;
 		if (this.aborted) {
 			return
 		}
@@ -691,11 +689,24 @@ OC.Uploader.prototype = _.extend({
 		// the upload info there still
 		var self = this;
 		var uploadId = upload.data.uploadId;
+		// mark as deleted for the progress bar
+		this._uploads[uploadId].deleted = true;
 		window.setTimeout(function() {
 			delete self._uploads[uploadId];
 		}, 5000)
 	},
 
+	_activeUploadCount: function() {
+		var count = 0;
+		for (var key in this._uploads) {
+			if (!this._uploads[key].deleted) {
+				count++;
+			}
+		}
+
+		return count;
+	},
+
 	showUploadCancelMessage: _.debounce(function() {
 		OC.Notification.show(t('files', 'Upload cancelled.'), {timeout : 7, type: 'error'});
 	}, 500),
@@ -1321,9 +1332,9 @@ OC.Uploader.prototype = _.extend({
 
 					self._pendingUploadDoneCount++;
 
-					upload.done().then(function() {
+					upload.done().always(function() {
 						self._pendingUploadDoneCount--;
-						if (Object.keys(self._uploads).length === 0 && self._pendingUploadDoneCount === 0) {
+						if (self._activeUploadCount() === 0 && self._pendingUploadDoneCount === 0) {
 							// All the uploads ended and there is no pending
 							// operation, so hide the progress bar.
 							// Note that this happens here only with chunked
@@ -1337,7 +1348,7 @@ OC.Uploader.prototype = _.extend({
 							// hides the progress bar in that case).
 							self._hideProgressBar();
 						}
-
+					}).done(function() {
 						self.trigger('done', e, upload);
 					}).fail(function(status, response) {
 						if (upload.aborted) {
