diff --git a/app/controllers/avo/actions_controller.rb b/app/controllers/avo/actions_controller.rb index 7ae03803fb..2510ce3fd3 100644 --- a/app/controllers/avo/actions_controller.rb +++ b/app/controllers/avo/actions_controller.rb @@ -69,7 +69,7 @@ def respond when :download # Trigger download, removes modal and flash the messages render turbo_stream: [ - turbo_stream.download(content: @response[:path], filename: @response[:filename]), + turbo_stream.download(content: Base64.encode64(@response[:path]), filename: @response[:filename]), turbo_stream.close_action_modal, turbo_stream.flash_alerts ] diff --git a/app/javascript/js/custom-stream-actions.js b/app/javascript/js/custom-stream-actions.js index 2f10383310..03d346ddd4 100644 --- a/app/javascript/js/custom-stream-actions.js +++ b/app/javascript/js/custom-stream-actions.js @@ -16,10 +16,18 @@ StreamActions.open_filter = function () { } // END TODO: move these to the avo_filters gem +// https://stackoverflow.com/a/77850750/9067704 StreamActions.download = function () { + var byteCharacters = atob(this.getAttribute('content');); + var byteNumbers = new Array(byteCharacters.length); + for (var i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i); + } + var byteArray = new Uint8Array(byteNumbers); + saveAs( new Blob( - [this.getAttribute('content')], + [byteArray], ), this.getAttribute('filename'), ) diff --git a/spec/dummy/app/avo/actions/download_file.rb b/spec/dummy/app/avo/actions/download_file.rb index e6946ea233..501ce98ffc 100644 --- a/spec/dummy/app/avo/actions/download_file.rb +++ b/spec/dummy/app/avo/actions/download_file.rb @@ -5,6 +5,7 @@ class Avo::Actions::DownloadFile < Avo::BaseAction # TODO: fix fields for actions def fields field :read_from_file, as: :boolean, name: "Read from file", default: false + field :read_from_pdf_file, as: :boolean, name: "Read from PDF file", default: false end def handle(**args) @@ -15,6 +16,10 @@ def handle(**args) file = File.open(Avo::Engine.root.join("spec", "dummy", "dummy-file.txt")) download file.read, "dummy-file.txt" + elsif fields["read_from_pdf_file"] + file = File.open(Avo::Engine.root.join("spec", "dummy", "dummy-file.pdf")) + + download file.read, "dummy-file.pdf" else download "On the fly dummy content.", "dummy-content.txt" end diff --git a/spec/dummy/dummy-file.pdf b/spec/dummy/dummy-file.pdf new file mode 100644 index 0000000000..774c2ea70c Binary files /dev/null and b/spec/dummy/dummy-file.pdf differ diff --git a/spec/system/avo/actions_spec.rb b/spec/system/avo/actions_spec.rb index b7f3d52c3e..c2216d24c6 100644 --- a/spec/system/avo/actions_spec.rb +++ b/spec/system/avo/actions_spec.rb @@ -120,6 +120,25 @@ expect(download.split("/").last).to eq file_name end end + + context "with File.open().read on pdf" do + let(:file_name) { "dummy-file.pdf" } + + it "downloads the file and closes the modal" do + visit "/admin/resources/users" + + click_on "Actions" + click_on "Download file" + check "fields[read_from_pdf_file]" + click_on "Run" + + wait_for_download + + expect(downloaded?).to be true + expect(download_content).to eq File.read(Rails.root.join(file_name)) + expect(download.split("/").last).to eq file_name + end + end end describe "default values" do