aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert2017-10-17 15:50:25 +0200
committerRobert2017-10-17 15:50:25 +0200
commit81d88f25a13246fe7983b5e0ffbbc50aa10a32d3 (patch)
treee65197a1072e907d21cf64f35c85adaeefb17991
parentc1ed07eadc07e878ad09feecb529c26623189878 (diff)
parent5559c8639f977b2ee946d3f982da1bbf0643a5a4 (diff)
downloadchouette-core-81d88f25a13246fe7983b5e0ffbbc50aa10a32d3.tar.bz2
Merge branch 'master' of github.com:af83/stif-boiv
-rw-r--r--app/controllers/time_tables_controller.rb1
-rw-r--r--app/views/compliance_control_blocks/edit.html.slim2
-rw-r--r--app/views/compliance_control_blocks/new.html.slim2
-rw-r--r--app/views/compliance_control_sets/edit.html.slim2
-rw-r--r--app/views/compliance_control_sets/index.html.slim2
-rw-r--r--app/views/compliance_control_sets/new.html.slim2
-rw-r--r--app/views/compliance_control_sets/show.html.slim2
-rw-r--r--app/views/compliance_controls/edit.html.slim2
-rw-r--r--app/views/compliance_controls/new.html.slim2
-rw-r--r--app/views/compliance_controls/select_type.html.slim2
-rw-r--r--app/views/compliance_controls/show.html.slim6
-rw-r--r--app/views/time_tables/_filter.html.slim2
-rw-r--r--app/workers/compliance_control_set_cloning_worker.rb8
-rw-r--r--config/locales/compliance_control_blocks.en.yml4
-rw-r--r--config/locales/compliance_control_blocks.fr.yml4
-rw-r--r--config/locales/compliance_control_sets.en.yml2
-rw-r--r--config/locales/compliance_control_sets.fr.yml2
-rw-r--r--config/locales/compliance_controls.en.yml2
-rw-r--r--config/locales/compliance_controls.fr.yml2
-rw-r--r--lib/compliance_control_set_cloner.rb94
-rw-r--r--spec/lib/compliance_control_set_cloner_spec.rb144
-rw-r--r--spec/workers/clean_up_worker_spec.rb1
-rw-r--r--spec/workers/compliance_control_set_cloning_worker_spec.rb15
23 files changed, 289 insertions, 16 deletions
diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb
index 2d24d5aa6..af74f635f 100644
--- a/app/controllers/time_tables_controller.rb
+++ b/app/controllers/time_tables_controller.rb
@@ -130,7 +130,6 @@ class TimeTablesController < ChouetteController
scope = select_time_tables
if params[:q] && params[:q]["tag_search"]
tags = params[:q]["tag_search"].reject {|c| c.empty?}
- params[:q].delete("tag_search")
scope = select_time_tables.tagged_with(tags, :any => true) if tags.any?
end
scope = self.ransack_period_range(scope: scope, error_message: t('referentials.errors.validity_period'), query: :overlapping)
diff --git a/app/views/compliance_control_blocks/edit.html.slim b/app/views/compliance_control_blocks/edit.html.slim
index 0ac507ece..637bb7311 100644
--- a/app/views/compliance_control_blocks/edit.html.slim
+++ b/app/views/compliance_control_blocks/edit.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-= pageheader 'modele-calendrier',
+= pageheader 'jeux-de-controle',
t('compliance_control_blocks.edit.title', compliance_control_block: @compliance_control_block.id)
diff --git a/app/views/compliance_control_blocks/new.html.slim b/app/views/compliance_control_blocks/new.html.slim
index 654a0dc7f..49404c552 100644
--- a/app/views/compliance_control_blocks/new.html.slim
+++ b/app/views/compliance_control_blocks/new.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-= pageheader 'modele-calendrier',
+= pageheader 'jeux-de-controle',
t('compliance_control_blocks.new.title')
diff --git a/app/views/compliance_control_sets/edit.html.slim b/app/views/compliance_control_sets/edit.html.slim
index 934bd81b0..649154b91 100644
--- a/app/views/compliance_control_sets/edit.html.slim
+++ b/app/views/compliance_control_sets/edit.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-= pageheader 'modele-calendrier',
+= pageheader 'jeux-de-controle',
t('compliance_control_sets.edit.title', name: @compliance_control_set.name)
/ PageContent
diff --git a/app/views/compliance_control_sets/index.html.slim b/app/views/compliance_control_sets/index.html.slim
index 68173fee9..1120ed186 100644
--- a/app/views/compliance_control_sets/index.html.slim
+++ b/app/views/compliance_control_sets/index.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-- header_params = ['jeux-de-donnees',
+- header_params = ['jeux-de-controle',
t('compliance_control_sets.index.title'),
'']
- header_params << link_to(t('compliance_control_sets.actions.new'), new_compliance_control_set_path, class: 'btn btn-default') if policy(Calendar).create?
diff --git a/app/views/compliance_control_sets/new.html.slim b/app/views/compliance_control_sets/new.html.slim
index d6be41ee8..35654b4d6 100644
--- a/app/views/compliance_control_sets/new.html.slim
+++ b/app/views/compliance_control_sets/new.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-= pageheader 'modele-calendrier',
+= pageheader 'jeux-de-controle',
t('compliance_control_sets.index.new')
diff --git a/app/views/compliance_control_sets/show.html.slim b/app/views/compliance_control_sets/show.html.slim
index b6e203a9e..7767bd0d9 100644
--- a/app/views/compliance_control_sets/show.html.slim
+++ b/app/views/compliance_control_sets/show.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-= pageheader 'jeux-de-donnees',
+= pageheader 'jeux-de-controle',
t('compliance_control_sets.show.title', name: @compliance_control_set.name),
'Lorem ipsum dolor sit amet'
diff --git a/app/views/compliance_controls/edit.html.slim b/app/views/compliance_controls/edit.html.slim
index d7497c0e2..1d478e845 100644
--- a/app/views/compliance_controls/edit.html.slim
+++ b/app/views/compliance_controls/edit.html.slim
@@ -1,4 +1,4 @@
-= pageheader 'compliance-control',
+= pageheader 'jeux-de-controle',
t('compliance_controls.edit.title')
diff --git a/app/views/compliance_controls/new.html.slim b/app/views/compliance_controls/new.html.slim
index 962f70ecc..181f49a15 100644
--- a/app/views/compliance_controls/new.html.slim
+++ b/app/views/compliance_controls/new.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-- header_params = ['jeux-de-donnees',
+- header_params = ['jeux-de-controle',
t('compliance_controls.new.title'),
'']
= pageheader(*header_params) do
diff --git a/app/views/compliance_controls/select_type.html.slim b/app/views/compliance_controls/select_type.html.slim
index c6e3b0427..98cc5a943 100644
--- a/app/views/compliance_controls/select_type.html.slim
+++ b/app/views/compliance_controls/select_type.html.slim
@@ -1,5 +1,5 @@
/ PageHeader
-- header_params = ['jeux-de-donnees',
+- header_params = ['jeux-de-controle',
t('compliance_controls.select_type.title'),
'']
= pageheader(*header_params) do
diff --git a/app/views/compliance_controls/show.html.slim b/app/views/compliance_controls/show.html.slim
index 8232dbe28..7f11b1041 100644
--- a/app/views/compliance_controls/show.html.slim
+++ b/app/views/compliance_controls/show.html.slim
@@ -1,7 +1,9 @@
/ PageHeader
-= pageheader 'jeux-de-donnees',
+- header_params = ['jeux-de-controle',
t('compliance_controls.show.title'),
- ''
+ '']
+= pageheader(*header_params) do
+
/ PageContent
.page_content
.container-fluid
diff --git a/app/views/time_tables/_filter.html.slim b/app/views/time_tables/_filter.html.slim
index 2672f7dfc..11e9987c4 100644
--- a/app/views/time_tables/_filter.html.slim
+++ b/app/views/time_tables/_filter.html.slim
@@ -9,7 +9,7 @@
.ffg-row
.form-group
= f.label Chouette::TimeTable.human_attribute_name(:tag_search), required: false, class: 'control-label'
- = f.input :tag_search, as: :tags, collection: Chouette::TimeTable.tags_on(:tags).pluck(:name), label: false, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': 'Indiquez une étiquette...' }, wrapper_html: { class: 'select2ed'}, include_blank: false
+ = f.input :tag_search, as: :tags, collection: Chouette::TimeTable.tags_on(:tags).pluck(:name), label: false, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': 'Indiquez une étiquette...' }, wrapper_html: { class: 'select2ed'}, include_blank: false, selected: params[:q] ? params[:q]['tag_search'] : nil
.form-group.togglable
= f.label Chouette::TimeTable.human_attribute_name(:bounding_dates), required: false, class: 'control-label'
diff --git a/app/workers/compliance_control_set_cloning_worker.rb b/app/workers/compliance_control_set_cloning_worker.rb
new file mode 100644
index 000000000..9cbe5c81a
--- /dev/null
+++ b/app/workers/compliance_control_set_cloning_worker.rb
@@ -0,0 +1,8 @@
+class ComplianceControlSetCloningWorker
+ include Sidekiq::Worker
+
+ def perform id, organisation_id
+ ComplianceControlSetCloner.new.copy id, organisation_id
+ end
+
+end
diff --git a/config/locales/compliance_control_blocks.en.yml b/config/locales/compliance_control_blocks.en.yml
index a37b41db5..fbface6b2 100644
--- a/config/locales/compliance_control_blocks.en.yml
+++ b/config/locales/compliance_control_blocks.en.yml
@@ -10,9 +10,11 @@ fr:
transport_mode: Transport mode
sub_transport_mode: Transport submode
compliance_control_blocks:
+ clone:
+ prefix: 'Copy of'
actions:
destroy_confirm: Are you sure you want to destroy this block ?
new:
title: Create a control block
edit:
- title: "Edit the control block : %{compliance_control_block}" \ No newline at end of file
+ title: "Edit the control block : %{compliance_control_block}"
diff --git a/config/locales/compliance_control_blocks.fr.yml b/config/locales/compliance_control_blocks.fr.yml
index f93cafa54..66df008be 100644
--- a/config/locales/compliance_control_blocks.fr.yml
+++ b/config/locales/compliance_control_blocks.fr.yml
@@ -10,9 +10,11 @@ fr:
transport_mode: Mode de transport
transport_submode: Sous-mode de transport
compliance_control_blocks:
+ clone:
+ prefix: 'Copie de'
actions:
destroy_confirm: Etes vous sûr de supprimer ce bloc ?
new:
title: Créer un groupe de contrôle(s)
edit:
- title: "Editer le groupe de contrôle : %{compliance_control_block}" \ No newline at end of file
+ title: "Editer le groupe de contrôle : %{compliance_control_block}"
diff --git a/config/locales/compliance_control_sets.en.yml b/config/locales/compliance_control_sets.en.yml
index 83b14642c..f72342894 100644
--- a/config/locales/compliance_control_sets.en.yml
+++ b/config/locales/compliance_control_sets.en.yml
@@ -1,5 +1,7 @@
en:
compliance_control_sets:
+ clone:
+ prefix: 'Copie de'
index:
title: Compliance control set
new: New compliance control set
diff --git a/config/locales/compliance_control_sets.fr.yml b/config/locales/compliance_control_sets.fr.yml
index 37851d7c4..c31eb9423 100644
--- a/config/locales/compliance_control_sets.fr.yml
+++ b/config/locales/compliance_control_sets.fr.yml
@@ -1,5 +1,7 @@
fr:
compliance_control_sets:
+ clone:
+ prefix: 'Copy of'
index:
title: "Liste des jeux de contrôles"
edit:
diff --git a/config/locales/compliance_controls.en.yml b/config/locales/compliance_controls.en.yml
index 3063c35a4..887bc2009 100644
--- a/config/locales/compliance_controls.en.yml
+++ b/config/locales/compliance_controls.en.yml
@@ -1,5 +1,7 @@
en:
compliance_controls:
+ clone:
+ prefix: 'Copy of'
min_max_values: "the minimum (%{min}) is not supposed to be greater than the maximum (%{max})"
errors:
incoherent_control_sets: "Impossible to assign a control to a set (id: %{direct_set_name}) differing from the one of its group (id: %{indirect_set_name})"
diff --git a/config/locales/compliance_controls.fr.yml b/config/locales/compliance_controls.fr.yml
index 2038b9eb7..2feb201bf 100644
--- a/config/locales/compliance_controls.fr.yml
+++ b/config/locales/compliance_controls.fr.yml
@@ -1,5 +1,7 @@
fr:
compliance_controls:
+ clone:
+ prefix: 'Copie de'
min_max_values: "la valeur de minimum (%{min}) ne doit pas être superieur à la valuer du maximum (%{max})"
errors:
incoherent_control_sets: "Le contrôle ne peut pas être associé à un jeu de contrôle (id: %{direct_set_name}) différent de celui de son groupe (id: %{indirect_set_name})"
diff --git a/lib/compliance_control_set_cloner.rb b/lib/compliance_control_set_cloner.rb
new file mode 100644
index 000000000..1cf58a38d
--- /dev/null
+++ b/lib/compliance_control_set_cloner.rb
@@ -0,0 +1,94 @@
+class ComplianceControlSetCloner
+
+ # Naming Convention: As we are in a domain with quite long names we
+ # abbreviate compliance_control to cc and
+ # compliance_check to cck iff used as prefixes.
+
+ attr_reader :organisation_id, :source_set_id
+
+ def copy source_set_id, organisation_id
+ @source_set_id = source_set_id
+ @organisation_id = organisation_id
+ copy_set
+ end
+
+
+ private
+
+ # Workers
+ # -------
+
+ # Copy Set:
+ def copy_set
+ # Force lazy creation of target_set, just in case source_set is _empty_.
+ target_set
+ copy_controls
+ copy_blocks
+ end
+
+ # Copy Blocks:
+ def copy_block source_block
+ target_set.compliance_control_blocks.create(
+ name: name_of_copy(:compliance_control_blocks, source_block.name),
+ condition_attributes: source_block.condition_attributes).tap do | target_block |
+ relink_checks_to_block source_block, target_block
+ end
+ end
+ def copy_blocks
+ source_set.compliance_control_blocks.order(:id).each(&method(:copy_block))
+ end
+ def relink_checks_to_block source_block, target_block
+ source_block
+ .compliance_controls
+ .order(:id)
+ .each do | source_control |
+ control_id_map[source_control.id]
+ .update(compliance_control_block_id: target_block.id)
+ end
+ end
+
+ # Copy Controls:
+ def copy_controls
+ source_set.compliance_controls.order(:id).each(&method(:copy_control))
+ end
+ def copy_control(compliance_control)
+ target_set.compliance_controls.create(
+ code: compliance_control.code,
+ comment: compliance_control.comment,
+ control_attributes: compliance_control.control_attributes,
+ criticity: compliance_control.criticity,
+ name: name_of_copy(:compliance_controls, compliance_control.name),
+ origin_code: compliance_control.origin_code,
+ target: compliance_control.target,
+ type: compliance_control.type
+ ).tap do | control |
+ control_id_map.update compliance_control.id => control
+ end
+ end
+
+ def name_of_copy resource, name
+ [I18n.t("#{resource}.clone.prefix"), name].join(' ')
+ end
+
+ # Lazy Values
+ # -----------
+ def organisation
+ @__organisation__ ||= Organisation.find(organisation_id)
+ end
+ def source_set
+ @__source_set__ ||= ComplianceControlSet.find(source_set_id)
+ end
+ def target_set
+ @__target_set__ ||= ComplianceControlSet.create!(
+ organisation: organisation,
+ name: name_of_copy(:compliance_control_sets, source_set.name)
+ )
+ end
+ def control_id_map
+ # Map: compliance_control_id -> compliance_control (origin_id -> copied object)
+ @__control_id_to_check__ ||= Hash.new
+ end
+ def referential
+ @__referential__ ||= Referential.find(referential_id)
+ end
+end
diff --git a/spec/lib/compliance_control_set_cloner_spec.rb b/spec/lib/compliance_control_set_cloner_spec.rb
new file mode 100644
index 000000000..4305ec70b
--- /dev/null
+++ b/spec/lib/compliance_control_set_cloner_spec.rb
@@ -0,0 +1,144 @@
+RSpec.describe ComplianceControlSetCloner do
+
+ subject{ described_class.new }
+
+ let( :new_organisation ){ create :organisation }
+
+ let( :source_set ){ create :compliance_control_set }
+ let( :set_prefix ){ I18n.t('compliance_control_sets.clone.prefix') }
+ let( :block_prefix ){ I18n.t('compliance_control_blocks.clone.prefix') }
+ let( :control_prefix ){ I18n.t('compliance_controls.clone.prefix') }
+
+
+ context 'Copying empty set' do
+
+ context 'correct organisation' do
+
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ # +-------------------+
+ # +---------------------+----------------| Control (direct0) |
+ # | | +-------------------+
+ # | |
+ # | | +-------------------+
+ # +---------------------)------------+---| Control (direct1) |
+ # | | | +-------------------+
+ # | | |
+ # | | | +-------------------+
+ # +---------------------)------------)---| Control (direct2) |
+ # | | | +-------------------+
+ # | | |
+ # | | |
+ # | | |
+ # v v |
+ # +------------+ +--------------+ | +---------------------+
+ # | ControlSet |<----+----| ControlBlock |<-)--| Control (indirect0) |
+ # +------------+ | +--------------+ | +---------------------+
+ # | |
+ # | +--------------+<-+ +---------------------+
+ # |<---| ControlBlock |<----| Control (indirect1) |
+ # | +--------------+ +---------------------+
+ # |
+ # | +--------------+ +---------------------+
+ # +----| ControlBlock |<----| Control (indirect2) |
+ # +--------------+ +---------------------+
+
+ context 'Directed Acyclic Graph is copied correctly' do
+ let(:source_blox){
+ 3.times.map{ |_| create :compliance_control_block, compliance_control_set: source_set }
+ }
+ let(:direct_ccs){
+ 3.times.map{ |n| create :generic_attribute_control_min_max, compliance_control_set: source_set, name: "direct #{n.succ}", code: "direct-#{n.succ}" }
+ }
+ # Needed to check we do not dulicate a node (compliance_control) twice
+ let(:indirect_ccs){
+ # Create 1 child for each block and also associate first of the direct ccs to the first block
+ # seconf of the direct css to the second block
+ source_blox.take(2).zip(direct_ccs.take(2)).each do | source_block, cc |
+ cc.update compliance_control_block_id: source_block.id
+ end
+ source_blox.each_with_index.map{ | source_block, n |
+ create(:generic_attribute_control_min_max, compliance_control_set: source_set, compliance_control_block: source_block, name: "indirect #{n.succ}", code: "indirect-#{n.succ}")
+ }
+ }
+ let( :sources ){ source_set.compliance_controls.order(:id) }
+
+ let( :target_set ){ ComplianceControlSet.last }
+ let( :target_blox ){ ComplianceControlBlock.last 3 }
+ let( :targets ){ target_set.compliance_controls.order(:id) }
+
+ before do
+ direct_ccs
+ indirect_ccs
+ end
+ it 'correctly creates a set for a complete DAG' do
+ # Slowness of tests constrains us to create a minimum of objects in the DB,
+ # hence only one example :(
+ #
+ # Execute copy and keep count
+ counts = object_counts
+ subject.copy(source_set.id, new_organisation.id)
+ delta = count_diff counts, object_counts
+
+ # Check correctly copied set
+ expect(target_set.organisation).to eq(new_organisation)
+ expect(target_set.name).to eq( [set_prefix, source_set.name].join(' ') )
+
+ # Check correctly copied controls
+ targets.zip(sources).each do | target, source |
+ expect( target.code ).to eq(source.code )
+ expect( target.comment ).to eq(source.comment )
+ expect( target.compliance_control_set ).to eq( target_set )
+ expect( target.control_attributes ).to eq(source.control_attributes)
+ expect( target.criticity ).to eq(source.criticity )
+ expect( target.name ).to eq([control_prefix, source.name].join(' '))
+ expect( target.origin_code ).to eq(source.origin_code )
+ expect( target.type ).to eq(source.type)
+ end
+ # Check correctly copied blocks
+ target_blox.zip(source_blox).each do | target_block, source_block |
+ expect( target_block.compliance_control_set ).to eq(target_set)
+ expect( target_block.name ).to eq( [block_prefix, source_block.name].join(' ') )
+ expect( target_block.condition_attributes ).to eq( source_block.condition_attributes )
+ end
+
+ # Check correct block associations
+ # See diagram above to understand the meaning of this:
+ # - The first two controls have been assigned to the first two blocks accordingly
+ # - The third has no block
+ # - The last three controls have been created from the three blocks in order
+ expected_block_ids = target_blox.take(2).map(&:id) + [ nil ] + target_blox.map(&:id)
+ expect( targets.pluck(:compliance_control_block_id) ).to eq( expected_block_ids )
+
+ # Check overall counts (no additional creations)
+ expect( delta ).to eq(counts)
+ end
+ end
+
+ end
+
+ def object_counts
+ {
+ source_set_count: ComplianceControlSet.count,
+ cc_block_count: ComplianceControlBlock.count,
+ cc_count: ComplianceControl.count,
+ cck_set_count: ComplianceCheckSet.count,
+ cck_block_count: ComplianceCheckBlock.count,
+ cck_count: ComplianceCheck.count
+ }
+ end
+
+ def count_diff count1, count2
+ count1.inject({}){ |h, (k,v)|
+ h.merge( k => count2[k] - v )
+ }
+ end
+
+ end
+
+end
diff --git a/spec/workers/clean_up_worker_spec.rb b/spec/workers/clean_up_worker_spec.rb
index e85768fa3..fd767db00 100644
--- a/spec/workers/clean_up_worker_spec.rb
+++ b/spec/workers/clean_up_worker_spec.rb
@@ -1,4 +1,3 @@
-require 'rails_helper'
RSpec.describe CleanUpWorker, type: :worker do
pending "add some examples to (or delete) #{__FILE__}"
end
diff --git a/spec/workers/compliance_control_set_cloning_worker_spec.rb b/spec/workers/compliance_control_set_cloning_worker_spec.rb
new file mode 100644
index 000000000..3a2332f62
--- /dev/null
+++ b/spec/workers/compliance_control_set_cloning_worker_spec.rb
@@ -0,0 +1,15 @@
+RSpec.describe ComplianceControlSetCloningWorker do
+
+
+ it 'is a worker' do
+ expect( described_class.new ).to be_a(Sidekiq::Worker)
+ end
+
+ it 'delegates perform to the correct lib call' do
+ id = double('id')
+ organisation_id = double('organisation_id')
+ expect_any_instance_of(ComplianceControlSetCloner).to receive(:copy).with(id, organisation_id)
+ described_class.new.perform(id, organisation_id)
+ end
+
+end