diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index d58ee8120..99e83edf7 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -206,7 +206,7 @@ class ReportsController < ApplicationController format.json do @report.docx_processing! log_activity(:generate_docx_report) - Reports::DocxJob.perform_later(@report, current_user, root_url) + Reports::DocxJob.perform_later(@report.id, current_user, root_url) render json: { message: I18n.t('projects.reports.index.generation.accepted_message') } diff --git a/app/jobs/reports/docx_job.rb b/app/jobs/reports/docx_job.rb index 24f9a7048..13b321b0c 100644 --- a/app/jobs/reports/docx_job.rb +++ b/app/jobs/reports/docx_job.rb @@ -51,6 +51,8 @@ module Reports report_link: "#{sanitize_input(report.name)}", team_name: sanitize_input(report.team.name)) ) + + Reports::DocxPreviewJob.perform_later(report.id) notification.create_user_notification(user) ensure file.close diff --git a/app/jobs/reports/docx_preview_job.rb b/app/jobs/reports/docx_preview_job.rb new file mode 100644 index 000000000..6fa10958b --- /dev/null +++ b/app/jobs/reports/docx_preview_job.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# Provides asynchronous generation of image previews for ActiveStorage::Blob records. +module Reports + class DocxPreviewJob < ApplicationJob + queue_as :reports + + discard_on StandardError do |job, error| + report = Report.find_by(id: job.arguments.first) + ActiveRecord::Base.no_touching do + report&.update(docx_preview_processing: false) + end + Rails.logger.error("Couldn't generate PDF preview for DOCX Report with id: #{job.arguments.first}. Error:\n #{error}") + end + + discard_on ActiveRecord::RecordNotFound + + def perform(report_id) + report = Report.find(report_id) + blob = report.docx_file.blob + blob.open(tmpdir: tempdir) do |input| + work_dir = File.dirname(input.path) + preview_filename = "#{File.basename(input.path, '.*')}.pdf" + preview_file = File.join(work_dir, preview_filename) + Rails.logger.info "Starting preparing document preview for file #{blob.filename.sanitized}..." + + ActiveRecord::Base.transaction do + success = system( + libreoffice_path, '--headless', '--invisible', '--convert-to', 'pdf', '--outdir', work_dir, input.path + ) + unless success && File.file?(preview_file) + raise StandardError, "There was an error generating PDF preview, blob id: #{blob.id}" + end + + ActiveRecord::Base.no_touching do + report.docx_preview_file.attach(io: File.open(preview_file), filename: "#{blob.filename.base}.pdf") + report.update(docx_preview_processing: false) + end + Rails.logger.info("Finished preparing PDF preview for file #{blob.filename.sanitized}.") + end + ensure + File.delete(preview_file) if File.file?(preview_file) + end + end + + private + + def tempdir + Rails.root.join('tmp') + end + + def libreoffice_path + ENV['LIBREOFFICE_PATH'] || 'soffice' + end + end +end diff --git a/app/models/report.rb b/app/models/report.rb index 3ec07e657..c4f86cbee 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -11,6 +11,7 @@ class Report < ApplicationRecord # ActiveStorage configuration has_one_attached :pdf_file has_one_attached :docx_file + has_one_attached :docx_preview_file auto_strip_attributes :name, :description, nullify: false validates :name, @@ -96,6 +97,16 @@ class Report < ApplicationRecord report_elements.order(:position).select { |el| el.parent.blank? } end + def docx_preview_ready? + return false if docx_preview_processing + + return true if docx_preview_file.attached? + + Reports::DocxPreviewJob.perform_later(id) + ActiveRecord::Base.no_touching { update(docx_preview_processing: true) } + false + end + # Clean report elements from report # the function runs before the report is edit def cleanup_report diff --git a/app/views/reports/_content_document_preview.html.erb b/app/views/reports/_content_document_preview.html.erb index fdfbb3aa4..7b9060033 100644 --- a/app/views/reports/_content_document_preview.html.erb +++ b/app/views/reports/_content_document_preview.html.erb @@ -11,6 +11,8 @@
<% if report_type == 'pdf' %> <%= render partial: 'shared/pdf_viewer.html.erb', locals: { asset: report.pdf_file, report_document: true } %> + <% elsif report_type == 'docx' && report.docx_preview_ready? %> + <%= render partial: 'shared/pdf_viewer.html.erb', locals: { asset: report.docx_preview_file, report_document: true } %> <% else %>
diff --git a/db/migrate/20210525143303_add_docx_preview_processing_to_reports.rb b/db/migrate/20210525143303_add_docx_preview_processing_to_reports.rb new file mode 100644 index 000000000..1e617a1ad --- /dev/null +++ b/db/migrate/20210525143303_add_docx_preview_processing_to_reports.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddDocxPreviewProcessingToReports < ActiveRecord::Migration[6.1] + def change + add_column :reports, :docx_preview_processing, :boolean, default: false, null: false + end +end diff --git a/db/structure.sql b/db/structure.sql index 5e7b05333..6188dd3c3 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1307,9 +1307,10 @@ CREATE TABLE public.reports ( updated_at timestamp without time zone NOT NULL, last_modified_by_id bigint, team_id bigint, - pdf_file_status integer DEFAULT 0, - docx_file_status integer DEFAULT 0, - settings jsonb DEFAULT '{}'::jsonb NOT NULL + pdf_file_status integer, + docx_file_status integer, + settings jsonb DEFAULT '{}'::jsonb NOT NULL, + docx_preview_processing boolean DEFAULT false NOT NULL ); @@ -7234,6 +7235,8 @@ INSERT INTO "schema_migrations" (version) VALUES ('20210312185911'), ('20210325152257'), ('20210407143303'), -('20210506125657'); +('20210410100006'), +('20210506125657'), +('20210525143303');