From 59c5be1cc572793a8d50e87ab589e1cc4cf2ed12 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 16 Dec 2015 17:35:53 +0100 Subject: Use Webdav PUT for uploads in the web browser - uses PUT method with jquery.fileupload for regular and public file lists - for IE and browsers that don't support it, use POST with iframe transport - implemented Sabre plugin to handle iframe transport and redirect the embedded PUT request to the proper handler - added RFC5995 POST to file collection with "add-member" property to make it possible to auto-rename conflicting file names - remove obsolete ajax/upload.php and obsolete ajax routes Signed-off-by: Roeland Jago Douma --- apps/files/tests/js/fileUploadSpec.js | 141 ++++++++++------------- apps/files/tests/js/filelistSpec.js | 208 +++++++++++++++++++++++++++++++--- 2 files changed, 257 insertions(+), 92 deletions(-) (limited to 'apps/files/tests/js') diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js index 0483d4649d4..bfaf0a9fe57 100644 --- a/apps/files/tests/js/fileUploadSpec.js +++ b/apps/files/tests/js/fileUploadSpec.js @@ -19,11 +19,11 @@ * */ -/* global FileList */ - describe('OC.Upload tests', function() { var $dummyUploader; var testFile; + var uploader; + var failStub; beforeEach(function() { testFile = { @@ -46,59 +46,64 @@ describe('OC.Upload tests', function() { '' ); $dummyUploader = $('#file_upload_start'); + uploader = new OC.Uploader($dummyUploader); + failStub = sinon.stub(); + $dummyUploader.on('fileuploadfail', failStub); }); afterEach(function() { - delete window.file_upload_param; $dummyUploader = undefined; + failStub = undefined; }); - describe('Adding files for upload', function() { - var params; - var failStub; - beforeEach(function() { - params = OC.Upload.init(); - failStub = sinon.stub(); - $dummyUploader.on('fileuploadfail', failStub); - }); - afterEach(function() { - params = undefined; - failStub = undefined; - }); - - /** - * Add file for upload - * @param file file data - */ - function addFile(file) { - return params.add.call( + /** + * Add file for upload + * @param {Array.} files array of file data to simulate upload + * @return {Array.} array of uploadinfo or null if add() returned false + */ + function addFiles(uploader, files) { + return _.map(files, function(file) { + var jqXHR = {status: 200}; + var uploadInfo = { + originalFiles: files, + files: [file], + jqXHR: jqXHR, + response: sinon.stub.returns(jqXHR), + submit: sinon.stub() + }; + if (uploader.fileUploadParam.add.call( $dummyUploader[0], {}, - { - originalFiles: {}, - files: [file] - }); - } + uploadInfo + )) { + return uploadInfo; + } + return null; + }); + } + describe('Adding files for upload', function() { it('adds file when size is below limits', function() { - var result = addFile(testFile); - expect(result).toEqual(true); + var result = addFiles(uploader, [testFile]); + expect(result[0]).not.toEqual(null); + expect(result[0].submit.calledOnce).toEqual(true); }); it('adds file when free space is unknown', function() { var result; $('#free_space').val(-2); - result = addFile(testFile); + result = addFiles(uploader, [testFile]); - expect(result).toEqual(true); + expect(result[0]).not.toEqual(null); + expect(result[0].submit.calledOnce).toEqual(true); expect(failStub.notCalled).toEqual(true); }); it('does not add file if it exceeds upload limit', function() { var result; $('#upload_limit').val(1000); - result = addFile(testFile); + result = addFiles(uploader, [testFile]); - expect(result).toEqual(false); + expect(result[0]).toEqual(null); expect(failStub.calledOnce).toEqual(true); expect(failStub.getCall(0).args[1].textStatus).toEqual('sizeexceedlimit'); expect(failStub.getCall(0).args[1].errorThrown).toEqual( @@ -109,9 +114,9 @@ describe('OC.Upload tests', function() { var result; $('#free_space').val(1000); - result = addFile(testFile); + result = addFiles(uploader, [testFile]); - expect(result).toEqual(false); + expect(result[0]).toEqual(null); expect(failStub.calledOnce).toEqual(true); expect(failStub.getCall(0).args[1].textStatus).toEqual('notenoughspace'); expect(failStub.getCall(0).args[1].errorThrown).toEqual( @@ -120,12 +125,10 @@ describe('OC.Upload tests', function() { }); }); describe('Upload conflicts', function() { - var oldFileList; var conflictDialogStub; - var callbacks; + var fileList; beforeEach(function() { - oldFileList = FileList; $('#testArea').append( '
' + '' + @@ -145,74 +148,56 @@ describe('OC.Upload tests', function() { '
' + '
' ); - FileList = new OCA.Files.FileList($('#tableContainer')); + fileList = new OCA.Files.FileList($('#tableContainer')); - FileList.add({name: 'conflict.txt', mimetype: 'text/plain'}); - FileList.add({name: 'conflict2.txt', mimetype: 'text/plain'}); + fileList.add({name: 'conflict.txt', mimetype: 'text/plain'}); + fileList.add({name: 'conflict2.txt', mimetype: 'text/plain'}); conflictDialogStub = sinon.stub(OC.dialogs, 'fileexists'); - callbacks = { - onNoConflicts: sinon.stub() - }; + + uploader = new OC.Uploader($dummyUploader, { + fileList: fileList + }); }); afterEach(function() { conflictDialogStub.restore(); - FileList.destroy(); - FileList = oldFileList; + fileList.destroy(); }); it('does not show conflict dialog when no client side conflict', function() { - var selection = { - // yes, the format of uploads is weird... - uploads: [ - {files: [{name: 'noconflict.txt'}]}, - {files: [{name: 'noconflict2.txt'}]} - ] - }; - - OC.Upload.checkExistingFiles(selection, callbacks); + var result = addFiles(uploader, [{name: 'noconflict.txt'}, {name: 'noconflict2.txt'}]); expect(conflictDialogStub.notCalled).toEqual(true); - expect(callbacks.onNoConflicts.calledOnce).toEqual(true); - expect(callbacks.onNoConflicts.calledWith(selection)).toEqual(true); + expect(result[0].submit.calledOnce).toEqual(true); + expect(result[1].submit.calledOnce).toEqual(true); }); it('shows conflict dialog when no client side conflict', function() { - var selection = { - // yes, the format of uploads is weird... - uploads: [ - {files: [{name: 'conflict.txt'}]}, - {files: [{name: 'conflict2.txt'}]}, - {files: [{name: 'noconflict.txt'}]} - ] - }; - var deferred = $.Deferred(); conflictDialogStub.returns(deferred.promise()); deferred.resolve(); - OC.Upload.checkExistingFiles(selection, callbacks); + var result = addFiles(uploader, [ + {name: 'conflict.txt'}, + {name: 'conflict2.txt'}, + {name: 'noconflict.txt'} + ]); expect(conflictDialogStub.callCount).toEqual(3); - expect(conflictDialogStub.getCall(1).args[0]) - .toEqual({files: [ { name: 'conflict.txt' } ]}); + expect(conflictDialogStub.getCall(1).args[0].getFileName()) + .toEqual('conflict.txt'); expect(conflictDialogStub.getCall(1).args[1]) .toEqual({ name: 'conflict.txt', mimetype: 'text/plain', directory: '/' }); expect(conflictDialogStub.getCall(1).args[2]).toEqual({ name: 'conflict.txt' }); // yes, the dialog must be called several times... - expect(conflictDialogStub.getCall(2).args[0]).toEqual({ - files: [ { name: 'conflict2.txt' } ] - }); + expect(conflictDialogStub.getCall(2).args[0].getFileName()).toEqual('conflict2.txt'); expect(conflictDialogStub.getCall(2).args[1]) .toEqual({ name: 'conflict2.txt', mimetype: 'text/plain', directory: '/' }); expect(conflictDialogStub.getCall(2).args[2]).toEqual({ name: 'conflict2.txt' }); - expect(callbacks.onNoConflicts.calledOnce).toEqual(true); - expect(callbacks.onNoConflicts.calledWith({ - uploads: [ - {files: [{name: 'noconflict.txt'}]} - ] - })).toEqual(true); + expect(result[0].submit.calledOnce).toEqual(false); + expect(result[1].submit.calledOnce).toEqual(false); + expect(result[2].submit.calledOnce).toEqual(true); }); }); }); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 304f8438a59..55ab2c535af 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -159,7 +159,8 @@ describe('OCA.Files.FileList tests', function() { pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20); fileList = new OCA.Files.FileList($('#app-content-files'), { filesClient: filesClient, - config: filesConfig + config: filesConfig, + enableUpload: true }); }); afterEach(function() { @@ -2441,7 +2442,7 @@ describe('OCA.Files.FileList tests', function() { deferredInfo.resolve( 200, - new FileInfo({ + new FileInfo({ path: '/subdir', name: 'test.txt', mimetype: 'text/plain' @@ -2501,12 +2502,70 @@ describe('OCA.Files.FileList tests', function() { // TODO: error cases // TODO: unique name cases }); + describe('addAndFetchFileInfo', function() { + var getFileInfoStub; + var getFileInfoDeferred; + + beforeEach(function() { + getFileInfoDeferred = $.Deferred(); + getFileInfoStub = sinon.stub(OC.Files.Client.prototype, 'getFileInfo'); + getFileInfoStub.returns(getFileInfoDeferred.promise()); + }); + afterEach(function() { + getFileInfoStub.restore(); + }); + it('does not fetch if the given folder is not the current one', function() { + var promise = fileList.addAndFetchFileInfo('testfile.txt', '/another'); + expect(getFileInfoStub.notCalled).toEqual(true); + + expect(promise.state()).toEqual('resolved'); + }); + it('fetches info when folder is the current one', function() { + fileList.addAndFetchFileInfo('testfile.txt', '/subdir'); + expect(getFileInfoStub.calledOnce).toEqual(true); + expect(getFileInfoStub.getCall(0).args[0]).toEqual('/subdir/testfile.txt'); + }); + it('adds file data to list when fetching is done', function() { + fileList.addAndFetchFileInfo('testfile.txt', '/subdir'); + getFileInfoDeferred.resolve(200, { + name: 'testfile.txt', + size: 100 + }); + expect(fileList.findFileEl('testfile.txt').attr('data-size')).toEqual('100'); + }); + it('replaces file data to list when fetching is done', function() { + fileList.addAndFetchFileInfo('testfile.txt', '/subdir', {replace: true}); + fileList.add({ + name: 'testfile.txt', + size: 95 + }); + getFileInfoDeferred.resolve(200, { + name: 'testfile.txt', + size: 100 + }); + expect(fileList.findFileEl('testfile.txt').attr('data-size')).toEqual('100'); + }); + it('resolves promise with file data when fetching is done', function() { + var promise = fileList.addAndFetchFileInfo('testfile.txt', '/subdir', {replace: true}); + getFileInfoDeferred.resolve(200, { + name: 'testfile.txt', + size: 100 + }); + expect(promise.state()).toEqual('resolved'); + promise.then(function(status, data) { + expect(status).toEqual(200); + expect(data.name).toEqual('testfile.txt'); + expect(data.size).toEqual(100); + }); + }); + }); /** * Test upload mostly by testing the code inside the event handlers * that were registered on the magic upload object */ describe('file upload', function() { var $uploader; + var uploadData; beforeEach(function() { // note: this isn't the real blueimp file uploader from jquery.fileupload @@ -2514,14 +2573,52 @@ describe('OCA.Files.FileList tests', function() { // test the response of the handlers $uploader = $('#file_upload_start'); fileList.setFiles(testFiles); + // simulate data structure from jquery.upload + uploadData = { + files: [{ + name: 'upload.txt' + }] + }; }); afterEach(function() { $uploader = null; + uploadData = null; }); + describe('enableupload', function() { + it('sets up uploader when enableUpload is true', function() { + expect(fileList._uploader).toBeDefined(); + }); + it('does not sets up uploader when enableUpload is false', function() { + fileList.destroy(); + fileList = new OCA.Files.FileList($('#app-content-files'), { + filesClient: filesClient + }); + expect(fileList._uploader).toBeFalsy(); + }); + }); + + describe('adding files for upload', function() { + /** + * Simulate add event on the given target + * + * @return event object including the result + */ + function addFile(data) { + var ev = new $.Event('fileuploadadd', {}); + // using triggerHandler instead of trigger so we can pass + // extra data + $uploader.triggerHandler(ev, data || {}); + return ev; + } + + it('sets target dir to the current directory', function() { + addFile(uploadData); + expect(uploadData.targetDir).toEqual('/subdir'); + }); + }); describe('dropping external files', function() { - var uploadData; /** * Simulate drop event on the given target @@ -2540,17 +2637,6 @@ describe('OCA.Files.FileList tests', function() { return ev; } - beforeEach(function() { - // simulate data structure from jquery.upload - uploadData = { - files: [{ - relativePath: 'fileToUpload.txt' - }] - }; - }); - afterEach(function() { - uploadData = null; - }); it('drop on a tr or crumb outside file list does not trigger upload', function() { var $anotherTable = $('
outside
crumb
'); var ev; @@ -2574,12 +2660,14 @@ describe('OCA.Files.FileList tests', function() { ev = dropOn(fileList.$fileList.find('th:first'), uploadData); expect(ev.result).not.toEqual(false); + expect(uploadData.targetDir).toEqual('/subdir'); }); it('drop on an element on the table container triggers upload', function() { var ev; ev = dropOn($('#app-content-files'), uploadData); expect(ev.result).not.toEqual(false); + expect(uploadData.targetDir).toEqual('/subdir'); }); it('drop on an element inside the table does not trigger upload if no upload permission', function() { $('#permissions').val(0); @@ -2603,6 +2691,7 @@ describe('OCA.Files.FileList tests', function() { ev = dropOn(fileList.findFileEl('One.txt').find('td:first'), uploadData); expect(ev.result).not.toEqual(false); + expect(uploadData.targetDir).toEqual('/subdir'); }); it('drop on a folder row inside the table triggers upload to target folder', function() { var ev; @@ -2635,6 +2724,97 @@ describe('OCA.Files.FileList tests', function() { expect(fileList.findFileEl('afile.txt').find('.uploadtext').length).toEqual(0); }); }); + + describe('after folder creation due to folder upload', function() { + it('fetches folder info', function() { + var fetchInfoStub = sinon.stub(fileList, 'addAndFetchFileInfo'); + + var ev = new $.Event('fileuploadcreatedfolder', {}); + $uploader.triggerHandler(ev, '/subdir/newfolder'); + + expect(fetchInfoStub.calledOnce).toEqual(true); + expect(fetchInfoStub.getCall(0).args[0]).toEqual('newfolder'); + expect(fetchInfoStub.getCall(0).args[1]).toEqual('/subdir'); + + fetchInfoStub.restore(); + }); + }); + + describe('after upload', function() { + var fetchInfoStub; + + beforeEach(function() { + fetchInfoStub = sinon.stub(fileList, 'addAndFetchFileInfo'); + + }); + afterEach(function() { + fetchInfoStub.restore(); + }); + + + function createUpload(name, dir) { + var data = { + files: [{ + name: name + }], + upload: { + getFileName: sinon.stub().returns(name), + getFullPath: sinon.stub().returns(dir) + }, + jqXHR: { + status: 200 + } + } + return data; + } + + /** + * Simulate add event on the given target + * + * @return event object including the result + */ + function addFile(data) { + var ev = new $.Event('fileuploaddone', {}); + // using triggerHandler instead of trigger so we can pass + // extra data + var deferred = $.Deferred(); + fetchInfoStub.returns(deferred.promise()); + $uploader.triggerHandler(ev, data || {}); + return deferred; + } + + it('fetches file info', function() { + addFile(createUpload('upload.txt', '/subdir')); + expect(fetchInfoStub.calledOnce).toEqual(true); + expect(fetchInfoStub.getCall(0).args[0]).toEqual('upload.txt'); + expect(fetchInfoStub.getCall(0).args[1]).toEqual('/subdir'); + }); + it('highlights all uploaded files after all fetches are done', function() { + var highlightStub = sinon.stub(fileList, 'highlightFiles'); + var def1 = addFile(createUpload('upload.txt', '/subdir')); + var def2 = addFile(createUpload('upload2.txt', '/subdir')); + var def3 = addFile(createUpload('upload3.txt', '/another')); + $uploader.triggerHandler(new $.Event('fileuploadstop')); + + expect(highlightStub.notCalled).toEqual(true); + def1.resolve(); + expect(highlightStub.notCalled).toEqual(true); + def2.resolve(); + def3.resolve(); + expect(highlightStub.calledOnce).toEqual(true); + expect(highlightStub.getCall(0).args[0]).toEqual(['upload.txt', 'upload2.txt']); + + highlightStub.restore(); + }); + it('queries storage stats', function() { + var statStub = sinon.stub(fileList, 'updateStorageStatistics'); + addFile(createUpload('upload.txt', '/subdir')); + expect(statStub.notCalled).toEqual(true); + $uploader.triggerHandler(new $.Event('fileuploadstop')); + expect(statStub.calledOnce).toEqual(true); + statStub.restore(); + }); + }); }); describe('Handling errors', function () { var deferredList; -- cgit v1.2.3 From f72ffa2f119f0b2644380e5c92f50dd2f05b6531 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 31 Aug 2016 16:32:14 +0200 Subject: Fix js unit tests for webdav put upload changes Signed-off-by: Roeland Jago Douma --- apps/files/js/file-upload.js | 16 +++++-- apps/files/js/filelist.js | 8 ++-- apps/files/tests/js/fileUploadSpec.js | 2 +- apps/files/tests/js/filelistSpec.js | 84 +++++++++++++++-------------------- 4 files changed, 54 insertions(+), 56 deletions(-) (limited to 'apps/files/tests/js') diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 3242ae7fa6b..b75505c5dfb 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -34,7 +34,12 @@ OC.FileUpload = function(uploader, data) { this.uploader = uploader; this.data = data; - var path = OC.joinPaths(this.uploader.fileList.getCurrentDirectory(), this.getFile().name); + var path = ''; + if (this.uploader.fileList) { + path = OC.joinPaths(this.uploader.fileList.getCurrentDirectory(), this.getFile().name); + } else { + path = this.getFile().name; + } this.id = 'web-file-upload-' + md5(path) + '-' + (new Date()).getTime(); }; OC.FileUpload.CONFLICT_MODE_DETECT = 0; @@ -364,6 +369,9 @@ OC.Uploader.prototype = _.extend({ * also see article @link http://blog.new-bamboo.co.uk/2012/01/10/ridiculously-simple-ajax-uploads-with-formdata */ _supportAjaxUploadWithProgress: function() { + if (window.TESTING) { + return true; + } return supportFileAPI() && supportAjaxUploadProgressEvents() && supportFormData(); // Is the File API supported? @@ -719,7 +727,6 @@ OC.Uploader.prototype = _.extend({ dropZone: options.dropZone, // restrict dropZone to content div autoUpload: false, sequentialUploads: true, - maxChunkSize: 10000000, //singleFileUploads is on by default, so the data.files array will always have length 1 /** * on first add of every selection @@ -920,7 +927,10 @@ OC.Uploader.prototype = _.extend({ // HTTP connection problem or other error OC.Notification.showTemporary(data.errorThrown, {timeout: 10}); } - upload.deleteUpload(); + + if (upload) { + upload.deleteUpload(); + } }, /** * called for every successful upload diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 2d6bca80f1a..d4a223058b4 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -2724,16 +2724,16 @@ // add target dir data.targetDir = dir; } else { - // we are dropping somewhere inside the file list, which will - // upload the file to the current directory - data.targetDir = self.getCurrentDirectory(); - // cancel uploads to current dir if no permission var isCreatable = (self.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0; if (!isCreatable) { self._showPermissionDeniedNotification(); return false; } + + // we are dropping somewhere inside the file list, which will + // upload the file to the current directory + data.targetDir = self.getCurrentDirectory(); } }); uploader.on('add', function(e, data) { diff --git a/apps/files/tests/js/fileUploadSpec.js b/apps/files/tests/js/fileUploadSpec.js index bfaf0a9fe57..19f8cde7e44 100644 --- a/apps/files/tests/js/fileUploadSpec.js +++ b/apps/files/tests/js/fileUploadSpec.js @@ -48,7 +48,7 @@ describe('OC.Upload tests', function() { $dummyUploader = $('#file_upload_start'); uploader = new OC.Uploader($dummyUploader); failStub = sinon.stub(); - $dummyUploader.on('fileuploadfail', failStub); + uploader.on('fail', failStub); }); afterEach(function() { $dummyUploader = undefined; diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 55ab2c535af..2064f570ca2 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -2564,15 +2564,12 @@ describe('OCA.Files.FileList tests', function() { * that were registered on the magic upload object */ describe('file upload', function() { - var $uploader; var uploadData; + var uploader; beforeEach(function() { - // note: this isn't the real blueimp file uploader from jquery.fileupload - // but it makes it possible to simulate the event triggering to - // test the response of the handlers - $uploader = $('#file_upload_start'); fileList.setFiles(testFiles); + uploader = fileList._uploader; // simulate data structure from jquery.upload uploadData = { files: [{ @@ -2582,7 +2579,7 @@ describe('OCA.Files.FileList tests', function() { }); afterEach(function() { - $uploader = null; + uploader = null; uploadData = null; }); @@ -2606,11 +2603,7 @@ describe('OCA.Files.FileList tests', function() { * @return event object including the result */ function addFile(data) { - var ev = new $.Event('fileuploadadd', {}); - // using triggerHandler instead of trigger so we can pass - // extra data - $uploader.triggerHandler(ev, data || {}); - return ev; + uploader.trigger('add', {}, data || {}); } it('sets target dir to the current directory', function() { @@ -2632,9 +2625,8 @@ describe('OCA.Files.FileList tests', function() { target: $target } }; - var ev = new $.Event('fileuploaddrop', eventData); - $uploader.trigger(ev, data || {}); - return ev; + uploader.trigger('drop', eventData, data || {}); + return !!data.targetDir; } it('drop on a tr or crumb outside file list does not trigger upload', function() { @@ -2642,62 +2634,62 @@ describe('OCA.Files.FileList tests', function() { var ev; $('#testArea').append($anotherTable); ev = dropOn($anotherTable.find('tr'), uploadData); - expect(ev.result).toEqual(false); + expect(ev).toEqual(false); - ev = dropOn($anotherTable.find('.crumb')); - expect(ev.result).toEqual(false); + ev = dropOn($anotherTable.find('.crumb'), uploadData); + expect(ev).toEqual(false); }); it('drop on an element outside file list container does not trigger upload', function() { var $anotherEl = $('
outside
'); var ev; $('#testArea').append($anotherEl); - ev = dropOn($anotherEl); + ev = dropOn($anotherEl, uploadData); - expect(ev.result).toEqual(false); + expect(ev).toEqual(false); }); it('drop on an element inside the table triggers upload', function() { var ev; ev = dropOn(fileList.$fileList.find('th:first'), uploadData); - expect(ev.result).not.toEqual(false); + expect(ev).not.toEqual(false); expect(uploadData.targetDir).toEqual('/subdir'); }); it('drop on an element on the table container triggers upload', function() { var ev; ev = dropOn($('#app-content-files'), uploadData); - expect(ev.result).not.toEqual(false); + expect(ev).not.toEqual(false); expect(uploadData.targetDir).toEqual('/subdir'); }); it('drop on an element inside the table does not trigger upload if no upload permission', function() { $('#permissions').val(0); var ev; - ev = dropOn(fileList.$fileList.find('th:first')); + ev = dropOn(fileList.$fileList.find('th:first'), uploadData); - expect(ev.result).toEqual(false); + expect(ev).toEqual(false); expect(notificationStub.calledOnce).toEqual(true); }); it('drop on an folder does not trigger upload if no upload permission on that folder', function() { var $tr = fileList.findFileEl('somedir'); var ev; $tr.data('permissions', OC.PERMISSION_READ); - ev = dropOn($tr); + ev = dropOn($tr, uploadData); - expect(ev.result).toEqual(false); + expect(ev).toEqual(false); expect(notificationStub.calledOnce).toEqual(true); }); it('drop on a file row inside the table triggers upload to current folder', function() { var ev; ev = dropOn(fileList.findFileEl('One.txt').find('td:first'), uploadData); - expect(ev.result).not.toEqual(false); + expect(ev).not.toEqual(false); expect(uploadData.targetDir).toEqual('/subdir'); }); it('drop on a folder row inside the table triggers upload to target folder', function() { var ev; ev = dropOn(fileList.findFileEl('somedir').find('td:eq(2)'), uploadData); - expect(ev.result).not.toEqual(false); + expect(ev).not.toEqual(false); expect(uploadData.targetDir).toEqual('/subdir/somedir'); }); it('drop on a breadcrumb inside the table triggers upload to target folder', function() { @@ -2705,7 +2697,7 @@ describe('OCA.Files.FileList tests', function() { fileList.changeDirectory('a/b/c/d'); ev = dropOn(fileList.$el.find('.crumb:eq(2)'), uploadData); - expect(ev.result).not.toEqual(false); + expect(ev).not.toEqual(false); expect(uploadData.targetDir).toEqual('/a/b'); }); it('renders upload indicator element for folders only', function() { @@ -2729,8 +2721,7 @@ describe('OCA.Files.FileList tests', function() { it('fetches folder info', function() { var fetchInfoStub = sinon.stub(fileList, 'addAndFetchFileInfo'); - var ev = new $.Event('fileuploadcreatedfolder', {}); - $uploader.triggerHandler(ev, '/subdir/newfolder'); + uploader.trigger('createdfolder', {}, '/subdir/newfolder'); expect(fetchInfoStub.calledOnce).toEqual(true); expect(fetchInfoStub.getCall(0).args[0]).toEqual('newfolder'); @@ -2753,19 +2744,16 @@ describe('OCA.Files.FileList tests', function() { function createUpload(name, dir) { - var data = { - files: [{ - name: name - }], - upload: { - getFileName: sinon.stub().returns(name), - getFullPath: sinon.stub().returns(dir) - }, - jqXHR: { - status: 200 + var jqXHR = { + status: 200 + }; + return { + getFileName: sinon.stub().returns(name), + getFullPath: sinon.stub().returns(dir), + data: { + jqXHR: jqXHR } - } - return data; + }; } /** @@ -2774,12 +2762,12 @@ describe('OCA.Files.FileList tests', function() { * @return event object including the result */ function addFile(data) { - var ev = new $.Event('fileuploaddone', {}); - // using triggerHandler instead of trigger so we can pass - // extra data + var ev = new $.Event('done', { + jqXHR: {status: 200} + }); var deferred = $.Deferred(); fetchInfoStub.returns(deferred.promise()); - $uploader.triggerHandler(ev, data || {}); + uploader.trigger('done', ev, data || {}); return deferred; } @@ -2794,7 +2782,7 @@ describe('OCA.Files.FileList tests', function() { var def1 = addFile(createUpload('upload.txt', '/subdir')); var def2 = addFile(createUpload('upload2.txt', '/subdir')); var def3 = addFile(createUpload('upload3.txt', '/another')); - $uploader.triggerHandler(new $.Event('fileuploadstop')); + uploader.trigger('stop', {}); expect(highlightStub.notCalled).toEqual(true); def1.resolve(); @@ -2810,7 +2798,7 @@ describe('OCA.Files.FileList tests', function() { var statStub = sinon.stub(fileList, 'updateStorageStatistics'); addFile(createUpload('upload.txt', '/subdir')); expect(statStub.notCalled).toEqual(true); - $uploader.triggerHandler(new $.Event('fileuploadstop')); + uploader.trigger('stop', {}); expect(statStub.calledOnce).toEqual(true); statStub.restore(); }); -- cgit v1.2.3 From f374eb5f1df6f84f94847dae2ee5700436322b50 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sat, 3 Sep 2016 18:06:35 +0200 Subject: More fixes to file upload Signed-off-by: Roeland Jago Douma --- apps/files/js/file-upload.js | 28 +++++++++++++------------ apps/files/js/filelist.js | 24 ++++++++++++++-------- apps/files/tests/js/filelistSpec.js | 2 +- core/js/files/client.js | 41 ++++++++++++++++++++++++++++++++++++- 4 files changed, 72 insertions(+), 23 deletions(-) (limited to 'apps/files/tests/js') diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index b75505c5dfb..30784528700 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -204,6 +204,14 @@ OC.FileUpload.prototype = { this.data.headers['X-OC-Mtime'] = file.lastModified / 1000; } + var userName = this.uploader.filesClient.getUserName(); + var password = this.uploader.filesClient.getPassword(); + if (userName) { + // copy username/password from DAV client + this.data.headers['Authorization'] = + 'Basic ' + btoa(userName + ':' + (password || '')); + } + if (!this.uploader.isXHRUpload()) { data.formData = []; @@ -222,7 +230,7 @@ OC.FileUpload.prototype = { && this.getFile().size > this.uploader.fileUploadParam.maxChunkSize ) { data.isChunked = true; - chunkFolderPromise = this.uploader.davClient.createDirectory( + chunkFolderPromise = this.uploader.filesClient.createDirectory( 'uploads/' + encodeURIComponent(OC.getCurrentUser().uid) + '/' + encodeURIComponent(this.getId()) ); // TODO: if fails, it means same id already existed, need to retry @@ -248,7 +256,7 @@ OC.FileUpload.prototype = { } var uid = OC.getCurrentUser().uid; - return this.uploader.davClient.move( + return this.uploader.filesClient.move( 'uploads/' + encodeURIComponent(uid) + '/' + encodeURIComponent(this.getId()) + '/.file', 'files/' + encodeURIComponent(uid) + '/' + OC.joinPaths(this.getFullPath(), this.getFileName()) ); @@ -260,7 +268,7 @@ OC.FileUpload.prototype = { abort: function() { if (this.data.isChunked) { // delete transfer directory for this upload - this.uploader.davClient.remove( + this.uploader.filesClient.remove( 'uploads/' + encodeURIComponent(OC.getCurrentUser().uid) + '/' + encodeURIComponent(this.getId()) ); } @@ -343,7 +351,7 @@ OC.Uploader.prototype = _.extend({ /** * @type Array */ - _uploads: [], + _uploads: {}, /** * List of directories known to exist. @@ -586,7 +594,7 @@ OC.Uploader.prototype = _.extend({ onReplace:function(upload) { this.log('replace', null, upload); upload.setConflictMode(OC.FileUpload.CONFLICT_MODE_OVERWRITE); - upload.submit(); + this.submitUploads([upload]); }, /** * handle uploading a file and letting the server decide a new name @@ -595,7 +603,7 @@ OC.Uploader.prototype = _.extend({ onAutorename:function(upload) { this.log('autorename', null, upload); upload.setConflictMode(OC.FileUpload.CONFLICT_MODE_AUTORENAME); - upload.submit(); + this.submitUploads([upload]); }, _trace:false, //TODO implement log handler for JS per class? log:function(caption, e, data) { @@ -707,19 +715,13 @@ OC.Uploader.prototype = _.extend({ this.fileList = options.fileList; this.filesClient = options.filesClient || OC.Files.getClient(); - this.davClient = new OC.Files.Client({ - host: OC.getHost(), - port: OC.getPort(), - root: OC.getRootPath() + '/remote.php/dav/', - useHTTPS: OC.getProtocol() === 'https' - }); $uploadEl = $($uploadEl); this.$uploadEl = $uploadEl; if ($uploadEl.exists()) { $('#uploadprogresswrapper .stop').on('click', function() { - this.cancelUploads(); + self.cancelUploads(); }); this.fileUploadParam = { diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index d4a223058b4..d932c06d853 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -2786,8 +2786,13 @@ if (OC.isSamePath(OC.dirname(upload.getFullPath() + '/'), self.getCurrentDirectory())) { self._uploads[fileName] = fetchInfoPromise; } + + var uploadText = self.$fileList.find('tr .uploadtext'); + self.showFileBusyState(uploadText.closest('tr'), false); + uploadText.fadeOut(); + uploadText.attr('currentUploads', 0); }); - uploader.on('createdfolder', function(e, fullPath) { + uploader.on('createdfolder', function(fullPath) { self.addAndFetchFileInfo(OC.basename(fullPath), OC.dirname(fullPath)); }); uploader.on('stop', function() { @@ -2805,6 +2810,11 @@ self.highlightFiles(fileNames); }); self.updateStorageStatistics(); + + var uploadText = self.$fileList.find('tr .uploadtext'); + self.showFileBusyState(uploadText.closest('tr'), false); + uploadText.fadeOut(); + uploadText.attr('currentUploads', 0); }); uploader.on('fail', function(e, data) { self._uploader.log('filelist handle fileuploadfail', e, data); @@ -2812,13 +2822,11 @@ self._uploads = []; //if user pressed cancel hide upload chrome - if (data.errorThrown === 'abort') { - //cleanup uploading to a dir - var uploadText = self.$fileList.find('tr .uploadtext'); - self.showFileBusyState(uploadText.closest('tr'), false); - uploadText.fadeOut(); - uploadText.attr('currentUploads', 0); - } + //cleanup uploading to a dir + var uploadText = self.$fileList.find('tr .uploadtext'); + self.showFileBusyState(uploadText.closest('tr'), false); + uploadText.fadeOut(); + uploadText.attr('currentUploads', 0); self.updateStorageStatistics(); }); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 2064f570ca2..1c73bc845c5 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -2721,7 +2721,7 @@ describe('OCA.Files.FileList tests', function() { it('fetches folder info', function() { var fetchInfoStub = sinon.stub(fileList, 'addAndFetchFileInfo'); - uploader.trigger('createdfolder', {}, '/subdir/newfolder'); + uploader.trigger('createdfolder', '/subdir/newfolder'); expect(fetchInfoStub.calledOnce).toEqual(true); expect(fetchInfoStub.getCall(0).args[0]).toEqual('newfolder'); diff --git a/core/js/files/client.js b/core/js/files/client.js index 572f7879e17..43743fb2d8c 100644 --- a/core/js/files/client.js +++ b/core/js/files/client.js @@ -722,8 +722,47 @@ */ addFileInfoParser: function(parserFunction) { this._fileInfoParsers.push(parserFunction); - } + }, + /** + * Returns the dav.Client instance used internally + * + * @since 9.2 + * @return {dav.Client} + */ + getClient: function() { + return this._client; + }, + + /** + * Returns the user name + * + * @since 9.2 + * @return {String} userName + */ + getUserName: function() { + return this._client.userName; + }, + + /** + * Returns the password + * + * @since 9.2 + * @return {String} password + */ + getPassword: function() { + return this._client.password; + }, + + /** + * Returns the base URL + * + * @since 9.2 + * @return {String} base URL + */ + getBaseUrl: function() { + return this._client.baseUrl; + } }; /** -- cgit v1.2.3