aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuc Donnet2016-11-03 11:02:28 +0100
committerLuc Donnet2016-11-03 11:02:28 +0100
commit552611c5a96134eff8515bbfe32870e900225bfb (patch)
treec3b7cc795d60d390457d201feb7cb845f4b433dd
parent7212356ab15ea1807c28a8dce4a11290d47facac (diff)
parentd67ed4c32b338070e4e4ff33f89fe64011e14c3b (diff)
downloadchouette-core-552611c5a96134eff8515bbfe32870e900225bfb.tar.bz2
Merge branch 'master' of github.com:AF83/stif-boiv
-rw-r--r--app/controllers/referentials_controller.rb8
-rw-r--r--app/models/referential.rb63
-rw-r--r--app/models/referential_cloning.rb38
-rw-r--r--app/models/referential_metadata.rb8
-rw-r--r--app/views/referentials/_form.html.slim4
-rw-r--r--app/views/workbenches/_referential.html.slim (renamed from app/views/offer_workbenches/_referential.html.slim)0
-rw-r--r--app/views/workbenches/show.html.slim (renamed from app/views/offer_workbenches/show.html.slim)0
-rw-r--r--app/workers/referential_cloning_worker.rb24
-rw-r--r--config/initializers/apartment.rb4
-rw-r--r--config/routes.rb1
-rw-r--r--db/migrate/20161024123819_add_created_from_to_referentials.rb5
-rw-r--r--db/migrate/20161024135931_create_referential_clonings.rb13
-rw-r--r--db/schema.rb18
-rw-r--r--spec/factories/referential_clonings.rb6
-rw-r--r--spec/features/companies_spec.rb4
-rw-r--r--spec/models/referential_cloning_spec.rb10
-rw-r--r--spec/models/referential_spec.rb21
-rw-r--r--spec/workers/referential_cloning_worker_spec.rb4
18 files changed, 208 insertions, 23 deletions
diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb
index 4ffb6ad65..3ae59f975 100644
--- a/app/controllers/referentials_controller.rb
+++ b/app/controllers/referentials_controller.rb
@@ -7,6 +7,7 @@ class ReferentialsController < BreadcrumbController
respond_to :js, :only => :show
def new
+ @referential = Referential.new_from(Referential.find(params[:from])) if params[:from]
new! do
@referential.data_format = current_organisation.data_format
end
@@ -56,7 +57,11 @@ class ReferentialsController < BreadcrumbController
end
def create_resource(referential)
- referential.organisation = current_organisation
+ if referential.created_from
+ referential.clone_association referential.created_from
+ else
+ referential.organisation = current_organisation
+ end
super
end
@@ -74,6 +79,7 @@ class ReferentialsController < BreadcrumbController
:projection_type,
:data_format,
:archived_at,
+ :created_from_id,
referential_metadata_attributes: [:referential_source_id, :line_ids => []]
)
end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index 9612b1022..afadf5edd 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -29,13 +29,14 @@ class Referential < ActiveRecord::Base
belongs_to :line_referential
validates_presence_of :line_referential
+ belongs_to :created_from, class_name: 'Referential'
has_many :lines, through: :line_referential
has_many :companies, through: :line_referential
has_many :group_of_lines, through: :line_referential
has_many :networks, through: :line_referential
- has_one :referential_metadata
- accepts_nested_attributes_for :referential_metadata
+ has_many :referential_metadatas,:dependent => :destroy
+ accepts_nested_attributes_for :referential_metadatas
belongs_to :stop_area_referential
validates_presence_of :stop_area_referential
@@ -112,6 +113,28 @@ class Referential < ActiveRecord::Base
self
end
+ def self.new_from from
+ Referential.new({
+ name: I18n.t("activerecord.copy", :name => from.name),
+ slug: "#{from.slug}_clone",
+ prefix: from.prefix,
+ time_zone: from.time_zone,
+ bounds: from.bounds,
+ organisation: from.organisation,
+ line_referential: from.line_referential,
+ stop_area_referential: from.stop_area_referential,
+ workbench: from.workbench,
+ created_from: from,
+ })
+ end
+
+ def clone_association from
+ self.organisation = from.organisation
+ self.line_referential = from.line_referential
+ self.stop_area_referential = from.stop_area_referential
+ self.workbench = from.workbench
+ end
+
def self.available_srids
[
[ "RGF 93 Lambert 93 (2154)", 2154 ],
@@ -148,30 +171,44 @@ class Referential < ActiveRecord::Base
projection_type || ""
end
- after_create :autocreate_referential_metadata
- def autocreate_referential_metadata
- self.create_referential_metadata if workbench
+ before_validation :assign_line_and_stop_area_referential, :on => :create, if: :workbench
+ before_create :create_schema
+
+ after_create :create_referential_metadata, if: :workbench, unless: :created_from
+ after_create :clone_referential_metadatas, if: :created_from
+ after_create :clone_schema, if: :created_from
+
+ before_destroy :destroy_schema
+ before_destroy :destroy_jobs
+
+ def create_referential_metadata
+ self.referential_metadatas.create
+ end
+
+ def clone_referential_metadatas
+ self.created_from.referential_metadatas.each do |meta|
+ self.referential_metadatas << ReferentialMetadata.new_from(meta)
+ end
+ self.save
+ end
+
+ def clone_schema
+ ReferentialCloning.create(source_referential: self.created_from, target_referential: self)
end
- before_create :create_schema
def create_schema
Apartment::Tenant.create slug
end
- before_validation :assign_line_and_stop_area_referential, :on => :create
def assign_line_and_stop_area_referential
- if workbench
- self.line_referential = workbench.line_referential
- self.stop_area_referential = workbench.stop_area_referential
- end
+ self.line_referential = workbench.line_referential
+ self.stop_area_referential = workbench.stop_area_referential
end
- before_destroy :destroy_schema
def destroy_schema
Apartment::Tenant.drop slug
end
- before_destroy :destroy_jobs
def destroy_jobs
#Ievkit.delete_jobs(slug)
true
diff --git a/app/models/referential_cloning.rb b/app/models/referential_cloning.rb
new file mode 100644
index 000000000..9bf824ac5
--- /dev/null
+++ b/app/models/referential_cloning.rb
@@ -0,0 +1,38 @@
+class ReferentialCloning < ActiveRecord::Base
+ include AASM
+ belongs_to :source_referential, class_name: 'Referential'
+ belongs_to :target_referential, class_name: 'Referential'
+ after_commit :perform_clone, :on => :create
+
+ private
+ def perform_clone
+ ReferentialCloningWorker.perform_async(self.id)
+ end
+
+ aasm column: :status do
+ state :new, :initial => true
+ state :pending
+ state :successful
+ state :failed
+
+ event :run, after: :update_started_at do
+ transitions :from => [:new, :failed], :to => :pending
+ end
+
+ event :successful, after: :update_ended_at do
+ transitions :from => [:pending, :failed], :to => :successful
+ end
+
+ event :failed, after: :update_ended_at do
+ transitions :from => :pending, :to => :failed
+ end
+ end
+
+ def update_started_at
+ update_attribute(:started_at, Time.now)
+ end
+
+ def update_ended_at
+ update_attribute(:ended_at, Time.now)
+ end
+end
diff --git a/app/models/referential_metadata.rb b/app/models/referential_metadata.rb
index 7b1cea301..57ef9f7ca 100644
--- a/app/models/referential_metadata.rb
+++ b/app/models/referential_metadata.rb
@@ -3,4 +3,12 @@ class ReferentialMetadata < ActiveRecord::Base
belongs_to :referential_source, class_name: 'Referential'
has_array_of :lines, class_name: 'Chouette::Line'
+
+ def self.new_from from
+ ReferentialMetadata.new({
+ referential_source: from.referential_source,
+ line_ids: from.line_ids,
+ periodes: from.periodes
+ })
+ end
end
diff --git a/app/views/referentials/_form.html.slim b/app/views/referentials/_form.html.slim
index dd426f426..ce53c2ede 100644
--- a/app/views/referentials/_form.html.slim
+++ b/app/views/referentials/_form.html.slim
@@ -15,8 +15,10 @@
= form.input :upper_corner, input_html: { title: t("formtastic.titles.referential.upper_corner") }
= form.input :lower_corner, input_html: { title: t("formtastic.titles.referential.lower_corner") }
= form.input :data_format, label: true, include_blank: false
+ - if @referential.created_from
+ = form.input :created_from
- = form.inputs for: [:referential_metadata, @referential.referential_metadata] do |meta|
+ = form.inputs for: [:referential_metadatas, @referential.referential_metadatas] do |meta|
= meta.inputs :referential_source
= form.actions do
diff --git a/app/views/offer_workbenches/_referential.html.slim b/app/views/workbenches/_referential.html.slim
index cc1964f30..cc1964f30 100644
--- a/app/views/offer_workbenches/_referential.html.slim
+++ b/app/views/workbenches/_referential.html.slim
diff --git a/app/views/offer_workbenches/show.html.slim b/app/views/workbenches/show.html.slim
index 49396a0e2..49396a0e2 100644
--- a/app/views/offer_workbenches/show.html.slim
+++ b/app/views/workbenches/show.html.slim
diff --git a/app/workers/referential_cloning_worker.rb b/app/workers/referential_cloning_worker.rb
new file mode 100644
index 000000000..dda569d7c
--- /dev/null
+++ b/app/workers/referential_cloning_worker.rb
@@ -0,0 +1,24 @@
+class ReferentialCloningWorker
+ include Sidekiq::Worker
+
+ def perform(id)
+ # Replace default apartment created schema with clone schema from source referential
+ ref_cloning = ReferentialCloning.find id
+ sql_func = "CREATE OR REPLACE FUNCTION clone_schema( source_schema text, dest_schema text, include_recs boolean) RETURNS void AS $BODY$ DECLARE src_oid oid; tbl_oid oid; func_oid oid; object text; buffer text; srctbl text; default_ text; column_ text; qry text; dest_qry text; v_def text; seqval bigint; sq_last_value bigint; sq_max_value bigint; sq_start_value bigint; sq_increment_by bigint; sq_min_value bigint; sq_cache_value bigint; sq_log_cnt bigint; sq_is_called boolean; sq_is_cycled boolean; sq_cycled char(10); BEGIN SELECT oid INTO src_oid FROM pg_namespace WHERE nspname = quote_ident(source_schema); IF NOT FOUND THEN RAISE NOTICE 'source schema % does not exist!', source_schema; RETURN ; END IF; PERFORM nspname FROM pg_namespace WHERE nspname = quote_ident(dest_schema); IF FOUND THEN RAISE NOTICE 'dest schema % already exists!', dest_schema; RETURN ; END IF; EXECUTE 'CREATE SCHEMA ' || quote_ident(dest_schema) ; FOR object IN SELECT sequence_name::text FROM information_schema.sequences WHERE sequence_schema = quote_ident(source_schema) LOOP EXECUTE 'CREATE SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object); srctbl := quote_ident(source_schema) || '.' || quote_ident(object); EXECUTE 'SELECT last_value, max_value, start_value, increment_by, min_value, cache_value, log_cnt, is_cycled, is_called FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';' INTO sq_last_value, sq_max_value, sq_start_value, sq_increment_by, sq_min_value, sq_cache_value, sq_log_cnt, sq_is_cycled, sq_is_called ; IF sq_is_cycled THEN sq_cycled := 'CYCLE'; ELSE sq_cycled := 'NO CYCLE'; END IF; EXECUTE 'ALTER SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object) || ' INCREMENT BY ' || sq_increment_by || ' MINVALUE ' || sq_min_value || ' MAXVALUE ' || sq_max_value || ' START WITH ' || sq_start_value || ' RESTART ' || sq_min_value || ' CACHE ' || sq_cache_value || sq_cycled || ' ;' ; buffer := quote_ident(dest_schema) || '.' || quote_ident(object); IF include_recs THEN EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_last_value || ', ' || sq_is_called || ');' ; ELSE EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_start_value || ', ' || sq_is_called || ');' ; END IF; END LOOP; FOR object IN SELECT TABLE_NAME::text FROM information_schema.tables WHERE table_schema = quote_ident(source_schema) AND table_type = 'BASE TABLE' LOOP buffer := dest_schema || '.' || quote_ident(object); EXECUTE 'CREATE TABLE ' || buffer || '(LIKE ' || quote_ident(source_schema) || '.' || quote_ident(object) || ' INCLUDING ALL)'; IF include_recs THEN EXECUTE 'INSERT INTO ' || buffer || ' SELECT * FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';'; END IF; FOR column_, default_ IN SELECT column_name::text, REPLACE(column_default::text, source_schema, dest_schema) FROM information_schema.COLUMNS WHERE table_schema = dest_schema AND TABLE_NAME = object AND column_default LIKE 'nextval(%' || quote_ident(source_schema) || '%::regclass)' LOOP EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_; END LOOP; END LOOP; FOR qry IN SELECT 'ALTER TABLE ' || quote_ident(dest_schema) || '.' || quote_ident(rn.relname) || ' ADD CONSTRAINT ' || quote_ident(ct.conname) || ' ' || pg_get_constraintdef(ct.oid) || ';' FROM pg_constraint ct JOIN pg_class rn ON rn.oid = ct.conrelid WHERE connamespace = src_oid AND rn.relkind = 'r' AND ct.contype = 'f' LOOP EXECUTE qry; END LOOP; FOR object IN SELECT table_name::text, view_definition FROM information_schema.views WHERE table_schema = quote_ident(source_schema) LOOP buffer := dest_schema || '.' || quote_ident(object); SELECT view_definition INTO v_def FROM information_schema.views WHERE table_schema = quote_ident(source_schema) AND table_name = quote_ident(object); EXECUTE 'CREATE OR REPLACE VIEW ' || buffer || ' AS ' || v_def || ';' ; END LOOP; FOR func_oid IN SELECT oid FROM pg_proc WHERE pronamespace = src_oid LOOP SELECT pg_get_functiondef(func_oid) INTO qry; SELECT replace(qry, source_schema, dest_schema) INTO dest_qry; EXECUTE dest_qry; END LOOP; RETURN; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100;"
+ sql_clone = "SELECT clone_schema('#{ref_cloning.source_referential.slug}', '#{ref_cloning.target_referential.slug}_tmp', TRUE);"
+ sql_drop = "DROP SCHEMA #{ref_cloning.target_referential.slug} CASCADE;"
+ sql_rename = "ALTER SCHEMA #{ref_cloning.target_referential.slug}_tmp RENAME TO #{ref_cloning.target_referential.slug};"
+ ref_cloning.run!
+
+ begin
+ ActiveRecord::Base.connection.execute sql_func
+ ActiveRecord::Base.connection.execute sql_clone
+ ActiveRecord::Base.connection.execute sql_drop
+ ActiveRecord::Base.connection.execute sql_rename
+ ref_cloning.successful!
+ rescue Exception => e
+ Rails.logger.error "ReferentialCloningWorker : #{e}"
+ ref_cloning.failed!
+ end
+ end
+end
diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb
index db352fa6f..7a3549c02 100644
--- a/config/initializers/apartment.rb
+++ b/config/initializers/apartment.rb
@@ -34,7 +34,9 @@ Apartment.configure do |config|
"Chouette::Line",
"Chouette::GroupOfLine",
"Chouette::Company",
- "Chouette::Network"
+ "Chouette::Network",
+ "ReferentialCloning",
+ "Workbench"
]
# use postgres schemas?
diff --git a/config/routes.rb b/config/routes.rb
index 4b4411ea5..842efda84 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -9,6 +9,7 @@ ChouetteIhm::Application.routes.draw do
devise_scope :user do
authenticated :user do
+ mount Sidekiq::Web => '/sidekiq'
root :to => 'referentials#index', as: :authenticated_root
end
diff --git a/db/migrate/20161024123819_add_created_from_to_referentials.rb b/db/migrate/20161024123819_add_created_from_to_referentials.rb
new file mode 100644
index 000000000..a125a0c21
--- /dev/null
+++ b/db/migrate/20161024123819_add_created_from_to_referentials.rb
@@ -0,0 +1,5 @@
+class AddCreatedFromToReferentials < ActiveRecord::Migration
+ def change
+ add_reference :referentials, :created_from, index: true
+ end
+end
diff --git a/db/migrate/20161024135931_create_referential_clonings.rb b/db/migrate/20161024135931_create_referential_clonings.rb
new file mode 100644
index 000000000..d82f30bb1
--- /dev/null
+++ b/db/migrate/20161024135931_create_referential_clonings.rb
@@ -0,0 +1,13 @@
+class CreateReferentialClonings < ActiveRecord::Migration
+ def change
+ create_table :referential_clonings do |t|
+ t.string :status
+ t.datetime :started_at
+ t.datetime :ended_at
+ t.references :source_referential, index: true
+ t.references :target_referential, index: true
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d54bc86e1..3e877de49 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20161020093344) do
+ActiveRecord::Schema.define(version: 20161024135931) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -377,6 +377,19 @@ ActiveRecord::Schema.define(version: 20161020093344) do
add_index "pt_links", ["objectid"], :name => "pt_links_objectid_key", :unique => true
+ create_table "referential_clonings", force: true do |t|
+ t.string "status"
+ t.datetime "started_at"
+ t.datetime "ended_at"
+ t.integer "source_referential_id"
+ t.integer "target_referential_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "referential_clonings", ["source_referential_id"], :name => "index_referential_clonings_on_source_referential_id"
+ add_index "referential_clonings", ["target_referential_id"], :name => "index_referential_clonings_on_target_referential_id"
+
create_table "referential_metadata", force: true do |t|
t.integer "referential_id"
t.integer "line_ids", array: true
@@ -408,8 +421,11 @@ ActiveRecord::Schema.define(version: 20161020093344) do
t.integer "stop_area_referential_id"
t.integer "workbench_id"
t.datetime "archived_at"
+ t.integer "created_from_id"
end
+ add_index "referentials", ["created_from_id"], :name => "index_referentials_on_created_from_id"
+
create_table "route_sections", force: true do |t|
t.integer "departure_id", limit: 8
t.integer "arrival_id", limit: 8
diff --git a/spec/factories/referential_clonings.rb b/spec/factories/referential_clonings.rb
new file mode 100644
index 000000000..e968d44f1
--- /dev/null
+++ b/spec/factories/referential_clonings.rb
@@ -0,0 +1,6 @@
+FactoryGirl.define do
+ factory :referential_cloning do
+ association :source_referential, :factory => :referential
+ association :target_referential, :factory => :referential
+ end
+end
diff --git a/spec/features/companies_spec.rb b/spec/features/companies_spec.rb
index adb5fa9f9..08221f637 100644
--- a/spec/features/companies_spec.rb
+++ b/spec/features/companies_spec.rb
@@ -11,8 +11,8 @@ describe "Companies", :type => :feature do
describe "list" do
it "display companies" do
visit line_referential_companies_path(line_referential)
- expect(page).to have_content(companies.first.name)
- expect(page).to have_content(companies.last.name)
+ expect(page).to have_content(companies.first.short_name)
+ expect(page).to have_content(companies.last.short_name)
end
end
diff --git a/spec/models/referential_cloning_spec.rb b/spec/models/referential_cloning_spec.rb
new file mode 100644
index 000000000..30391b53e
--- /dev/null
+++ b/spec/models/referential_cloning_spec.rb
@@ -0,0 +1,10 @@
+require 'rails_helper'
+
+RSpec.describe ReferentialCloning, :type => :model do
+ it 'should have a valid factory' do
+ expect(FactoryGirl.build(:referential_cloning)).to be_valid
+ end
+
+ it { should belong_to :source_referential }
+ it { should belong_to :target_referential }
+end
diff --git a/spec/models/referential_spec.rb b/spec/models/referential_spec.rb
index f8e6ffacc..c76b157f8 100644
--- a/spec/models/referential_spec.rb
+++ b/spec/models/referential_spec.rb
@@ -1,12 +1,25 @@
require 'spec_helper'
describe Referential, :type => :model do
+ let(:ref) { create :referential }
- it "create a rule_parameter_set" do
- referential = create(:referential)
+ # it "create a rule_parameter_set" do
+ # referential = create(:referential)
#expect(referential.rule_parameter_sets.size).to eq(1)
- end
+ # end
- it { should have_one(:referential_metadata) }
+ it { should have_many(:referential_metadatas) }
it { should belong_to(:workbench) }
+
+ context "Cloning referential" do
+ let(:cloned) { create(:referential, created_from: ref) }
+
+ it 'should create a ReferentialCloning' do
+ expect { cloned }.to change{ReferentialCloning.count}.by(1)
+ end
+
+ it 'should clone referential_metadatas' do
+ expect(cloned.referential_metadatas).not_to be_empty
+ end
+ end
end
diff --git a/spec/workers/referential_cloning_worker_spec.rb b/spec/workers/referential_cloning_worker_spec.rb
new file mode 100644
index 000000000..dd7b33f23
--- /dev/null
+++ b/spec/workers/referential_cloning_worker_spec.rb
@@ -0,0 +1,4 @@
+require 'rails_helper'
+RSpec.describe ReferentialCloningWorker, type: :worker do
+ pending "add some examples to (or delete) #{__FILE__}"
+end