From 40a2270f6b36bb8f37721fcac0b2c0167e68e9a4 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 24 Oct 2024 10:05:16 -0700 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=9A=A7=20WIP:=20enable=20chunked=20up?= =?UTF-8?q?loads?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/javascripts/hyrax/uploader.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/hyrax/uploader.js b/app/assets/javascripts/hyrax/uploader.js index 9b7a93981f..84e7709fd9 100644 --- a/app/assets/javascripts/hyrax/uploader.js +++ b/app/assets/javascripts/hyrax/uploader.js @@ -23,14 +23,18 @@ hyraxUploader: function( options ) { // Initialize our jQuery File Upload widget. this.fileupload($.extend({ - // xhrFields: {withCredentials: true}, // to send cross-domain cookies - // acceptFileTypes: /(\.|\/)(png|mov|jpe?g|pdf)$/i, // not a strong check, just a regex on the filename - // limitMultiFileUploadSize: 500000000, // bytes + maxChunkSize: 500, // 10 MB autoUpload: true, url: '/uploads/', type: 'POST', dropZone: $(this).find('.dropzone') }, Hyrax.config.uploader, options)) + .on('fileuploadsend', function(e, data) { + if (data.files[0].size > data.maxChunkSize) { + console.log('Chunking in progress...'); + } + console.log('Sending chunk or full file: ', data); + }) .on('fileuploadadded', function (e, data) { $(e.currentTarget).find('button.cancel').removeAttr("hidden"); }); From 77e18b8eb43279b8dfb2947c930167797ee376db Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 24 Oct 2024 11:00:56 -0700 Subject: [PATCH 2/6] Adds resume_upload --- app/assets/javascripts/hyrax/uploader.js | 31 +++++++++++++++------ app/controllers/hyrax/uploads_controller.rb | 13 ++++++++- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/hyrax/uploader.js b/app/assets/javascripts/hyrax/uploader.js index 84e7709fd9..4c7cf7bdc2 100644 --- a/app/assets/javascripts/hyrax/uploader.js +++ b/app/assets/javascripts/hyrax/uploader.js @@ -23,18 +23,32 @@ hyraxUploader: function( options ) { // Initialize our jQuery File Upload widget. this.fileupload($.extend({ - maxChunkSize: 500, // 10 MB + maxChunkSize: 10000000, // 10 MB autoUpload: true, url: '/uploads/', type: 'POST', - dropZone: $(this).find('.dropzone') - }, Hyrax.config.uploader, options)) - .on('fileuploadsend', function(e, data) { - if (data.files[0].size > data.maxChunkSize) { - console.log('Chunking in progress...'); + dropZone: $(this).find('.dropzone'), + add: function (e, data) { + var that = this; + $.getJSON('/uploads/resume_upload', {file: data.files[0].name}, function (result) { + var file = result.file; + if (file && file.size) { + if (file.size >= data.files[0].size) { + console.log('File already fully uploaded.'); + // Skip upload since the file is already uploaded + return; + } + console.log('Resuming upload from byte: ', file.size); + data.uploadedBytes = file.size; + } else { + console.log('No file found, starting new upload.'); + data.uploadedBytes = 0; // Start fresh + } + $.blueimp.fileupload.prototype.options.add.call(that, e, data); + }); } - console.log('Sending chunk or full file: ', data); - }) + + }, Hyrax.config.uploader, options)) .on('fileuploadadded', function (e, data) { $(e.currentTarget).find('button.cancel').removeAttr("hidden"); }); @@ -69,3 +83,4 @@ } }); })(jQuery); + diff --git a/app/controllers/hyrax/uploads_controller.rb b/app/controllers/hyrax/uploads_controller.rb index 8583e3d8d3..13b460cff0 100644 --- a/app/controllers/hyrax/uploads_controller.rb +++ b/app/controllers/hyrax/uploads_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Hyrax class UploadsController < ApplicationController - load_and_authorize_resource class: Hyrax::UploadedFile + load_and_authorize_resource class: Hyrax::UploadedFile, except: :resume_upload def create @upload.attributes = { file: params[:files].first, @@ -13,5 +13,16 @@ def destroy @upload.destroy head :no_content end + + def resume_upload + file_name = params[:file] + uploaded_file = Hyrax::UploadedFile.find_by(file: file_name) + + if uploaded_file + render json: { file: { name: uploaded_file.file_set_uri, size: uploaded_file.file.size } } + else + render json: { file: nil } + end + end end end From e3961c762b6168451eca81c1d659437bc2ec3cf4 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 24 Oct 2024 12:56:08 -0700 Subject: [PATCH 3/6] Adds delete_incomplete functionality --- app/assets/javascripts/hyrax/uploader.js | 84 +++++++++++++++------ app/controllers/hyrax/uploads_controller.rb | 14 +++- config/routes.rb | 3 + 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/hyrax/uploader.js b/app/assets/javascripts/hyrax/uploader.js index 4c7cf7bdc2..c848ded20f 100644 --- a/app/assets/javascripts/hyrax/uploader.js +++ b/app/assets/javascripts/hyrax/uploader.js @@ -10,7 +10,6 @@ * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan - * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT @@ -23,29 +22,70 @@ hyraxUploader: function( options ) { // Initialize our jQuery File Upload widget. this.fileupload($.extend({ - maxChunkSize: 10000000, // 10 MB + maxChunkSize: 5000000, // 5 MB chunk size autoUpload: true, url: '/uploads/', type: 'POST', dropZone: $(this).find('.dropzone'), + + // Override the add function to handle resume or fresh upload add: function (e, data) { var that = this; - $.getJSON('/uploads/resume_upload', {file: data.files[0].name}, function (result) { + + // Check with the server if a partial upload exists for this file + $.getJSON('/uploads/resume_upload', { file: data.files[0].name }, function (result) { var file = result.file; - if (file && file.size) { - if (file.size >= data.files[0].size) { - console.log('File already fully uploaded.'); - // Skip upload since the file is already uploaded - return; - } + + // If file exists and is partially uploaded, resume from the correct byte + if (file && file.size && file.size < data.files[0].size) { console.log('Resuming upload from byte: ', file.size); data.uploadedBytes = file.size; + + // If file exists and is fully uploaded, force a new upload + } else if (file && file.size >= data.files[0].size) { + console.log('File already fully uploaded, starting a new upload.'); + data.uploadedBytes = 0; + + // Otherwise, this is a fresh upload } else { console.log('No file found, starting new upload.'); - data.uploadedBytes = 0; // Start fresh + data.uploadedBytes = 0; } + + // Proceed with the upload $.blueimp.fileupload.prototype.options.add.call(that, e, data); }); + }, + + // Handle failed uploads and send a DELETE request to remove incomplete files + fail: function (e, data) { + console.log('Upload failed or aborted. Deleting incomplete upload...'); + + // Make a DELETE request to remove incomplete uploads + $.ajax({ + url: '/uploads/delete_incomplete', + type: 'DELETE', + contentType: 'application/json', + data: JSON.stringify({ file_name: data.files[0].name }), + success: function (response) { + console.log('Incomplete upload deleted successfully.'); + + // Remove the file row from the upload list in the UI + $(data.context).fadeOut(function () { + $(this).remove(); // Remove the row from the UI + }); + + // Alternatively, mark it as "Cancelled" + // $(data.context).find('.status').text('Cancelled').addClass('text-danger'); + }, + error: function (xhr, status, error) { + console.error('Failed to delete incomplete upload:', error); + + $(data.context).fadeOut(function () { + $(this).remove(); // Remove the row from the UI + }); + } + }); } }, Hyrax.config.uploader, options)) @@ -53,34 +93,34 @@ $(e.currentTarget).find('button.cancel').removeAttr("hidden"); }); + // Add the drag and drop event handlers for visual feedback $(document).on('dragover', function(e) { var dropZone = $('.dropzone'), timeout = window.dropZoneTimeout; if (!timeout) { - dropZone.addClass('in'); + dropZone.addClass('in'); } else { - clearTimeout(timeout); + clearTimeout(timeout); } var found = false, node = e.target; do { - if (node === dropZone[0]) { - found = true; - break; - } - node = node.parentNode; + if (node === dropZone[0]) { + found = true; + break; + } + node = node.parentNode; } while (node !== null); if (found) { - dropZone.addClass('hover'); + dropZone.addClass('hover'); } else { - dropZone.removeClass('hover'); + dropZone.removeClass('hover'); } window.dropZoneTimeout = setTimeout(function () { - window.dropZoneTimeout = null; - dropZone.removeClass('in hover'); + window.dropZoneTimeout = null; + dropZone.removeClass('in hover'); }, 100); }); } }); })(jQuery); - diff --git a/app/controllers/hyrax/uploads_controller.rb b/app/controllers/hyrax/uploads_controller.rb index 13b460cff0..835b31b302 100644 --- a/app/controllers/hyrax/uploads_controller.rb +++ b/app/controllers/hyrax/uploads_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Hyrax class UploadsController < ApplicationController - load_and_authorize_resource class: Hyrax::UploadedFile, except: :resume_upload + load_and_authorize_resource class: Hyrax::UploadedFile, except: [:resume_upload, :delete_incomplete] def create @upload.attributes = { file: params[:files].first, @@ -24,5 +24,17 @@ def resume_upload render json: { file: nil } end end + + def delete_incomplete + file_name = params[:file_name] + uploaded_file = Hyrax::UploadedFile.find_by(file: file_name) + + if uploaded_file + uploaded_file.destroy + render json: { success: true, message: "Incomplete upload deleted." }, status: :ok + else + render json: { success: false, message: "File not found." }, status: :not_found + end + end end end diff --git a/config/routes.rb b/config/routes.rb index 69e6dbfecb..4c485c844d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,7 @@ get '/resourcelist' => 'resource_sync#resource_list', as: :resource_list get '/changelist' => 'resource_sync#change_list', as: :change_list + delete '/uploads/delete_incomplete', to: 'uploads#delete_incomplete' delete '/uploads/:id', to: 'uploads#destroy', as: :uploaded_file post '/uploads', to: 'uploads#create' # This is a hack that is required because the rails form the uploader is on @@ -25,6 +26,8 @@ # Eventually it would be good to update the javascript so that it doesn't # submit the form, just the file and always uses POST. patch '/uploads', to: 'uploads#create' + get '/uploads/resume_upload', to: 'uploads#resume_upload' + match 'batch_edits/clear' => 'batch_edits#clear', as: :batch_edits_clear, via: [:get, :post] resources :batch_edits, only: [:index] do From f3dbf543e384d5bea27cd6471d18e4f5423ac578 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 24 Oct 2024 15:45:48 -0700 Subject: [PATCH 4/6] Implements chunking on the server side This is also backwards compatible and enables chunked uploading of Hyrax files. --- app/assets/javascripts/hyrax/uploader.js | 63 +------------------- app/controllers/hyrax/uploads_controller.rb | 45 +++++++------- app/views/hyrax/uploads/create.json.jbuilder | 4 +- config/routes.rb | 2 - 4 files changed, 25 insertions(+), 89 deletions(-) diff --git a/app/assets/javascripts/hyrax/uploader.js b/app/assets/javascripts/hyrax/uploader.js index c848ded20f..8cbc5cd565 100644 --- a/app/assets/javascripts/hyrax/uploader.js +++ b/app/assets/javascripts/hyrax/uploader.js @@ -20,80 +20,23 @@ $.fn.extend({ hyraxUploader: function( options ) { - // Initialize our jQuery File Upload widget. this.fileupload($.extend({ - maxChunkSize: 5000000, // 5 MB chunk size + maxChunkSize: 10000000, // 10 MB chunk size autoUpload: true, url: '/uploads/', type: 'POST', dropZone: $(this).find('.dropzone'), - - // Override the add function to handle resume or fresh upload add: function (e, data) { var that = this; - - // Check with the server if a partial upload exists for this file - $.getJSON('/uploads/resume_upload', { file: data.files[0].name }, function (result) { - var file = result.file; - - // If file exists and is partially uploaded, resume from the correct byte - if (file && file.size && file.size < data.files[0].size) { - console.log('Resuming upload from byte: ', file.size); - data.uploadedBytes = file.size; - - // If file exists and is fully uploaded, force a new upload - } else if (file && file.size >= data.files[0].size) { - console.log('File already fully uploaded, starting a new upload.'); - data.uploadedBytes = 0; - - // Otherwise, this is a fresh upload - } else { - console.log('No file found, starting new upload.'); - data.uploadedBytes = 0; - } - - // Proceed with the upload + $.post('/uploads/', { files: [data.files[0].name] }, function (result) { + data.formData = {id: result.files[0].id}; $.blueimp.fileupload.prototype.options.add.call(that, e, data); }); - }, - - // Handle failed uploads and send a DELETE request to remove incomplete files - fail: function (e, data) { - console.log('Upload failed or aborted. Deleting incomplete upload...'); - - // Make a DELETE request to remove incomplete uploads - $.ajax({ - url: '/uploads/delete_incomplete', - type: 'DELETE', - contentType: 'application/json', - data: JSON.stringify({ file_name: data.files[0].name }), - success: function (response) { - console.log('Incomplete upload deleted successfully.'); - - // Remove the file row from the upload list in the UI - $(data.context).fadeOut(function () { - $(this).remove(); // Remove the row from the UI - }); - - // Alternatively, mark it as "Cancelled" - // $(data.context).find('.status').text('Cancelled').addClass('text-danger'); - }, - error: function (xhr, status, error) { - console.error('Failed to delete incomplete upload:', error); - - $(data.context).fadeOut(function () { - $(this).remove(); // Remove the row from the UI - }); - } - }); } - }, Hyrax.config.uploader, options)) .on('fileuploadadded', function (e, data) { $(e.currentTarget).find('button.cancel').removeAttr("hidden"); }); - - // Add the drag and drop event handlers for visual feedback $(document).on('dragover', function(e) { var dropZone = $('.dropzone'), timeout = window.dropZoneTimeout; diff --git a/app/controllers/hyrax/uploads_controller.rb b/app/controllers/hyrax/uploads_controller.rb index 835b31b302..1b0cfb5fc1 100644 --- a/app/controllers/hyrax/uploads_controller.rb +++ b/app/controllers/hyrax/uploads_controller.rb @@ -4,8 +4,26 @@ class UploadsController < ApplicationController load_and_authorize_resource class: Hyrax::UploadedFile, except: [:resume_upload, :delete_incomplete] def create - @upload.attributes = { file: params[:files].first, - user: current_user } + + if params[:id].blank? + @upload.attributes = { file: params[:files].first, + user: current_user } + else + @upload = Hyrax::UploadedFile.find(params[:id]) + unpersisted_upload = Hyrax::UploadedFile.new(file: params[:files].first, user: current_user) + + # deal with chunks + current_size = @upload.file.size + content_range = request.headers['CONTENT-RANGE'] + begin_of_chunk = content_range[/\ (.*?)-/,1].to_i # "bytes 100-999999/1973660678" will return '100' + + # Add the following chunk to the incomplete upload + if @upload.file.present? && begin_of_chunk == current_size + File.open(@upload.file.path, "ab") { |f| f.write(params[:files].first.read) } + else + @upload.file = unpersisted_upload.file + end + end @upload.save! end @@ -13,28 +31,5 @@ def destroy @upload.destroy head :no_content end - - def resume_upload - file_name = params[:file] - uploaded_file = Hyrax::UploadedFile.find_by(file: file_name) - - if uploaded_file - render json: { file: { name: uploaded_file.file_set_uri, size: uploaded_file.file.size } } - else - render json: { file: nil } - end - end - - def delete_incomplete - file_name = params[:file_name] - uploaded_file = Hyrax::UploadedFile.find_by(file: file_name) - - if uploaded_file - uploaded_file.destroy - render json: { success: true, message: "Incomplete upload deleted." }, status: :ok - else - render json: { success: false, message: "File not found." }, status: :not_found - end - end end end diff --git a/app/views/hyrax/uploads/create.json.jbuilder b/app/views/hyrax/uploads/create.json.jbuilder index 1db266cabe..58a16b5b35 100644 --- a/app/views/hyrax/uploads/create.json.jbuilder +++ b/app/views/hyrax/uploads/create.json.jbuilder @@ -1,8 +1,8 @@ # frozen_string_literal: true json.files [@upload] do |uploaded_file| json.id uploaded_file.id - json.name uploaded_file.file.file.filename - json.size uploaded_file.file.file.size + json.name uploaded_file.file&.file&.filename + json.size uploaded_file.file&.file&.size # TODO: implement these # json.url "/uploads/#{uploaded_file.id}" # json.thumbnail_url uploaded_file.id diff --git a/config/routes.rb b/config/routes.rb index 4c485c844d..c54ab00c39 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,7 +18,6 @@ get '/resourcelist' => 'resource_sync#resource_list', as: :resource_list get '/changelist' => 'resource_sync#change_list', as: :change_list - delete '/uploads/delete_incomplete', to: 'uploads#delete_incomplete' delete '/uploads/:id', to: 'uploads#destroy', as: :uploaded_file post '/uploads', to: 'uploads#create' # This is a hack that is required because the rails form the uploader is on @@ -26,7 +25,6 @@ # Eventually it would be good to update the javascript so that it doesn't # submit the form, just the file and always uses POST. patch '/uploads', to: 'uploads#create' - get '/uploads/resume_upload', to: 'uploads#resume_upload' match 'batch_edits/clear' => 'batch_edits#clear', as: :batch_edits_clear, via: [:get, :post] From b47aff4eb1db3044cd0d1469df399844f6a889b1 Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Thu, 24 Oct 2024 16:19:34 -0700 Subject: [PATCH 5/6] Adds specs to reflect chunked uploads --- app/controllers/hyrax/uploads_controller.rb | 55 ++++++++++++------ config/routes.rb | 1 - .../hyrax/uploads_controller_spec.rb | 51 ++++++++++++++++ spec/fixtures/different_file.png | Bin 0 -> 156 bytes 4 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 spec/fixtures/different_file.png diff --git a/app/controllers/hyrax/uploads_controller.rb b/app/controllers/hyrax/uploads_controller.rb index 1b0cfb5fc1..1672ac1211 100644 --- a/app/controllers/hyrax/uploads_controller.rb +++ b/app/controllers/hyrax/uploads_controller.rb @@ -1,28 +1,13 @@ # frozen_string_literal: true module Hyrax class UploadsController < ApplicationController - load_and_authorize_resource class: Hyrax::UploadedFile, except: [:resume_upload, :delete_incomplete] + load_and_authorize_resource class: Hyrax::UploadedFile def create - if params[:id].blank? - @upload.attributes = { file: params[:files].first, - user: current_user } + handle_new_upload else - @upload = Hyrax::UploadedFile.find(params[:id]) - unpersisted_upload = Hyrax::UploadedFile.new(file: params[:files].first, user: current_user) - - # deal with chunks - current_size = @upload.file.size - content_range = request.headers['CONTENT-RANGE'] - begin_of_chunk = content_range[/\ (.*?)-/,1].to_i # "bytes 100-999999/1973660678" will return '100' - - # Add the following chunk to the incomplete upload - if @upload.file.present? && begin_of_chunk == current_size - File.open(@upload.file.path, "ab") { |f| f.write(params[:files].first.read) } - else - @upload.file = unpersisted_upload.file - end + handle_chunked_upload end @upload.save! end @@ -31,5 +16,39 @@ def destroy @upload.destroy head :no_content end + + private + + def handle_new_upload + @upload.attributes = { file: params[:files].first, user: current_user } + end + + def handle_chunked_upload + @upload = Hyrax::UploadedFile.find(params[:id]) + unpersisted_upload = Hyrax::UploadedFile.new(file: params[:files].first, user: current_user) + + if chunk_valid?(@upload) + append_chunk(@upload) + else + replace_file(@upload, unpersisted_upload) + end + end + + def chunk_valid?(upload) + current_size = upload.file.size + content_range = request.headers['CONTENT-RANGE'] + begin_of_chunk = content_range[/\ (.*?)-/, 1].to_i + upload.file.present? && begin_of_chunk == current_size + end + + def append_chunk(upload) + File.open(upload.file.path, "ab") { |f| f.write(params[:files].first.read) } + end + + def replace_file(upload, unpersisted_upload) + upload.file = unpersisted_upload.file + upload.save! + upload.reload + end end end diff --git a/config/routes.rb b/config/routes.rb index c54ab00c39..69e6dbfecb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,7 +25,6 @@ # Eventually it would be good to update the javascript so that it doesn't # submit the form, just the file and always uses POST. patch '/uploads', to: 'uploads#create' - match 'batch_edits/clear' => 'batch_edits#clear', as: :batch_edits_clear, via: [:get, :post] resources :batch_edits, only: [:index] do diff --git a/spec/controllers/hyrax/uploads_controller_spec.rb b/spec/controllers/hyrax/uploads_controller_spec.rb index a27e9d324b..095531951e 100644 --- a/spec/controllers/hyrax/uploads_controller_spec.rb +++ b/spec/controllers/hyrax/uploads_controller_spec.rb @@ -1,14 +1,17 @@ # frozen_string_literal: true RSpec.describe Hyrax::UploadsController do let(:user) { create(:user) } + let(:chunk) { fixture_file_upload('/world.png', 'image/png') } describe "#create" do let(:file) { fixture_file_upload('/world.png', 'image/png') } + let!(:existing_file) { create(:uploaded_file, file: file, user: user) } context "when signed in" do before do sign_in user end + it "is successful" do post :create, params: { files: [file], format: 'json' } expect(response).to be_successful @@ -16,6 +19,53 @@ expect(assigns(:upload)).to be_persisted expect(assigns(:upload).user).to eq user end + + context "when uploading in chunks" do + it "appends chunks when they are valid" do + original_file = fixture_file_upload('/world.png', 'image/png') + post :create, params: { files: [original_file], format: 'json' } + original_upload = assigns(:upload) + + request.headers['CONTENT-RANGE'] = 'bytes 0-99/1000' + new_chunk = fixture_file_upload('/world.png', 'image/png') + post :create, params: { files: [new_chunk], id: original_upload.id, format: 'json' } + + original_upload.reload + expect(original_upload.file.size).to eq(File.size(original_upload.file.path)) + end + + it "replaces file if chunks are mismatched" do + original_file = fixture_file_upload('/world.png', 'image/png') + post :create, params: { files: [original_file], format: 'json' } + original_upload = assigns(:upload) + original_content = File.read(original_upload.file.path) + + request.headers['CONTENT-RANGE'] = 'bytes 101-200/1000' + different_chunk = fixture_file_upload('/different_file.png', 'image/png') + post :create, params: { files: [different_chunk], id: original_upload.id, format: 'json' } + + original_upload.reload + new_content = File.read(original_upload.file.path) + + expect(new_content).not_to eq(original_content) + end + + it "updates the file size after replacing mismatched chunks" do + original_file = fixture_file_upload('/world.png', 'image/png') + post :create, params: { files: [original_file], format: 'json' } + original_upload = assigns(:upload) + original_size = original_upload.file.size + + request.headers['CONTENT-RANGE'] = 'bytes 101-200/1000' + different_chunk = fixture_file_upload('/different_file.png', 'image/png') + post :create, params: { files: [different_chunk], id: original_upload.id, format: 'json' } + + original_upload.reload + new_size = original_upload.file.size + + expect(new_size).not_to eq(original_size) + end + end end context "when not signed in" do @@ -34,6 +84,7 @@ before do sign_in user end + it "destroys the uploaded file" do delete :destroy, params: { id: uploaded_file } expect(response.status).to eq 204 diff --git a/spec/fixtures/different_file.png b/spec/fixtures/different_file.png new file mode 100644 index 0000000000000000000000000000000000000000..aa1eb92f57ed853bb2964dabf8eaa7bd5cf09f63 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGJMWKS2zkcv5P&pYxSP+&OVa6mRm wpy_qzgTly5!57ZezWcFxDRZ3Z0!m Date: Fri, 25 Oct 2024 08:24:09 -0700 Subject: [PATCH 6/6] FIx for failing dassie specs --- app/controllers/hyrax/uploads_controller.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/controllers/hyrax/uploads_controller.rb b/app/controllers/hyrax/uploads_controller.rb index 1672ac1211..cb744dcfab 100644 --- a/app/controllers/hyrax/uploads_controller.rb +++ b/app/controllers/hyrax/uploads_controller.rb @@ -37,6 +37,9 @@ def handle_chunked_upload def chunk_valid?(upload) current_size = upload.file.size content_range = request.headers['CONTENT-RANGE'] + + return false unless content_range + begin_of_chunk = content_range[/\ (.*?)-/, 1].to_i upload.file.present? && begin_of_chunk == current_size end