Add FailureNotifiableJob jobs concerns for creating failure notifications for users [SCI-9119] (#6147)

This commit is contained in:
Alex Kriuchykhin 2023-09-06 12:51:34 +02:00 committed by GitHub
parent d671471b44
commit eea24a69e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 146 additions and 76 deletions

View file

@ -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

View file

@ -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!

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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: "<a href='#{report_path}'>#{escape_input(report.name)}</a>",
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: "<a href='#{report_path}'>#{escape_input(report.name)}</a>",
team_name: escape_input(report.team.name))
end
end
end

View file

@ -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: "<a href='#{report_path}'>#{escape_input(report.name)}</a>",
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: "<a href='#{report_path}'>#{escape_input(report.name)}</a>",
team_name: escape_input(report.team.name))
end
end
end

View file

@ -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

View file

@ -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 <a href="%{url}">here.</a>'
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"