diff --git a/Gemfile b/Gemfile index 988861a90..13763e699 100644 --- a/Gemfile +++ b/Gemfile @@ -79,7 +79,7 @@ gem 'zipline' gem 'zxcvbn-ruby', require: 'zxcvbn' group :test do - gem 'capybara' # Integration testing + gem 'capybara', '3.13.2' # Integration testing gem 'capybara-email' # Access emails during integration tests gem 'capybara-screenshot' # Save a dump of the page when an integration test fails gem 'capybara-selenium' diff --git a/Gemfile.lock b/Gemfile.lock index 41c577d6b..bbfe3c9ab 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -119,13 +119,13 @@ GEM browser (2.5.3) builder (3.2.3) byebug (10.0.2) - capybara (3.29.0) + capybara (3.13.2) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - regexp_parser (~> 1.5) + regexp_parser (~> 1.2) xpath (~> 3.2) capybara-email (3.0.1) capybara (>= 2.4, < 4.0) @@ -722,7 +722,7 @@ DEPENDENCIES brakeman browser byebug - capybara + capybara (= 3.13.2) capybara-email capybara-screenshot capybara-selenium diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index a30a52f7e..3bd2f35e1 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -207,16 +207,19 @@ module Instructeurs def download_export export_format = params[:export_format] - + notice_message = "Nous générons cet export. Lorsque celui-ci sera disponible, vous recevrez une notification par email accompagnée d'un lien de téléchargement." if procedure.should_generate_export?(export_format) procedure.queue_export(current_instructeur, export_format) respond_to do |format| format.js do - flash.notice = "Nous générons cet export. Lorsque celui-ci sera disponible, vous recevrez une notification par email accompagnée d'un lien de téléchargement." + flash.notice = notice_message @procedure = procedure end end + elsif procedure.export_queued?(export_format) + flash.notice = notice_message + redirect_to procedure else redirect_to url_for(procedure.export_file(export_format)) end diff --git a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js index b158d51da..5b4dc12fa 100644 --- a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js +++ b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js @@ -31,7 +31,7 @@ const TypeDeChamp = sortableElement( !isHeaderSection && !isExplication && !state.isAnnotation; const [ref, inView] = useInView({ - threshold: [0.6] + threshold: 0.6 }); const updateHandlers = createUpdateHandlers( diff --git a/app/javascript/shared/activestorage/ujs.js b/app/javascript/shared/activestorage/ujs.js index 72d464b26..8efd98b86 100644 --- a/app/javascript/shared/activestorage/ujs.js +++ b/app/javascript/shared/activestorage/ujs.js @@ -1,4 +1,5 @@ import ProgressBar from './progress-bar'; +import { fire } from '@utils'; const INITIALIZE_EVENT = 'direct-upload:initialize'; const START_EVENT = 'direct-upload:start'; @@ -36,8 +37,18 @@ addUploadEventListener(PROGRESS_EVENT, ({ detail: { id, progress } }) => { ProgressBar.progress(id, progress); }); -addUploadEventListener(ERROR_EVENT, ({ detail: { id, error } }) => { - ProgressBar.error(id, error); +addUploadEventListener(ERROR_EVENT, event => { + // Display an error message + alert( + `Nous sommes désolés, une erreur s’est produite lors de l’envoi du fichier. + + (${event.detail.error})` + ); + // Prevent ActiveStorage from displaying its own error message + event.preventDefault(); + + ProgressBar.error(event.detail.id, event.detail.error); + fire(document, 'sentry:capture-exception', new Error(event.detail.error)); }); addUploadEventListener(END_EVENT, ({ detail: { id } }) => { diff --git a/app/javascript/shared/track/sentry.js b/app/javascript/shared/track/sentry.js index 23410535a..2db2fd708 100644 --- a/app/javascript/shared/track/sentry.js +++ b/app/javascript/shared/track/sentry.js @@ -10,4 +10,10 @@ if (enabled && key) { scope.setUser(user); scope.setExtra('browser', browser.modern ? 'modern' : 'legacy'); }); + + // Register a way to explicitely capture messages from a different bundle. + addEventListener('sentry:capture-exception', event => { + const error = event.detail; + Sentry.captureException(error); + }); } diff --git a/app/jobs/cleanup_stale_exports_job.rb b/app/jobs/cleanup_stale_exports_job.rb index f00346124..9344d4f14 100644 --- a/app/jobs/cleanup_stale_exports_job.rb +++ b/app/jobs/cleanup_stale_exports_job.rb @@ -2,9 +2,25 @@ class CleanupStaleExportsJob < ApplicationJob queue_as :cron def perform(*args) - ActiveStorage::Attachment.where( + attachments = ActiveStorage::Attachment.where( "name in ('csv_export_file', 'ods_export_file', 'xlsx_export_file') and created_at < ?", Procedure::MAX_DUREE_CONSERVATION_EXPORT.ago - ).find_each(&:purge_later) + ) + attachments.each do |attachment| + procedure = Procedure.find(attachment.record_id) + # export can't be queued if it's already attached + #  so we clean the flag up just in case it was not removed during + # the asynchronous generation + case attachment.name + when 'csv_export_file' + procedure.update(csv_export_queued: false) + when 'ods_export_file' + procedure.update(ods_export_queued: false) + when 'xlsx_export_file' + procedure.update(xlsx_export_queued: false) + end + # and we remove the stale attachment + attachment.purge_later + end end end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index d4703b465..6a6d3ecd6 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -145,6 +145,18 @@ class Procedure < ApplicationRecord !ods_export_file.attached? || ods_export_file.created_at < MAX_DUREE_CONSERVATION_EXPORT.ago end + def export_queued?(format) + case format.to_sym + when :csv + return csv_export_queued? + when :xlsx + return xlsx_export_queued? + when :ods + return ods_export_queued? + end + false + end + def should_generate_export?(format) case format.to_sym when :csv @@ -169,7 +181,6 @@ class Procedure < ApplicationRecord end def queue_export(instructeur, export_format) - ExportProcedureJob.perform_now(self, instructeur, export_format) case export_format.to_sym when :csv update(csv_export_queued: true) @@ -178,6 +189,7 @@ class Procedure < ApplicationRecord when :ods update(ods_export_queued: true) end + ExportProcedureJob.perform_later(self, instructeur, export_format) end def prepare_export_download(format) diff --git a/config/deploy.rb b/config/deploy.rb index b8cfdd565..5e7b2062e 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -94,6 +94,8 @@ desc "Deploys the current version to the server." task :deploy do command 'export PATH=$PATH:/home/ds/.rbenv/bin:/home/ds/.rbenv/shims' command 'source /home/ds/.profile' + # increase db timeout to 5 minutes to allow long migration + command 'export PG_STATEMENT_TIMEOUT=300000' deploy do # Put things that will set up an empty directory into a fully set-up