diff --git a/app/controllers/protocols_controller.rb b/app/controllers/protocols_controller.rb
index 2019bce38..8a84255e5 100644
--- a/app/controllers/protocols_controller.rb
+++ b/app/controllers/protocols_controller.rb
@@ -835,7 +835,7 @@ class ProtocolsController < ApplicationController
temp_files_ids << temp_file.id
end
end
- @job = Protocols::DocxImportJob.perform_later(temp_files_ids, current_user.id, current_team.id)
+ @job = Protocols::DocxImportJob.perform_later(temp_files_ids, user_id: current_user.id, team_id: current_team.id)
render json: { job_id: @job.job_id }
end
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index 5388244d5..dafa45d00 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -184,7 +184,7 @@ class ReportsController < ApplicationController
log_activity(:generate_docx_report)
ensure_report_template!
- Reports::DocxJob.perform_later(@report.id, current_user.id, root_url)
+ Reports::DocxJob.perform_later(@report.id, user_id: current_user.id, root_url: root_url)
render json: {
message: I18n.t('projects.reports.index.generation.accepted_message')
}
@@ -400,7 +400,7 @@ class ReportsController < ApplicationController
log_activity(:generate_pdf_report)
ensure_report_template!
- Reports::PdfJob.perform_later(@report.id, current_user.id)
+ Reports::PdfJob.perform_later(@report.id, user_id: current_user.id)
end
def ensure_report_template!
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 67ccc98fb..15ed92752 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -349,7 +349,7 @@ class RepositoriesController < ApplicationController
repositories = Repository.viewable_by_user(current_user, current_team).where(id: params[:repository_ids])
if repositories.present? && current_user.has_available_exports?
current_user.increase_daily_exports_counter!
- RepositoriesExportJob.perform_later(repositories.pluck(:id), current_user.id, current_team)
+ RepositoriesExportJob.perform_later(repositories.pluck(:id), user_id: current_user.id, team_id: current_team.id)
render json: { message: t('zip_export.export_request_success') }
else
render json: { message: t('zip_export.export_error') }, status: :unprocessable_entity
diff --git a/app/jobs/concerns/failed_deivery_notifiable_job.rb b/app/jobs/concerns/failed_deivery_notifiable_job.rb
new file mode 100644
index 000000000..07d12d487
--- /dev/null
+++ b/app/jobs/concerns/failed_deivery_notifiable_job.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module FailedDeliveryNotifiableJobJob
+ extend ActiveSupport::Concern
+
+ included do
+ before_enqueue do |job|
+ unless job.arguments.last.is_a?(Hash) && job.arguments.last[:user_id].present?
+ raise ArgumentError, 'required :user_id argument is missing! Needed for user notification in case of failure.'
+ end
+ end
+
+ rescue_from StandardError do |e|
+ logger.error e.message
+ logger.error e.backtrace.join("\n")
+ create_failed_notification!
+ end
+ end
+
+ private
+
+ def create_failed_notification!
+ @user = User.find_by(id: arguments.last[:user_id])
+ return if @user.blank?
+
+ notification = Notification.create!(
+ type_of: :deliver_error,
+ title: failed_notification_title,
+ message: failed_notification_message
+ )
+ notification.create_user_notification(@user)
+ end
+
+ def failed_notification_title
+ I18n.t('activejob.failure_notifiable_job.general_notification_title')
+ end
+
+ def failed_notification_message
+ I18n.backend.date_format = @user.settings[:date_format]
+ timestamp = I18n.l(enqueued_at.in_time_zone(@user.time_zone), format: :full)
+ I18n.t('activejob.failure_notifiable_job.general_notification_message', request_timestamp: timestamp)
+ ensure
+ I18n.backend.date_format = nil
+ end
+end
diff --git a/app/jobs/protocols/docx_import_job.rb b/app/jobs/protocols/docx_import_job.rb
index 0b1ae3003..04e6d2084 100644
--- a/app/jobs/protocols/docx_import_job.rb
+++ b/app/jobs/protocols/docx_import_job.rb
@@ -3,10 +3,11 @@
module Protocols
class DocxImportJob < ApplicationJob
include RenamingUtil
+ include FailedDeliveryNotifiableJob
class RequestFailureException < StandardError; end
- def perform(temp_files_ids, user_id, team_id)
+ def perform(temp_files_ids, user_id:, team_id:)
@user = User.find(user_id)
@team = @user.teams.find(team_id)
@tmp_files = TempFile.where(id: temp_files_ids)
@@ -30,10 +31,7 @@ module Protocols
}
)
- unless response.success?
- create_failed_notification!
- raise RequestFailureException, "#{response.code}: #{response.message}"
- end
+ raise RequestFailureException, "#{response.code}: #{response.message}" unless response.success?
ActiveRecord::Base.transaction do
@protocol = @team.protocols.new(
@@ -50,9 +48,6 @@ module Protocols
@protocol.save!
create_steps!(response['steps']) if response['steps'].present?
create_notification!
- rescue ActiveRecord::RecordInvalid => e
- create_failed_notification!
- Rails.logger.error(e.message)
end
end
@@ -153,13 +148,14 @@ module Protocols
UserNotification.create!(notification: notification, user: @user)
end
- def create_failed_notification!
- notification = Notification.create!(
- type_of: :deliver_error,
- title: I18n.t('protocols.import_export.import_protocol_notification_error.title')
- )
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_title
+ I18n.t('protocols.import_export.import_protocol_notification_error.title')
+ end
- UserNotification.create!(notification: notification, user: @user)
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_message
+ I18n.t('protocols.import_export.import_protocol_notification_error.message')
end
end
end
diff --git a/app/jobs/reports/docx_job.rb b/app/jobs/reports/docx_job.rb
index 53fa27ba3..6f9cc6d92 100644
--- a/app/jobs/reports/docx_job.rb
+++ b/app/jobs/reports/docx_job.rb
@@ -4,36 +4,11 @@ module Reports
class DocxJob < ApplicationJob
extend InputSanitizeHelper
include InputSanitizeHelper
+ include FailedDeliveryNotifiableJob
queue_as :reports
- discard_on StandardError do |job, error|
- report = Report.find_by(id: job.arguments.first)
- next unless report
-
- ActiveRecord::Base.no_touching do
- report.docx_error!
- end
- 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 = User.find(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: "#{escape_input(report.name)}",
- team_name: escape_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_id, user_id, root_url)
+ def perform(report_id, user_id:, root_url:)
report = Report.find(report_id)
user = User.find(user_id)
file = Tempfile.new(['report', '.docx'])
@@ -61,6 +36,39 @@ module Reports
file.close
file.unlink
end
+ rescue StandardError => e
+ raise e if report.blank?
+
+ ActiveRecord::Base.no_touching do
+ report.docx_error!
+ end
+ Rails.logger.error("Couldn't generate DOCX for Report with id: #{report.id}. Error:\n #{e.message}")
+ raise e
+ end
+
+ private
+
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_title
+ I18n.t('projects.reports.index.generation.error_docx_notification_title')
+ end
+
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_message
+ report = Report.find_by(id: arguments.first)
+ return '' if report.blank?
+
+ 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
+
+ I18n.t('projects.reports.index.generation.error_notification_message',
+ report_link: "#{escape_input(report.name)}",
+ team_name: escape_input(report.team.name))
end
end
end
diff --git a/app/jobs/reports/pdf_job.rb b/app/jobs/reports/pdf_job.rb
index 2fb9a95bc..2bce30b56 100644
--- a/app/jobs/reports/pdf_job.rb
+++ b/app/jobs/reports/pdf_job.rb
@@ -6,40 +6,15 @@ module Reports
include InputSanitizeHelper
include ReportsHelper
include Canaid::Helpers::PermissionsHelper
+ include FailedDeliveryNotifiableJob
PDFUNITE_ENCRYPTED_PDF_ERROR_STRING = 'Unimplemented Feature: Could not merge encrypted files'
queue_as :reports
- discard_on StandardError do |job, error|
- report = Report.find_by(id: job.arguments.first)
- next unless report
-
- ActiveRecord::Base.no_touching do
- report.pdf_error!
- end
- 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 = User.find(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: "#{escape_input(report.name)}",
- team_name: escape_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
- def perform(report_id, user_id)
+ def perform(report_id, user_id:)
report = Report.find(report_id)
user = User.find(user_id)
file = Tempfile.new(['report', '.pdf'], binmode: true)
@@ -97,6 +72,14 @@ module Reports
I18n.backend.date_format = nil
file.close(true)
end
+ rescue StandardError => e
+ raise e if report.blank?
+
+ ActiveRecord::Base.no_touching do
+ report.pdf_error!
+ end
+ Rails.logger.error("Couldn't generate PDF for Report with id: #{report.id}. Error:\n #{e.message}")
+ raise e
end
private
@@ -195,5 +178,27 @@ module Reports
'scinote_logo.svg'
end
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_title
+ I18n.t('projects.reports.index.generation.error_pdf_notification_title')
+ end
+
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_message
+ report = Report.find_by(id: arguments.first)
+ return '' if report.blank?
+
+ 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
+
+ I18n.t('projects.reports.index.generation.error_notification_message',
+ report_link: "#{escape_input(report.name)}",
+ team_name: escape_input(report.team.name))
+ end
end
end
diff --git a/app/jobs/repositories_export_job.rb b/app/jobs/repositories_export_job.rb
index 288506a82..bd5c46e37 100644
--- a/app/jobs/repositories_export_job.rb
+++ b/app/jobs/repositories_export_job.rb
@@ -2,10 +2,11 @@
class RepositoriesExportJob < ApplicationJob
include StringUtility
+ include FailedDeliveryNotifiableJob
- def perform(repository_ids, user_id, team)
+ def perform(repository_ids, user_id:, team_id:)
@user = User.find(user_id)
- @team = team
+ @team = Team.find(team_id)
@repositories = Repository.viewable_by_user(@user, @team).where(id: repository_ids).order(:id)
zip_input_dir = FileUtils.mkdir_p(Rails.root.join("tmp/temp_zip_#{Time.now.to_i}")).first
zip_dir = FileUtils.mkdir_p(Rails.root.join('tmp/zip-ready')).first
@@ -95,4 +96,9 @@ class RepositoriesExportJob < ApplicationJob
)
UserNotification.create!(notification: notification, user: @user)
end
+
+ # Overrides method from FailedDeliveryNotifiableJob concern
+ def failed_notification_title
+ I18n.t('repositories.index.export.notification.error.title')
+ end
end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 41673a71a..11d1a8408 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -253,6 +253,11 @@ en:
full_name: "Full name"
initials: "Initials"
avatar: "Avatar"
+
+ activejob:
+ failure_notifiable_job:
+ general_notification_title: "Your export failed. Please contact support."
+ general_notification_message: "Request timestamp: %{request_timestamp}"
head:
title: "SciNote | %{title}"
@@ -1892,6 +1897,10 @@ en:
all_teams: "All teams (current & new)"
all_teams_tooltip: "This will disable individual team settings"
success_message: "Selected sharing options for the Inventory %{inventory_name} have been saved."
+ export:
+ notification:
+ error:
+ title: "Your Inventories export failed. Please contact support."
show:
name: "Name"
archived_inventory_items: "%{repository_name} archived items"
@@ -2773,7 +2782,7 @@ en:
body_html: 'The protocol has been successfully imported. You can access the draft of protocol template here.'
failed:
title: "Import failed"
- body_html: "We're sorry, but the file import has failed. Please ensure you have a stable internet connection and try again. If the problem persists, please contact support for further assistance."
+ body_html: "We're sorry but the file import process has encountered an error. Please make another attempt, and if the issue persists, please contact support for further assistance."
import: "Import"
cancel: "Cancel"
close: "Close"
@@ -2872,7 +2881,8 @@ en:
title: "The import process has been successfully completed. You can download original file here: %{link}"
message: "Protocol template:"
import_protocol_notification_error:
- title: "We're sorry, but the file import has failed. Please ensure you have a stable internet connection and try again. If the problem persists, please contact support for further assistance."
+ title: "Import failed"
+ message: "We're sorry but the file import process has encountered an error. Please make another attempt, and if the issue persists, please contact support for further assistance."
export:
export_results:
title: "Export results"