From 78a40b51764ccf88dd363c839c550f150b5acf60 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 3 Dec 2020 10:26:05 +0100 Subject: [PATCH 01/10] Increase api_entreprise_timeout --- app/lib/api_entreprise/api.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/api_entreprise/api.rb b/app/lib/api_entreprise/api.rb index c0bc5899a..56ecf2ea7 100644 --- a/app/lib/api_entreprise/api.rb +++ b/app/lib/api_entreprise/api.rb @@ -10,7 +10,7 @@ class ApiEntreprise::API BILANS_BDF_RESOURCE_NAME = "bilans_entreprises_bdf" PRIVILEGES_RESOURCE_NAME = "privileges" - TIMEOUT = 15 + TIMEOUT = 20 class ResourceNotFound < StandardError end From f56235c7eee3add9120c53e333ade18616baf2fe Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 3 Dec 2020 10:39:51 +0100 Subject: [PATCH 02/10] retry exponentially on api entreprise timeout --- app/controllers/users/dossiers_controller.rb | 2 +- app/jobs/api_entreprise/job.rb | 2 ++ app/lib/api_entreprise/api.rb | 6 +++++- spec/jobs/api_entreprise/job_spec.rb | 9 +++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 61f111fc3..19d30a5e6 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -105,7 +105,7 @@ module Users sanitized_siret = siret_model.siret begin etablissement = ApiEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id) - rescue ApiEntreprise::API::RequestFailed, ApiEntreprise::API::BadGateway + rescue ApiEntreprise::API::RequestFailed, ApiEntreprise::API::BadGateway, ApiEntreprise::API::TimedOut return render_siret_error(t('errors.messages.siret_network_error')) end if etablissement.nil? diff --git a/app/jobs/api_entreprise/job.rb b/app/jobs/api_entreprise/job.rb index c3ae9a73e..e6114dd69 100644 --- a/app/jobs/api_entreprise/job.rb +++ b/app/jobs/api_entreprise/job.rb @@ -5,6 +5,8 @@ class ApiEntreprise::Job < ApplicationJob ApiEntreprise::API::BadGateway, wait: 1.day + retry_on ApiEntreprise::API::TimedOut, wait: :exponentially_longer + DEFAULT_MAX_ATTEMPTS_API_ENTREPRISE_JOBS = 5 # If by the time the job runs the Etablissement has been deleted diff --git a/app/lib/api_entreprise/api.rb b/app/lib/api_entreprise/api.rb index 56ecf2ea7..01d786287 100644 --- a/app/lib/api_entreprise/api.rb +++ b/app/lib/api_entreprise/api.rb @@ -27,6 +27,9 @@ class ApiEntreprise::API class ServiceUnavailable < StandardError end + class TimedOut < StandardError + end + def self.entreprise(siren, procedure_id) call_with_siret(ENTREPRISE_RESOURCE_NAME, siren, procedure_id) end @@ -104,6 +107,8 @@ class ApiEntreprise::API raise BadGateway, "url: #{url}" elsif response.code == 503 raise ServiceUnavailable, "url: #{url}" + elsif response.timed_out? + raise TimedOut, "url: #{url}" else raise RequestFailed, <<~TEXT @@ -111,7 +116,6 @@ class ApiEntreprise::API headers: #{response.headers} body: #{response.body} curl message: #{response.return_message} - timeout: #{response.timed_out?} TEXT end end diff --git a/spec/jobs/api_entreprise/job_spec.rb b/spec/jobs/api_entreprise/job_spec.rb index 63e9a5edc..59af2288f 100644 --- a/spec/jobs/api_entreprise/job_spec.rb +++ b/spec/jobs/api_entreprise/job_spec.rb @@ -29,6 +29,13 @@ RSpec.describe ApiEntreprise::Job, type: :job do it { subject } end + + context 'when it is timed out' do + let(:error) { :timed_out } + let(:try) { 5 } + + it { subject } + end end class ExceptionJob < ApiEntreprise::Job @@ -38,6 +45,8 @@ RSpec.describe ApiEntreprise::Job, type: :job do raise ApiEntreprise::API::ServiceUnavailable when :bad_gateway raise ApiEntreprise::API::BadGateway + when :timed_out + raise ApiEntreprise::API::TimedOut else raise StandardError end From 05e91306349096497cbc7642a85d53bbdab6c06a Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 3 Dec 2020 11:17:27 +0100 Subject: [PATCH 03/10] refator test --- spec/jobs/api_entreprise/job_spec.rb | 53 ++++++++++++---------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/spec/jobs/api_entreprise/job_spec.rb b/spec/jobs/api_entreprise/job_spec.rb index 59af2288f..e9173a2e6 100644 --- a/spec/jobs/api_entreprise/job_spec.rb +++ b/spec/jobs/api_entreprise/job_spec.rb @@ -1,46 +1,37 @@ include ActiveJob::TestHelper RSpec.describe ApiEntreprise::Job, type: :job do - # https://api.rubyonrails.org/classes/ActiveJob/Exceptions/ClassMethods.html#method-i-retry_on - context 'when an exception is raised' do - subject do - assert_performed_jobs(try) do - ExceptionJob.perform_later(error) rescue StandardError + # https://api.rubyonrails.org/classes/ActiveJob/Exceptions/ClassMethods.html + # #method-i-retry_on + describe '#perform' do + context 'when a un retryable error is raised' do + let(:errors) { [:standard_error] } + + it 'does not retry' do + ensure_errors_force_n_retry(errors, 1) end end - context 'when it is a service_unavaible' do - let(:error) { :standard_error } - let(:try) { 1 } + context 'when a retryable error is raised' do + let(:errors) { [:service_unavaible, :bad_gateway, :timed_out] } - it { subject } + it 'retries 5 times' do + ensure_errors_force_n_retry(errors, 5) + end end - context 'when it is a service_unavaible' do - let(:error) { :service_unavaible } - let(:try) { 5 } - - it { subject } - end - - context 'when it is a bad gateway' do - let(:error) { :bad_gateway } - let(:try) { 5 } - - it { subject } - end - - context 'when it is timed out' do - let(:error) { :timed_out } - let(:try) { 5 } - - it { subject } + def ensure_errors_force_n_retry(errors, retry_nb) + errors.each do |error| + assert_performed_jobs(retry_nb) do + ErrorJob.perform_later(error) rescue StandardError + end + end end end - class ExceptionJob < ApiEntreprise::Job - def perform(exception) - case exception + class ErrorJob < ApiEntreprise::Job + def perform(error) + case error when :service_unavaible raise ApiEntreprise::API::ServiceUnavailable when :bad_gateway From 46c355beb2c26dfa986f2f2f8fcc2cce0729d1c3 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 3 Dec 2020 11:36:26 +0100 Subject: [PATCH 04/10] Add comments --- app/jobs/api_entreprise/job.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/jobs/api_entreprise/job.rb b/app/jobs/api_entreprise/job.rb index e6114dd69..fd79bba3e 100644 --- a/app/jobs/api_entreprise/job.rb +++ b/app/jobs/api_entreprise/job.rb @@ -1,14 +1,22 @@ class ApiEntreprise::Job < ApplicationJob + DEFAULT_MAX_ATTEMPTS_API_ENTREPRISE_JOBS = 5 + queue_as :api_entreprise + # BadGateway could mean + # - acoss: réessayer ultérieurement + # - bdf: erreur interne + # so we retry every day for 5 days + # same logic for ServiceUnavailable retry_on ApiEntreprise::API::ServiceUnavailable, ApiEntreprise::API::BadGateway, wait: 1.day + # We guess the backend is slow but not broken + # and the information we are looking for is available + # so we retry few seconds later (exponentially to avoid overload) retry_on ApiEntreprise::API::TimedOut, wait: :exponentially_longer - DEFAULT_MAX_ATTEMPTS_API_ENTREPRISE_JOBS = 5 - # If by the time the job runs the Etablissement has been deleted # (it can happen through EtablissementUpdateJob for instance), ignore the job discard_on ActiveRecord::RecordNotFound From b187244a29820c6daf7602abf83b856b48f3bbc5 Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Thu, 3 Dec 2020 16:52:58 +0100 Subject: [PATCH 05/10] extract and refactor api errors --- app/controllers/champs/siret_controller.rb | 2 +- app/controllers/users/dossiers_controller.rb | 2 +- app/jobs/api_entreprise/exercices_job.rb | 2 +- app/jobs/api_entreprise/job.rb | 10 ++--- app/lib/api_entreprise/adapter.rb | 2 +- app/lib/api_entreprise/api.rb | 38 ++++--------------- app/lib/api_entreprise/api/error.rb | 18 +++++++++ .../api/error/bad_format_request.rb | 4 ++ .../api_entreprise/api/error/bad_gateway.rb | 4 ++ .../api/error/request_failed.rb | 4 ++ .../api/error/resource_not_found.rb | 4 ++ .../api/error/service_unavailable.rb | 4 ++ app/lib/api_entreprise/api/error/timed_out.rb | 4 ++ app/services/api_entreprise_service.rb | 2 +- spec/jobs/api_entreprise/job_spec.rb | 16 ++++++-- spec/lib/api_entreprise/api_spec.rb | 28 +++++++------- .../api_entreprise/entreprise_adapter_spec.rb | 2 +- spec/services/api_entreprise_service_spec.rb | 4 +- 18 files changed, 89 insertions(+), 61 deletions(-) create mode 100644 app/lib/api_entreprise/api/error.rb create mode 100644 app/lib/api_entreprise/api/error/bad_format_request.rb create mode 100644 app/lib/api_entreprise/api/error/bad_gateway.rb create mode 100644 app/lib/api_entreprise/api/error/request_failed.rb create mode 100644 app/lib/api_entreprise/api/error/resource_not_found.rb create mode 100644 app/lib/api_entreprise/api/error/service_unavailable.rb create mode 100644 app/lib/api_entreprise/api/error/timed_out.rb diff --git a/app/controllers/champs/siret_controller.rb b/app/controllers/champs/siret_controller.rb index 4e8ba19a2..8d0183380 100644 --- a/app/controllers/champs/siret_controller.rb +++ b/app/controllers/champs/siret_controller.rb @@ -16,7 +16,7 @@ class Champs::SiretController < ApplicationController begin etablissement = find_etablissement_with_siret - rescue ApiEntreprise::API::RequestFailed, ApiEntreprise::API::ServiceUnavailable + rescue ApiEntreprise::API::Error::RequestFailed, ApiEntreprise::API::Error::ServiceUnavailable return siret_error(:network_error) end if etablissement.nil? diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 19d30a5e6..362657b35 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -105,7 +105,7 @@ module Users sanitized_siret = siret_model.siret begin etablissement = ApiEntrepriseService.create_etablissement(@dossier, sanitized_siret, current_user.id) - rescue ApiEntreprise::API::RequestFailed, ApiEntreprise::API::BadGateway, ApiEntreprise::API::TimedOut + rescue ApiEntreprise::API::Error::RequestFailed, ApiEntreprise::API::Error::BadGateway, ApiEntreprise::API::Error::TimedOut return render_siret_error(t('errors.messages.siret_network_error')) end if etablissement.nil? diff --git a/app/jobs/api_entreprise/exercices_job.rb b/app/jobs/api_entreprise/exercices_job.rb index f288c6773..343dd93da 100644 --- a/app/jobs/api_entreprise/exercices_job.rb +++ b/app/jobs/api_entreprise/exercices_job.rb @@ -1,5 +1,5 @@ class ApiEntreprise::ExercicesJob < ApiEntreprise::Job - rescue_from(ApiEntreprise::API::BadFormatRequest) do |exception| + rescue_from(ApiEntreprise::API::Error::BadFormatRequest) do |exception| end def perform(etablissement_id, procedure_id) diff --git a/app/jobs/api_entreprise/job.rb b/app/jobs/api_entreprise/job.rb index fd79bba3e..c7d749307 100644 --- a/app/jobs/api_entreprise/job.rb +++ b/app/jobs/api_entreprise/job.rb @@ -8,24 +8,24 @@ class ApiEntreprise::Job < ApplicationJob # - bdf: erreur interne # so we retry every day for 5 days # same logic for ServiceUnavailable - retry_on ApiEntreprise::API::ServiceUnavailable, - ApiEntreprise::API::BadGateway, + retry_on ApiEntreprise::API::Error::ServiceUnavailable, + ApiEntreprise::API::Error::BadGateway, wait: 1.day # We guess the backend is slow but not broken # and the information we are looking for is available # so we retry few seconds later (exponentially to avoid overload) - retry_on ApiEntreprise::API::TimedOut, wait: :exponentially_longer + retry_on ApiEntreprise::API::Error::TimedOut, wait: :exponentially_longer # If by the time the job runs the Etablissement has been deleted # (it can happen through EtablissementUpdateJob for instance), ignore the job discard_on ActiveRecord::RecordNotFound - rescue_from(ApiEntreprise::API::ResourceNotFound) do |exception| + rescue_from(ApiEntreprise::API::Error::ResourceNotFound) do |exception| error(self, exception) end - rescue_from(ApiEntreprise::API::BadFormatRequest) do |exception| + rescue_from(ApiEntreprise::API::Error::BadFormatRequest) do |exception| error(self, exception) end diff --git a/app/lib/api_entreprise/adapter.rb b/app/lib/api_entreprise/adapter.rb index fdf5527e4..efa731096 100644 --- a/app/lib/api_entreprise/adapter.rb +++ b/app/lib/api_entreprise/adapter.rb @@ -9,7 +9,7 @@ class ApiEntreprise::Adapter def data_source begin @data_source ||= get_resource - rescue ApiEntreprise::API::ResourceNotFound + rescue ApiEntreprise::API::Error::ResourceNotFound @data_source = nil end end diff --git a/app/lib/api_entreprise/api.rb b/app/lib/api_entreprise/api.rb index 01d786287..8d28430ad 100644 --- a/app/lib/api_entreprise/api.rb +++ b/app/lib/api_entreprise/api.rb @@ -12,24 +12,6 @@ class ApiEntreprise::API TIMEOUT = 20 - class ResourceNotFound < StandardError - end - - class RequestFailed < StandardError - end - - class BadFormatRequest < StandardError - end - - class BadGateway < StandardError - end - - class ServiceUnavailable < StandardError - end - - class TimedOut < StandardError - end - def self.entreprise(siren, procedure_id) call_with_siret(ENTREPRISE_RESOURCE_NAME, siren, procedure_id) end @@ -84,7 +66,7 @@ class ApiEntreprise::API if response.success? JSON.parse(response.body, symbolize_names: true) else - raise RequestFailed, "HTTP Error Code: #{response.code} for #{url}\nheaders: #{response.headers}\nbody: #{response.body}" + raise RequestFailed.new(response) end end @@ -100,23 +82,17 @@ class ApiEntreprise::API if response.success? JSON.parse(response.body, symbolize_names: true) elsif response.code&.between?(401, 499) - raise ResourceNotFound, "url: #{url}" + raise Error::ResourceNotFound.new(response) elsif response.code == 400 - raise BadFormatRequest, "url: #{url}" + raise Error::BadFormatRequest.new(response) elsif response.code == 502 - raise BadGateway, "url: #{url}" + raise Error::BadGateway.new(response) elsif response.code == 503 - raise ServiceUnavailable, "url: #{url}" + raise Error::ServiceUnavailable.new(response) elsif response.timed_out? - raise TimedOut, "url: #{url}" + raise Error::TimedOut.new(response) else - raise RequestFailed, - <<~TEXT - HTTP Error Code: #{response.code} for #{url} - headers: #{response.headers} - body: #{response.body} - curl message: #{response.return_message} - TEXT + raise Error::RequestFailed.new(response) end end diff --git a/app/lib/api_entreprise/api/error.rb b/app/lib/api_entreprise/api/error.rb new file mode 100644 index 000000000..6719ba7f1 --- /dev/null +++ b/app/lib/api_entreprise/api/error.rb @@ -0,0 +1,18 @@ +class ApiEntreprise::API::Error < ::StandardError + def initialize(response) + # use uri to avoid sending token + uri = URI.parse(response.effective_url) + + msg = <<~TEXT + url: #{uri.host}#{uri.path} + HTTP error code: #{response.code} + body: #{CGI.escape(response.body)} + curl message: #{response.return_message} + total time: #{response.total_time} + connect time: #{response.connect_time} + response headers: #{response.headers} + TEXT + + super(msg) + end +end diff --git a/app/lib/api_entreprise/api/error/bad_format_request.rb b/app/lib/api_entreprise/api/error/bad_format_request.rb new file mode 100644 index 000000000..c5a1210eb --- /dev/null +++ b/app/lib/api_entreprise/api/error/bad_format_request.rb @@ -0,0 +1,4 @@ +class ApiEntreprise::API::Error + class BadFormatRequest < ApiEntreprise::API::Error + end +end diff --git a/app/lib/api_entreprise/api/error/bad_gateway.rb b/app/lib/api_entreprise/api/error/bad_gateway.rb new file mode 100644 index 000000000..dd2a7065b --- /dev/null +++ b/app/lib/api_entreprise/api/error/bad_gateway.rb @@ -0,0 +1,4 @@ +class ApiEntreprise::API::Error + class BadGateway < ApiEntreprise::API::Error + end +end diff --git a/app/lib/api_entreprise/api/error/request_failed.rb b/app/lib/api_entreprise/api/error/request_failed.rb new file mode 100644 index 000000000..e4680c631 --- /dev/null +++ b/app/lib/api_entreprise/api/error/request_failed.rb @@ -0,0 +1,4 @@ +class ApiEntreprise::API::Error + class RequestFailed < ApiEntreprise::API::Error + end +end diff --git a/app/lib/api_entreprise/api/error/resource_not_found.rb b/app/lib/api_entreprise/api/error/resource_not_found.rb new file mode 100644 index 000000000..27b9fd053 --- /dev/null +++ b/app/lib/api_entreprise/api/error/resource_not_found.rb @@ -0,0 +1,4 @@ +class ApiEntreprise::API::Error + class ResourceNotFound < ApiEntreprise::API::Error + end +end diff --git a/app/lib/api_entreprise/api/error/service_unavailable.rb b/app/lib/api_entreprise/api/error/service_unavailable.rb new file mode 100644 index 000000000..684574ed4 --- /dev/null +++ b/app/lib/api_entreprise/api/error/service_unavailable.rb @@ -0,0 +1,4 @@ +class ApiEntreprise::API::Error + class ServiceUnavailable < ApiEntreprise::API::Error + end +end diff --git a/app/lib/api_entreprise/api/error/timed_out.rb b/app/lib/api_entreprise/api/error/timed_out.rb new file mode 100644 index 000000000..7921afcf2 --- /dev/null +++ b/app/lib/api_entreprise/api/error/timed_out.rb @@ -0,0 +1,4 @@ +class ApiEntreprise::API::Error + class TimedOut < ApiEntreprise::API::Error + end +end diff --git a/app/services/api_entreprise_service.rb b/app/services/api_entreprise_service.rb index 1fd4130db..5fdc7f205 100644 --- a/app/services/api_entreprise_service.rb +++ b/app/services/api_entreprise_service.rb @@ -5,7 +5,7 @@ class ApiEntrepriseService # # Returns nil if the SIRET is unknown # - # Raises a ApiEntreprise::API::RequestFailed exception on transient errors + # Raises a ApiEntreprise::API::Error::RequestFailed exception on transient errors # (timeout, 5XX HTTP error code, etc.) def self.create_etablissement(dossier_or_champ, siret, user_id = nil) etablissement_params = ApiEntreprise::EtablissementAdapter.new(siret, dossier_or_champ.procedure.id).to_params diff --git a/spec/jobs/api_entreprise/job_spec.rb b/spec/jobs/api_entreprise/job_spec.rb index e9173a2e6..3b09d3874 100644 --- a/spec/jobs/api_entreprise/job_spec.rb +++ b/spec/jobs/api_entreprise/job_spec.rb @@ -31,13 +31,23 @@ RSpec.describe ApiEntreprise::Job, type: :job do class ErrorJob < ApiEntreprise::Job def perform(error) + response = OpenStruct.new( + effective_url: 'http://host.com/path', + code: '666', + body: 'body', + return_message: 'return_message', + total_time: 10, + connect_time: 20, + headers: 'headers' + ) + case error when :service_unavaible - raise ApiEntreprise::API::ServiceUnavailable + raise ApiEntreprise::API::Error::ServiceUnavailable.new(response) when :bad_gateway - raise ApiEntreprise::API::BadGateway + raise ApiEntreprise::API::Error::BadGateway.new(response) when :timed_out - raise ApiEntreprise::API::TimedOut + raise ApiEntreprise::API::Error::TimedOut.new(response) else raise StandardError end diff --git a/spec/lib/api_entreprise/api_spec.rb b/spec/lib/api_entreprise/api_spec.rb index e10895020..c14d6811c 100644 --- a/spec/lib/api_entreprise/api_spec.rb +++ b/spec/lib/api_entreprise/api_spec.rb @@ -17,8 +17,8 @@ describe ApiEntreprise::API do let(:status) { 502 } let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_unavailable.json') } - it 'raises ApiEntreprise::API::RequestFailed' do - expect { subject }.to raise_error(ApiEntreprise::API::BadGateway) + it 'raises ApiEntreprise::API::Error::RequestFailed' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::BadGateway) end end @@ -27,8 +27,8 @@ describe ApiEntreprise::API do let(:status) { 404 } let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_not_found.json') } - it 'raises ApiEntreprise::API::ResourceNotFound' do - expect { subject }.to raise_error(ApiEntreprise::API::ResourceNotFound) + it 'raises ApiEntreprise::API::Error::ResourceNotFound' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::ResourceNotFound) end end @@ -37,8 +37,8 @@ describe ApiEntreprise::API do let(:status) { 400 } let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_not_found.json') } - it 'raises ApiEntreprise::API::BadFormatRequest' do - expect { subject }.to raise_error(ApiEntreprise::API::BadFormatRequest) + it 'raises ApiEntreprise::API::Error::BadFormatRequest' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::BadFormatRequest) end end @@ -47,8 +47,8 @@ describe ApiEntreprise::API do let(:status) { 403 } let(:body) { File.read('spec/fixtures/files/api_entreprise/entreprises_private.json') } - it 'raises ApiEntreprise::API::ResourceNotFound' do - expect { subject }.to raise_error(ApiEntreprise::API::ResourceNotFound) + it 'raises ApiEntreprise::API::Error::ResourceNotFound' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::ResourceNotFound) end end @@ -97,8 +97,8 @@ describe ApiEntreprise::API do let(:status) { 404 } let(:body) { '' } - it 'raises ApiEntreprise::API::ResourceNotFound' do - expect { subject }.to raise_error(ApiEntreprise::API::ResourceNotFound) + it 'raises ApiEntreprise::API::Error::ResourceNotFound' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::ResourceNotFound) end end @@ -127,8 +127,8 @@ describe ApiEntreprise::API do let(:status) { 404 } let(:body) { '' } - it 'raises ApiEntreprise::API::ResourceNotFound' do - expect { subject }.to raise_error(ApiEntreprise::API::ResourceNotFound) + it 'raises ApiEntreprise::API::Error::ResourceNotFound' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::ResourceNotFound) end end @@ -159,8 +159,8 @@ describe ApiEntreprise::API do let(:status) { 404 } let(:body) { '' } - it 'raises ApiEntreprise::API::ResourceNotFound' do - expect { subject }.to raise_error(ApiEntreprise::API::ResourceNotFound) + it 'raises ApiEntreprise::API::Error::ResourceNotFound' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::ResourceNotFound) end end diff --git a/spec/lib/api_entreprise/entreprise_adapter_spec.rb b/spec/lib/api_entreprise/entreprise_adapter_spec.rb index b9d320ff4..b1f163b45 100644 --- a/spec/lib/api_entreprise/entreprise_adapter_spec.rb +++ b/spec/lib/api_entreprise/entreprise_adapter_spec.rb @@ -84,7 +84,7 @@ describe ApiEntreprise::EntrepriseAdapter do let(:status) { 500 } it 'raises an exception' do - expect { subject }.to raise_error(ApiEntreprise::API::RequestFailed) + expect { subject }.to raise_error(ApiEntreprise::API::Error::RequestFailed) end end end diff --git a/spec/services/api_entreprise_service_spec.rb b/spec/services/api_entreprise_service_spec.rb index aff2cb557..974bf564c 100644 --- a/spec/services/api_entreprise_service_spec.rb +++ b/spec/services/api_entreprise_service_spec.rb @@ -38,8 +38,8 @@ describe ApiEntrepriseService do let(:etablissements_status) { 504 } let(:etablissements_body) { '' } - it 'should raise ApiEntreprise::API::RequestFailed' do - expect { subject }.to raise_error(ApiEntreprise::API::RequestFailed) + it 'should raise ApiEntreprise::API::Error::RequestFailed' do + expect { subject }.to raise_error(ApiEntreprise::API::Error::RequestFailed) end end From 43b6f198d5b062460e91d53e293a16d0670575d3 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 25 Nov 2020 18:16:32 +0100 Subject: [PATCH 06/10] Adapt 2FA issuer for local and staging environements --- app/controllers/super_admins_controller.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/super_admins_controller.rb b/app/controllers/super_admins_controller.rb index e6c726426..aa1c608c1 100644 --- a/app/controllers/super_admins_controller.rb +++ b/app/controllers/super_admins_controller.rb @@ -22,7 +22,13 @@ class SuperAdminsController < ApplicationController def generate_qr_code issuer = 'DSManager' - issuer += "-dev" if Rails.env.development? + + if Rails.env.development? + issuer += " (local)" + elsif staging? + issuer += " (dev)" + end + label = "#{issuer}:#{current_super_admin.email}" RQRCode::QRCode.new(current_super_admin.otp_provisioning_uri(label, issuer: issuer)) end From 12d1a5bece799b8ee4aeef850409d634508cabec Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Wed, 25 Nov 2020 15:17:59 +0100 Subject: [PATCH 07/10] implement ComboPaysSearch --- app/javascript/components/ComboPaysSearch.js | 21 + .../components/shared/queryCache.js | 6 + app/javascript/loaders/ComboPaysSearch.js | 3 + .../dossiers/editable_champs/_pays.html.haml | 8 +- public/pays.json | 848 ++++++++++++++++++ spec/features/users/brouillon_spec.rb | 5 +- 6 files changed, 884 insertions(+), 7 deletions(-) create mode 100644 app/javascript/components/ComboPaysSearch.js create mode 100644 app/javascript/loaders/ComboPaysSearch.js create mode 100644 public/pays.json diff --git a/app/javascript/components/ComboPaysSearch.js b/app/javascript/components/ComboPaysSearch.js new file mode 100644 index 000000000..826b352c9 --- /dev/null +++ b/app/javascript/components/ComboPaysSearch.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { ReactQueryCacheProvider } from 'react-query'; + +import ComboSearch from './ComboSearch'; +import { queryCache } from './shared/queryCache'; + +function ComboPaysSearch(params) { + return ( + + [nom, nom]} + /> + + ); +} + +export default ComboPaysSearch; diff --git a/app/javascript/components/shared/queryCache.js b/app/javascript/components/shared/queryCache.js index 501b6e45a..6809c0473 100644 --- a/app/javascript/components/shared/queryCache.js +++ b/app/javascript/components/shared/queryCache.js @@ -1,5 +1,6 @@ import { QueryCache } from 'react-query'; import { isNumeric } from '@utils'; +import matchSorter from 'match-sorter'; const { api_geo_url, api_adresse_url } = gon.autocomplete || {}; @@ -31,6 +32,11 @@ function buildOptions() { } async function defaultQueryFn(scope, term) { + if (scope == 'pays') { + const pays = await fetch('/pays.json').then((response) => response.json()); + return matchSorter(pays, term, { keys: ['nom'] }); + } + const url = buildURL(scope, term); const [options, controller] = buildOptions(); const promise = fetch(url, options).then((response) => response.json()); diff --git a/app/javascript/loaders/ComboPaysSearch.js b/app/javascript/loaders/ComboPaysSearch.js new file mode 100644 index 000000000..e4e6ed33d --- /dev/null +++ b/app/javascript/loaders/ComboPaysSearch.js @@ -0,0 +1,3 @@ +import Loadable from '../components/Loadable'; + +export default Loadable(() => import('../components/ComboPaysSearch')); diff --git a/app/views/shared/dossiers/editable_champs/_pays.html.haml b/app/views/shared/dossiers/editable_champs/_pays.html.haml index 0e686fee9..5a9ca2523 100644 --- a/app/views/shared/dossiers/editable_champs/_pays.html.haml +++ b/app/views/shared/dossiers/editable_champs/_pays.html.haml @@ -1,5 +1,3 @@ -= form.select :value, - Champs::PaysChamp.pays, - { disabled: Champs::PaysChamp.disabled_options, include_blank: true }, - required: champ.mandatory?, - class: 'select2 pays' +- hidden_field_id = SecureRandom.uuid += form.hidden_field :value, { data: { uuid: hidden_field_id } } += react_component("ComboPaysSearch", mandatory: champ.mandatory?, hiddenFieldId: hidden_field_id) diff --git a/public/pays.json b/public/pays.json new file mode 100644 index 000000000..a56e16923 --- /dev/null +++ b/public/pays.json @@ -0,0 +1,848 @@ +[ + { + "nom": "FRANCE" + }, + { + "nom": "ACORES, MADERE" + }, + { + "nom": "AFGHANISTAN" + }, + { + "nom": "AFRIQUE DU SUD" + }, + { + "nom": "ALASKA" + }, + { + "nom": "ALBANIE" + }, + { + "nom": "ALGERIE" + }, + { + "nom": "ALLEMAGNE" + }, + { + "nom": "ANDORRE" + }, + { + "nom": "ANGOLA" + }, + { + "nom": "ANGUILLA" + }, + { + "nom": "ANTIGUA-ET-BARBUDA" + }, + { + "nom": "ANTILLES NEERLANDAISES" + }, + { + "nom": "ARABIE SAOUDITE" + }, + { + "nom": "ARGENTINE" + }, + { + "nom": "ARMENIE" + }, + { + "nom": "ARUBA" + }, + { + "nom": "AUSTRALIE" + }, + { + "nom": "AUTRICHE" + }, + { + "nom": "AZERBAIDJAN" + }, + { + "nom": "BAHAMAS" + }, + { + "nom": "BAHREIN" + }, + { + "nom": "BANGLADESH" + }, + { + "nom": "BARBADE" + }, + { + "nom": "BELGIQUE" + }, + { + "nom": "BELIZE" + }, + { + "nom": "BENIN" + }, + { + "nom": "BERMUDES" + }, + { + "nom": "BHOUTAN" + }, + { + "nom": "BIELORUSSIE" + }, + { + "nom": "BIRMANIE" + }, + { + "nom": "BOLIVIE" + }, + { + "nom": "BONAIRE, SAINT EUSTACHE ET SABA" + }, + { + "nom": "BOSNIE-HERZEGOVINE" + }, + { + "nom": "BOTSWANA" + }, + { + "nom": "BOUVET (ILE)" + }, + { + "nom": "BRESIL" + }, + { + "nom": "BRUNEI" + }, + { + "nom": "BULGARIE" + }, + { + "nom": "BURKINA" + }, + { + "nom": "BURUNDI" + }, + { + "nom": "CAIMANES (ILES)" + }, + { + "nom": "CAMBODGE" + }, + { + "nom": "CAMEROUN" + }, + { + "nom": "CAMEROUN ET TOGO" + }, + { + "nom": "CANADA" + }, + { + "nom": "CANARIES (ILES)" + }, + { + "nom": "CAP-VERT" + }, + { + "nom": "CENTRAFRICAINE (REPUBLIQUE)" + }, + { + "nom": "CHILI" + }, + { + "nom": "CHINE" + }, + { + "nom": "CHRISTMAS (ILE)" + }, + { + "nom": "CHYPRE" + }, + { + "nom": "CLIPPERTON (ILE)" + }, + { + "nom": "COCOS ou KEELING (ILES)" + }, + { + "nom": "COLOMBIE" + }, + { + "nom": "COMORES" + }, + { + "nom": "CONGO" + }, + { + "nom": "CONGO (REPUBLIQUE DEMOCRATIQUE)" + }, + { + "nom": "COOK (ILES)" + }, + { + "nom": "COREE" + }, + { + "nom": "COREE (REPUBLIQUE DE)" + }, + { + "nom": "COREE (REPUBLIQUE POPULAIRE DEMOCRATIQUE DE)" + }, + { + "nom": "COSTA RICA" + }, + { + "nom": "COTE D'IVOIRE" + }, + { + "nom": "CROATIE" + }, + { + "nom": "CUBA" + }, + { + "nom": "CURAÇAO" + }, + { + "nom": "DANEMARK" + }, + { + "nom": "DJIBOUTI" + }, + { + "nom": "DOMINICAINE (REPUBLIQUE)" + }, + { + "nom": "DOMINIQUE" + }, + { + "nom": "EGYPTE" + }, + { + "nom": "EL SALVADOR" + }, + { + "nom": "EMIRATS ARABES UNIS" + }, + { + "nom": "EQUATEUR" + }, + { + "nom": "ERYTHREE" + }, + { + "nom": "ESPAGNE" + }, + { + "nom": "ESTONIE" + }, + { + "nom": "ETATS MALAIS NON FEDERES" + }, + { + "nom": "ETATS-UNIS" + }, + { + "nom": "ETHIOPIE" + }, + { + "nom": "FEROE (ILES)" + }, + { + "nom": "FIDJI" + }, + { + "nom": "FINLANDE" + }, + { + "nom": "GABON" + }, + { + "nom": "GAMBIE" + }, + { + "nom": "GEORGIE" + }, + { + "nom": "GEORGIE DU SUD ET LES ILES SANDWICH DU SUD" + }, + { + "nom": "GHANA" + }, + { + "nom": "GIBRALTAR" + }, + { + "nom": "GOA" + }, + { + "nom": "GRECE" + }, + { + "nom": "GRENADE" + }, + { + "nom": "GROENLAND" + }, + { + "nom": "GUADELOUPE" + }, + { + "nom": "GUAM" + }, + { + "nom": "GUATEMALA" + }, + { + "nom": "GUERNESEY" + }, + { + "nom": "GUINEE" + }, + { + "nom": "GUINEE EQUATORIALE" + }, + { + "nom": "GUINEE-BISSAU" + }, + { + "nom": "GUYANA" + }, + { + "nom": "GUYANE" + }, + { + "nom": "HAITI" + }, + { + "nom": "HAWAII (ILES)" + }, + { + "nom": "HEARD ET MACDONALD (ILES)" + }, + { + "nom": "HONDURAS" + }, + { + "nom": "HONG-KONG" + }, + { + "nom": "HONGRIE" + }, + { + "nom": "ILES PORTUGAISES DE L'OCEAN INDIEN" + }, + { + "nom": "INDE" + }, + { + "nom": "INDONESIE" + }, + { + "nom": "IRAN" + }, + { + "nom": "IRAQ" + }, + { + "nom": "IRLANDE, ou EIRE" + }, + { + "nom": "ISLANDE" + }, + { + "nom": "ISRAEL" + }, + { + "nom": "ITALIE" + }, + { + "nom": "JAMAIQUE" + }, + { + "nom": "JAPON" + }, + { + "nom": "JERSEY" + }, + { + "nom": "JORDANIE" + }, + { + "nom": "KAMTCHATKA" + }, + { + "nom": "KAZAKHSTAN" + }, + { + "nom": "KENYA" + }, + { + "nom": "KIRGHIZISTAN" + }, + { + "nom": "KIRIBATI" + }, + { + "nom": "KOSOVO" + }, + { + "nom": "KOWEIT" + }, + { + "nom": "LA REUNION" + }, + { + "nom": "LABRADOR" + }, + { + "nom": "LAOS" + }, + { + "nom": "LESOTHO" + }, + { + "nom": "LETTONIE" + }, + { + "nom": "LIBAN" + }, + { + "nom": "LIBERIA" + }, + { + "nom": "LIBYE" + }, + { + "nom": "LIECHTENSTEIN" + }, + { + "nom": "LITUANIE" + }, + { + "nom": "LUXEMBOURG" + }, + { + "nom": "MACAO" + }, + { + "nom": "MACEDOINE DU NORD (REPUBLIQUE DE)" + }, + { + "nom": "MADAGASCAR" + }, + { + "nom": "MALAISIE" + }, + { + "nom": "MALAWI" + }, + { + "nom": "MALDIVES" + }, + { + "nom": "MALI" + }, + { + "nom": "MALOUINES, OU FALKLAND (ILES)" + }, + { + "nom": "MALTE" + }, + { + "nom": "MAN (ILE)" + }, + { + "nom": "MANDCHOURIE" + }, + { + "nom": "MARIANNES DU NORD (ILES)" + }, + { + "nom": "MAROC" + }, + { + "nom": "MARSHALL (ILES)" + }, + { + "nom": "MARTINIQUE" + }, + { + "nom": "MAURICE" + }, + { + "nom": "MAURITANIE" + }, + { + "nom": "MAYOTTE" + }, + { + "nom": "MEXIQUE" + }, + { + "nom": "MICRONESIE (ETATS FEDERES DE)" + }, + { + "nom": "MOLDAVIE" + }, + { + "nom": "MONACO" + }, + { + "nom": "MONGOLIE" + }, + { + "nom": "MONTENEGRO" + }, + { + "nom": "MONTSERRAT" + }, + { + "nom": "MOZAMBIQUE" + }, + { + "nom": "NAMIBIE" + }, + { + "nom": "NAURU" + }, + { + "nom": "NEPAL" + }, + { + "nom": "NICARAGUA" + }, + { + "nom": "NIGER" + }, + { + "nom": "NIGERIA" + }, + { + "nom": "NIUE" + }, + { + "nom": "NORFOLK (ILE)" + }, + { + "nom": "NORVEGE" + }, + { + "nom": "NOUVELLE-CALEDONIE" + }, + { + "nom": "NOUVELLE-ZELANDE" + }, + { + "nom": "OCEAN INDIEN (TERRITOIRE BRITANNIQUE DE L')" + }, + { + "nom": "OMAN" + }, + { + "nom": "OUGANDA" + }, + { + "nom": "OUZBEKISTAN" + }, + { + "nom": "PAKISTAN" + }, + { + "nom": "PALAOS (ILES)" + }, + { + "nom": "PALESTINE (Etat de)" + }, + { + "nom": "PANAMA" + }, + { + "nom": "PAPOUASIE-NOUVELLE-GUINEE" + }, + { + "nom": "PARAGUAY" + }, + { + "nom": "PAYS-BAS" + }, + { + "nom": "PEROU" + }, + { + "nom": "PHILIPPINES" + }, + { + "nom": "PITCAIRN (ILE)" + }, + { + "nom": "POLOGNE" + }, + { + "nom": "POLYNESIE FRANCAISE" + }, + { + "nom": "PORTO RICO" + }, + { + "nom": "PORTUGAL" + }, + { + "nom": "POSSESSIONS BRITANNIQUES AU PROCHE-ORIENT" + }, + { + "nom": "PRESIDES" + }, + { + "nom": "PROVINCES ESPAGNOLES D'AFRIQUE" + }, + { + "nom": "QATAR" + }, + { + "nom": "REPUBLIQUE DEMOCRATIQUE ALLEMANDE" + }, + { + "nom": "REPUBLIQUE FEDERALE D'ALLEMAGNE" + }, + { + "nom": "ROUMANIE" + }, + { + "nom": "ROYAUME-UNI" + }, + { + "nom": "RUSSIE" + }, + { + "nom": "RWANDA" + }, + { + "nom": "SAHARA OCCIDENTAL" + }, + { + "nom": "SAINT-BARTHELEMY" + }, + { + "nom": "SAINT-CHRISTOPHE-ET-NIEVES" + }, + { + "nom": "SAINT-MARIN" + }, + { + "nom": "SAINT-MARTIN" + }, + { + "nom": "SAINT-MARTIN (PARTIE NEERLANDAISE)" + }, + { + "nom": "SAINT-PIERRE-ET-MIQUELON" + }, + { + "nom": "SAINT-VINCENT-ET-LES GRENADINES" + }, + { + "nom": "SAINTE HELENE, ASCENSION ET TRISTAN DA CUNHA" + }, + { + "nom": "SAINTE-LUCIE" + }, + { + "nom": "SALOMON (ILES)" + }, + { + "nom": "SAMOA AMERICAINES" + }, + { + "nom": "SAMOA OCCIDENTALES" + }, + { + "nom": "SAO TOME-ET-PRINCIPE" + }, + { + "nom": "SENEGAL" + }, + { + "nom": "SERBIE" + }, + { + "nom": "SEYCHELLES" + }, + { + "nom": "SIBERIE" + }, + { + "nom": "SIERRA LEONE" + }, + { + "nom": "SINGAPOUR" + }, + { + "nom": "SLOVAQUIE" + }, + { + "nom": "SLOVENIE" + }, + { + "nom": "SOMALIE" + }, + { + "nom": "SOUDAN" + }, + { + "nom": "SOUDAN ANGLO-EGYPTIEN, KENYA, OUGANDA" + }, + { + "nom": "SOUDAN DU SUD" + }, + { + "nom": "SRI LANKA" + }, + { + "nom": "SUEDE" + }, + { + "nom": "SUISSE" + }, + { + "nom": "SURINAME" + }, + { + "nom": "SVALBARD et ILE JAN MAYEN" + }, + { + "nom": "SWAZILAND" + }, + { + "nom": "SYRIE" + }, + { + "nom": "TADJIKISTAN" + }, + { + "nom": "TAIWAN" + }, + { + "nom": "TANGER" + }, + { + "nom": "TANZANIE" + }, + { + "nom": "TCHAD" + }, + { + "nom": "TCHECOSLOVAQUIE" + }, + { + "nom": "TCHEQUE (REPUBLIQUE)" + }, + { + "nom": "TERR. DES ETATS-UNIS D'AMERIQUE EN AMERIQUE" + }, + { + "nom": "TERR. DES ETATS-UNIS D'AMERIQUE EN OCEANIE" + }, + { + "nom": "TERR. DU ROYAUME-UNI DANS L'ATLANTIQUE SUD" + }, + { + "nom": "TERRE-NEUVE" + }, + { + "nom": "TERRES AUSTRALES FRANCAISES" + }, + { + "nom": "TERRITOIRES DU ROYAUME-UNI AUX ANTILLES" + }, + { + "nom": "THAILANDE" + }, + { + "nom": "TIMOR ORIENTAL" + }, + { + "nom": "TOGO" + }, + { + "nom": "TOKELAU" + }, + { + "nom": "TONGA" + }, + { + "nom": "TRINITE-ET-TOBAGO" + }, + { + "nom": "TUNISIE" + }, + { + "nom": "TURKESTAN RUSSE" + }, + { + "nom": "TURKMENISTAN" + }, + { + "nom": "TURKS ET CAIQUES (ILES)" + }, + { + "nom": "TURQUIE" + }, + { + "nom": "TURQUIE D'EUROPE" + }, + { + "nom": "TUVALU" + }, + { + "nom": "UKRAINE" + }, + { + "nom": "URUGUAY" + }, + { + "nom": "VANUATU" + }, + { + "nom": "VATICAN, ou SAINT-SIEGE" + }, + { + "nom": "VENEZUELA" + }, + { + "nom": "VIERGES BRITANNIQUES (ILES)" + }, + { + "nom": "VIERGES DES ETATS-UNIS (ILES)" + }, + { + "nom": "VIET NAM" + }, + { + "nom": "VIET NAM DU NORD" + }, + { + "nom": "VIET NAM DU SUD" + }, + { + "nom": "WALLIS-ET-FUTUNA" + }, + { + "nom": "YEMEN" + }, + { + "nom": "YEMEN (REPUBLIQUE ARABE DU)" + }, + { + "nom": "YEMEN DEMOCRATIQUE" + }, + { + "nom": "ZAMBIE" + }, + { + "nom": "ZANZIBAR" + }, + { + "nom": "ZIMBABWE" + } +] diff --git a/spec/features/users/brouillon_spec.rb b/spec/features/users/brouillon_spec.rb index f73d69475..39d170fbc 100644 --- a/spec/features/users/brouillon_spec.rb +++ b/spec/features/users/brouillon_spec.rb @@ -27,7 +27,7 @@ feature 'The user' do select('bravo', from: form_id_for('simple_choice_drop_down_list_long')) select('alpha', from: form_id_for('multiple_choice_drop_down_list_long')) select('charly', from: form_id_for('multiple_choice_drop_down_list_long')) - select('AUSTRALIE', from: 'pays') + select_champ_geo('pays', 'aust', 'AUSTRALIE') select_champ_geo('regions', 'Ma', 'Martinique') @@ -40,6 +40,7 @@ feature 'The user' do find('.editable-champ-piece_justificative input[type=file]').attach_file(Rails.root + 'spec/fixtures/files/file.pdf') blur + sleep(0.7) expect(page).to have_css('span', text: 'Brouillon enregistré', visible: true) # check data on the dossier @@ -83,7 +84,7 @@ feature 'The user' do expect(page).to have_checked_field('val3') expect(page).to have_selected_value('simple_choice_drop_down_list_long', selected: 'bravo') expect(page).to have_selected_value('multiple_choice_drop_down_list_long', selected: ['alpha', 'charly']) - expect(page).to have_selected_value('pays', selected: 'AUSTRALIE') + expect(page).to have_hidden_field('pays', with: 'AUSTRALIE') expect(page).to have_hidden_field('regions', with: 'Martinique') expect(page).to have_hidden_field('departements', with: '02 - Aisne') expect(page).to have_hidden_field('communes', with: 'Ambléon (01300)') From a8ed9ef172681b7c88d99c37d7ed551036dd3e63 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Wed, 25 Nov 2020 15:28:27 +0100 Subject: [PATCH 08/10] remove dead code --- app/models/champs/pays_champ.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/models/champs/pays_champ.rb b/app/models/champs/pays_champ.rb index c1c82081e..d158aa6a9 100644 --- a/app/models/champs/pays_champ.rb +++ b/app/models/champs/pays_champ.rb @@ -15,13 +15,4 @@ # type_de_champ_id :integer # class Champs::PaysChamp < Champs::TextChamp - PAYS = JSON.parse(Rails.root.join('app', 'lib', 'api_geo', 'pays.json').read, symbolize_names: true) - - def self.pays - PAYS.pluck(:nom) - end - - def self.disabled_options - pays.filter { |v| (v =~ /^--.*--$/).present? } - end end From ddd50993a5b9412d59c1d7d6d0f4558b187d49c1 Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Mon, 30 Nov 2020 10:53:55 +0100 Subject: [PATCH 09/10] cache pays --- app/javascript/components/shared/queryCache.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/javascript/components/shared/queryCache.js b/app/javascript/components/shared/queryCache.js index 6809c0473..2e474a5f4 100644 --- a/app/javascript/components/shared/queryCache.js +++ b/app/javascript/components/shared/queryCache.js @@ -33,8 +33,7 @@ function buildOptions() { async function defaultQueryFn(scope, term) { if (scope == 'pays') { - const pays = await fetch('/pays.json').then((response) => response.json()); - return matchSorter(pays, term, { keys: ['nom'] }); + return matchSorter(await getPays(), term, { keys: ['nom'] }); } const url = buildURL(scope, term); @@ -43,3 +42,11 @@ async function defaultQueryFn(scope, term) { promise.cancel = () => controller && controller.abort(); return promise; } + +let paysCache; +async function getPays() { + if (!paysCache) { + paysCache = await fetch('/pays.json').then((response) => response.json()); + } + return paysCache; +} From 513d4f6ff1541515d1f30daf3249e0e8a5e46f91 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Fri, 13 Nov 2020 14:34:53 +0100 Subject: [PATCH 10/10] move all the cron jobs in a dedicated directory --- .../administrateur_activate_before_expiration_job.rb | 2 +- app/jobs/{ => cron}/auto_archive_procedure_job.rb | 2 +- app/jobs/{ => cron}/cron_job.rb | 2 +- app/jobs/{ => cron}/declarative_procedures_job.rb | 2 +- app/jobs/{ => cron}/discarded_dossiers_deletion_job.rb | 2 +- app/jobs/{ => cron}/discarded_procedures_deletion_job.rb | 2 +- app/jobs/{ => cron}/expired_dossiers_deletion_job.rb | 2 +- app/jobs/{ => cron}/find_dubious_procedures_job.rb | 2 +- app/jobs/{ => cron}/instructeur_email_notification_job.rb | 2 +- app/jobs/{ => cron}/notify_draft_not_submitted_job.rb | 2 +- app/jobs/{ => cron}/operations_signature_job.rb | 2 +- app/jobs/{ => cron}/purge_stale_exports_job.rb | 2 +- app/jobs/{ => cron}/purge_unattached_blobs_job.rb | 2 +- .../update_administrateur_usage_statistics_job.rb | 2 +- app/jobs/{ => cron}/update_stats_job.rb | 2 +- app/jobs/{ => cron}/weekly_overview_job.rb | 2 +- .../administrateur_activate_before_expiration_job_spec.rb | 4 ++-- spec/jobs/{ => cron}/auto_archive_procedure_job_spec.rb | 4 ++-- spec/jobs/{ => cron}/declarative_procedures_job_spec.rb | 4 ++-- spec/jobs/{ => cron}/find_dubious_procedures_job_spec.rb | 4 ++-- spec/jobs/{ => cron}/weekly_overview_job_spec.rb | 8 ++++---- spec/models/instructeur_spec.rb | 6 +++--- spec/services/notification_service_spec.rb | 6 +++--- 23 files changed, 34 insertions(+), 34 deletions(-) rename app/jobs/{ => cron}/administrateur_activate_before_expiration_job.rb (76%) rename app/jobs/{ => cron}/auto_archive_procedure_job.rb (86%) rename app/jobs/{ => cron}/cron_job.rb (95%) rename app/jobs/{ => cron}/declarative_procedures_job.rb (71%) rename app/jobs/{ => cron}/discarded_dossiers_deletion_job.rb (77%) rename app/jobs/{ => cron}/discarded_procedures_deletion_job.rb (79%) rename app/jobs/{ => cron}/expired_dossiers_deletion_job.rb (80%) rename app/jobs/{ => cron}/find_dubious_procedures_job.rb (95%) rename app/jobs/{ => cron}/instructeur_email_notification_job.rb (72%) rename app/jobs/{ => cron}/notify_draft_not_submitted_job.rb (71%) rename app/jobs/{ => cron}/operations_signature_job.rb (89%) rename app/jobs/{ => cron}/purge_stale_exports_job.rb (67%) rename app/jobs/{ => cron}/purge_unattached_blobs_job.rb (80%) rename app/jobs/{ => cron}/update_administrateur_usage_statistics_job.rb (68%) rename app/jobs/{ => cron}/update_stats_job.rb (69%) rename app/jobs/{ => cron}/weekly_overview_job.rb (90%) rename spec/jobs/{ => cron}/administrateur_activate_before_expiration_job_spec.rb (93%) rename spec/jobs/{ => cron}/auto_archive_procedure_job_spec.rb (96%) rename spec/jobs/{ => cron}/declarative_procedures_job_spec.rb (96%) rename spec/jobs/{ => cron}/find_dubious_procedures_job_spec.rb (94%) rename spec/jobs/{ => cron}/weekly_overview_job_spec.rb (87%) diff --git a/app/jobs/administrateur_activate_before_expiration_job.rb b/app/jobs/cron/administrateur_activate_before_expiration_job.rb similarity index 76% rename from app/jobs/administrateur_activate_before_expiration_job.rb rename to app/jobs/cron/administrateur_activate_before_expiration_job.rb index 958ed9635..4c5c518e8 100644 --- a/app/jobs/administrateur_activate_before_expiration_job.rb +++ b/app/jobs/cron/administrateur_activate_before_expiration_job.rb @@ -1,4 +1,4 @@ -class AdministrateurActivateBeforeExpirationJob < CronJob +class Cron::AdministrateurActivateBeforeExpirationJob < Cron::CronJob self.schedule_expression = "every day at 8 am" def perform(*args) diff --git a/app/jobs/auto_archive_procedure_job.rb b/app/jobs/cron/auto_archive_procedure_job.rb similarity index 86% rename from app/jobs/auto_archive_procedure_job.rb rename to app/jobs/cron/auto_archive_procedure_job.rb index d8611b291..8887fda3c 100644 --- a/app/jobs/auto_archive_procedure_job.rb +++ b/app/jobs/cron/auto_archive_procedure_job.rb @@ -1,4 +1,4 @@ -class AutoArchiveProcedureJob < CronJob +class Cron::AutoArchiveProcedureJob < Cron::CronJob self.schedule_expression = "every 1 minute" def perform(*args) diff --git a/app/jobs/cron_job.rb b/app/jobs/cron/cron_job.rb similarity index 95% rename from app/jobs/cron_job.rb rename to app/jobs/cron/cron_job.rb index adbc74dd4..1fe79f81b 100644 --- a/app/jobs/cron_job.rb +++ b/app/jobs/cron/cron_job.rb @@ -1,4 +1,4 @@ -class CronJob < ApplicationJob +class Cron::CronJob < ApplicationJob queue_as :cron class_attribute :schedule_expression diff --git a/app/jobs/declarative_procedures_job.rb b/app/jobs/cron/declarative_procedures_job.rb similarity index 71% rename from app/jobs/declarative_procedures_job.rb rename to app/jobs/cron/declarative_procedures_job.rb index af2bb395c..4a2bc613d 100644 --- a/app/jobs/declarative_procedures_job.rb +++ b/app/jobs/cron/declarative_procedures_job.rb @@ -1,4 +1,4 @@ -class DeclarativeProceduresJob < CronJob +class Cron::DeclarativeProceduresJob < Cron::CronJob self.schedule_expression = "every 1 minute" def perform(*args) diff --git a/app/jobs/discarded_dossiers_deletion_job.rb b/app/jobs/cron/discarded_dossiers_deletion_job.rb similarity index 77% rename from app/jobs/discarded_dossiers_deletion_job.rb rename to app/jobs/cron/discarded_dossiers_deletion_job.rb index 6b8e780d5..2a8d4b748 100644 --- a/app/jobs/discarded_dossiers_deletion_job.rb +++ b/app/jobs/cron/discarded_dossiers_deletion_job.rb @@ -1,4 +1,4 @@ -class DiscardedDossiersDeletionJob < CronJob +class Cron::DiscardedDossiersDeletionJob < Cron::CronJob self.schedule_expression = "every day at 2 am" def perform(*args) diff --git a/app/jobs/discarded_procedures_deletion_job.rb b/app/jobs/cron/discarded_procedures_deletion_job.rb similarity index 79% rename from app/jobs/discarded_procedures_deletion_job.rb rename to app/jobs/cron/discarded_procedures_deletion_job.rb index 5361a422f..8f1a6b92d 100644 --- a/app/jobs/discarded_procedures_deletion_job.rb +++ b/app/jobs/cron/discarded_procedures_deletion_job.rb @@ -1,4 +1,4 @@ -class DiscardedProceduresDeletionJob < CronJob +class Cron::DiscardedProceduresDeletionJob < Cron::CronJob self.schedule_expression = "every day at 1 am" def perform(*args) diff --git a/app/jobs/expired_dossiers_deletion_job.rb b/app/jobs/cron/expired_dossiers_deletion_job.rb similarity index 80% rename from app/jobs/expired_dossiers_deletion_job.rb rename to app/jobs/cron/expired_dossiers_deletion_job.rb index 65c80d23d..565c66975 100644 --- a/app/jobs/expired_dossiers_deletion_job.rb +++ b/app/jobs/cron/expired_dossiers_deletion_job.rb @@ -1,4 +1,4 @@ -class ExpiredDossiersDeletionJob < CronJob +class Cron::ExpiredDossiersDeletionJob < Cron::CronJob self.schedule_expression = "every day at 7 am" def perform(*args) diff --git a/app/jobs/find_dubious_procedures_job.rb b/app/jobs/cron/find_dubious_procedures_job.rb similarity index 95% rename from app/jobs/find_dubious_procedures_job.rb rename to app/jobs/cron/find_dubious_procedures_job.rb index 13c9a91ab..d2ed23561 100644 --- a/app/jobs/find_dubious_procedures_job.rb +++ b/app/jobs/cron/find_dubious_procedures_job.rb @@ -1,4 +1,4 @@ -class FindDubiousProceduresJob < CronJob +class Cron::FindDubiousProceduresJob < Cron::CronJob self.schedule_expression = "every day at midnight" FORBIDDEN_KEYWORDS = [ diff --git a/app/jobs/instructeur_email_notification_job.rb b/app/jobs/cron/instructeur_email_notification_job.rb similarity index 72% rename from app/jobs/instructeur_email_notification_job.rb rename to app/jobs/cron/instructeur_email_notification_job.rb index 5b49576bf..a81354da8 100644 --- a/app/jobs/instructeur_email_notification_job.rb +++ b/app/jobs/cron/instructeur_email_notification_job.rb @@ -1,4 +1,4 @@ -class InstructeurEmailNotificationJob < CronJob +class Cron::InstructeurEmailNotificationJob < Cron::CronJob self.schedule_expression = "from monday through friday at 10 am" def perform(*args) diff --git a/app/jobs/notify_draft_not_submitted_job.rb b/app/jobs/cron/notify_draft_not_submitted_job.rb similarity index 71% rename from app/jobs/notify_draft_not_submitted_job.rb rename to app/jobs/cron/notify_draft_not_submitted_job.rb index 2fbfe382f..24100930a 100644 --- a/app/jobs/notify_draft_not_submitted_job.rb +++ b/app/jobs/cron/notify_draft_not_submitted_job.rb @@ -1,4 +1,4 @@ -class NotifyDraftNotSubmittedJob < CronJob +class Cron::NotifyDraftNotSubmittedJob < Cron::CronJob self.schedule_expression = "from monday through friday at 7 am" def perform(*args) diff --git a/app/jobs/operations_signature_job.rb b/app/jobs/cron/operations_signature_job.rb similarity index 89% rename from app/jobs/operations_signature_job.rb rename to app/jobs/cron/operations_signature_job.rb index 2ad62da43..605cea333 100644 --- a/app/jobs/operations_signature_job.rb +++ b/app/jobs/cron/operations_signature_job.rb @@ -1,4 +1,4 @@ -class OperationsSignatureJob < CronJob +class Cron::OperationsSignatureJob < Cron::CronJob self.schedule_expression = "every day at 6 am" def perform(*args) diff --git a/app/jobs/purge_stale_exports_job.rb b/app/jobs/cron/purge_stale_exports_job.rb similarity index 67% rename from app/jobs/purge_stale_exports_job.rb rename to app/jobs/cron/purge_stale_exports_job.rb index 1f3480752..5e0fbcf6c 100644 --- a/app/jobs/purge_stale_exports_job.rb +++ b/app/jobs/cron/purge_stale_exports_job.rb @@ -1,4 +1,4 @@ -class PurgeStaleExportsJob < CronJob +class Cron::PurgeStaleExportsJob < Cron::CronJob self.schedule_expression = "every 5 minutes" def perform diff --git a/app/jobs/purge_unattached_blobs_job.rb b/app/jobs/cron/purge_unattached_blobs_job.rb similarity index 80% rename from app/jobs/purge_unattached_blobs_job.rb rename to app/jobs/cron/purge_unattached_blobs_job.rb index 6ca57ba9f..fe0ec87a4 100644 --- a/app/jobs/purge_unattached_blobs_job.rb +++ b/app/jobs/cron/purge_unattached_blobs_job.rb @@ -1,4 +1,4 @@ -class PurgeUnattachedBlobsJob < CronJob +class Cron::PurgeUnattachedBlobsJob < Cron::CronJob self.schedule_expression = "every day at midnight" def perform(*args) diff --git a/app/jobs/update_administrateur_usage_statistics_job.rb b/app/jobs/cron/update_administrateur_usage_statistics_job.rb similarity index 68% rename from app/jobs/update_administrateur_usage_statistics_job.rb rename to app/jobs/cron/update_administrateur_usage_statistics_job.rb index d873ee362..f7f018411 100644 --- a/app/jobs/update_administrateur_usage_statistics_job.rb +++ b/app/jobs/cron/update_administrateur_usage_statistics_job.rb @@ -1,4 +1,4 @@ -class UpdateAdministrateurUsageStatisticsJob < CronJob +class Cron::UpdateAdministrateurUsageStatisticsJob < Cron::CronJob self.schedule_expression = "every day at 10 am" def perform diff --git a/app/jobs/update_stats_job.rb b/app/jobs/cron/update_stats_job.rb similarity index 69% rename from app/jobs/update_stats_job.rb rename to app/jobs/cron/update_stats_job.rb index b1202b67e..a5dcd2c43 100644 --- a/app/jobs/update_stats_job.rb +++ b/app/jobs/cron/update_stats_job.rb @@ -1,4 +1,4 @@ -class UpdateStatsJob < CronJob +class Cron::UpdateStatsJob < Cron::CronJob self.schedule_expression = "every 1 hour" def perform(*args) diff --git a/app/jobs/weekly_overview_job.rb b/app/jobs/cron/weekly_overview_job.rb similarity index 90% rename from app/jobs/weekly_overview_job.rb rename to app/jobs/cron/weekly_overview_job.rb index e1e17541f..bc009a1b4 100644 --- a/app/jobs/weekly_overview_job.rb +++ b/app/jobs/cron/weekly_overview_job.rb @@ -1,4 +1,4 @@ -class WeeklyOverviewJob < CronJob +class Cron::WeeklyOverviewJob < Cron::CronJob self.schedule_expression = "every monday at 7 am" def perform(*args) diff --git a/spec/jobs/administrateur_activate_before_expiration_job_spec.rb b/spec/jobs/cron/administrateur_activate_before_expiration_job_spec.rb similarity index 93% rename from spec/jobs/administrateur_activate_before_expiration_job_spec.rb rename to spec/jobs/cron/administrateur_activate_before_expiration_job_spec.rb index 504f8cef4..0f6334efb 100644 --- a/spec/jobs/administrateur_activate_before_expiration_job_spec.rb +++ b/spec/jobs/cron/administrateur_activate_before_expiration_job_spec.rb @@ -1,10 +1,10 @@ -RSpec.describe AdministrateurActivateBeforeExpirationJob, type: :job do +RSpec.describe Cron::AdministrateurActivateBeforeExpirationJob, type: :job do describe 'perform' do let(:administrateur) { create(:administrateur) } let(:user) { administrateur.user } let(:mailer_double) { double('mailer', deliver_later: true) } - subject { AdministrateurActivateBeforeExpirationJob.perform_now } + subject { Cron::AdministrateurActivateBeforeExpirationJob.perform_now } before do Timecop.freeze(Time.zone.local(2018, 03, 20)) diff --git a/spec/jobs/auto_archive_procedure_job_spec.rb b/spec/jobs/cron/auto_archive_procedure_job_spec.rb similarity index 96% rename from spec/jobs/auto_archive_procedure_job_spec.rb rename to spec/jobs/cron/auto_archive_procedure_job_spec.rb index 3f1600b6c..fd414482a 100644 --- a/spec/jobs/auto_archive_procedure_job_spec.rb +++ b/spec/jobs/cron/auto_archive_procedure_job_spec.rb @@ -1,10 +1,10 @@ -RSpec.describe AutoArchiveProcedureJob, type: :job do +RSpec.describe Cron::AutoArchiveProcedureJob, type: :job do let!(:procedure) { create(:procedure, :published, :with_instructeur, auto_archive_on: nil) } let!(:procedure_hier) { create(:procedure, :published, :with_instructeur, auto_archive_on: 1.day.ago.to_date) } let!(:procedure_aujourdhui) { create(:procedure, :published, :with_instructeur, auto_archive_on: Time.zone.today) } let!(:procedure_demain) { create(:procedure, :published, :with_instructeur, auto_archive_on: 1.day.from_now.to_date) } - subject { AutoArchiveProcedureJob.new.perform } + subject { Cron::AutoArchiveProcedureJob.new.perform } context "when procedures have no auto_archive_on" do before do diff --git a/spec/jobs/declarative_procedures_job_spec.rb b/spec/jobs/cron/declarative_procedures_job_spec.rb similarity index 96% rename from spec/jobs/declarative_procedures_job_spec.rb rename to spec/jobs/cron/declarative_procedures_job_spec.rb index 4a4238174..6b96939fe 100644 --- a/spec/jobs/declarative_procedures_job_spec.rb +++ b/spec/jobs/cron/declarative_procedures_job_spec.rb @@ -1,4 +1,4 @@ -RSpec.describe DeclarativeProceduresJob, type: :job do +RSpec.describe Cron::DeclarativeProceduresJob, type: :job do describe "perform" do let(:date) { Time.utc(2017, 9, 1, 10, 5, 0) } let(:instruction_date) { date + 120 } @@ -20,7 +20,7 @@ RSpec.describe DeclarativeProceduresJob, type: :job do ] create(:attestation_template, procedure: procedure) - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossiers.each(&:reload) end diff --git a/spec/jobs/find_dubious_procedures_job_spec.rb b/spec/jobs/cron/find_dubious_procedures_job_spec.rb similarity index 94% rename from spec/jobs/find_dubious_procedures_job_spec.rb rename to spec/jobs/cron/find_dubious_procedures_job_spec.rb index acbc8df52..cbacacf82 100644 --- a/spec/jobs/find_dubious_procedures_job_spec.rb +++ b/spec/jobs/cron/find_dubious_procedures_job_spec.rb @@ -1,4 +1,4 @@ -RSpec.describe FindDubiousProceduresJob, type: :job do +RSpec.describe Cron::FindDubiousProceduresJob, type: :job do describe 'perform' do let(:mailer_double) { double('mailer', deliver_later: true) } let(:procedure) { create(:procedure, types_de_champ: tdcs) } @@ -11,7 +11,7 @@ RSpec.describe FindDubiousProceduresJob, type: :job do @dubious_procedures_args = arg end.and_return(mailer_double) - FindDubiousProceduresJob.new.perform + Cron::FindDubiousProceduresJob.new.perform end context 'with suspicious champs' do diff --git a/spec/jobs/weekly_overview_job_spec.rb b/spec/jobs/cron/weekly_overview_job_spec.rb similarity index 87% rename from spec/jobs/weekly_overview_job_spec.rb rename to spec/jobs/cron/weekly_overview_job_spec.rb index 3aa7a44e2..df62333d9 100644 --- a/spec/jobs/weekly_overview_job_spec.rb +++ b/spec/jobs/cron/weekly_overview_job_spec.rb @@ -1,4 +1,4 @@ -RSpec.describe WeeklyOverviewJob, type: :job do +RSpec.describe Cron::WeeklyOverviewJob, type: :job do describe 'perform' do let!(:instructeur) { create(:instructeur) } let(:overview) { double('overview') } @@ -16,7 +16,7 @@ RSpec.describe WeeklyOverviewJob, type: :job do before do expect_any_instance_of(Instructeur).to receive(:last_week_overview).and_return(overview) allow(InstructeurMailer).to receive(:last_week_overview).and_return(mailer_double) - WeeklyOverviewJob.new.perform + Cron::WeeklyOverviewJob.new.perform end it { expect(InstructeurMailer).to have_received(:last_week_overview).with(instructeur) } @@ -27,7 +27,7 @@ RSpec.describe WeeklyOverviewJob, type: :job do before do expect_any_instance_of(Instructeur).to receive(:last_week_overview).and_return(nil) allow(InstructeurMailer).to receive(:last_week_overview) - WeeklyOverviewJob.new.perform + Cron::WeeklyOverviewJob.new.perform end it { expect(InstructeurMailer).not_to have_received(:last_week_overview) } @@ -37,7 +37,7 @@ RSpec.describe WeeklyOverviewJob, type: :job do context 'if the feature is disabled' do before do allow(Instructeur).to receive(:all) - WeeklyOverviewJob.new.perform + Cron::WeeklyOverviewJob.new.perform end it { expect(Instructeur).not_to receive(:all) } diff --git a/spec/models/instructeur_spec.rb b/spec/models/instructeur_spec.rb index 717b6fccd..37dbfa3dc 100644 --- a/spec/models/instructeur_spec.rb +++ b/spec/models/instructeur_spec.rb @@ -455,7 +455,7 @@ describe Instructeur, type: :model do before do procedure_to_assign.update(declarative_with_state: "en_instruction") - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossier.reload end @@ -480,7 +480,7 @@ describe Instructeur, type: :model do before do procedure_to_assign.update(declarative_with_state: "accepte") - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossier.reload end @@ -497,7 +497,7 @@ describe Instructeur, type: :model do before do procedure_to_assign.update(declarative_with_state: "accepte") - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossier.traitements.last.update(processed_at: Time.zone.yesterday.beginning_of_day) dossier.reload end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 59266eab2..1f1b858c3 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -51,7 +51,7 @@ describe NotificationService do let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do procedure.update(declarative_with_state: "en_instruction") - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossier.reload end @@ -65,7 +65,7 @@ describe NotificationService do let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do procedure.update(declarative_with_state: "accepte") - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossier.traitements.last.update!(processed_at: Time.zone.yesterday.beginning_of_day) dossier.reload end @@ -80,7 +80,7 @@ describe NotificationService do let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do procedure.update(declarative_with_state: "accepte") - DeclarativeProceduresJob.new.perform + Cron::DeclarativeProceduresJob.new.perform dossier.reload end