diff options
19 files changed, 200 insertions, 83 deletions
diff --git a/app/controllers/autocomplete_stop_areas_controller.rb b/app/controllers/autocomplete_stop_areas_controller.rb index 233012028..be1badff0 100644 --- a/app/controllers/autocomplete_stop_areas_controller.rb +++ b/app/controllers/autocomplete_stop_areas_controller.rb @@ -18,7 +18,7 @@ class AutocompleteStopAreasController < ChouetteController scope = scope.possible_parents if relation_children? end args = [].tap{|arg| 4.times{arg << "%#{params[:q]}%"}} - @stop_areas = scope.where("name ILIKE ? OR city_name ILIKE ? OR registration_number ILIKE ? OR objectid ILIKE ?", *args).limit(50) + @stop_areas = scope.where("unaccent(name) ILIKE unaccent(?) OR unaccent(city_name) ILIKE unaccent(?) OR registration_number ILIKE ? OR objectid ILIKE ?", *args).limit(50) @stop_areas end diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index ee1236912..40e8264ce 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -17,6 +17,8 @@ class ReferentialsController < ChouetteController build_referenial if !!@referential.created_from_id + flash[:notice] = t('notice.referentials.duplicate') + format.html { redirect_to workbench_path(@referential.workbench) } end end @@ -60,7 +62,7 @@ class ReferentialsController < ChouetteController def validate ComplianceControlSetCopyWorker.perform_async(params[:compliance_control_set], params[:id]) - flash[:notice] = I18n.t("referentials.operation_in_progress") + flash[:notice] = t('notice.referentials.validate') redirect_to(referential_path) end diff --git a/app/decorators/company_decorator.rb b/app/decorators/company_decorator.rb index 9416c73ae..50b82d276 100644 --- a/app/decorators/company_decorator.rb +++ b/app/decorators/company_decorator.rb @@ -18,13 +18,6 @@ class CompanyDecorator < Draper::Decorator def action_links links = [] - if h.policy(Chouette::Company).create? - links << Link.new( - content: h.t('companies.actions.new'), - href: h.new_line_referential_company_path(context[:referential]) - ) - end - if h.policy(object).update? links << Link.new( content: h.t('companies.actions.edit'), @@ -37,7 +30,7 @@ class CompanyDecorator < Draper::Decorator if h.policy(object).destroy? links << Link.new( - content: t('companies.actions.destroy'), + content: h.destroy_link_content('companies.actions.destroy'), href: h.line_referential_company_path( context[:referential], object diff --git a/app/models/referential_cloning.rb b/app/models/referential_cloning.rb index 5bf283814..24117e6c8 100644 --- a/app/models/referential_cloning.rb +++ b/app/models/referential_cloning.rb @@ -2,14 +2,27 @@ 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 + after_commit :clone, on: :create - private - def perform_clone + def clone ReferentialCloningWorker.perform_async(id) - # ReferentialCloningWorker.new.perform(id) end + def clone! + run! + + AF83::SchemaCloner + .new(source_referential.slug, target_referential.slug) + .clone_schema + + successful! + rescue Exception => e + Rails.logger.error "Clone failed : #{e}" + failed! + end + + private + aasm column: :status do state :new, :initial => true state :pending diff --git a/app/views/companies/index.html.slim b/app/views/companies/index.html.slim index 5d746642f..e031f3776 100644 --- a/app/views/companies/index.html.slim +++ b/app/views/companies/index.html.slim @@ -34,7 +34,7 @@ end \ ) \ ], - links: [:show, :edit], + links: [:show], cls: 'table has-search' = new_pagination @companies, 'pull-right' diff --git a/app/views/layouts/navigation/_main_nav_top.html.slim b/app/views/layouts/navigation/_main_nav_top.html.slim index d6c849d3f..363a89b48 100644 --- a/app/views/layouts/navigation/_main_nav_top.html.slim +++ b/app/views/layouts/navigation/_main_nav_top.html.slim @@ -11,7 +11,7 @@ span.fa.fa-lg.fa-tasks = link_to '#', class: 'menu-item', data: { panel: 'toggle', target: '#profile_panel' }, title: 'Profil' do - span = current_user.username + span = current_user.name span.fa.fa-lg.fa-user diff --git a/app/views/referential_companies/index.html.slim b/app/views/referential_companies/index.html.slim index de0f7de69..07de2bc9d 100644 --- a/app/views/referential_companies/index.html.slim +++ b/app/views/referential_companies/index.html.slim @@ -46,7 +46,7 @@ attribute: 'url' \ ) \ ], - links: [:show, :edit], + links: [:show], cls: 'table has-search' = new_pagination @companies, 'pull-right' diff --git a/app/workers/referential_cloning_worker.rb b/app/workers/referential_cloning_worker.rb index 6592160ec..e20148055 100644 --- a/app/workers/referential_cloning_worker.rb +++ b/app/workers/referential_cloning_worker.rb @@ -1,32 +1,7 @@ class ReferentialCloningWorker include Sidekiq::Worker - # Replace default apartment created schema with clone schema from source referential def perform(id) - ref_cloning = ReferentialCloning.find id - - source_schema = ref_cloning.source_referential.slug - target_schema = ref_cloning.target_referential.slug - - clone_schema ref_cloning, source_schema, target_schema - end - - private - - def clone_schema ref_cloning, source_schema, target_schema - ref_cloning.run! - - AF83::SchemaCloner - .new(source_schema, target_schema) - .clone_schema - - ref_cloning.successful! - rescue Exception => e - Rails.logger.error "ReferentialCloningWorker : #{e}" - ref_cloning.failed! - end - - def execute_sql sql - ActiveRecord::Base.connection.execute sql + ReferentialCloning.find(id).clone! end end diff --git a/config/locales/imports.en.yml b/config/locales/imports.en.yml index 0bb54d90d..462b17196 100644 --- a/config/locales/imports.en.yml +++ b/config/locales/imports.en.yml @@ -74,3 +74,7 @@ en: max_distance_for_connection_link: "Max distance for connection link" ignore_last_word: "ignore last word" ignore_end_chars: "ignore last chars" + flash: + imports: + create: + notice: "The import is in progress. Please wait and refresh the page in a few moments." diff --git a/config/locales/imports.fr.yml b/config/locales/imports.fr.yml index 207f5cc31..b545f90df 100644 --- a/config/locales/imports.fr.yml +++ b/config/locales/imports.fr.yml @@ -74,3 +74,7 @@ fr: max_distance_for_connection_link: "Distance max pour créer les correspondances" ignore_last_word: "ignorer le dernier mot" ignore_end_chars: "ignorer les n derniers caractères" + flash: + imports: + create: + notice: "L'import est en cours, veuillez patienter. Actualiser votre page si vous voulez voir l'avancement de votre traitement." diff --git a/config/locales/referentials.en.yml b/config/locales/referentials.en.yml index 8420e9539..f41e35446 100644 --- a/config/locales/referentials.en.yml +++ b/config/locales/referentials.en.yml @@ -5,7 +5,6 @@ en: name: 'Search by name' line: 'Seach by associated lines' search_no_results: 'No data space matching your query' - operation_in_progress: The validation process is in progress error_period_filter: "The period filter must have valid bounding dates" index: title: 'Data spaces' @@ -126,6 +125,8 @@ en: notice: referentials: deleted: "Datasets has been successfully destroyed" + duplicate: "The duplication is in progress. Please wait and refresh the page in a few moments." + validate: "The validation is in progress. Please wait and refresh the page in a few moments." referential: archived: "The data space has been successfully archived" unarchived: "The data space has been successfully unarchived" diff --git a/config/locales/referentials.fr.yml b/config/locales/referentials.fr.yml index ec7ed776d..9250a033c 100644 --- a/config/locales/referentials.fr.yml +++ b/config/locales/referentials.fr.yml @@ -5,7 +5,6 @@ fr: name: 'Indiquez un nom de jeu de données...' line: 'Indiquez une ligne...' search_no_results: 'Aucun jeu de données ne correspond à votre recherche' - operation_in_progress: L'opération de validation est en cours error_period_filter: "Le filtre par période doit contenir une date de début et de fin valides" index: title: 'Jeux de données' @@ -124,6 +123,8 @@ fr: notice: referentials: deleted: "Les jeux de données on été supprimés" + duplicate: "La duplication est en cours, veuillez patienter. Actualiser votre page si vous voulez voir l'avancement de votre traitement." + validate: "La validation est en cours, veuillez patienter. Actualiser votre page si vous voulez voir l'avancement de votre traitement." referential: archived: "Le jeu de données a été correctement conservé" unarchived: "Le jeu de données a été correctement déconservé" diff --git a/db/migrate/20171214130636_enable_unaccent_extension.rb b/db/migrate/20171214130636_enable_unaccent_extension.rb new file mode 100644 index 000000000..f7411b1f4 --- /dev/null +++ b/db/migrate/20171214130636_enable_unaccent_extension.rb @@ -0,0 +1,9 @@ +class EnableUnaccentExtension < ActiveRecord::Migration + def up + execute 'CREATE EXTENSION IF NOT EXISTS unaccent SCHEMA shared_extensions;' + end + + def down + execute 'DROP EXTENSION IF EXISTS unaccent SCHEMA shared_extensions;' + end +end diff --git a/db/schema.rb b/db/schema.rb index 4a04dac26..f2642f8fc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,12 +11,13 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171130180144) do +ActiveRecord::Schema.define(version: 20171214130636) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" enable_extension "postgis" enable_extension "hstore" + enable_extension "unaccent" create_table "access_links", id: :bigserial, force: :cascade do |t| t.integer "access_point_id", limit: 8 diff --git a/spec/controllers/autocomplete_stop_areas_controller_spec.rb b/spec/controllers/autocomplete_stop_areas_controller_spec.rb new file mode 100644 index 000000000..50fc877dd --- /dev/null +++ b/spec/controllers/autocomplete_stop_areas_controller_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe AutocompleteStopAreasController, type: :controller do + login_user + + let(:referential) { Referential.first } + let!(:stop_area) { create :stop_area, name: 'écolà militaire' } + + describe 'GET #index' do + it 'should be successful' do + get :index, referential_id: referential.id + expect(response).to be_success + end + + context 'search by name' do + it 'should be successful' do + get :index, referential_id: referential.id, q: 'écolà', :format => :json + expect(response).to be_success + expect(assigns(:stop_areas)).to eq([stop_area]) + end + + it 'should be accent insensitive' do + get :index, referential_id: referential.id, q: 'ecola', :format => :json + expect(response).to be_success + expect(assigns(:stop_areas)).to eq([stop_area]) + end + end + end +end diff --git a/spec/controllers/imports_controller_spec.rb b/spec/controllers/imports_controller_spec.rb index 22be9f6ed..08495ff47 100644 --- a/spec/controllers/imports_controller_spec.rb +++ b/spec/controllers/imports_controller_spec.rb @@ -17,6 +17,20 @@ RSpec.describe ImportsController, :type => :controller do end end + describe "POST #create" do + it "displays a flash message" do + post :create, workbench_id: workbench.id, + import: { + name: 'Offre', + file: fixture_file_upload('nozip.zip') + } + + expect(controller).to set_flash[:notice].to( + I18n.t('flash.imports.create.notice') + ) + end + end + describe 'GET #download' do it 'should be successful' do get :download, workbench_id: workbench.id, id: import.id, token: import.token_download diff --git a/spec/controllers/referentials_controller_spec.rb b/spec/controllers/referentials_controller_spec.rb index fba063085..4050a8812 100644 --- a/spec/controllers/referentials_controller_spec.rb +++ b/spec/controllers/referentials_controller_spec.rb @@ -30,4 +30,33 @@ describe ReferentialsController, :type => :controller do expect(assigns[:compliance_control_sets]).to eq([compliance_control_set]) end end + + describe "POST #validate" do + it "displays a flash message" do + post :validate, id: referential.id, params: { + compliance_control_set: create(:compliance_control_set).id + } + + expect(controller).to set_flash[:notice].to( + I18n.t('notice.referentials.validate') + ) + end + end + + describe "POST #create" do + context "when duplicating" do + it "displays a flash message" do + post :create, + from: referential.id, + current_workbench_id: referential.workbench_id, + referential: { + name: 'Duplicated' + } + + expect(controller).to set_flash[:notice].to( + I18n.t('notice.referentials.duplicate') + ) + end + end + end end diff --git a/spec/models/referential_cloning_spec.rb b/spec/models/referential_cloning_spec.rb index 5acd433ec..4327c98aa 100644 --- a/spec/models/referential_cloning_spec.rb +++ b/spec/models/referential_cloning_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' RSpec.describe ReferentialCloning, :type => :model do + it 'should have a valid factory' do expect(FactoryGirl.build(:referential_cloning)).to be_valid end @@ -8,11 +9,69 @@ RSpec.describe ReferentialCloning, :type => :model do it { should belong_to :source_referential } it { should belong_to :target_referential } - describe "ReferentialCloningWorker" do + describe 'after commit' do + let(:referential_cloning) { FactoryGirl.create(:referential_cloning) } + + it 'invoke clone method' do + expect(referential_cloning).to receive(:clone) + referential_cloning.run_callbacks(:commit) + end + end + + describe '#clone' do let(:referential_cloning) { FactoryGirl.create(:referential_cloning) } it "should schedule a job in worker" do - expect{referential_cloning.run_callbacks(:commit)}.to change {ReferentialCloningWorker.jobs.count}.by(1) + expect{referential_cloning.clone}.to change {ReferentialCloningWorker.jobs.count}.by(1) + end + end + + describe '#clone!' do + let(:source_referential) { Referential.new slug: "source"} + let(:target_referential) { Referential.new slug: "target"} + let(:referential_cloning) do + ReferentialCloning.new source_referential: source_referential, + target_referential: target_referential + end + + let(:cloner) { double } + + before do + allow(AF83::SchemaCloner).to receive(:new).and_return cloner + allow(cloner).to receive(:clone_schema) end + + it 'creates a schema cloner with source and target schemas and clone schema' do + expect(AF83::SchemaCloner).to receive(:new).with(source_referential.slug, target_referential.slug).and_return(cloner) + expect(cloner).to receive(:clone_schema) + + referential_cloning.clone! + end + + context 'when clone_schema is performed without error' do + it "should have successful status" do + referential_cloning.clone! + expect(referential_cloning.status).to eq("successful") + end + end + + context 'when clone_schema raises an error' do + it "should have failed status" do + expect(cloner).to receive(:clone_schema).and_raise("#fail") + referential_cloning.clone! + expect(referential_cloning.status).to eq("failed") + end + end + + it "defines started_at" do + referential_cloning.clone! + expect(referential_cloning.started_at).not_to be_nil + end + + it "defines ended_at" do + referential_cloning.clone! + expect(referential_cloning.ended_at).not_to be_nil + end + end end diff --git a/spec/workers/referential_cloning_worker_spec.rb b/spec/workers/referential_cloning_worker_spec.rb index 7e4a2357a..2b9a54805 100644 --- a/spec/workers/referential_cloning_worker_spec.rb +++ b/spec/workers/referential_cloning_worker_spec.rb @@ -2,52 +2,35 @@ require 'spec_helper' require 'ostruct' RSpec.describe ReferentialCloningWorker do + alias_method :worker, :subject context "given a referential cloning" do + let(:id) { double } + let(:referential_cloning) { double } - let( :id ){ double } + it "invokes the clone! method of the associated ReferentialCloning" do + expect(ReferentialCloning).to receive(:find).with(id).and_return(referential_cloning) + expect(referential_cloning).to receive(:clone!) - let( :worker ){ described_class.new } - - def make_referential(schema_name) - return OpenStruct.new( slug: schema_name ) - end - - let( :source_schema ){ "source_schema" } - let( :target_schema ){ "target_schema" } - let( :referential_cloning ){ OpenStruct.new(source_referential: make_referential(source_schema), - target_referential: make_referential(target_schema)) } - let( :cloner ){ 'cloner' } - - - before do - expect( ReferentialCloning ).to receive(:find).with(id).and_return(referential_cloning) - expect( AF83::SchemaCloner ).to receive(:new).with( source_schema, target_schema ).and_return(cloner) - expect( cloner ).to receive(:clone_schema) - - expect( referential_cloning ).to receive(:run!) - end - - it "invokes the correct stored procedure, updates the database and the AASM" do - expect( referential_cloning ).to receive(:successful!) worker.perform(id) end end - it "should clone an existing Referential" do - source_referential = create :referential - - source_referential.switch - source_time_table = create :time_table + context 'with existing Referential' do + it "preserve existing data" do + source_referential = create :referential - target_referential = create :referential, created_from: source_referential + source_referential.switch + source_time_table = create :time_table - cloning = ReferentialCloning.create source_referential: source_referential, target_referential: target_referential - ReferentialCloningWorker.new.perform(cloning) + target_referential = create :referential, created_from: source_referential - target_referential.switch - expect(Chouette::TimeTable.where(objectid: source_time_table.objectid).exists?) - end + cloning = ReferentialCloning.create source_referential: source_referential, target_referential: target_referential + worker.perform(cloning.id) + target_referential.switch + expect(Chouette::TimeTable.where(objectid: source_time_table.objectid).exists?) + end + end end |
