diff --git a/Gemfile b/Gemfile index 54a8df2d0..30941507c 100644 --- a/Gemfile +++ b/Gemfile @@ -36,6 +36,8 @@ gem "decidim-user_extension", path: "decidim-user_extension" gem "slack-ruby-client" +gem "ferrum" + group :development, :test do gem "byebug", "~> 11.0", platform: :mri gem "figaro" diff --git a/Gemfile.lock b/Gemfile.lock index b5876f389..2405dfb65 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -447,6 +447,11 @@ GEM faraday-multipart (1.0.4) multipart-post (~> 2) faraday-net_http (3.0.2) + ferrum (0.13) + addressable (~> 2.5) + concurrent-ruby (~> 1.1) + webrick (~> 1.7) + websocket-driver (>= 0.6, < 0.8) ffi (1.15.5) figaro (1.2.0) thor (>= 0.14.0, < 2) @@ -890,6 +895,7 @@ GEM jwt (~> 2.0) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) + webrick (1.8.1) websocket-extensions (0.1.5) wicked_pdf (2.6.3) activesupport @@ -920,6 +926,7 @@ DEPENDENCIES dotenv-rails factory_bot_rails faker (~> 3.2) + ferrum figaro fog-aws image_processing diff --git a/config/initializers/decidim.rb b/config/initializers/decidim.rb index 687b466c1..b3acbca7f 100644 --- a/config/initializers/decidim.rb +++ b/config/initializers/decidim.rb @@ -490,6 +490,7 @@ Decidim.register_assets_path File.expand_path("app/packs", Rails.application.root) require "decidim/map/provider/static_map/cfj_osm" +require "decidim/exporters/pdf" ## Set default comments limit. It's used in Decidim::Comments component. Default value is 100. Rails.application.config.default_comments_limit = ENV.fetch("DECIDIM_COMMENTS_LIMIT", 100).to_i diff --git a/lib/decidim/exporters/pdf.rb b/lib/decidim/exporters/pdf.rb new file mode 100644 index 000000000..d92b49c5b --- /dev/null +++ b/lib/decidim/exporters/pdf.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Decidim + module Exporters + # Exports a PDF using the provided hash, given a collection and a + # Serializer. This is an abstract class that should be inherited + # to create PDF exporters, with each PDF exporter class setting + # the desired template, layout and orientation. + # + class PDF < Exporter + # Public: Exports a PDF version of the collection by rendering + # the template into html and then converting it to PDF. + # + # Returns an ExportData instance. + def export + html = controller.render_to_string( + template: template, + layout: layout, + locals: locals + ) + + Dir.mktmpdir do |dir| + html_path = File.join(dir, "tmp.html") + File.write(html_path, html) + pdf_path = File.join(dir, "tmp.pdf") + url = URI::File.build([nil, html_path]) + + browser = Ferrum::Browser.new + browser.go_to(url) + browser.pdf(path: pdf_path, landscape: orientation != "Portrait", printBackground: true) + + document = File.read(pdf_path) + ExportData.new(document, "pdf") + end + end + + # may be overwritten if needed + def orientation + "Portrait" + end + + # implementing classes should return a valid ERB path here + def template + raise NotImplementedError + end + + # implementing classes should return a valid ERB path here + def layout + raise NotImplementedError + end + + # This method may be overwritten if the template needs more local variables + def locals + { collection: collection } + end + + protected + + def controller + raise NotImplementedError + end + end + end +end