diff --git a/app/assets/javascripts/reports/reports_datatable.js b/app/assets/javascripts/reports/reports_datatable.js index 27d85550c..522d05ce0 100644 --- a/app/assets/javascripts/reports/reports_datatable.js +++ b/app/assets/javascripts/reports/reports_datatable.js @@ -64,9 +64,16 @@ function renderDocxFile(data) { if (data.error) { + let oldLink = ''; + if (data.preview_url) { + oldLink = ` + ( + ${I18n.t('projects.reports.index.previous_docx')}) + `; + } return ` - ${I18n.t('projects.reports.index.error')} + ${I18n.t('projects.reports.index.error')}${oldLink} `; } @@ -88,9 +95,16 @@ function renderPdfFile(data) { if (data.error) { + let oldLink = ''; + if (data.preview_url) { + oldLink = ` + ( + ${I18n.t('projects.reports.index.previous_pdf')}) + `; + } return ` - ${I18n.t('projects.reports.index.error')} + ${I18n.t('projects.reports.index.error')}${oldLink} `; } diff --git a/app/assets/stylesheets/notifications.scss b/app/assets/stylesheets/notifications.scss index 650d7bd12..03744bdce 100644 --- a/app/assets/stylesheets/notifications.scss +++ b/app/assets/stylesheets/notifications.scss @@ -80,6 +80,17 @@ padding-top: 5px; width: 30px; } + + .deliver-error { + background-color: $brand-danger; + border-radius: 50%; + color: $color-concrete; + display: inline-block; + font-size: $font-size-small; + height: 30px; + padding-top: 5px; + width: 30px; + } } .btn-more-notifications { diff --git a/app/assets/stylesheets/themes/main_navigation.scss b/app/assets/stylesheets/themes/main_navigation.scss index 8025e0496..2dfc8ac52 100644 --- a/app/assets/stylesheets/themes/main_navigation.scss +++ b/app/assets/stylesheets/themes/main_navigation.scss @@ -116,6 +116,17 @@ width: 45px; } + .deliver-error { + background-color: $brand-danger; + border-radius: 50%; + color: $color-concrete; + display: block; + font-size: $font-size-h3; + height: 45px; + padding-top: 5px; + width: 45px; + } + .system-message { background-color: $brand-success; border-radius: 50%; diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 5fe9054e1..7ea2e7bf0 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -87,7 +87,6 @@ class ReportsController < ApplicationController @report.project = @project @report.user = current_user @report.team = current_team - @report.pdf_file_processing = true @report.settings = report_params[:settings] @report.last_modified_by = current_user @@ -99,6 +98,7 @@ class ReportsController < ApplicationController ).save_with_content if @report.errors.blank? + @report.pdf_processing! log_activity(:create_report) flash[:success] = t('projects.reports.index.generation.accepted_message') @@ -125,7 +125,6 @@ class ReportsController < ApplicationController # Updating existing report from the _save modal of the new page def update @report.last_modified_by = current_user - @report.pdf_file_processing = true @report.assign_attributes(report_params) ReportActions::ReportContent.new( @@ -136,6 +135,7 @@ class ReportsController < ApplicationController ).save_with_content if @report.errors.blank? + @report.pdf_processing! log_activity(:edit_report) flash[:success] = t('projects.reports.index.generation.accepted_message') @@ -173,14 +173,14 @@ class ReportsController < ApplicationController format.json do render json: { docx: { - processing: @report.docx_file_processing, + processing: @report.docx_processing?, preview_url: docx, - error: false + error: @report.docx_error? }, pdf: { - processing: @report.pdf_file_processing, + processing: @report.pdf_processing?, preview_url: pdf, - error: false + error: @report.pdf_error? } } end @@ -191,7 +191,7 @@ class ReportsController < ApplicationController def generate_pdf respond_to do |format| format.json do - @report.update!(pdf_file_processing: true) + @report.pdf_processing! log_activity(:generate_pdf_report) Reports::PdfJob.perform_later(@report.id, current_user) render json: { @@ -204,7 +204,7 @@ class ReportsController < ApplicationController def generate_docx respond_to do |format| format.json do - @report.update!(docx_file_processing: true) + @report.docx_processing! log_activity(:generate_docx_report) Reports::DocxJob.perform_later(@report, current_user, current_team, root_url) render json: { diff --git a/app/datatables/report_datatable.rb b/app/datatables/report_datatable.rb index 944e7b754..d8bfe1d78 100644 --- a/app/datatables/report_datatable.rb +++ b/app/datatables/report_datatable.rb @@ -35,11 +35,11 @@ class ReportDatatable < CustomDatatable when 'reports.docx_file' records.left_joins(:docx_file_attachment) .order(active_storage_attachments: sort_direction(order_params)) - .order(docx_file_processing: sort_direction(order_params) == 'ASC' ? :desc : :asc) + .order(docx_file_status: sort_direction(order_params) == 'ASC' ? :desc : :asc) when 'reports.pdf_file' records.left_joins(:pdf_file_attachment) .order(active_storage_attachments: sort_direction(order_params)) - .order(pdf_file_processing: sort_direction(order_params) == 'ASC' ? :desc : :asc) + .order(pdf_file_status: sort_direction(order_params) == 'ASC' ? :desc : :asc) else sort_by = "#{sort_column(order_params)} #{sort_direction(order_params)}" records.order(sort_by) @@ -72,18 +72,18 @@ class ReportDatatable < CustomDatatable def docx_file(report) docx = document_preview_report_path(report, report_type: :docx) if report.docx_file.attached? { - processing: report.docx_file_processing, + processing: report.docx_processing?, preview_url: docx, - error: false + error: report.docx_error? } end def pdf_file(report) pdf = document_preview_report_path(report, report_type: :pdf) if report.pdf_file.attached? { - processing: report.pdf_file_processing, + processing: report.pdf_processing?, preview_url: pdf, - error: false + error: report.pdf_error? } end diff --git a/app/jobs/reports/docx_job.rb b/app/jobs/reports/docx_job.rb index fcf0612f1..7416fc59a 100644 --- a/app/jobs/reports/docx_job.rb +++ b/app/jobs/reports/docx_job.rb @@ -2,16 +2,35 @@ module Reports class DocxJob < ApplicationJob + extend InputSanitizeHelper include InputSanitizeHelper queue_as :reports discard_on StandardError do |job, error| report = Report.find_by(id: job.arguments.first) + return if report.blank? + ActiveRecord::Base.no_touching do - report&.update(docx_file_processing: false) + report.docx_error! end - Rails.logger.error("Couldn't generate DOCX for Report with id: #{job.arguments.first}. Error:\n #{error}") + report_path = + if report.docx_file.attached? + Rails.application.routes.url_helpers + .reports_path(team: report.team.id, preview_report_id: report.id, preview_type: :docx) + else + Rails.application.routes.url_helpers.reports_path(team: report.team.id) + end + user = job.arguments.second + notification = Notification.create( + type_of: :deliver_error, + title: I18n.t('projects.reports.index.generation.error_docx_notification_title'), + message: I18n.t('projects.reports.index.generation.error_notification_message', + report_link: "#{sanitize_input(report.name)}", + team_name: sanitize_input(report.team.name)) + ) + notification.create_user_notification(user) + Rails.logger.error("Couldn't generate DOCX for Report with id: #{report.id}. Error:\n #{error}") end def perform(report, user, team, root_url) @@ -21,7 +40,7 @@ module Reports Reports::Docx.new(report, docx, user: user, team: team, scinote_url: root_url).draw docx.save report.docx_file.attach(io: file, filename: 'report.docx') - report.update!(docx_file_processing: false) + report.docx_ready! report_path = Rails.application.routes.url_helpers .reports_path(team: report.team.id, preview_report_id: report.id, preview_type: :docx) notification = Notification.create( diff --git a/app/jobs/reports/pdf_job.rb b/app/jobs/reports/pdf_job.rb index aebdb327d..957fc7495 100644 --- a/app/jobs/reports/pdf_job.rb +++ b/app/jobs/reports/pdf_job.rb @@ -2,6 +2,7 @@ module Reports class PdfJob < ApplicationJob + extend InputSanitizeHelper include InputSanitizeHelper include ReportsHelper @@ -9,10 +10,28 @@ module Reports discard_on StandardError do |job, error| report = Report.find_by(id: job.arguments.first) + return if report.blank? + ActiveRecord::Base.no_touching do - report&.update(pdf_file_processing: false) + report.pdf_error! end - Rails.logger.error("Couldn't generate PDF for Report with id: #{job.arguments.first}. Error:\n #{error}") + report_path = + if report.pdf_file.attached? + Rails.application.routes.url_helpers + .reports_path(team: report.team.id, preview_report_id: report.id, preview_type: :pdf) + else + Rails.application.routes.url_helpers.reports_path(team: report.team.id) + end + user = job.arguments.second + notification = Notification.create( + type_of: :deliver_error, + title: I18n.t('projects.reports.index.generation.error_pdf_notification_title'), + message: I18n.t('projects.reports.index.generation.error_notification_message', + report_link: "#{sanitize_input(report.name)}", + team_name: sanitize_input(report.team.name)) + ) + notification.create_user_notification(user) + Rails.logger.error("Couldn't generate PDF for Report with id: #{report.id}. Error:\n #{error}") end PREVIEW_EXTENSIONS = %w(docx pdf).freeze @@ -51,7 +70,7 @@ module Reports file = append_result_asset_previews(report, file) if report.settings.dig(:task, :file_results_previews) report.pdf_file.attach(io: file, filename: 'report.pdf') - report.update!(pdf_file_processing: false) + report.pdf_ready! report_path = Rails.application.routes.url_helpers .reports_path(team: report.team.id, preview_report_id: report.id, preview_type: :pdf) diff --git a/app/models/report.rb b/app/models/report.rb index 43e3243d3..b45dd1642 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -5,6 +5,9 @@ class Report < ApplicationRecord include SearchableModel include SearchableByNameModel + enum pdf_file_status: { pdf_processing: 0, pdf_ready: 1, pdf_error: 2 } + enum docx_file_status: { docx_processing: 0, docx_ready: 1, docx_error: 2 } + # ActiveStorage configuration has_one_attached :pdf_file has_one_attached :docx_file diff --git a/app/models/user.rb b/app/models/user.rb index 348da5bbd..fdb582fdf 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -559,7 +559,7 @@ class User < ApplicationRecord end def enabled_notifications_for?(notification_type, channel) - return true if notification_type == :deliver + return true if %i(deliver deliver_error).include?(notification_type) case channel when :web diff --git a/app/views/user_notifications/icons/_deliver_error.html.erb b/app/views/user_notifications/icons/_deliver_error.html.erb new file mode 100644 index 000000000..daad1aef8 --- /dev/null +++ b/app/views/user_notifications/icons/_deliver_error.html.erb @@ -0,0 +1,5 @@ +