commit
b49606bfb3
123 changed files with 875 additions and 264 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -59,7 +59,7 @@ jobs:
|
|||
- bin/rspec spec/controllers/*_spec.rb
|
||||
- bin/rspec spec/controllers/[a-l]**/*_spec.rb
|
||||
- bin/rspec spec/controllers/[m-z]**/*_spec.rb
|
||||
- bin/rspec spec/features
|
||||
- bin/rspec spec/system
|
||||
- bin/rspec spec/helpers spec/lib spec/middlewares
|
||||
- bin/rspec spec/mailers spec/jobs spec/policies
|
||||
- bin/rspec spec/models
|
||||
|
|
|
@ -722,7 +722,7 @@ Rails/DelegateAllowBlank:
|
|||
Rails/DynamicFindBy:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
- "spec/features/**/*.rb"
|
||||
- "spec/system/**/*.rb"
|
||||
|
||||
Rails/EnumUniqueness:
|
||||
Enabled: true
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -89,11 +89,10 @@ group :test do
|
|||
gem 'capybara' # 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'
|
||||
gem 'database_cleaner'
|
||||
gem 'factory_bot'
|
||||
gem 'launchy'
|
||||
gem 'rails-controller-testing'
|
||||
gem 'selenium-webdriver'
|
||||
gem 'shoulda-matchers', require: false
|
||||
gem 'timecop'
|
||||
gem 'vcr'
|
||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -162,9 +162,6 @@ GEM
|
|||
capybara-screenshot (1.0.25)
|
||||
capybara (>= 1.0, < 4)
|
||||
launchy
|
||||
capybara-selenium (0.0.6)
|
||||
capybara
|
||||
selenium-webdriver
|
||||
case_transform (0.2)
|
||||
activesupport
|
||||
caxlsx (3.1.0)
|
||||
|
@ -189,12 +186,6 @@ GEM
|
|||
css_parser (1.9.0)
|
||||
addressable
|
||||
daemons (1.3.1)
|
||||
database_cleaner (2.0.1)
|
||||
database_cleaner-active_record (~> 2.0.0)
|
||||
database_cleaner-active_record (2.0.0)
|
||||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
datetime_picker_rails (0.0.7)
|
||||
momentjs-rails (>= 2.8.1)
|
||||
deep_cloneable (3.0.0)
|
||||
|
@ -798,13 +789,11 @@ DEPENDENCIES
|
|||
capybara
|
||||
capybara-email
|
||||
capybara-screenshot
|
||||
capybara-selenium
|
||||
charlock_holmes
|
||||
chartkick
|
||||
chunky_png
|
||||
clamav-client
|
||||
daemons
|
||||
database_cleaner
|
||||
deep_cloneable
|
||||
delayed_cron_job
|
||||
delayed_job_active_record
|
||||
|
@ -874,6 +863,7 @@ DEPENDENCIES
|
|||
sanitize-url
|
||||
sassc-rails
|
||||
scss_lint
|
||||
selenium-webdriver
|
||||
sentry-delayed_job
|
||||
sentry-rails
|
||||
sentry-ruby
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# More info at https://github.com/guard/guard#readme
|
||||
|
||||
## Uncomment and set this to only include directories you want to watch
|
||||
# directories %w(app lib config test spec features) \
|
||||
# directories %w(app lib config test spec system) \
|
||||
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
||||
|
||||
## Note: if you are using the `directories` clause above and you are not
|
||||
|
@ -77,8 +77,8 @@ guard :rspec, cmd: 'spring rspec' do
|
|||
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
||||
watch('spec/rails_helper.rb') { "spec" }
|
||||
|
||||
# Capybara features specs
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
||||
# Capybara system specs
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/system/#{m[1]}_spec.rb" }
|
||||
|
||||
# Turnip features and steps
|
||||
watch(%r{^spec/acceptance/(.+)\.feature$})
|
||||
|
|
|
@ -57,6 +57,9 @@ module NewAdministrateur
|
|||
],
|
||||
methods: [
|
||||
:drop_down_list_value,
|
||||
:drop_down_other,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:piece_justificative_template_filename,
|
||||
:piece_justificative_template_url,
|
||||
:editable_options
|
||||
|
@ -73,6 +76,9 @@ module NewAdministrateur
|
|||
:parent_id,
|
||||
:private,
|
||||
:drop_down_list_value,
|
||||
:drop_down_other,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:piece_justificative_template,
|
||||
editable_options: [
|
||||
:cadastres,
|
||||
|
@ -94,6 +100,9 @@ module NewAdministrateur
|
|||
:description,
|
||||
:mandatory,
|
||||
:drop_down_list_value,
|
||||
:drop_down_other,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:piece_justificative_template,
|
||||
editable_options: [
|
||||
:cadastres,
|
||||
|
|
|
@ -337,8 +337,8 @@ module Users
|
|||
def champs_params
|
||||
params.permit(dossier: {
|
||||
champs_attributes: [
|
||||
:id, :value, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, value: []]
|
||||
:id, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, value: [],
|
||||
champs_attributes: [:id, :_destroy, :value, :value_other, :external_id, :primary_value, :secondary_value, :numero_allocataire, :code_postal, :piece_justificative_file, value: []]
|
||||
]
|
||||
})
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ module Users
|
|||
.joins(:dossiers)
|
||||
.find_by!(id: params[:id], dossiers: { user: current_user })
|
||||
|
||||
transfer.destroy
|
||||
transfer.destroy_and_nullify
|
||||
redirect_to dossiers_path
|
||||
end
|
||||
|
||||
|
|
|
@ -11,9 +11,11 @@ import MoveButton from './MoveButton';
|
|||
import TypeDeChampCarteOption from './TypeDeChampCarteOption';
|
||||
import TypeDeChampCarteOptions from './TypeDeChampCarteOptions';
|
||||
import TypeDeChampDropDownOptions from './TypeDeChampDropDownOptions';
|
||||
import TypeDeChampDropDownOther from './TypeDeChampDropDownOther';
|
||||
import TypeDeChampPieceJustificative from './TypeDeChampPieceJustificative';
|
||||
import TypeDeChampRepetitionOptions from './TypeDeChampRepetitionOptions';
|
||||
import TypeDeChampTypesSelect from './TypeDeChampTypesSelect';
|
||||
import TypeDeChampDropDownSecondary from './TypeDeChampDropDownSecondary';
|
||||
|
||||
const TypeDeChamp = sortableElement(
|
||||
({ typeDeChamp, dispatch, idx: index, isFirstItem, isLastItem, state }) => {
|
||||
|
@ -22,6 +24,8 @@ const TypeDeChamp = sortableElement(
|
|||
'multiple_drop_down_list',
|
||||
'linked_drop_down_list'
|
||||
].includes(typeDeChamp.type_champ);
|
||||
const isLinkedDropDown = typeDeChamp.type_champ === 'linked_drop_down_list';
|
||||
const isSimpleDropDown = typeDeChamp.type_champ === 'drop_down_list';
|
||||
const isFile = typeDeChamp.type_champ === 'piece_justificative';
|
||||
const isCarte = typeDeChamp.type_champ === 'carte';
|
||||
const isExplication = typeDeChamp.type_champ === 'explication';
|
||||
|
@ -130,6 +134,15 @@ const TypeDeChamp = sortableElement(
|
|||
isVisible={isDropDown}
|
||||
handler={updateHandlers.drop_down_list_value}
|
||||
/>
|
||||
<TypeDeChampDropDownSecondary
|
||||
isVisible={isLinkedDropDown}
|
||||
libelleHandler={updateHandlers.drop_down_secondary_libelle}
|
||||
descriptionHandler={updateHandlers.drop_down_secondary_description}
|
||||
/>
|
||||
<TypeDeChampDropDownOther
|
||||
isVisible={isSimpleDropDown}
|
||||
handler={updateHandlers.drop_down_other}
|
||||
/>
|
||||
<TypeDeChampPieceJustificative
|
||||
isVisible={isFile}
|
||||
directUploadUrl={state.directUploadUrl}
|
||||
|
@ -234,12 +247,15 @@ const OPTIONS_FIELDS = {
|
|||
export const FIELDS = [
|
||||
'description',
|
||||
'drop_down_list_value',
|
||||
'drop_down_other',
|
||||
'libelle',
|
||||
'mandatory',
|
||||
'parent_id',
|
||||
'piece_justificative_template',
|
||||
'private',
|
||||
'type_champ',
|
||||
'drop_down_secondary_libelle',
|
||||
'drop_down_secondary_description',
|
||||
...Object.keys(OPTIONS_FIELDS)
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
function TypeDeChampDropDownOther({ isVisible, handler }) {
|
||||
if (isVisible) {
|
||||
return (
|
||||
<div className="cell">
|
||||
<label htmlFor={handler.id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={handler.id}
|
||||
name={handler.name}
|
||||
checked={!!handler.value}
|
||||
onChange={handler.onChange}
|
||||
className="small-margin small"
|
||||
/>
|
||||
Proposer une option 'autre' avec un texte libre
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeDeChampDropDownOther.propTypes = {
|
||||
isVisible: PropTypes.bool,
|
||||
handler: PropTypes.object
|
||||
};
|
||||
|
||||
export default TypeDeChampDropDownOther;
|
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function TypeDeChampDropDownSecondary({
|
||||
isVisible,
|
||||
libelleHandler,
|
||||
descriptionHandler
|
||||
}) {
|
||||
if (isVisible) {
|
||||
return (
|
||||
<div className="cell">
|
||||
<label htmlFor={libelleHandler.id}>Libellé secondaire</label>
|
||||
<input
|
||||
type="text"
|
||||
id={libelleHandler.id}
|
||||
name={libelleHandler.name}
|
||||
value={libelleHandler.value ?? ''}
|
||||
onChange={libelleHandler.onChange}
|
||||
className="small-margin small"
|
||||
/>
|
||||
<label htmlFor={descriptionHandler.id}>Description secondaire</label>
|
||||
<textarea
|
||||
id={descriptionHandler.id}
|
||||
name={descriptionHandler.name}
|
||||
value={descriptionHandler.value ?? ''}
|
||||
onChange={descriptionHandler.onChange}
|
||||
rows={3}
|
||||
cols={40}
|
||||
className="small-margin small"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeDeChampDropDownSecondary.propTypes = {
|
||||
isVisible: PropTypes.bool,
|
||||
libelleHandler: PropTypes.object,
|
||||
descriptionHandler: PropTypes.object
|
||||
};
|
20
app/javascript/new_design/champs/drop-down-list.js
Normal file
20
app/javascript/new_design/champs/drop-down-list.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { delegate, show, hide } from '@utils';
|
||||
|
||||
delegate(
|
||||
'change',
|
||||
'.editable-champ-drop_down_list select, .editable-champ-drop_down_list input[type="radio"]',
|
||||
(event) => {
|
||||
const parent = event.target.closest('.editable-champ-drop_down_list');
|
||||
const inputGroup = parent?.querySelector('.drop_down_other');
|
||||
if (inputGroup) {
|
||||
const input = inputGroup.querySelector('input');
|
||||
if (event.target.value === '__other__') {
|
||||
show(inputGroup);
|
||||
input.disabled = false;
|
||||
} else {
|
||||
hide(inputGroup);
|
||||
input.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
|
@ -27,6 +27,7 @@ import '../new_design/dossiers/auto-upload';
|
|||
import '../new_design/champs/carte';
|
||||
import '../new_design/champs/linked-drop-down-list';
|
||||
import '../new_design/champs/repetition';
|
||||
import '../new_design/champs/drop-down-list';
|
||||
|
||||
import {
|
||||
toggleCondidentielExplanation,
|
||||
|
|
|
@ -1,16 +1,7 @@
|
|||
class Cron::DiscardedDossiersDeletionJob < Cron::CronJob
|
||||
self.schedule_expression = "every day at 2 am"
|
||||
|
||||
def perform(*args)
|
||||
DossierOperationLog.where(dossier: Dossier.discarded_en_construction_expired)
|
||||
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
|
||||
.destroy_all
|
||||
DossierOperationLog.where(dossier: Dossier.discarded_termine_expired)
|
||||
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
|
||||
.destroy_all
|
||||
|
||||
Dossier.discarded_brouillon_expired.destroy_all
|
||||
Dossier.discarded_en_construction_expired.destroy_all
|
||||
Dossier.discarded_termine_expired.destroy_all
|
||||
def perform
|
||||
Dossier.purge_discarded
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,6 @@ class Cron::PurgeStaleTransfersJob < Cron::CronJob
|
|||
self.schedule_expression = "every day at midnight"
|
||||
|
||||
def perform
|
||||
DossierTransfer.stale.destroy_all
|
||||
DossierTransfer.destroy_stale
|
||||
end
|
||||
end
|
||||
|
|
8
app/jobs/dossier_rebase_job.rb
Normal file
8
app/jobs/dossier_rebase_job.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
class DossierRebaseJob < ApplicationJob
|
||||
# If by the time the job runs the Dossier has been deleted, ignore the rebase
|
||||
discard_on ActiveRecord::RecordNotFound
|
||||
|
||||
def perform(dossier)
|
||||
dossier.rebase!
|
||||
end
|
||||
end
|
|
@ -49,6 +49,7 @@ class Avis < ApplicationRecord
|
|||
scope :for_dossier, -> (dossier_id) { where(dossier_id: dossier_id) }
|
||||
scope :by_latest, -> { order(updated_at: :desc) }
|
||||
scope :updated_since?, -> (date) { where('avis.updated_at > ?', date) }
|
||||
scope :discarded_termine_expired, -> { unscope(:joins).where(dossier: Dossier.discarded_termine_expired) }
|
||||
|
||||
# The form allows subtmitting avis requests to several emails at once,
|
||||
# hence this virtual attribute.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
@ -37,9 +38,12 @@ class Champ < ApplicationRecord
|
|||
:mandatory?,
|
||||
:description,
|
||||
:drop_down_list_options,
|
||||
:drop_down_other,
|
||||
:drop_down_list_options?,
|
||||
:drop_down_list_disabled_options,
|
||||
:drop_down_list_enabled_non_empty_options,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:exclude_from_export?,
|
||||
:exclude_from_view?,
|
||||
:repetition?,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
@ -20,6 +21,7 @@
|
|||
#
|
||||
class Champs::DropDownListChamp < Champ
|
||||
THRESHOLD_NB_OPTIONS_AS_RADIO = 5
|
||||
OTHER = '__other__'
|
||||
|
||||
def render_as_radios?
|
||||
enabled_non_empty_options.size <= THRESHOLD_NB_OPTIONS_AS_RADIO
|
||||
|
@ -30,7 +32,15 @@ class Champs::DropDownListChamp < Champ
|
|||
end
|
||||
|
||||
def options
|
||||
drop_down_list_options
|
||||
if drop_down_other?
|
||||
drop_down_list_options + [["Autre", OTHER]]
|
||||
else
|
||||
drop_down_list_options
|
||||
end
|
||||
end
|
||||
|
||||
def selected
|
||||
other_value_present? ? OTHER : value
|
||||
end
|
||||
|
||||
def disabled_options
|
||||
|
@ -40,4 +50,26 @@ class Champs::DropDownListChamp < Champ
|
|||
def enabled_non_empty_options
|
||||
drop_down_list_enabled_non_empty_options
|
||||
end
|
||||
|
||||
def other_value_present?
|
||||
drop_down_other? && value.present? && drop_down_list_options.exclude?(value)
|
||||
end
|
||||
|
||||
def drop_down_other?
|
||||
drop_down_other
|
||||
end
|
||||
|
||||
def value=(value)
|
||||
if value != OTHER
|
||||
write_attribute(:value, value)
|
||||
end
|
||||
end
|
||||
|
||||
def value_other=(value)
|
||||
write_attribute(:value, value)
|
||||
end
|
||||
|
||||
def value_other
|
||||
other_value_present? ? value : ""
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
# data :jsonb
|
||||
# fetch_external_data_exceptions :string is an Array
|
||||
# private :boolean default(FALSE), not null
|
||||
# rebased_at :datetime
|
||||
# row :integer
|
||||
# type :string
|
||||
# value :string
|
||||
|
|
121
app/models/concerns/dossier_rebase_concern.rb
Normal file
121
app/models/concerns/dossier_rebase_concern.rb
Normal file
|
@ -0,0 +1,121 @@
|
|||
module DossierRebaseConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def rebase!
|
||||
if brouillon? && revision != procedure.published_revision
|
||||
transaction do
|
||||
rebase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rebase
|
||||
attachments_to_purge = []
|
||||
geo_areas_to_delete = []
|
||||
changes_by_type_de_champ = revision.compare(procedure.published_revision).group_by { |change| change[:stable_id] }
|
||||
|
||||
changes_by_type_de_champ.each do |stable_id, changes|
|
||||
type_de_champ = find_type_de_champ_by_stable_id(stable_id)
|
||||
published_type_de_champ = find_type_de_champ_by_stable_id(stable_id, published: true)
|
||||
|
||||
changes.each do |change|
|
||||
case change[:op]
|
||||
when :add
|
||||
add_new_champs_for_revision(published_type_de_champ)
|
||||
when :remove
|
||||
delete_champs_for_revision(type_de_champ)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
flattened_all_champs.each do |champ|
|
||||
changes_by_stable_id = (changes_by_type_de_champ[champ.stable_id] || [])
|
||||
.filter { |change| change[:op] == :update }
|
||||
|
||||
update_champ_for_revision(champ) do |update|
|
||||
changes_by_stable_id.each do |change|
|
||||
case change[:attribute]
|
||||
when :type_champ
|
||||
update[:type] = "Champs::#{change[:to].classify}Champ"
|
||||
update[:value] = nil
|
||||
update[:external_id] = nil
|
||||
update[:data] = nil
|
||||
geo_areas_to_delete += champ.geo_areas
|
||||
if champ.piece_justificative_file.attached?
|
||||
attachments_to_purge << champ.piece_justificative_file
|
||||
end
|
||||
when :drop_down_options
|
||||
update[:value] = nil
|
||||
when :carte_layers
|
||||
geo_areas_to_delete += champ.geo_areas
|
||||
end
|
||||
update[:rebased_at] = Time.zone.now
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.update_column(:revision_id, procedure.published_revision_id)
|
||||
attachments_to_purge.each(&:purge_later)
|
||||
geo_areas_to_delete.each(&:destroy)
|
||||
end
|
||||
|
||||
def add_new_champs_for_revision(published_type_de_champ)
|
||||
if published_type_de_champ.parent
|
||||
find_champs_by_stable_id(published_type_de_champ.parent.stable_id).each do |champ_repetition|
|
||||
champ_repetition.rows.size.times do |row|
|
||||
champ = published_type_de_champ.champ.build(row: row)
|
||||
champ_repetition.champs << champ
|
||||
end
|
||||
end
|
||||
else
|
||||
champ = published_type_de_champ.build_champ
|
||||
self.champs << champ
|
||||
end
|
||||
end
|
||||
|
||||
def update_champ_for_revision(champ)
|
||||
published_type_de_champ = find_type_de_champ_by_stable_id(champ.stable_id, published: true)
|
||||
return if !published_type_de_champ
|
||||
|
||||
update = {}
|
||||
|
||||
yield update
|
||||
|
||||
if champ.type_de_champ != published_type_de_champ
|
||||
update[:type_de_champ_id] = published_type_de_champ.id
|
||||
end
|
||||
|
||||
if update.present?
|
||||
champ.update_columns(update)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_champs_for_revision(published_type_de_champ)
|
||||
Champ.where(id: find_champs_by_stable_id(published_type_de_champ.stable_id).map(&:id))
|
||||
.destroy_all
|
||||
end
|
||||
|
||||
def flattened_all_types_de_champ(published: false)
|
||||
revision = published ? procedure.published_revision : self.revision
|
||||
types_de_champ = revision.types_de_champ + revision.types_de_champ_private
|
||||
(types_de_champ + types_de_champ.filter(&:repetition?).flat_map(&:types_de_champ))
|
||||
.index_by(&:stable_id)
|
||||
end
|
||||
|
||||
def flattened_all_champs
|
||||
all_champs = (champs + champs_private)
|
||||
all_champs + all_champs.filter(&:repetition?).flat_map(&:champs)
|
||||
end
|
||||
|
||||
def find_type_de_champ_by_stable_id(stable_id, published: false)
|
||||
flattened_all_types_de_champ(published: published)[stable_id]
|
||||
end
|
||||
|
||||
def find_champs_by_stable_id(stable_id)
|
||||
flattened_all_champs.filter do |champ|
|
||||
champ.stable_id == stable_id
|
||||
end
|
||||
end
|
||||
end
|
|
@ -36,6 +36,7 @@
|
|||
class Dossier < ApplicationRecord
|
||||
self.ignored_columns = [:en_construction_conservation_extension]
|
||||
include DossierFilteringConcern
|
||||
include DossierRebaseConcern
|
||||
|
||||
include Discard::Model
|
||||
self.discard_column = :hidden_at
|
||||
|
@ -677,6 +678,7 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
update!(dossier_transfer_id: nil)
|
||||
discard!
|
||||
end
|
||||
|
||||
|
@ -958,6 +960,21 @@ class Dossier < ApplicationRecord
|
|||
user&.locale || I18n.default_locale
|
||||
end
|
||||
|
||||
def self.purge_discarded
|
||||
discarded_brouillon_expired.destroy_all
|
||||
|
||||
transaction do
|
||||
DossierOperationLog.discarded_en_construction_expired.destroy_all
|
||||
discarded_en_construction_expired.destroy_all
|
||||
end
|
||||
|
||||
transaction do
|
||||
DossierOperationLog.discarded_termine_expired.destroy_all
|
||||
Avis.discarded_termine_expired.destroy_all
|
||||
discarded_termine_expired.destroy_all
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def defaut_groupe_instructeur?
|
||||
|
|
|
@ -36,6 +36,10 @@ class DossierOperationLog < ApplicationRecord
|
|||
belongs_to :dossier, optional: true
|
||||
belongs_to :bill_signature, optional: true
|
||||
|
||||
scope :not_deletion, -> { where.not(operation: operations.fetch(:supprimer)) }
|
||||
scope :discarded_en_construction_expired, -> { where(dossier: Dossier.discarded_en_construction_expired).not_deletion }
|
||||
scope :discarded_termine_expired, -> { where(dossier: Dossier.discarded_termine_expired).not_deletion }
|
||||
|
||||
def self.create_and_serialize(params)
|
||||
dossier = params.fetch(:dossier)
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class DossierTransfer < ApplicationRecord
|
|||
}
|
||||
end)
|
||||
transfer.dossiers.update_all(user_id: current_user.id)
|
||||
transfer.destroy
|
||||
transfer.destroy_and_nullify
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -45,6 +45,22 @@ class DossierTransfer < ApplicationRecord
|
|||
User.find_by(email: email)&.locale || I18n.default_locale
|
||||
end
|
||||
|
||||
def destroy_and_nullify
|
||||
transaction do
|
||||
# Rails cascading is not working with default scopes. Doing nullify cascade manually.
|
||||
dossiers.with_discarded.update_all(dossier_transfer_id: nil)
|
||||
destroy
|
||||
end
|
||||
end
|
||||
|
||||
def self.destroy_stale
|
||||
transaction do
|
||||
# Rails cascading is not working with default scopes. Doing nullify cascade manually.
|
||||
Dossier.with_discarded.where(transfer: stale).update_all(dossier_transfer_id: nil)
|
||||
stale.destroy_all
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def send_notification
|
||||
|
|
|
@ -714,6 +714,9 @@ class Procedure < ApplicationRecord
|
|||
def publish_revision!
|
||||
update!(draft_revision: create_new_revision, published_revision: draft_revision)
|
||||
published_revision.touch(:published_at)
|
||||
dossiers.state_brouillon.find_each do |dossier|
|
||||
DossierRebaseJob.perform_later(dossier)
|
||||
end
|
||||
end
|
||||
|
||||
def cnaf_enabled?
|
||||
|
|
|
@ -134,11 +134,11 @@ class ProcedureRevision < ApplicationRecord
|
|||
to_sids = to_h.keys
|
||||
|
||||
removed = (from_sids - to_sids).map do |sid|
|
||||
{ op: :remove, label: from_h[sid].libelle, private: from_h[sid].private?, position: from_sids.index(sid) }
|
||||
{ op: :remove, label: from_h[sid].libelle, private: from_h[sid].private?, position: from_sids.index(sid), stable_id: sid }
|
||||
end
|
||||
|
||||
added = (to_sids - from_sids).map do |sid|
|
||||
{ op: :add, label: to_h[sid].libelle, private: to_h[sid].private?, position: to_sids.index(sid) }
|
||||
{ op: :add, label: to_h[sid].libelle, private: to_h[sid].private?, position: to_sids.index(sid), stable_id: sid }
|
||||
end
|
||||
|
||||
kept = from_sids.intersection(to_sids)
|
||||
|
@ -147,7 +147,7 @@ class ProcedureRevision < ApplicationRecord
|
|||
.map { |sid| [sid, from_sids.index(sid), to_sids.index(sid)] }
|
||||
.filter { |_, from_index, to_index| from_index != to_index }
|
||||
.map do |sid, from_index, to_index|
|
||||
{ op: :move, label: from_h[sid].libelle, private: from_h[sid].private?, from: from_index, to: to_index, position: to_index }
|
||||
{ op: :move, label: from_h[sid].libelle, private: from_h[sid].private?, from: from_index, to: to_index, position: to_index, stable_id: sid }
|
||||
end
|
||||
|
||||
changed = kept
|
||||
|
@ -172,7 +172,8 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.type_champ,
|
||||
to: to_type_de_champ.type_champ
|
||||
to: to_type_de_champ.type_champ,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if from_type_de_champ.libelle != to_type_de_champ.libelle
|
||||
|
@ -182,7 +183,8 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.libelle,
|
||||
to: to_type_de_champ.libelle
|
||||
to: to_type_de_champ.libelle,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if from_type_de_champ.description != to_type_de_champ.description
|
||||
|
@ -192,7 +194,8 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.description,
|
||||
to: to_type_de_champ.description
|
||||
to: to_type_de_champ.description,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if from_type_de_champ.mandatory? != to_type_de_champ.mandatory?
|
||||
|
@ -202,7 +205,8 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.mandatory?,
|
||||
to: to_type_de_champ.mandatory?
|
||||
to: to_type_de_champ.mandatory?,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if to_type_de_champ.drop_down_list?
|
||||
|
@ -213,7 +217,41 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.drop_down_list_options,
|
||||
to: to_type_de_champ.drop_down_list_options
|
||||
to: to_type_de_champ.drop_down_list_options,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
if to_type_de_champ.linked_drop_down_list?
|
||||
if from_type_de_champ.drop_down_secondary_libelle != to_type_de_champ.drop_down_secondary_libelle
|
||||
changes << {
|
||||
op: :update,
|
||||
attribute: :drop_down_secondary_libelle,
|
||||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.drop_down_secondary_libelle,
|
||||
to: to_type_de_champ.drop_down_secondary_libelle
|
||||
}
|
||||
end
|
||||
if from_type_de_champ.drop_down_secondary_description != to_type_de_champ.drop_down_secondary_description
|
||||
changes << {
|
||||
op: :update,
|
||||
attribute: :drop_down_secondary_description,
|
||||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.drop_down_secondary_description,
|
||||
to: to_type_de_champ.drop_down_secondary_description
|
||||
}
|
||||
end
|
||||
end
|
||||
if from_type_de_champ.drop_down_other != to_type_de_champ.drop_down_other
|
||||
changes << {
|
||||
op: :update,
|
||||
attribute: :drop_down_other,
|
||||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.drop_down_other,
|
||||
to: to_type_de_champ.drop_down_other,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
elsif to_type_de_champ.carte?
|
||||
|
@ -224,7 +262,8 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.carte_optional_layers,
|
||||
to: to_type_de_champ.carte_optional_layers
|
||||
to: to_type_de_champ.carte_optional_layers,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
elsif to_type_de_champ.piece_justificative?
|
||||
|
@ -235,7 +274,8 @@ class ProcedureRevision < ApplicationRecord
|
|||
label: from_type_de_champ.libelle,
|
||||
private: from_type_de_champ.private?,
|
||||
from: from_type_de_champ.piece_justificative_template_filename,
|
||||
to: to_type_de_champ.piece_justificative_template_filename
|
||||
to: to_type_de_champ.piece_justificative_template_filename,
|
||||
stable_id: from_type_de_champ.stable_id
|
||||
}
|
||||
end
|
||||
elsif to_type_de_champ.repetition?
|
||||
|
|
|
@ -58,7 +58,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
belongs_to :parent, class_name: 'TypeDeChamp', optional: true
|
||||
has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy
|
||||
|
||||
store_accessor :options, :cadastres, :old_pj, :drop_down_options, :skip_pj_validation, :skip_content_type_pj_validation
|
||||
store_accessor :options, :cadastres, :old_pj, :drop_down_options, :skip_pj_validation, :skip_content_type_pj_validation, :drop_down_secondary_libelle, :drop_down_secondary_description, :drop_down_other
|
||||
has_many :revision_types_de_champ, class_name: 'ProcedureRevisionTypeDeChamp', dependent: :destroy, inverse_of: :type_de_champ
|
||||
has_many :revisions, through: :revision_types_de_champ
|
||||
|
||||
|
@ -331,9 +331,12 @@ class TypeDeChamp < ApplicationRecord
|
|||
],
|
||||
methods: [
|
||||
:drop_down_list_value,
|
||||
:drop_down_other,
|
||||
:piece_justificative_template_filename,
|
||||
:piece_justificative_template_url,
|
||||
:editable_options
|
||||
:editable_options,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description
|
||||
]
|
||||
}
|
||||
TYPES_DE_CHAMP = TYPES_DE_CHAMP_BASE
|
||||
|
|
|
@ -182,17 +182,16 @@ class User < ApplicationRecord
|
|||
raise "Cannot delete this user because they are also instructeur, expert or administrateur"
|
||||
end
|
||||
|
||||
Invite.where(dossier: dossiers.with_discarded).destroy_all
|
||||
dossiers.state_en_construction.each do |dossier|
|
||||
dossier.discard_and_keep_track!(administration, :user_removed)
|
||||
transaction do
|
||||
Invite.where(dossier: dossiers.with_discarded).destroy_all
|
||||
dossiers.state_en_construction.each do |dossier|
|
||||
dossier.discard_and_keep_track!(administration, :user_removed)
|
||||
end
|
||||
DossierOperationLog.where(dossier: dossiers.with_discarded.discarded).not_deletion.destroy_all
|
||||
dossiers.with_discarded.discarded.destroy_all
|
||||
dossiers.update_all(deleted_user_email_never_send: email, user_id: nil, dossier_transfer_id: nil)
|
||||
destroy!
|
||||
end
|
||||
DossierOperationLog
|
||||
.where(dossier: dossiers.with_discarded.discarded)
|
||||
.where.not(operation: DossierOperationLog.operations.fetch(:supprimer))
|
||||
.destroy_all
|
||||
dossiers.with_discarded.discarded.destroy_all
|
||||
dossiers.update_all(deleted_user_email_never_send: email, user_id: nil)
|
||||
destroy!
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -1,4 +1,32 @@
|
|||
class ZxcvbnService
|
||||
@tester_mutex = Mutex.new
|
||||
|
||||
class << self
|
||||
# Returns an Zxcvbn instance cached between classes instances and between threads.
|
||||
#
|
||||
# The tester weights ~20 Mo, and we'd like to save some memory – so rather
|
||||
# that storing it in a per-thread accessor, we prefer to use a mutex
|
||||
# to cache it between threads.
|
||||
def tester
|
||||
@tester_mutex.synchronize do
|
||||
@tester ||= build_tester
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns a fully initializer tester from the on-disk dictionary.
|
||||
#
|
||||
# This is slow: loading and parsing the dictionary may take around 1s.
|
||||
def build_tester
|
||||
dictionaries = YAML.safe_load(File.read(Rails.root.join("config", "initializers", "zxcvbn_dictionnaries.yaml")))
|
||||
|
||||
tester = Zxcvbn::Tester.new
|
||||
tester.add_word_lists(dictionaries)
|
||||
tester
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(password)
|
||||
@password = password
|
||||
end
|
||||
|
@ -18,6 +46,6 @@ class ZxcvbnService
|
|||
private
|
||||
|
||||
def compute_zxcvbn
|
||||
Zxcvbn.test(@password, [], ZXCVBN_DICTIONNARIES)
|
||||
self.class.tester.test(@password)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
%li.mb-1= t("update_type_champ#{postfix}", label: change[:label], to: t("activerecord.attributes.type_de_champ.type_champs.#{change[:to]}"), scope: [:new_administrateur, :revision_changes])
|
||||
- when :description
|
||||
%li.mb-1= t("update_description#{postfix}", label: change[:label], to: change[:to], scope: [:new_administrateur, :revision_changes])
|
||||
- when :drop_down_secondary_libelle
|
||||
%li.mb-1= t("update_drop_down_secondary_libelle#{postfix}", label: change[:label], to: change[:to], scope: [:new_administrateur, :revision_changes])
|
||||
- when :drop_down_secondary_description
|
||||
%li.mb-1= t("update_drop_down_secondary_description#{postfix}", label: change[:label], to: change[:to], scope: [:new_administrateur, :revision_changes])
|
||||
- when :mandatory
|
||||
- if change[:from] == false
|
||||
-# i18n-tasks-use t('new_administrateur.revision_changes.update_mandatory.enabled')
|
||||
|
@ -37,6 +41,11 @@
|
|||
%li= t(:add_option, scope: [:new_administrateur, :revision_changes], items: added.map{ |term| "« #{term.strip} »" }.join(", "))
|
||||
- if removed.present?
|
||||
%li= t(:remove_option, scope: [:new_administrateur, :revision_changes], items: removed.map{ |term| "« #{term.strip} »" }.join(", "))
|
||||
- when :drop_down_other
|
||||
- if change[:from] == false
|
||||
%li.mb-1= t("new_administrateur.revision_changes.update_drop_down_other#{postfix}.enabled", label: change[:label])
|
||||
- else
|
||||
%li.mb-1= t("new_administrateur.revision_changes.update_drop_down_other#{postfix}.disabled", label: change[:label])
|
||||
- when :carte_layers
|
||||
- added = change[:to].sort - change[:from].sort
|
||||
- removed = change[:from].sort - change[:to].sort
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.drop_down_other{ class: champ.other_value_present? ? '' : 'hidden' }
|
||||
.notice
|
||||
%p Veuillez saisir votre autre choix
|
||||
= form.text_field :value_other, maxlength: "200", placeholder: "Saisissez ici", disabled: !champ.other_value_present?
|
|
@ -5,3 +5,7 @@
|
|||
- if champ.updated_at.present? && seen_at.present?
|
||||
%span.updated-at{ class: highlight_if_unseen_class(seen_at, champ.updated_at) }
|
||||
= "modifié le #{try_format_datetime(champ.updated_at)}"
|
||||
|
||||
- if champ.rebased_at.present? && champ.rebased_at > (seen_at || champ.updated_at) && current_user.owns_or_invite?(champ.dossier)
|
||||
%span.updated-at.highlighted
|
||||
Le type de ce champ où sa description a été modifiée par l'administration. Vérifier son contenu.
|
||||
|
|
|
@ -5,13 +5,18 @@
|
|||
%label
|
||||
= form.radio_button :value, option
|
||||
= option
|
||||
|
||||
- if !champ.mandatory?
|
||||
%label.blank-radio
|
||||
= form.radio_button :value, ''
|
||||
Non renseigné
|
||||
|
||||
- if champ.drop_down_other?
|
||||
%label
|
||||
= form.radio_button :value, Champs::DropDownListChamp::OTHER, checked: champ.other_value_present?
|
||||
Autre
|
||||
- else
|
||||
= form.select :value,
|
||||
champ.options,
|
||||
disabled: champ.disabled_options,
|
||||
required: champ.mandatory?
|
||||
= form.select :value, champ.options, selected: champ.selected, required: champ.mandatory?
|
||||
|
||||
- if champ.drop_down_other?
|
||||
= render partial: "shared/dossiers/drop_down_other_input", locals: { form: form, champ: champ }
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
{ required: champ.mandatory? },
|
||||
{ data: { secondary_options: champ.secondary_options } }
|
||||
%span
|
||||
= form.label :secondary_value, class: 'hidden' do
|
||||
Valeur secondaire dépendant de la première
|
||||
= form.label :secondary_value do
|
||||
= champ.drop_down_secondary_libelle.presence || "Valeur secondaire dépendant de la première"
|
||||
- if champ.mandatory?
|
||||
%span.mandatory *
|
||||
- if champ.drop_down_secondary_description.present?
|
||||
.notice= string_to_html(champ.drop_down_secondary_description)
|
||||
= form.select :secondary_value,
|
||||
champ.secondary_options[champ.primary_value],
|
||||
{ required: champ.mandatory? },
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ZXCVBN_DICTIONNARIES = YAML.safe_load(File.read(Rails.root.join("config", "initializers", "zxcvbn_dictionnaries.yaml")))
|
|
@ -9,12 +9,17 @@ fr:
|
|||
other: Les positions de %{count} champs ont été modifiées
|
||||
update_libelle: Le libellé du champ « %{label} » a été modifié. Le nouveau libellé est « %{to} »
|
||||
update_description: La description du champ « %{label} » a été modifiée. La nouvelle description est « %{to} »
|
||||
update_drop_down_secondary_libelle: Le libellé secondaire du champ « %{label} » a été modifié. Le nouveau libellé est « %{to} »
|
||||
update_drop_down_secondary_description: La description secondaire du champ « %{label} » a été modifiée. La nouvelle description est « %{to} »
|
||||
update_type_champ: Le type du champ « %{label} » a été modifié. Il est maintenant de type « %{to} »
|
||||
update_mandatory:
|
||||
enabled: Le champ « %{label} » est maintenant obligatoire
|
||||
disabled: Le champ « %{label} » n’est plus obligatoire
|
||||
update_piece_justificative_template: Le modèle de pièce justificative du champ « %{label} » a été modifié
|
||||
update_drop_down_options: Les options de sélection du champ « %{label} » ont été modifiées
|
||||
update_drop_down_other:
|
||||
enabled: Le champ « %{label} » comporte maintenant un choix « Autre »
|
||||
disabled: Le champ « %{label} » ne comporte plus de choix « Autre »
|
||||
update_carte_layers: Les référentiels cartographiques du champ « %{label} » ont été modifiés
|
||||
add_private: L’annotation privée « %{label} » a été ajoutée
|
||||
remove_private: L’annotation privée « %{label} » a été supprimée
|
||||
|
@ -23,6 +28,8 @@ fr:
|
|||
other: Les positions de %{count} annotations privées ont été modifiées
|
||||
update_libelle_private: Le libellé de l’annotation privée « %{label} » a été modifié. Le nouveau libellé est « %{to} »
|
||||
update_description_private: La description de l’annotation privée « %{label} » a été modifiée. La nouvelle description est « %{to} »
|
||||
update_drop_down_secondary_libelle_private: Le libellé secondaire de l’annotation « %{label} » a été modifié. Le nouveau libellé est « %{to} »
|
||||
update_drop_down_secondary_description_private: La description secondaire de l’annotation « %{label} » a été modifiée. La nouvelle description est « %{to} »
|
||||
update_type_champ_private: Le type de l’annotation privée « %{label} » a été modifié. Elle est maintenant de type « %{to} »
|
||||
update_mandatory_private:
|
||||
enabled: L’annotation privée « %{label} » est maintenant obligatoire
|
||||
|
|
|
@ -36,30 +36,9 @@ if ENV.fetch("RAILS_ENV") == "production"
|
|||
# Use the `preload_app!` method when specifying a `workers` number.
|
||||
# This directive tells Puma to first boot the application and load code
|
||||
# before forking the application. This takes advantage of Copy On Write
|
||||
# process behavior so workers use less memory. If you use this option
|
||||
# you need to make sure to reconnect any threads in the `on_worker_boot`
|
||||
# block.
|
||||
# process behavior so workers use less memory.
|
||||
#
|
||||
preload_app!
|
||||
|
||||
# If you are preloading your application and using Active Record, it's
|
||||
# recommended that you close any connections to the database before workers
|
||||
# are forked to prevent connection leakage.
|
||||
#
|
||||
before_fork do
|
||||
ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
|
||||
end
|
||||
|
||||
# The code in the `on_worker_boot` will be called if you are using
|
||||
# clustered mode by specifying a number of `workers`. After each worker
|
||||
# process is booted, this block will be run. If you are using the `preload_app!`
|
||||
# option, you will want to use this block to reconnect to any threads
|
||||
# or connections that may have been created at application boot, as Ruby
|
||||
# cannot share connections between processes.
|
||||
#
|
||||
on_worker_boot do
|
||||
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
|
||||
end
|
||||
end
|
||||
|
||||
# Allow puma to be restarted by `rails restart` command.
|
||||
|
|
5
db/migrate/20211013131241_add_rebased_at_to_champs.rb
Normal file
5
db/migrate/20211013131241_add_rebased_at_to_champs.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddRebasedAtToChamps < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :champs, :rebased_at, :datetime
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_10_20_104237) do
|
||||
ActiveRecord::Schema.define(version: 2021_10_20_114237) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -190,6 +190,7 @@ ActiveRecord::Schema.define(version: 2021_10_20_104237) do
|
|||
t.string "external_id"
|
||||
t.string "fetch_external_data_exceptions", array: true
|
||||
t.jsonb "value_json"
|
||||
t.datetime "rebased_at"
|
||||
t.index ["dossier_id"], name: "index_champs_on_dossier_id"
|
||||
t.index ["etablissement_id"], name: "index_champs_on_etablissement_id"
|
||||
t.index ["parent_id"], name: "index_champs_on_parent_id"
|
||||
|
|
|
@ -61,7 +61,7 @@ describe Manager::UsersController, type: :controller do
|
|||
context 'and the old account belongs to an instructeur, expert and administrateur' do
|
||||
let!(:instructeur) { create(:instructeur, user: user) }
|
||||
let!(:expert) { create(:expert, user: user) }
|
||||
let!(:administrateur) { create(:administrateur, user: user) }
|
||||
let!(:administrateur) { create(:administrateur, user: user, instructeur: instructeur) }
|
||||
|
||||
it 'transfers instructeur account' do
|
||||
subject
|
||||
|
|
|
@ -40,7 +40,7 @@ describe WebhookController, type: :controller do
|
|||
|
||||
context 'when there are an associated Instructeur and Administrateur' do
|
||||
let!(:instructeur) { create(:instructeur, user: user) }
|
||||
let!(:admin) { create(:administrateur, user: user) }
|
||||
let!(:admin) { create(:administrateur, user: user, instructeur: instructeur) }
|
||||
|
||||
it 'returns a link to the Instructeur profile in the Manager' do
|
||||
expect(payload).to have_key('html')
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
FactoryBot.define do
|
||||
sequence(:administrateur_email) { |n| "admin#{n}@admin.com" }
|
||||
factory :administrateur do
|
||||
user { association :user, email: email, password: password }
|
||||
|
||||
transient do
|
||||
email { generate(:administrateur_email) }
|
||||
password { 'Mon [hien 4im3 {es banane$' }
|
||||
instructeur { build(:instructeur, user: user) }
|
||||
end
|
||||
|
||||
initialize_with do
|
||||
User.create_or_promote_to_administrateur(email, password).administrateur
|
||||
after(:build) do |administrateur, evaluator|
|
||||
if administrateur.user
|
||||
administrateur.user.instructeur = evaluator.instructeur
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,13 +2,11 @@ FactoryBot.define do
|
|||
sequence(:create_expert_email) { |n| "expert#{n}@expert.com" }
|
||||
|
||||
factory :expert do
|
||||
user { association :user, email: email, password: password }
|
||||
|
||||
transient do
|
||||
email { generate(:expert_email) }
|
||||
password { 'somethingverycomplated!' }
|
||||
end
|
||||
|
||||
initialize_with do
|
||||
User.create_or_promote_to_expert(email, password).expert
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,13 +2,11 @@ FactoryBot.define do
|
|||
sequence(:instructeur_email) { |n| "inst#{n}@inst.com" }
|
||||
|
||||
factory :instructeur do
|
||||
user { association :user, email: email, password: password }
|
||||
|
||||
transient do
|
||||
email { generate(:instructeur_email) }
|
||||
password { 'somethingverycomplated!' }
|
||||
end
|
||||
|
||||
initialize_with do
|
||||
User.create_or_promote_to_instructeur(email, password).instructeur
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,7 +24,7 @@ FactoryBot.define do
|
|||
if evaluator.administrateur
|
||||
procedure.administrateurs = [evaluator.administrateur]
|
||||
elsif procedure.administrateurs.empty?
|
||||
procedure.administrateurs = [create(:administrateur)]
|
||||
procedure.administrateurs = [build(:administrateur)]
|
||||
end
|
||||
procedure.draft_revision = build(:procedure_revision, procedure: procedure)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
describe Administrateur, type: :model do
|
||||
let(:administration) { create(:administration) }
|
||||
|
||||
describe 'assocations' do
|
||||
describe 'associations' do
|
||||
it { is_expected.to have_and_belong_to_many(:instructeurs) }
|
||||
it { is_expected.to have_many(:procedures) }
|
||||
end
|
||||
|
|
|
@ -1,38 +1,44 @@
|
|||
describe Champs::PhoneChamp do
|
||||
let(:phone_champ) { build(:champ_phone) }
|
||||
|
||||
describe '#valid?' do
|
||||
it do
|
||||
expect(build(:champ_phone, value: nil)).to be_valid
|
||||
expect(build(:champ_phone, value: "0123456789 0123456789")).to_not be_valid
|
||||
expect(build(:champ_phone, value: "01.23.45.67.89 01.23.45.67.89")).to_not be_valid
|
||||
expect(build(:champ_phone, value: "3646")).to be_valid
|
||||
expect(build(:champ_phone, value: "0123456789")).to be_valid
|
||||
expect(build(:champ_phone, value: "01.23.45.67.89")).to be_valid
|
||||
expect(build(:champ_phone, value: "0123 45.67.89")).to be_valid
|
||||
expect(build(:champ_phone, value: "0033 123-456-789")).to be_valid
|
||||
expect(build(:champ_phone, value: "0033 123-456-789")).to be_valid
|
||||
expect(build(:champ_phone, value: "0033(0)123456789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+33-1.23.45.67.89")).to be_valid
|
||||
expect(build(:champ_phone, value: "+33 - 123 456 789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+33(0) 123 456 789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+33 (0)123 45 67 89")).to be_valid
|
||||
expect(build(:champ_phone, value: "+33 (0)1 2345-6789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+33(0) - 123456789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+1(0) - 123456789")).to be_valid
|
||||
expect(build(:champ_phone, value: "+49 2109 87654321")).to be_valid
|
||||
expect(build(:champ_phone, value: "012345678")).to be_valid
|
||||
expect(champ_with_value(nil)).to be_valid
|
||||
expect(champ_with_value("0123456789 0123456789")).to_not be_valid
|
||||
expect(champ_with_value("01.23.45.67.89 01.23.45.67.89")).to_not be_valid
|
||||
expect(champ_with_value("3646")).to be_valid
|
||||
expect(champ_with_value("0123456789")).to be_valid
|
||||
expect(champ_with_value("01.23.45.67.89")).to be_valid
|
||||
expect(champ_with_value("0123 45.67.89")).to be_valid
|
||||
expect(champ_with_value("0033 123-456-789")).to be_valid
|
||||
expect(champ_with_value("0033 123-456-789")).to be_valid
|
||||
expect(champ_with_value("0033(0)123456789")).to be_valid
|
||||
expect(champ_with_value("+33-1.23.45.67.89")).to be_valid
|
||||
expect(champ_with_value("+33 - 123 456 789")).to be_valid
|
||||
expect(champ_with_value("+33(0) 123 456 789")).to be_valid
|
||||
expect(champ_with_value("+33 (0)123 45 67 89")).to be_valid
|
||||
expect(champ_with_value("+33 (0)1 2345-6789")).to be_valid
|
||||
expect(champ_with_value("+33(0) - 123456789")).to be_valid
|
||||
expect(champ_with_value("+1(0) - 123456789")).to be_valid
|
||||
expect(champ_with_value("+49 2109 87654321")).to be_valid
|
||||
expect(champ_with_value("012345678")).to be_valid
|
||||
# polynesian numbers should not return errors in any way
|
||||
## landline numbers start with 40 or 45
|
||||
expect(build(:champ_phone, value: "45187272")).to be_valid
|
||||
expect(build(:champ_phone, value: "40 473 500")).to be_valid
|
||||
expect(build(:champ_phone, value: "40473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "45473500")).to be_valid
|
||||
expect(champ_with_value("45187272")).to be_valid
|
||||
expect(champ_with_value("40 473 500")).to be_valid
|
||||
expect(champ_with_value("40473500")).to be_valid
|
||||
expect(champ_with_value("45473500")).to be_valid
|
||||
## +689 is the international indicator
|
||||
expect(build(:champ_phone, value: "+689 45473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "0145473500")).to be_valid
|
||||
expect(champ_with_value("+689 45473500")).to be_valid
|
||||
expect(champ_with_value("0145473500")).to be_valid
|
||||
## polynesian mobile numbers start with 87, 88, 89
|
||||
expect(build(:champ_phone, value: "87473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "88473500")).to be_valid
|
||||
expect(build(:champ_phone, value: "89473500")).to be_valid
|
||||
expect(champ_with_value("87473500")).to be_valid
|
||||
expect(champ_with_value("88473500")).to be_valid
|
||||
expect(champ_with_value("89473500")).to be_valid
|
||||
end
|
||||
|
||||
def champ_with_value(number)
|
||||
phone_champ.tap { |c| c.value = number }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,8 +47,8 @@ describe Commentaire do
|
|||
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||
|
||||
context 'with a commentaire created by a instructeur' do
|
||||
let(:instructeur) { create :instructeur, email: 'some_user@exemple.fr' }
|
||||
let(:commentaire) { build :commentaire, instructeur: instructeur, dossier: dossier }
|
||||
let(:instructeur) { build :instructeur, email: 'some_user@exemple.fr' }
|
||||
|
||||
context 'when the procedure shows instructeurs email' do
|
||||
before { Flipper.disable(:hide_instructeur_email, procedure) }
|
||||
|
|
|
@ -1459,4 +1459,71 @@ describe Dossier do
|
|||
|
||||
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["État du dossier", "Brouillon"]) }
|
||||
end
|
||||
|
||||
describe "#rebase" do
|
||||
let(:procedure) { create(:procedure, :with_type_de_champ_mandatory, :with_yes_no, :with_repetition, :with_datetime) }
|
||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||
|
||||
let(:yes_no_type_de_champ) { procedure.types_de_champ.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:yes_no) } }
|
||||
|
||||
let(:text_type_de_champ) { procedure.types_de_champ.find(&:mandatory?) }
|
||||
let(:text_champ) { dossier.champs.find(&:mandatory?) }
|
||||
let(:rebased_text_champ) { dossier.champs.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:text) } }
|
||||
|
||||
let(:datetime_type_de_champ) { procedure.types_de_champ.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:datetime) } }
|
||||
let(:datetime_champ) { dossier.champs.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:datetime) } }
|
||||
let(:rebased_datetime_champ) { dossier.champs.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:date) } }
|
||||
|
||||
let(:repetition_type_de_champ) { procedure.types_de_champ.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:repetition) } }
|
||||
let(:repetition_text_type_de_champ) { repetition_type_de_champ.types_de_champ.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:text) } }
|
||||
let(:repetition_champ) { dossier.champs.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:repetition) } }
|
||||
let(:rebased_repetition_champ) { dossier.champs.find { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:repetition) } }
|
||||
|
||||
before do
|
||||
procedure.publish!
|
||||
procedure.draft_revision.add_type_de_champ({
|
||||
type_champ: TypeDeChamp.type_champs.fetch(:text),
|
||||
libelle: "Un champ text"
|
||||
})
|
||||
procedure.draft_revision.find_or_clone_type_de_champ(text_type_de_champ).update(mandatory: false, libelle: "nouveau libelle")
|
||||
procedure.draft_revision.find_or_clone_type_de_champ(datetime_type_de_champ).update(type_champ: TypeDeChamp.type_champs.fetch(:date))
|
||||
procedure.draft_revision.find_or_clone_type_de_champ(repetition_text_type_de_champ).update(libelle: "nouveau libelle dans une repetition")
|
||||
procedure.draft_revision.add_type_de_champ({
|
||||
type_champ: TypeDeChamp.type_champs.fetch(:checkbox),
|
||||
libelle: "oui ou non",
|
||||
parent_id: repetition_type_de_champ.stable_id
|
||||
})
|
||||
procedure.draft_revision.remove_type_de_champ(yes_no_type_de_champ.stable_id)
|
||||
|
||||
datetime_champ.update(value: Date.today.to_s)
|
||||
text_champ.update(value: 'bonjour')
|
||||
end
|
||||
|
||||
it "updates the brouillon champs with the latest revision changes" do
|
||||
revision_id = dossier.revision_id
|
||||
libelle = text_type_de_champ.libelle
|
||||
|
||||
expect(dossier.revision).to eq(procedure.published_revision)
|
||||
expect(dossier.champs.size).to eq(4)
|
||||
expect(repetition_champ.rows.size).to eq(1)
|
||||
expect(repetition_champ.rows[0].size).to eq(1)
|
||||
|
||||
procedure.publish_revision!
|
||||
perform_enqueued_jobs
|
||||
procedure.reload
|
||||
dossier.reload
|
||||
|
||||
expect(procedure.revisions.size).to eq(3)
|
||||
expect(dossier.revision).to eq(procedure.published_revision)
|
||||
expect(dossier.champs.size).to eq(4)
|
||||
expect(rebased_text_champ.value).to eq(text_champ.value)
|
||||
expect(rebased_text_champ.type_de_champ_id).not_to eq(text_champ.type_de_champ_id)
|
||||
expect(rebased_datetime_champ.type_champ).to eq(TypeDeChamp.type_champs.fetch(:date))
|
||||
expect(rebased_datetime_champ.value).to be_nil
|
||||
expect(rebased_repetition_champ.rows.size).to eq(1)
|
||||
expect(rebased_repetition_champ.rows[0].size).to eq(2)
|
||||
expect(rebased_text_champ.rebased_at).not_to be_nil
|
||||
expect(rebased_datetime_champ.rebased_at).not_to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,16 +46,36 @@ RSpec.describe DossierTransfer, type: :model do
|
|||
it { expect(DossierTransfer.with_dossiers.count).to eq(0) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'dossier relationship' do
|
||||
let(:transfer) { create(:dossier_transfer) }
|
||||
let(:dossier) { create(:dossier, user: user, transfer: transfer) }
|
||||
describe '#destroy_and_nullify' do
|
||||
let(:transfer) { create(:dossier_transfer) }
|
||||
let(:dossier) { create(:dossier, user: user, transfer: transfer) }
|
||||
let(:discarded_dossier) { create(:dossier, user: user, transfer: dossier.transfer) }
|
||||
|
||||
it 'nullify transfer relationship on dossier' do
|
||||
expect(dossier.transfer).to eq(transfer)
|
||||
transfer.destroy
|
||||
expect(dossier.reload.transfer).to be_nil
|
||||
end
|
||||
before do
|
||||
discarded_dossier.discard!
|
||||
end
|
||||
|
||||
it 'nullify transfer relationship on dossier' do
|
||||
expect(dossier.transfer).to eq(transfer)
|
||||
transfer.destroy_and_nullify
|
||||
expect(dossier.reload.transfer).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy_stale' do
|
||||
let(:transfer) { create(:dossier_transfer, created_at: 1.month.ago) }
|
||||
let(:dossier) { create(:dossier, user: user, transfer: transfer) }
|
||||
let(:discarded_dossier) { create(:dossier, user: user, transfer: dossier.transfer) }
|
||||
|
||||
before do
|
||||
discarded_dossier.discard!
|
||||
end
|
||||
|
||||
it 'nullify the transfer on discarded dossier' do
|
||||
DossierTransfer.destroy_stale
|
||||
expect(DossierTransfer.count).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
RSpec.describe GeoArea, type: :model do
|
||||
describe '#area' do
|
||||
let(:geo_area) { build(:geo_area, :polygon) }
|
||||
let(:geo_area) { build(:geo_area, :polygon, champ: nil) }
|
||||
|
||||
it { expect(geo_area.area).to eq(103.6) }
|
||||
end
|
||||
|
||||
describe '#area (hourglass polygon)' do
|
||||
let(:geo_area) { build(:geo_area, :hourglass_polygon) }
|
||||
let(:geo_area) { build(:geo_area, :hourglass_polygon, champ: nil) }
|
||||
|
||||
it { expect(geo_area.area).to eq(32.4) }
|
||||
end
|
||||
|
||||
describe '#length' do
|
||||
let(:geo_area) { build(:geo_area, :line_string) }
|
||||
let(:geo_area) { build(:geo_area, :line_string, champ: nil) }
|
||||
|
||||
it { expect(geo_area.length).to eq(21.2) }
|
||||
end
|
||||
|
||||
describe '#location' do
|
||||
let(:geo_area) { build(:geo_area, :point) }
|
||||
let(:geo_area) { build(:geo_area, :point, champ: nil) }
|
||||
|
||||
it { expect(geo_area.location).to eq("46°32'19\"N 2°25'42\"E") }
|
||||
end
|
||||
|
||||
describe '#rgeo_geometry' do
|
||||
let(:geo_area) { build(:geo_area, :polygon) }
|
||||
let(:geo_area) { build(:geo_area, :polygon, champ: nil) }
|
||||
let(:polygon) do
|
||||
{
|
||||
"type" => "Polygon",
|
||||
|
@ -46,44 +46,47 @@ RSpec.describe GeoArea, type: :model do
|
|||
it { expect(geo_area.geometry).to eq(polygon) }
|
||||
|
||||
context 'polygon_with_extra_coordinate' do
|
||||
let(:geo_area) { build(:geo_area, :polygon_with_extra_coordinate) }
|
||||
let(:geo_area) { build(:geo_area, :polygon_with_extra_coordinate, champ: nil) }
|
||||
|
||||
it { expect(geo_area.geometry).not_to eq(polygon) }
|
||||
it { expect(geo_area.safe_geometry).to eq(polygon) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#valid?' do
|
||||
let(:geo_area) { build(:geo_area, :polygon) }
|
||||
describe 'validations' do
|
||||
context 'geometry' do
|
||||
subject! { geo_area.validate }
|
||||
|
||||
context 'polygon' do
|
||||
it { expect(geo_area.valid?).to be_truthy }
|
||||
end
|
||||
context 'polygon' do
|
||||
let(:geo_area) { build(:geo_area, :polygon, champ: nil) }
|
||||
it { expect(geo_area.errors).not_to have_key(:geometry) }
|
||||
end
|
||||
|
||||
context 'hourglass_polygon' do
|
||||
let(:geo_area) { build(:geo_area, :hourglass_polygon) }
|
||||
it { expect(geo_area.valid?).to be_falsey }
|
||||
end
|
||||
context 'hourglass_polygon' do
|
||||
let(:geo_area) { build(:geo_area, :hourglass_polygon, champ: nil) }
|
||||
it { expect(geo_area.errors).to have_key(:geometry) }
|
||||
end
|
||||
|
||||
context 'line_string' do
|
||||
let(:geo_area) { build(:geo_area, :line_string) }
|
||||
it { expect(geo_area.valid?).to be_truthy }
|
||||
end
|
||||
context 'line_string' do
|
||||
let(:geo_area) { build(:geo_area, :line_string, champ: nil) }
|
||||
it { expect(geo_area.errors).not_to have_key(:geometry) }
|
||||
end
|
||||
|
||||
context 'point' do
|
||||
let(:geo_area) { build(:geo_area, :point) }
|
||||
it { expect(geo_area.valid?).to be_truthy }
|
||||
end
|
||||
context 'point' do
|
||||
let(:geo_area) { build(:geo_area, :point, champ: nil) }
|
||||
it { expect(geo_area.errors).not_to have_key(:geometry) }
|
||||
end
|
||||
|
||||
context 'invalid_right_hand_rule_polygon' do
|
||||
let(:geo_area) { build(:geo_area, :invalid_right_hand_rule_polygon) }
|
||||
it { expect(geo_area.valid?).to be_falsey }
|
||||
context 'invalid_right_hand_rule_polygon' do
|
||||
let(:geo_area) { build(:geo_area, :invalid_right_hand_rule_polygon, champ: nil) }
|
||||
it { expect(geo_area.errors).to have_key(:geometry) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "cadastre properties" do
|
||||
let(:geo_area) { build(:geo_area, :cadastre) }
|
||||
let(:legacy_geo_area) { build(:geo_area, :legacy_cadastre) }
|
||||
let(:geo_area) { build(:geo_area, :cadastre, champ: nil) }
|
||||
let(:legacy_geo_area) { build(:geo_area, :legacy_cadastre, champ: nil) }
|
||||
|
||||
it "should be backward compatible" do
|
||||
expect("#{geo_area.code_dep}#{geo_area.code_com}").to eq(geo_area.commune)
|
||||
|
@ -103,7 +106,7 @@ RSpec.describe GeoArea, type: :model do
|
|||
|
||||
describe 'description' do
|
||||
context 'when properties is nil' do
|
||||
let(:geo_area) { build(:geo_area, properties: nil) }
|
||||
let(:geo_area) { build(:geo_area, properties: nil, champ: nil) }
|
||||
|
||||
it { expect(geo_area.description).to be_nil }
|
||||
end
|
||||
|
|
|
@ -174,7 +174,8 @@ describe ProcedureRevision do
|
|||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -186,12 +187,14 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_first.libelle,
|
||||
private: false,
|
||||
from: type_de_champ_first.libelle,
|
||||
to: "modifier le libelle"
|
||||
to: "modifier le libelle",
|
||||
stable_id: type_de_champ_first.stable_id
|
||||
},
|
||||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
}
|
||||
])
|
||||
expect(new_revision.types_de_champ.first.revision).to eq(new_revision)
|
||||
|
@ -204,19 +207,22 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_first.libelle,
|
||||
private: false,
|
||||
from: type_de_champ_first.libelle,
|
||||
to: "modifier le libelle"
|
||||
to: "modifier le libelle",
|
||||
stable_id: type_de_champ_first.stable_id
|
||||
},
|
||||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
},
|
||||
{
|
||||
op: :move,
|
||||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: 1,
|
||||
to: 2
|
||||
to: 2,
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
}
|
||||
])
|
||||
expect(new_revision.types_de_champ.last.revision).to eq(revision)
|
||||
|
@ -226,12 +232,14 @@ describe ProcedureRevision do
|
|||
{
|
||||
op: :remove,
|
||||
label: type_de_champ_first.libelle,
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: type_de_champ_first.stable_id
|
||||
},
|
||||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -241,12 +249,14 @@ describe ProcedureRevision do
|
|||
{
|
||||
op: :remove,
|
||||
label: type_de_champ_first.libelle,
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: type_de_champ_first.stable_id
|
||||
},
|
||||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -254,7 +264,8 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: type_de_champ_second.description,
|
||||
to: "une description"
|
||||
to: "une description",
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -262,7 +273,8 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: false,
|
||||
to: true
|
||||
to: true,
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -272,12 +284,14 @@ describe ProcedureRevision do
|
|||
{
|
||||
op: :remove,
|
||||
label: type_de_champ_first.libelle,
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: type_de_champ_first.stable_id
|
||||
},
|
||||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -285,7 +299,8 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: type_de_champ_second.description,
|
||||
to: "une description"
|
||||
to: "une description",
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -293,7 +308,8 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: false,
|
||||
to: true
|
||||
to: true,
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -301,7 +317,8 @@ describe ProcedureRevision do
|
|||
label: "sub type de champ",
|
||||
private: false,
|
||||
from: "text",
|
||||
to: "drop_down_list"
|
||||
to: "drop_down_list",
|
||||
stable_id: new_revision.types_de_champ.last.types_de_champ.first.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -309,7 +326,8 @@ describe ProcedureRevision do
|
|||
label: "sub type de champ",
|
||||
private: false,
|
||||
from: [],
|
||||
to: ["one", "two"]
|
||||
to: ["one", "two"],
|
||||
stable_id: new_revision.types_de_champ.last.types_de_champ.first.stable_id
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -319,12 +337,14 @@ describe ProcedureRevision do
|
|||
{
|
||||
op: :remove,
|
||||
label: type_de_champ_first.libelle,
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: type_de_champ_first.stable_id
|
||||
},
|
||||
{
|
||||
op: :add,
|
||||
label: "Un champ text",
|
||||
private: false
|
||||
private: false,
|
||||
stable_id: new_type_de_champ.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -332,7 +352,8 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: type_de_champ_second.description,
|
||||
to: "une description"
|
||||
to: "une description",
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -340,7 +361,8 @@ describe ProcedureRevision do
|
|||
label: type_de_champ_second.libelle,
|
||||
private: false,
|
||||
from: false,
|
||||
to: true
|
||||
to: true,
|
||||
stable_id: type_de_champ_second.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -348,7 +370,8 @@ describe ProcedureRevision do
|
|||
label: "sub type de champ",
|
||||
private: false,
|
||||
from: "text",
|
||||
to: "carte"
|
||||
to: "carte",
|
||||
stable_id: new_revision.types_de_champ.last.types_de_champ.first.stable_id
|
||||
},
|
||||
{
|
||||
op: :update,
|
||||
|
@ -356,7 +379,8 @@ describe ProcedureRevision do
|
|||
label: "sub type de champ",
|
||||
private: false,
|
||||
from: [],
|
||||
to: [:cadastres, :znieff]
|
||||
to: [:cadastres, :znieff],
|
||||
stable_id: new_revision.types_de_champ.last.types_de_champ.first.stable_id
|
||||
}
|
||||
])
|
||||
end
|
||||
|
|
|
@ -372,7 +372,7 @@ describe User, type: :model do
|
|||
end
|
||||
|
||||
context 'for administrateurs' do
|
||||
let(:user) { build(:user, email: 'admin@exemple.fr', password: password, administrateur: build(:administrateur)) }
|
||||
let(:user) { build(:user, email: 'admin@exemple.fr', password: password, administrateur: create(:administrateur, user: nil)) }
|
||||
|
||||
context 'when the password is too short' do
|
||||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
|
|
@ -52,7 +52,7 @@ describe ChampPolicy do
|
|||
end
|
||||
|
||||
context 'when the user also has instruction rights' do
|
||||
let(:instructeur) { create(:instructeur, email: signed_in_user.email, password: signed_in_user.password) }
|
||||
let(:instructeur) { create(:instructeur, user: signed_in_user) }
|
||||
let(:account) { { user: signed_in_user, instructeur: instructeur } }
|
||||
|
||||
context 'as the dossier instructeur and owner' do
|
||||
|
|
|
@ -58,7 +58,7 @@ RSpec.configure do |config|
|
|||
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
||||
# examples within a transaction, remove the following line or assign false
|
||||
# instead of true.
|
||||
config.use_transactional_fixtures = false
|
||||
config.use_transactional_fixtures = true
|
||||
|
||||
# RSpec Rails can automatically mix in different behaviours to your tests
|
||||
# based on their file location, for example enabling you to call `get` and
|
||||
|
@ -127,4 +127,5 @@ RSpec.configure do |config|
|
|||
config.include Shoulda::Matchers::ActiveModel, type: :model
|
||||
config.include Devise::Test::ControllerHelpers, type: :controller
|
||||
config.include Devise::Test::ControllerHelpers, type: :view
|
||||
config.include Devise::Test::IntegrationHelpers, type: :system
|
||||
end
|
||||
|
|
47
spec/services/zxcvbn_service_spec.rb
Normal file
47
spec/services/zxcvbn_service_spec.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
describe ZxcvbnService do
|
||||
let(:password) { 'medium-strength-password' }
|
||||
subject(:service) { ZxcvbnService.new(password) }
|
||||
|
||||
describe '#score' do
|
||||
it 'returns the password complexity score' do
|
||||
expect(service.score).to eq 3
|
||||
end
|
||||
end
|
||||
|
||||
describe '#complexity' do
|
||||
it 'returns the password score, vulnerability and length' do
|
||||
expect(service.complexity).to eq [3, 'medium, strength, password', 24]
|
||||
end
|
||||
end
|
||||
|
||||
describe 'caching' do
|
||||
it 'lazily caches the tester between calls and instances' do
|
||||
allow(Zxcvbn::Tester).to receive(:new).and_call_original
|
||||
allow(YAML).to receive(:safe_load).and_call_original
|
||||
|
||||
first_service = ZxcvbnService.new('some-password')
|
||||
first_service.score
|
||||
first_service.complexity
|
||||
other_service = ZxcvbnService.new('other-password')
|
||||
other_service.score
|
||||
other_service.complexity
|
||||
|
||||
expect(Zxcvbn::Tester).to have_received(:new).at_most(:once)
|
||||
expect(YAML).to have_received(:safe_load).at_most(:once)
|
||||
end
|
||||
|
||||
it 'lazily caches the tester between threads' do
|
||||
allow(Zxcvbn::Tester).to receive(:new).and_call_original
|
||||
|
||||
threads = 1.upto(4).map do
|
||||
Thread.new do
|
||||
ZxcvbnService.new(password).score
|
||||
end
|
||||
end.map(&:join)
|
||||
|
||||
scores = threads.map(&:value)
|
||||
expect(scores).to eq([3, 3, 3, 3])
|
||||
expect(Zxcvbn::Tester).to have_received(:new).at_most(:once)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,9 +3,6 @@ require 'capybara-screenshot/rspec'
|
|||
require 'capybara/email/rspec'
|
||||
require 'selenium/webdriver'
|
||||
|
||||
Capybara.javascript_driver = :headless_chrome
|
||||
Capybara.ignore_hidden_elements = false
|
||||
|
||||
Capybara.register_driver :chrome do |app|
|
||||
Capybara::Selenium::Driver.new(app, browser: :chrome)
|
||||
end
|
||||
|
@ -34,11 +31,10 @@ Capybara.register_driver :headless_chrome do |app|
|
|||
end
|
||||
end
|
||||
|
||||
# FIXME: remove this line when https://github.com/rspec/rspec-rails/issues/1897 has been fixed
|
||||
Capybara.server = :puma, { Silent: true }
|
||||
|
||||
Capybara.default_max_wait_time = 2
|
||||
|
||||
Capybara.ignore_hidden_elements = false
|
||||
|
||||
# Save a snapshot of the HTML page when an integration test fails
|
||||
Capybara::Screenshot.autosave_on_failure = true
|
||||
# Keep only the screenshots generated from the last failing test suite
|
||||
|
@ -49,13 +45,21 @@ Capybara::Screenshot.register_driver :headless_chrome do |driver, path|
|
|||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
# Set the user preferred language before Javascript feature specs.
|
||||
config.before(:each, type: :system) do
|
||||
driven_by :rack_test
|
||||
end
|
||||
|
||||
config.before(:each, type: :system, js: true) do
|
||||
driven_by :headless_chrome
|
||||
end
|
||||
|
||||
# Set the user preferred language before Javascript system specs.
|
||||
#
|
||||
# Features specs without Javascript run in a Rack stack, and respect the Accept-Language value.
|
||||
# System specs without Javascript run in a Rack stack, and respect the Accept-Language value.
|
||||
# However specs using Javascript are run into a Headless Chrome, which doesn't support setting
|
||||
# the default Accept-Language value reliably.
|
||||
# So instead we set the locale cookie explicitly before each Javascript test.
|
||||
config.before(:each, js: true) do
|
||||
config.before(:each, type: :system, js: true) do
|
||||
visit '/' # Webdriver needs visiting a page before setting the cookie
|
||||
Capybara.current_session.driver.browser.manage.add_cookie(
|
||||
name: :locale,
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
RSpec.configure do |config|
|
||||
expect_list = []
|
||||
|
||||
config.before(:suite) do
|
||||
DatabaseCleaner.clean_with(:truncation, except: expect_list)
|
||||
end
|
||||
|
||||
config.before(:each) do
|
||||
DatabaseCleaner.strategy = :transaction
|
||||
end
|
||||
|
||||
config.before(:each, js: true) do
|
||||
DatabaseCleaner.strategy = :deletion, { except: expect_list }
|
||||
end
|
||||
|
||||
config.before(:each) do
|
||||
DatabaseCleaner.start
|
||||
end
|
||||
|
||||
config.after(:each) do
|
||||
DatabaseCleaner.clean
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
module FeatureHelpers
|
||||
module SystemHelpers
|
||||
include ActiveJob::TestHelper
|
||||
|
||||
def login_admin
|
||||
|
@ -177,5 +177,5 @@ module FeatureHelpers
|
|||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include FeatureHelpers, type: :feature
|
||||
config.include SystemHelpers, type: :system
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
feature 'wcag rules for usager', js: true do
|
||||
describe 'wcag rules for usager', js: true do
|
||||
let(:procedure) { create(:procedure, :with_type_de_champ, :with_all_champs, :with_service, :for_individual, :published) }
|
||||
let(:password) { 'a very complicated password' }
|
||||
let(:litteraire_user) { create(:user, password: password) }
|
|
@ -1,4 +1,4 @@
|
|||
feature 'As an administrateur', js: true do
|
||||
describe 'As an administrateur', js: true do
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:admin_email) { 'new_admin@gouv.fr' }
|
||||
let(:new_admin) { Administrateur.by_email(admin_email) }
|
|
@ -1,6 +1,6 @@
|
|||
require 'features/admin/procedure_spec_helper'
|
||||
require 'system/admin/procedure_spec_helper'
|
||||
|
||||
feature 'As an administrateur I wanna clone a procedure', js: true do
|
||||
describe 'As an administrateur I wanna clone a procedure', js: true do
|
||||
include ProcedureSpecHelper
|
||||
|
||||
let(:administrateur) { create(:administrateur) }
|
|
@ -1,6 +1,6 @@
|
|||
require 'features/admin/procedure_spec_helper'
|
||||
require 'system/admin/procedure_spec_helper'
|
||||
|
||||
feature 'As an administrateur I wanna create a new procedure', js: true do
|
||||
describe 'As an administrateur I wanna create a new procedure', js: true do
|
||||
include ProcedureSpecHelper
|
||||
|
||||
let(:administrateur) { create(:administrateur, :with_procedure) }
|
|
@ -1,4 +1,4 @@
|
|||
feature 'procedure locked' do
|
||||
describe 'procedure locked' do
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
|
||||
before do
|
|
@ -1,6 +1,6 @@
|
|||
require 'features/admin/procedure_spec_helper'
|
||||
require 'system/admin/procedure_spec_helper'
|
||||
|
||||
feature 'Publication de démarches', js: true do
|
||||
describe 'Publication de démarches', js: true do
|
||||
include ProcedureSpecHelper
|
||||
|
||||
let(:administrateur) { create(:administrateur) }
|
|
@ -1,6 +1,6 @@
|
|||
require 'features/admin/procedure_spec_helper'
|
||||
require 'system/admin/procedure_spec_helper'
|
||||
|
||||
feature 'Administrateurs can edit procedures', js: true do
|
||||
describe 'Administrateurs can edit procedures', js: true do
|
||||
include ProcedureSpecHelper
|
||||
|
||||
let(:administrateur) { create(:administrateur) }
|
|
@ -1,4 +1,4 @@
|
|||
feature 'fetch API Particulier Data', js: true do
|
||||
describe 'fetch API Particulier Data', js: true do
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
|
||||
let(:expected_token) { 'd7e9c9f4c3ca00caadde31f50fd4521a' }
|
|
@ -1,4 +1,4 @@
|
|||
feature 'Inviting an expert:' do
|
||||
describe 'Inviting an expert:' do
|
||||
include ActiveJob::TestHelper
|
||||
include ActionView::Helpers
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
feature 'Protecting against request forgeries:', :allow_forgery_protection, :show_exception_pages do
|
||||
describe 'Protecting against request forgeries:', :allow_forgery_protection, :show_exception_pages do
|
||||
let(:user) { create(:user, password: password) }
|
||||
let(:password) { 'ThisIsTheUserPassword' }
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
feature 'France Connect Particulier Connexion' do
|
||||
describe 'France Connect Particulier Connexion' do
|
||||
let(:code) { 'plop' }
|
||||
let(:given_name) { 'titi' }
|
||||
let(:family_name) { 'toto' }
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue