Merge pull request #6363 from betagouv/main
This commit is contained in:
commit
414e216972
26 changed files with 233 additions and 157 deletions
|
@ -812,7 +812,7 @@ Rails/UniqBeforePluck:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
Rails/UniqueValidationWithoutIndex:
|
Rails/UniqueValidationWithoutIndex:
|
||||||
Enabled: false
|
Enabled: true
|
||||||
|
|
||||||
Rails/UnknownEnv:
|
Rails/UnknownEnv:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default class AutoSaveController {
|
||||||
|
|
||||||
// Add a new autosave request to the queue.
|
// Add a new autosave request to the queue.
|
||||||
// It will be started after the previous one finishes (to prevent older form data
|
// It will be started after the previous one finishes (to prevent older form data
|
||||||
// to overwrite newer data if the server does not repond in order.)
|
// to overwrite newer data if the server does not respond in order.)
|
||||||
enqueueAutosaveRequest(form) {
|
enqueueAutosaveRequest(form) {
|
||||||
this.latestPromise = this.latestPromise.finally(() => {
|
this.latestPromise = this.latestPromise.finally(() => {
|
||||||
return this._sendAutosaveRequest(form)
|
return this._sendAutosaveRequest(form)
|
||||||
|
|
|
@ -62,6 +62,15 @@ addEventListener('autosave:end', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
addEventListener('autosave:error', (event) => {
|
addEventListener('autosave:error', (event) => {
|
||||||
|
let error = event.detail;
|
||||||
|
|
||||||
|
if (error.xhr.status == 401) {
|
||||||
|
// If we are unauthenticated, reload the page using a GET request.
|
||||||
|
// This will allow Devise to properly redirect us to sign-in, and then back to this page.
|
||||||
|
document.location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
enable(document.querySelector('button.autosave-retry'));
|
enable(document.querySelector('button.autosave-retry'));
|
||||||
setState('failed');
|
setState('failed');
|
||||||
logError(event.detail);
|
logError(event.detail);
|
||||||
|
|
|
@ -50,6 +50,13 @@ export function delegate(eventNames, selector, callback) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A promise-based wrapper for Rails.ajax().
|
||||||
|
//
|
||||||
|
// Returns a Promise that is either:
|
||||||
|
// - resolved in case of a 20* HTTP response code,
|
||||||
|
// - rejected with an Error object otherwise.
|
||||||
|
//
|
||||||
|
// See Rails.ajax() code for more details.
|
||||||
export function ajax(options) {
|
export function ajax(options) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
Object.assign(options, {
|
Object.assign(options, {
|
||||||
|
@ -57,7 +64,10 @@ export function ajax(options) {
|
||||||
resolve({ response, statusText, xhr });
|
resolve({ response, statusText, xhr });
|
||||||
},
|
},
|
||||||
error: (response, statusText, xhr) => {
|
error: (response, statusText, xhr) => {
|
||||||
let error = new Error(`Erreur ${xhr.status} : ${statusText}`);
|
// NB: on HTTP/2 connections, statusText is always empty.
|
||||||
|
let error = new Error(
|
||||||
|
`Erreur ${xhr.status}` + (statusText ? ` : ${statusText}` : '')
|
||||||
|
);
|
||||||
Object.assign(error, { response, statusText, xhr });
|
Object.assign(error, { response, statusText, xhr });
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,16 +39,12 @@ class AttestationTemplate < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def unspecified_champs_for_dossier(dossier)
|
def unspecified_champs_for_dossier(dossier)
|
||||||
all_champs_with_libelle_index = (dossier.champs + dossier.champs_private)
|
all_champs_with_libelle_index = (dossier.champs + dossier.champs_private).index_by { |champ| "tdc#{champ.stable_id}" }
|
||||||
.reduce({}) do |acc, champ|
|
|
||||||
acc[champ.libelle] = champ
|
|
||||||
acc
|
|
||||||
end
|
|
||||||
|
|
||||||
used_tags.filter_map do |used_tag|
|
used_tags.filter_map do |used_tag|
|
||||||
corresponding_champ = all_champs_with_libelle_index[used_tag]
|
corresponding_champ = all_champs_with_libelle_index[used_tag]
|
||||||
|
|
||||||
if corresponding_champ && corresponding_champ.value.blank?
|
if corresponding_champ && corresponding_champ.blank?
|
||||||
corresponding_champ
|
corresponding_champ
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -113,7 +109,7 @@ class AttestationTemplate < ApplicationRecord
|
||||||
# We can't use flat_map as scan will return 3 levels of array,
|
# We can't use flat_map as scan will return 3 levels of array,
|
||||||
# using flat_map would give us 2, whereas flatten will
|
# using flat_map would give us 2, whereas flatten will
|
||||||
# give us 1, which is what we want
|
# give us 1, which is what we want
|
||||||
[title, body]
|
[normalize_tags(title), normalize_tags(body)]
|
||||||
.map { |str| str.scan(delimiters_regex) }
|
.map { |str| str.scan(delimiters_regex) }
|
||||||
.flatten
|
.flatten
|
||||||
end
|
end
|
||||||
|
|
|
@ -95,15 +95,8 @@ class Champ < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def blank?
|
def blank?
|
||||||
case type_de_champ.type_champ
|
|
||||||
when TypeDeChamp.type_champs.fetch(:carte)
|
|
||||||
geo_areas.blank? || value == '[]'
|
|
||||||
when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
|
||||||
value.blank? || value == '[]'
|
|
||||||
else
|
|
||||||
value.blank?
|
value.blank?
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def search_terms
|
def search_terms
|
||||||
[to_s]
|
[to_s]
|
||||||
|
|
|
@ -109,6 +109,10 @@ class Champs::CarteChamp < Champ
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def blank?
|
||||||
|
geo_areas.blank?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def selection_utilisateur_legacy_geometry
|
def selection_utilisateur_legacy_geometry
|
||||||
|
|
|
@ -62,6 +62,10 @@ class Champs::MultipleDropDownListChamp < Champ
|
||||||
enabled_non_empty_options.size <= THRESHOLD_NB_OPTIONS_AS_CHECKBOX
|
enabled_non_empty_options.size <= THRESHOLD_NB_OPTIONS_AS_CHECKBOX
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def blank?
|
||||||
|
selected_options.blank?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def format_before_save
|
def format_before_save
|
||||||
|
|
|
@ -30,8 +30,8 @@ class Champs::RepetitionChamp < Champ
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def mandatory_and_blank?
|
def blank?
|
||||||
mandatory? && champs.empty?
|
champs.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def search_terms
|
def search_terms
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
# deleted_user_email_never_send :string
|
# deleted_user_email_never_send :string
|
||||||
# en_construction_at :datetime
|
# en_construction_at :datetime
|
||||||
# en_construction_close_to_expiration_notice_sent_at :datetime
|
# en_construction_close_to_expiration_notice_sent_at :datetime
|
||||||
# en_construction_conservation_extension :interval default(0 seconds)
|
|
||||||
# en_instruction_at :datetime
|
# en_instruction_at :datetime
|
||||||
# groupe_instructeur_updated_at :datetime
|
# groupe_instructeur_updated_at :datetime
|
||||||
# hidden_at :datetime
|
# hidden_at :datetime
|
||||||
|
|
14
db/migrate/20210722133440_add_unique_index_to_champs.rb
Normal file
14
db/migrate/20210722133440_add_unique_index_to_champs.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
class AddUniqueIndexToChamps < ActiveRecord::Migration[6.1]
|
||||||
|
include Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
delete_duplicates :champs, [:type_de_champ_id, :dossier_id, :row]
|
||||||
|
add_concurrent_index :champs, [:type_de_champ_id, :dossier_id, :row], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :champs, [:type_de_champ_id, :dossier_id, :row]
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,14 @@
|
||||||
|
class AddUniqueIndexToDeletedDossiers < ActiveRecord::Migration[6.1]
|
||||||
|
include Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
delete_duplicates :deleted_dossiers, [:dossier_id]
|
||||||
|
add_concurrent_index :deleted_dossiers, [:dossier_id], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :deleted_dossiers, [:dossier_id]
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
class AddUniqueIndexToEtablissement < ActiveRecord::Migration[6.1]
|
||||||
|
include Database::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
delete_duplicates :etablissements, [:dossier_id]
|
||||||
|
remove_index :etablissements, [:dossier_id]
|
||||||
|
add_concurrent_index :etablissements, [:dossier_id], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :etablissements, [:dossier_id]
|
||||||
|
add_concurrent_index :etablissements, [:dossier_id]
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2021_06_05_095054) do
|
ActiveRecord::Schema.define(version: 2021_07_22_133553) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -174,6 +174,7 @@ ActiveRecord::Schema.define(version: 2021_06_05_095054) do
|
||||||
t.index ["parent_id"], name: "index_champs_on_parent_id"
|
t.index ["parent_id"], name: "index_champs_on_parent_id"
|
||||||
t.index ["private"], name: "index_champs_on_private"
|
t.index ["private"], name: "index_champs_on_private"
|
||||||
t.index ["row"], name: "index_champs_on_row"
|
t.index ["row"], name: "index_champs_on_row"
|
||||||
|
t.index ["type_de_champ_id", "dossier_id", "row"], name: "index_champs_on_type_de_champ_id_and_dossier_id_and_row", unique: true
|
||||||
t.index ["type_de_champ_id"], name: "index_champs_on_type_de_champ_id"
|
t.index ["type_de_champ_id"], name: "index_champs_on_type_de_champ_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -228,6 +229,7 @@ ActiveRecord::Schema.define(version: 2021_06_05_095054) do
|
||||||
t.bigint "user_id"
|
t.bigint "user_id"
|
||||||
t.bigint "groupe_instructeur_id"
|
t.bigint "groupe_instructeur_id"
|
||||||
t.bigint "revision_id"
|
t.bigint "revision_id"
|
||||||
|
t.index ["dossier_id"], name: "index_deleted_dossiers_on_dossier_id", unique: true
|
||||||
t.index ["procedure_id"], name: "index_deleted_dossiers_on_procedure_id"
|
t.index ["procedure_id"], name: "index_deleted_dossiers_on_procedure_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -276,9 +278,9 @@ ActiveRecord::Schema.define(version: 2021_06_05_095054) do
|
||||||
t.string "api_entreprise_job_exceptions", array: true
|
t.string "api_entreprise_job_exceptions", array: true
|
||||||
t.interval "conservation_extension", default: "PT0S"
|
t.interval "conservation_extension", default: "PT0S"
|
||||||
t.string "deleted_user_email_never_send"
|
t.string "deleted_user_email_never_send"
|
||||||
|
t.datetime "declarative_triggered_at"
|
||||||
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
||||||
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
||||||
t.datetime "declarative_triggered_at"
|
|
||||||
t.index ["archived"], name: "index_dossiers_on_archived"
|
t.index ["archived"], name: "index_dossiers_on_archived"
|
||||||
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
||||||
t.index ["hidden_at"], name: "index_dossiers_on_hidden_at"
|
t.index ["hidden_at"], name: "index_dossiers_on_hidden_at"
|
||||||
|
@ -338,7 +340,7 @@ ActiveRecord::Schema.define(version: 2021_06_05_095054) do
|
||||||
t.jsonb "entreprise_bilans_bdf"
|
t.jsonb "entreprise_bilans_bdf"
|
||||||
t.string "entreprise_bilans_bdf_monnaie"
|
t.string "entreprise_bilans_bdf_monnaie"
|
||||||
t.string "enseigne"
|
t.string "enseigne"
|
||||||
t.index ["dossier_id"], name: "index_etablissements_on_dossier_id"
|
t.index ["dossier_id"], name: "index_etablissements_on_dossier_id", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "exercices", id: :serial, force: :cascade do |t|
|
create_table "exercices", id: :serial, force: :cascade do |t|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
namespace :after_party do
|
|
||||||
desc 'Deployment task: migrate service organisme'
|
|
||||||
task migrate_service_organisme: :environment do
|
|
||||||
table = {
|
|
||||||
'commune': 'collectivite_territoriale',
|
|
||||||
'departement': 'collectivite_territoriale',
|
|
||||||
'region': 'collectivite_territoriale',
|
|
||||||
'prefecture': 'service_deconcentre_de_l_etat'
|
|
||||||
}
|
|
||||||
|
|
||||||
table.each do |(old_name, new_name)|
|
|
||||||
Service.where(type_organisme: old_name).update_all(type_organisme: new_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
AfterParty::TaskRecord.create version: '20190201121252'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,19 +0,0 @@
|
||||||
require Rails.root.join("lib", "tasks", "task_helper")
|
|
||||||
|
|
||||||
namespace :fix_timestamps_of_migrated_dossiers do
|
|
||||||
desc 'Fix the timestamps of dossiers affected by the faulty PJ migration'
|
|
||||||
task run: :environment do
|
|
||||||
affected_time_range = Time.utc(2019, 6, 4, 8, 0)..Time.utc(2019, 6, 4, 18, 0)
|
|
||||||
dossiers = Dossier.with_discarded.includes(:groupe_instructeur).where(groupe_instructeurs: { procedure_id: 0..1000 }).where(updated_at: affected_time_range)
|
|
||||||
|
|
||||||
progress = ProgressReport.new(dossiers.count)
|
|
||||||
|
|
||||||
dossiers.find_each do |dossier|
|
|
||||||
fixed_updated_at = dossier.processed_at || dossier.en_instruction_at || dossier.en_construction_at || dossier.champs.last.updated_at || nil
|
|
||||||
dossier.update_column(:updated_at, fixed_updated_at)
|
|
||||||
|
|
||||||
progress.inc
|
|
||||||
end
|
|
||||||
progress.finish
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
namespace :after_party do
|
||||||
|
desc 'Deployment task: remove_migration_status_on_filters'
|
||||||
|
task remove_migration_status_on_filters: :environment do
|
||||||
|
rake_puts "Running deploy task 'remove_migration_status_on_filters'"
|
||||||
|
|
||||||
|
# In a9a4f6e2a801b19b127aae8eaec0d1f384b1a53a, a task to migrate ProcedurePresentation's filters
|
||||||
|
# was added.
|
||||||
|
# This task added a "migrated: true" key to all migrated filters.
|
||||||
|
#
|
||||||
|
# Now that this task has run, we can safely remove the extra key.
|
||||||
|
|
||||||
|
procedure_presentations = ProcedurePresentation.where("filters -> 'migrated' IS NOT NULL")
|
||||||
|
progress = ProgressReport.new(procedure_presentations.count)
|
||||||
|
|
||||||
|
procedure_presentations.find_each do |pp|
|
||||||
|
pp.filters.delete('migrated')
|
||||||
|
pp.save!
|
||||||
|
progress.inc
|
||||||
|
end
|
||||||
|
progress.finish
|
||||||
|
|
||||||
|
AfterParty::TaskRecord
|
||||||
|
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,6 +15,17 @@ def rake_print(*args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Display progress of a long-running Rake task.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# progress = ProgressReport.new(100)
|
||||||
|
# (0..100).times do
|
||||||
|
# progress.inc
|
||||||
|
# end
|
||||||
|
# progress.finish
|
||||||
|
# ````
|
||||||
class ProgressReport
|
class ProgressReport
|
||||||
def initialize(total)
|
def initialize(total)
|
||||||
@start = Time.zone.now
|
@start = Time.zone.now
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
require Rails.root.join("lib", "tasks", "task_helper")
|
|
||||||
|
|
||||||
namespace :tmp_set_dossiers_last_updated_at do
|
|
||||||
desc 'set for all dossiers last_updated_at'
|
|
||||||
task run: :environment do
|
|
||||||
start_id = ENV.fetch('DOSSIER_START_AT', 0)
|
|
||||||
|
|
||||||
all_dossiers = Dossier.with_discarded
|
|
||||||
.where('dossiers.id > ?', start_id)
|
|
||||||
.includes(:champs, :avis, :commentaires)
|
|
||||||
.order(:id)
|
|
||||||
|
|
||||||
progress = ProgressReport.new(all_dossiers.count)
|
|
||||||
|
|
||||||
all_dossiers.in_batches do |dossiers|
|
|
||||||
dossiers.each do |dossier|
|
|
||||||
last_commentaire_updated_at = dossier.commentaires
|
|
||||||
.where.not(email: OLD_CONTACT_EMAIL)
|
|
||||||
.where.not(email: CONTACT_EMAIL)
|
|
||||||
.maximum(:updated_at)
|
|
||||||
last_avis_updated_at = dossier.avis.maximum(:updated_at)
|
|
||||||
last_champ_updated_at = dossier.champs.maximum(:updated_at)
|
|
||||||
last_champ_private_updated_at = dossier.champs_private.maximum(:updated_at)
|
|
||||||
dossier.update_columns(
|
|
||||||
last_commentaire_updated_at: last_commentaire_updated_at,
|
|
||||||
last_avis_updated_at: last_avis_updated_at,
|
|
||||||
last_champ_updated_at: last_champ_updated_at,
|
|
||||||
last_champ_private_updated_at: last_champ_private_updated_at
|
|
||||||
)
|
|
||||||
progress.inc
|
|
||||||
end
|
|
||||||
rake_puts "dossiers lastid: #{dossiers.last.id}"
|
|
||||||
end
|
|
||||||
|
|
||||||
progress.finish
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -176,7 +176,11 @@ FactoryBot.define do
|
||||||
factory :champ_repetition, class: 'Champs::RepetitionChamp' do
|
factory :champ_repetition, class: 'Champs::RepetitionChamp' do
|
||||||
type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure }
|
type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure }
|
||||||
|
|
||||||
after(:build) do |champ_repetition, _evaluator|
|
transient do
|
||||||
|
rows { 2 }
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:build) do |champ_repetition, evaluator|
|
||||||
types_de_champ = champ_repetition.type_de_champ.types_de_champ
|
types_de_champ = champ_repetition.type_de_champ.types_de_champ
|
||||||
existing_type_de_champ_text = types_de_champ.find { |tdc| tdc.libelle == 'Nom' }
|
existing_type_de_champ_text = types_de_champ.find { |tdc| tdc.libelle == 'Nom' }
|
||||||
type_de_champ_text = existing_type_de_champ_text || build(
|
type_de_champ_text = existing_type_de_champ_text || build(
|
||||||
|
@ -195,13 +199,13 @@ FactoryBot.define do
|
||||||
)
|
)
|
||||||
|
|
||||||
champ_repetition.type_de_champ.types_de_champ << [type_de_champ_text, type_de_champ_number]
|
champ_repetition.type_de_champ.types_de_champ << [type_de_champ_text, type_de_champ_number]
|
||||||
|
evaluator.rows.times do |row|
|
||||||
champ_repetition.champs << [
|
champ_repetition.champs << [
|
||||||
build(:champ_text, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition),
|
build(:champ_text, dossier: champ_repetition.dossier, row: row, type_de_champ: type_de_champ_text, parent: champ_repetition),
|
||||||
build(:champ_number, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition),
|
build(:champ_number, dossier: champ_repetition.dossier, row: row, type_de_champ: type_de_champ_number, parent: champ_repetition)
|
||||||
build(:champ_text, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_text, parent: champ_repetition),
|
|
||||||
build(:champ_number, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_number, parent: champ_repetition)
|
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
trait :without_champs do
|
trait :without_champs do
|
||||||
after(:build) do |champ_repetition, _evaluator|
|
after(:build) do |champ_repetition, _evaluator|
|
||||||
|
|
|
@ -255,24 +255,46 @@ feature 'The user' do
|
||||||
expect(page).to have_field('texte obligatoire', with: 'a valid user input')
|
expect(page).to have_field('texte obligatoire', with: 'a valid user input')
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'retry on autosave error', js: true do
|
scenario 'retry on autosave error', :capybara_ignore_server_errors, js: true do
|
||||||
log_in(user, simple_procedure)
|
log_in(user, simple_procedure)
|
||||||
fill_individual
|
fill_individual
|
||||||
|
|
||||||
# Test autosave failure
|
# Test autosave failure
|
||||||
logout(:user) # Make the subsequent autosave requests fail
|
allow_any_instance_of(Users::DossiersController).to receive(:update_brouillon).and_raise("Server is busy")
|
||||||
fill_in('texte obligatoire', with: 'a valid user input')
|
fill_in('texte obligatoire', with: 'a valid user input')
|
||||||
blur
|
blur
|
||||||
expect(page).to have_css('span', text: 'Impossible d’enregistrer le brouillon', visible: true)
|
expect(page).to have_css('span', text: 'Impossible d’enregistrer le brouillon', visible: true)
|
||||||
|
|
||||||
# Test that retrying after a failure works
|
# Test that retrying after a failure works
|
||||||
login_as(user, scope: :user) # Make the autosave requests work again
|
allow_any_instance_of(Users::DossiersController).to receive(:update_brouillon).and_call_original
|
||||||
click_on 'réessayer'
|
click_on 'réessayer'
|
||||||
expect(page).to have_css('span', text: 'Brouillon enregistré', visible: true)
|
expect(page).to have_css('span', text: 'Brouillon enregistré', visible: true)
|
||||||
|
|
||||||
visit current_path
|
visit current_path
|
||||||
expect(page).to have_field('texte obligatoire', with: 'a valid user input')
|
expect(page).to have_field('texte obligatoire', with: 'a valid user input')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'autosave redirects to sign-in after being disconnected', js: true do
|
||||||
|
log_in(user, simple_procedure)
|
||||||
|
fill_individual
|
||||||
|
|
||||||
|
# When the user is disconnected
|
||||||
|
# (either because signing-out in another tab, or because the session cookie expired)
|
||||||
|
logout(:user)
|
||||||
|
fill_in('texte obligatoire', with: 'a valid user input')
|
||||||
|
blur
|
||||||
|
|
||||||
|
# … they are redirected to the sign-in page.
|
||||||
|
expect(page).to have_current_path(new_user_session_path)
|
||||||
|
|
||||||
|
# After sign-in, they are redirected back to their brouillon
|
||||||
|
sign_in_with(user.email, password)
|
||||||
|
expect(page).to have_current_path(brouillon_dossier_path(user_dossier))
|
||||||
|
|
||||||
|
fill_in('texte obligatoire', with: 'a valid user input')
|
||||||
|
blur
|
||||||
|
expect(page).to have_css('span', text: 'Brouillon enregistré', visible: true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
describe '2019_06_06_fix_timestamps_of_migrated_dossiers' do
|
|
||||||
let(:affected_procedure) { create(:simple_procedure, id: 500) }
|
|
||||||
let(:procedure_outside_range) { create(:simple_procedure, id: 5000) }
|
|
||||||
|
|
||||||
let(:affected_dossier) { create(:dossier, procedure: affected_procedure) }
|
|
||||||
let(:dossier_outside_time_range) { create(:dossier, procedure: affected_procedure) }
|
|
||||||
let(:dossier_outside_procedure_range) { create(:dossier, procedure: procedure_outside_range) }
|
|
||||||
|
|
||||||
let(:creation_time) { Time.utc(2017, 1, 1, 12, 0) }
|
|
||||||
let(:en_construction_time) { Time.utc(2018, 1, 1, 12, 0) }
|
|
||||||
let(:pj_migration_time) { Time.utc(2019, 6, 4, 12, 0) }
|
|
||||||
|
|
||||||
let(:rake_task) { Rake::Task['fix_timestamps_of_migrated_dossiers:run'] }
|
|
||||||
|
|
||||||
before do
|
|
||||||
Timecop.freeze(creation_time) do
|
|
||||||
affected_dossier
|
|
||||||
dossier_outside_time_range
|
|
||||||
dossier_outside_procedure_range
|
|
||||||
end
|
|
||||||
Timecop.freeze(en_construction_time) do
|
|
||||||
affected_dossier.update_column(:en_construction_at, Time.zone.now)
|
|
||||||
end
|
|
||||||
Timecop.freeze(pj_migration_time.prev_week) do
|
|
||||||
dossier_outside_time_range.tap(&:touch).reload
|
|
||||||
end
|
|
||||||
Timecop.freeze(pj_migration_time) do
|
|
||||||
dossier_outside_procedure_range.tap(&:touch).reload
|
|
||||||
affected_dossier.tap(&:touch).reload
|
|
||||||
end
|
|
||||||
|
|
||||||
rake_task.invoke
|
|
||||||
end
|
|
||||||
|
|
||||||
after { rake_task.reenable }
|
|
||||||
|
|
||||||
it 'fix the updated_at of affected dossiers' do
|
|
||||||
expect(affected_dossier.reload.updated_at).to eq(en_construction_time)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'ignores dossiers with a procedure_id outside of the procedure range' do
|
|
||||||
expect(dossier_outside_procedure_range.reload.updated_at).to eq(pj_migration_time)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'ignores dossiers with an updated_at outside of the time range' do
|
|
||||||
expect(dossier_outside_time_range.reload.updated_at).to eq(pj_migration_time.prev_week)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
describe '20201001161931_migrate_filters_to_use_stable_id' do
|
||||||
|
let(:rake_task) { Rake::Task['after_party:remove_migration_status_on_filters'] }
|
||||||
|
|
||||||
|
let(:procedure) { create(:simple_procedure) }
|
||||||
|
let(:instructeur_1) { create(:instructeur) }
|
||||||
|
let(:instructeur_2) { create(:instructeur) }
|
||||||
|
|
||||||
|
let(:assign_to_1) { create(:assign_to, procedure: procedure, instructeur: instructeur_1) }
|
||||||
|
let(:assign_to_2) { create(:assign_to, procedure: procedure, instructeur: instructeur_2) }
|
||||||
|
|
||||||
|
let(:procedure_presentation_with_migration) { create(:procedure_presentation, assign_to: assign_to_1, filters: filters.merge('migrated': true)) }
|
||||||
|
let(:procedure_presentation_without_migration) { create(:procedure_presentation, assign_to: assign_to_2, filters: filters) }
|
||||||
|
|
||||||
|
let(:filters) do
|
||||||
|
{ "suivis" => [{ "table" => "user", "column" => "email", "value" => "test@example.com" }] }
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
procedure_presentation_with_migration
|
||||||
|
procedure_presentation_without_migration
|
||||||
|
|
||||||
|
rake_task.invoke
|
||||||
|
|
||||||
|
procedure_presentation_with_migration.reload
|
||||||
|
procedure_presentation_without_migration.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
after { rake_task.reenable }
|
||||||
|
|
||||||
|
context 'when the procedure presentation has a "migrated" key' do
|
||||||
|
it 'removes the "migrated" key' do
|
||||||
|
expect(procedure_presentation_with_migration.filters).not_to have_key('migrated')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'leaves other keys unchanged' do
|
||||||
|
expect(procedure_presentation_with_migration.filters['suivis']).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the procedure presentation doesn’t have a "migrated" key' do
|
||||||
|
it 'leaves keys unchanged' do
|
||||||
|
expect(procedure_presentation_without_migration.filters['suivis']).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,16 +11,32 @@ shared_examples 'champ_spec' do
|
||||||
|
|
||||||
context 'when carte mandatory and blank' do
|
context 'when carte mandatory and blank' do
|
||||||
let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) }
|
let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) }
|
||||||
let(:value) { '[]' }
|
let(:champ) { build(:champ_carte, type_de_champ: type_de_champ, value: value) }
|
||||||
|
let(:value) { nil }
|
||||||
it { expect(champ.mandatory_and_blank?).to be(true) }
|
it { expect(champ.mandatory_and_blank?).to be(true) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when multiple_drop_down_list mandatory and blank' do
|
context 'when multiple_drop_down_list mandatory and blank' do
|
||||||
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) }
|
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) }
|
||||||
|
let(:champ) { build(:champ_multiple_drop_down_list, type_de_champ: type_de_champ, value: value) }
|
||||||
let(:value) { '[]' }
|
let(:value) { '[]' }
|
||||||
it { expect(champ.mandatory_and_blank?).to be(true) }
|
it { expect(champ.mandatory_and_blank?).to be(true) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when repetition blank' do
|
||||||
|
let(:type_de_champ) { build(:type_de_champ_repetition) }
|
||||||
|
let(:champ) { build(:champ_repetition, type_de_champ: type_de_champ, rows: 0) }
|
||||||
|
|
||||||
|
it { expect(champ.blank?).to be(true) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when repetition not blank' do
|
||||||
|
let(:type_de_champ) { build(:type_de_champ_repetition) }
|
||||||
|
let(:champ) { build(:champ_repetition, type_de_champ: type_de_champ) }
|
||||||
|
|
||||||
|
it { expect(champ.blank?).to be(false) }
|
||||||
|
end
|
||||||
|
|
||||||
context 'when not blank' do
|
context 'when not blank' do
|
||||||
let(:value) { 'yop' }
|
let(:value) { 'yop' }
|
||||||
it { expect(champ.mandatory_and_blank?).to be(false) }
|
it { expect(champ.mandatory_and_blank?).to be(false) }
|
||||||
|
|
|
@ -564,7 +564,7 @@ describe Dossier do
|
||||||
|
|
||||||
describe "#unspecified_attestation_champs" do
|
describe "#unspecified_attestation_champs" do
|
||||||
let(:procedure) { create(:procedure, attestation_template: attestation_template, types_de_champ: types_de_champ, types_de_champ_private: types_de_champ_private) }
|
let(:procedure) { create(:procedure, attestation_template: attestation_template, types_de_champ: types_de_champ, types_de_champ_private: types_de_champ_private) }
|
||||||
let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) }
|
let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
|
||||||
let(:types_de_champ) { [] }
|
let(:types_de_champ) { [] }
|
||||||
let(:types_de_champ_private) { [] }
|
let(:types_de_champ_private) { [] }
|
||||||
|
|
||||||
|
|
|
@ -47,3 +47,16 @@ Capybara::Screenshot.prune_strategy = :keep_last_run
|
||||||
Capybara::Screenshot.register_driver :headless_chrome do |driver, path|
|
Capybara::Screenshot.register_driver :headless_chrome do |driver, path|
|
||||||
driver.browser.save_screenshot(path)
|
driver.browser.save_screenshot(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
RSpec.configure do |config|
|
||||||
|
# Examples tagged with :capybara_ignore_server_errors will allow Capybara
|
||||||
|
# to continue when an exception in raised by Rails.
|
||||||
|
# This allows to test for error cases.
|
||||||
|
config.around(:each, :capybara_ignore_server_errors) do |example|
|
||||||
|
Capybara.raise_server_errors = false
|
||||||
|
|
||||||
|
example.run
|
||||||
|
ensure
|
||||||
|
Capybara.raise_server_errors = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue