diff --git a/Gemfile b/Gemfile index a8704f9b5..036ad31cd 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/config/initializers/decidim.rb b/config/initializers/decidim.rb index f296c634e..d46a0673b 100644 --- a/config/initializers/decidim.rb +++ b/config/initializers/decidim.rb @@ -247,6 +247,7 @@ end require "decidim/map/provider/static_map/cfj_osm" +require "decidim/exporters/pdf" Rails.application.config.i18n.available_locales = Decidim.available_locales Rails.application.config.i18n.default_locale = Decidim.default_locale 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