From c180636da2f237d44e088f677e0df1e6130866f5 Mon Sep 17 00:00:00 2001
From: Zog
Date: Thu, 14 Dec 2017 16:42:00 +0100
Subject: Remove duplicate links in StopArea index view
Refs #5287
---
 app/views/stop_areas/index.html.slim | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/stop_areas/index.html.slim b/app/views/stop_areas/index.html.slim
index c4d880081..99b399f5c 100644
--- a/app/views/stop_areas/index.html.slim
+++ b/app/views/stop_areas/index.html.slim
@@ -51,7 +51,7 @@
                 attribute: Proc.new { |s| (s.area_type.nil? ? '-' : t("enumerize.stop_area.area_type.#{s.try(:area_type)}")) } \
               ), \
             ],
-            links: [:show, :edit, :delete],
+            links: [:show],
             cls: 'table has-filter has-search'
 
           = new_pagination @stop_areas, 'pull-right'
-- 
cgit v1.2.3
From 88b8e30a415f300108be4a19a53ca9768671d21e Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 15 Dec 2017 09:11:04 +0100
Subject: Refs #5287;
Add specs for the view.
Refactor to come
---
 app/helpers/table_builder_helper.rb          | 10 +++-
 spec/helpers/table_builder_helper_spec.rb    |  6 +--
 spec/support/integration_spec_helper.rb      | 17 ++++++
 spec/support/pundit/pundit_view_policy.rb    | 16 +++---
 spec/views/stop_areas/index.html.erb_spec.rb | 78 +++++++++++++++++++++++-----
 5 files changed, 102 insertions(+), 25 deletions(-)
 create mode 100644 spec/support/integration_spec_helper.rb
diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb
index 37f01ce0d..64bec6bae 100644
--- a/app/helpers/table_builder_helper.rb
+++ b/app/helpers/table_builder_helper.rb
@@ -188,10 +188,16 @@ module TableBuilderHelper
   end
 
   def tbody(collection, columns, selectable, links, overhead)
+    if collection.respond_to?(:model)
+      model_name = collection.model.name.split("::").last
+    else
+      model_name = "item"
+    end
+
     content_tag :tbody do
       collection.map do |item|
-
-        content_tag :tr do
+        klass = "#{model_name.parameterize}-#{item.id}"
+        content_tag :tr, class: klass do
           bcont = []
 
           if selectable
diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb
index 3b0a18379..3b3504c60 100644
--- a/spec/helpers/table_builder_helper_spec.rb
+++ b/spec/helpers/table_builder_helper_spec.rb
@@ -59,7 +59,7 @@ describe TableBuilderHelper, type: :helper do
         
     
     
-        
+        
             | @@ -213,7 +213,7 @@ describe TableBuilderHelper, type: :helper do | 
     
     
-        
+        
             | #{company.get_objectid.local_id} | #{company.name} | @@ -326,7 +326,7 @@ describe TableBuilderHelper, type: :helper do | 
     
     
-        
+        
             | #{company.get_objectid.local_id} | #{company.name} | diff --git a/spec/support/integration_spec_helper.rb b/spec/support/integration_spec_helper.rb
new file mode 100644
index 000000000..958aab9d5
--- /dev/null
+++ b/spec/support/integration_spec_helper.rb
@@ -0,0 +1,17 @@
+module IntegrationSpecHelper
+  extend ActiveSupport::Concern
+
+  included do
+    def self.with_permission permission, &block
+      context "with permission #{permission}" do
+        let(:permissions){ [permission] }
+        context('', &block) if block_given?
+      end
+    end
+  end
+end
+
+
+RSpec.configure do |config|
+  config.include IntegrationSpecHelper, type: :view
+end
diff --git a/spec/support/pundit/pundit_view_policy.rb b/spec/support/pundit/pundit_view_policy.rb
index b8434cac0..02a78a4e0 100644
--- a/spec/support/pundit/pundit_view_policy.rb
+++ b/spec/support/pundit/pundit_view_policy.rb
@@ -3,14 +3,16 @@ module Pundit
     extend ActiveSupport::Concern
 
     included do
+
+      let(:permissions){ nil }
+      let(:current_referential){ build_stubbed :referential }
+      let(:current_user){ build_stubbed :user, permissions: permissions }
+      let(:pundit_user){ UserContext.new(current_user, referential: current_referential) }
       before do
-        controller.singleton_class.class_eval do
-          def policy(instance)
-            Class.new do
-              def method_missing(*args, &block); true; end
-            end.new
-          end
-          helper_method :policy
+        allow(view).to receive(:pundit_user) { pundit_user }
+
+        allow(view).to receive(:policy) do |instance|
+          ::Pundit.policy pundit_user, instance
         end
       end
     end
diff --git a/spec/views/stop_areas/index.html.erb_spec.rb b/spec/views/stop_areas/index.html.erb_spec.rb
index 2dfae1bfd..a354586d2 100644
--- a/spec/views/stop_areas/index.html.erb_spec.rb
+++ b/spec/views/stop_areas/index.html.erb_spec.rb
@@ -1,25 +1,77 @@
 require 'spec_helper'
 
 describe "/stop_areas/index", :type => :view do
-
   let!(:stop_area_referential) { assign :stop_area_referential, create(:stop_area_referential) }
-  let!(:stop_areas) { assign :stop_areas, Array.new(2) { create(:stop_area, stop_area_referential: stop_area_referential) }.paginate }
+  let!(:stop_areas) do
+    2.times { create(:stop_area, stop_area_referential: stop_area_referential) }
+    assign :stop_areas, ModelDecorator.decorate( Chouette::StopArea.page(1), with: StopAreaDecorator )
+  end
   let!(:q) { assign :q, Ransack::Search.new(Chouette::StopArea) }
 
   before :each do
     allow(view).to receive(:link_with_search).and_return("#")
+    allow(view).to receive(:collection).and_return(stop_areas)
+    allow(view).to receive(:current_referential).and_return(stop_area_referential)
+    controller.request.path_parameters[:stop_area_referential_id] = stop_area_referential.id
+    render
+  end
+
+  it "should render a row for each group" do
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id}", count: 1)
+    end
+  end
+
+  it "should render a show link for each group" do
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", count: 1)
+    end
+  end
+
+  it "should render no other link for each group" do
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: 1)
+    end
   end
 
-  # it "should render a show link for each group" do
-  #   render
-  #   stop_areas.each do |stop_area|
-  #     expect(rendered).to have_selector(".stop_area a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", :text => stop_area.name)
-  #   end
-  # end
-  #
-  # it "should render a link to create a new group" do
-  #   render
-  #   expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{new_stop_area_referential_stop_area_path(stop_area_referential)}']")
-  # end
+  with_permission "stop_areas.create" do
+    it "should render a show link for each group" do
+      stop_areas.each do |stop_area|
+        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", count: 1)
+      end
+    end
+
+    it "should render a create link for each group" do
+      stop_areas.each do |stop_area|
+        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.new_stop_area_referential_stop_area_path(stop_area_referential)}']", count: 1)
+      end
+    end
+
+    it "should render no other link for each group" do
+      stop_areas.each do |stop_area|
+        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: 2)
+      end
+    end
+  end
+
+  with_permission "stop_areas.update" do
+    it "should render a show link for each group" do
+      stop_areas.each do |stop_area|
+        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", count: 1)
+      end
+    end
+
+    it "should render a edit link for each group" do
+      stop_areas.each do |stop_area|
+        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area.id)}']", count: 1)
+      end
+    end
+
+    it "should render no other link for each group" do
+      stop_areas.each do |stop_area|
+        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: 2)
+      end
+    end
+  end
 
 end
-- 
cgit v1.2.3
From cd92a6e07393b1b6ee57a8d980f072aa8a034874 Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 15 Dec 2017 11:27:14 +0100
Subject: - Fix specs on connections_links/index - Fix specs on
 connections_links/show - Update pundit view specs helper to use the current
 referential when it has already been defined
---
 spec/support/pundit/pundit_view_policy.rb          |  5 +++--
 spec/views/connection_links/index.html.erb_spec.rb |  8 +++++---
 spec/views/connection_links/show.html.erb_spec.rb  | 23 ++++++++++------------
 3 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/spec/support/pundit/pundit_view_policy.rb b/spec/support/pundit/pundit_view_policy.rb
index 02a78a4e0..6a663a471 100644
--- a/spec/support/pundit/pundit_view_policy.rb
+++ b/spec/support/pundit/pundit_view_policy.rb
@@ -5,8 +5,9 @@ module Pundit
     included do
 
       let(:permissions){ nil }
-      let(:current_referential){ build_stubbed :referential }
-      let(:current_user){ build_stubbed :user, permissions: permissions }
+      let(:organisation){ referential.try(:organisation) }
+      let(:current_referential){ referential || build_stubbed(:referential) }
+      let(:current_user){ build_stubbed :user, permissions: permissions, organisation: organisation }
       let(:pundit_user){ UserContext.new(current_user, referential: current_referential) }
       before do
         allow(view).to receive(:pundit_user) { pundit_user }
diff --git a/spec/views/connection_links/index.html.erb_spec.rb b/spec/views/connection_links/index.html.erb_spec.rb
index a01380094..1f133e31e 100644
--- a/spec/views/connection_links/index.html.erb_spec.rb
+++ b/spec/views/connection_links/index.html.erb_spec.rb
@@ -17,9 +17,11 @@ describe "/connection_links/index", :type => :view do
     end
   end
 
-  it "should render a link to create a new group" do
-    render
-    expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{new_referential_connection_link_path(referential)}']")
+  with_permission "connection_links.create" do
+    it "should render a link to create a new group" do
+      render
+      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{new_referential_connection_link_path(referential)}']")
+    end
   end
 
 end
diff --git a/spec/views/connection_links/show.html.erb_spec.rb b/spec/views/connection_links/show.html.erb_spec.rb
index c04a4f3f1..afe94fc6c 100644
--- a/spec/views/connection_links/show.html.erb_spec.rb
+++ b/spec/views/connection_links/show.html.erb_spec.rb
@@ -15,21 +15,18 @@ describe "/connection_links/show", :type => :view do
     expect(rendered).to have_selector("h2", :text => Regexp.new(connection_link.name))
   end
 
-#  it "should display a map with class 'connection_link'" do
-#    pending ": map not yet implemented"
-#     render
-#     expect(rendered).to have_selector("#map", :class => 'connection_link')
-#  end
-
-  it "should render a link to edit the connection_link" do
-    render
-    expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.edit_referential_connection_link_path(referential, connection_link)}']")
+  with_permission "connection_links.update" do
+    it "should render a link to edit the connection_link" do
+      render
+      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.edit_referential_connection_link_path(referential, connection_link)}']")
+    end
   end
 
-  it "should render a link to remove the connection_link" do
-    render
-    expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.referential_connection_link_path(referential, connection_link)}'][class='remove']")
+  with_permission "connection_links.destroy" do
+    it "should render a link to remove the connection_link" do
+      render
+      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.referential_connection_link_path(referential, connection_link)}'][class='remove']")
+    end
   end
 
 end
-
-- 
cgit v1.2.3
From b4551be86b397ddd441f94d8d49490f0f9891c5b Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 15 Dec 2017 14:52:33 +0100
Subject: Refactor stopareas index specs
---
 spec/views/stop_areas/index.html.erb_spec.rb | 78 ++++++++++------------------
 1 file changed, 27 insertions(+), 51 deletions(-)
diff --git a/spec/views/stop_areas/index.html.erb_spec.rb b/spec/views/stop_areas/index.html.erb_spec.rb
index a354586d2..e0c50685c 100644
--- a/spec/views/stop_areas/index.html.erb_spec.rb
+++ b/spec/views/stop_areas/index.html.erb_spec.rb
@@ -1,6 +1,25 @@
 require 'spec_helper'
 
+RSpec::Matchers.define :have_link_for_each_stop_area do |stop_areas, name, href|
+  match do |actual|
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{href.call(stop_area)}']", count: 1)
+    end
+  end
+  description { "have #{name} link for each stop area" }
+end
+
+RSpec::Matchers.define :have_the_right_number_of_links do |stop_areas, count|
+  match do |actual|
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: count)
+    end
+  end
+  description { "have #{count} links for each stop area" }
+end
+
 describe "/stop_areas/index", :type => :view do
+
   let!(:stop_area_referential) { assign :stop_area_referential, create(:stop_area_referential) }
   let!(:stop_areas) do
     2.times { create(:stop_area, stop_area_referential: stop_area_referential) }
@@ -16,62 +35,19 @@ describe "/stop_areas/index", :type => :view do
     render
   end
 
-  it "should render a row for each group" do
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id}", count: 1)
-    end
-  end
-
-  it "should render a show link for each group" do
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", count: 1)
-    end
-  end
-
-  it "should render no other link for each group" do
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: 1)
-    end
-  end
+  it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+  it { should have_the_right_number_of_links(stop_areas, 1) }
 
   with_permission "stop_areas.create" do
-    it "should render a show link for each group" do
-      stop_areas.each do |stop_area|
-        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", count: 1)
-      end
-    end
-
-    it "should render a create link for each group" do
-      stop_areas.each do |stop_area|
-        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.new_stop_area_referential_stop_area_path(stop_area_referential)}']", count: 1)
-      end
-    end
-
-    it "should render no other link for each group" do
-      stop_areas.each do |stop_area|
-        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: 2)
-      end
-    end
+    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_stop_area(stop_areas, "create", -> (stop_area){ view.new_stop_area_referential_stop_area_path(stop_area_referential) }) }
+    it { should have_the_right_number_of_links(stop_areas, 2) }
   end
 
   with_permission "stop_areas.update" do
-    it "should render a show link for each group" do
-      stop_areas.each do |stop_area|
-        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.stop_area_referential_stop_area_path(stop_area_referential, stop_area)}']", count: 1)
-      end
-    end
-
-    it "should render a edit link for each group" do
-      stop_areas.each do |stop_area|
-        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area.id)}']", count: 1)
-      end
-    end
-
-    it "should render no other link for each group" do
-      stop_areas.each do |stop_area|
-        expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: 2)
-      end
-    end
+    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_stop_area(stop_areas, "edit", -> (stop_area){ view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_the_right_number_of_links(stop_areas, 2) }
   end
 
 end
-- 
cgit v1.2.3
From 2e8b3c13e0bb9bcc8e9026830cce47cb0c37af4a Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Thu, 14 Dec 2017 12:19:19 +0100
Subject: Make dashboard bloc title clickable
Refs #5302
---
 app/views/dashboards/_dashboard.html.slim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim
index f03301e23..e5aa5093a 100644
--- a/app/views/dashboards/_dashboard.html.slim
+++ b/app/views/dashboards/_dashboard.html.slim
@@ -5,7 +5,7 @@
         .panel-heading
           h3.panel-title.with_actions
             div
-              = workbench.name
+              = link_to workbench.name, workbench_path(workbench)
               span.badge.ml-xs = workbench.referentials.count if workbench.referentials.present?
 
             div
@@ -22,7 +22,7 @@
     .panel.panel-default
       .panel-heading
         h3.panel-title.with_actions
-          = "Modèles de calendrier"
+          = link_to "Modèles de calendrier", calendars_path
           div
             = link_to '', calendars_path, class: ' fa fa-chevron-right pull-right'
       - if @dashboard.current_organisation.calendars.present?
-- 
cgit v1.2.3
From df2f87fceea07fcf47c66666d74b47aa4b3c0eac Mon Sep 17 00:00:00 2001
From: Alban Peignier
Date: Thu, 14 Dec 2017 18:39:47 +0100
Subject: Define content_for page_header_title in Devise views. Refs #5309
---
 app/views/devise/invitations/edit.html.slim | 33 +++++++++++++++++------------
 app/views/devise/passwords/edit.html.slim   | 28 +++++++++++++-----------
 app/views/devise/passwords/new.html.slim    |  4 ++--
 app/views/devise/sessions/new.html.slim     |  2 ++
 4 files changed, 39 insertions(+), 28 deletions(-)
diff --git a/app/views/devise/invitations/edit.html.slim b/app/views/devise/invitations/edit.html.slim
index 6c9a6f436..7a22146c0 100644
--- a/app/views/devise/invitations/edit.html.slim
+++ b/app/views/devise/invitations/edit.html.slim
@@ -1,14 +1,19 @@
-.col-md-offset-2.col-md-8
-  .panel.panel-default
-    .panel-heading = t('devise.invitations.edit.header')
-    
-    .panel-body
-      = simple_form_for resource, as: resource_name, :url => invitation_path(resource_name), :html => { :method => :put, class: "form-horizontal" } do |form|
-        = form.hidden_field :invitation_token
-
-        = form.input :name
-        = form.input :password, as: :password
-        = form.input :password_confirmation, as: :password
-
-        .submit
-          = form.button :submit, value: t('devise.invitations.edit.submit_button'), class: 'btn-info'
\ No newline at end of file
+/ PageHeader
+
+- content_for :page_header_title, t('.title')
+
+/ PageContent
+.page_content
+  .container-fluid
+    .row
+      .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1
+        = simple_form_for resource, as: resource_name, :url => invitation_path(resource_name), :html => { :method => :put, class: "form-horizontal", id: 'invitation_form' } do |form|
+            .row
+              .col-lg-12
+                = form.hidden_field :invitation_token
+
+                = form.input :name
+                = form.input :password, as: :password
+                = form.input :password_confirmation, as: :password
+
+            = form.button :submit, value: t('devise.invitations.edit.submit_button'), class: 'btn-info btn-default formSubmitr', form: 'invitation_form'
diff --git a/app/views/devise/passwords/edit.html.slim b/app/views/devise/passwords/edit.html.slim
index 864a44499..0d18f657c 100644
--- a/app/views/devise/passwords/edit.html.slim
+++ b/app/views/devise/passwords/edit.html.slim
@@ -1,13 +1,17 @@
-.col-md-offset-2.col-md-8
-  .panel.panel-default
-    .panel-heading = t('.title')
-    .panel-body
-      = simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, class: "form-horizontal" }) do |f|
+/ PageHeader
 
-        = f.input :reset_password_token, as: :hidden
-        = f.input :password, as: :password
-        = f.input :password_confirmation, as: :password
-        
-        .form-actions
-          = link_to t("cancel"), unauthenticated_root_path, class: 'btn btn-default'
-          = f.button :submit, :value => t("devise.passwords.edit.commit"), class: 'btn-info'
\ No newline at end of file
+- content_for :page_header_title, t('.title')
+
+/ PageContent
+.page_content
+  .container-fluid
+    .row
+      .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1
+        = simple_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, class: "form-horizontal", id: 'password_form' }) do |f|
+          .row
+            .col-lg-12
+              = f.input :reset_password_token, as: :hidden
+              = f.input :password, as: :password
+              = f.input :password_confirmation, as: :password
+
+          = f.button :submit, :value => t("devise.passwords.edit.commit"), class: 'btn btn-default formSubmitr', form: 'password_form'
diff --git a/app/views/devise/passwords/new.html.slim b/app/views/devise/passwords/new.html.slim
index 6e03595fc..303f78f0e 100644
--- a/app/views/devise/passwords/new.html.slim
+++ b/app/views/devise/passwords/new.html.slim
@@ -1,6 +1,6 @@
 / PageHeader
 
-= pageheader '', t('.title')
+- content_for :page_header_title, t('.title')
 
 / PageContent
 .page_content
@@ -12,4 +12,4 @@
             .col-lg-12
               = form.input :email, :as => :email, placeholder: 'user@domain.com'
 
-          = form.button :submit, :value => t("devise.passwords.new.commit"), class: 'btn btn-default formSubmitr', form: 'invitation_form'
+          = form.button :submit, :value => t("devise.passwords.new.commit"), class: 'btn btn-default formSubmitr', form: 'password_form'
diff --git a/app/views/devise/sessions/new.html.slim b/app/views/devise/sessions/new.html.slim
index 0ed17e24a..a812726e5 100644
--- a/app/views/devise/sessions/new.html.slim
+++ b/app/views/devise/sessions/new.html.slim
@@ -1,3 +1,5 @@
+- content_for :page_header_title, t('.title')
+
 .page_content#devise
   .container-fluid
     #sessions_new.row
-- 
cgit v1.2.3
From 1b2c50949d827d8f82a40d591489394f5dc2f993 Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 09:25:10 +0100
Subject: Refs #5287; CR 1
- Get rid of ActiveSupport::Concern in the spec helpers
- Rename misnamed spec files
---
 spec/support/integration_spec_helper.rb            | 15 ++----
 spec/support/pundit/pundit_view_policy.rb          | 17 +++----
 spec/views/connection_links/show.html.erb_spec.rb  | 32 -------------
 spec/views/connection_links/show.html.slim_spec.rb | 32 +++++++++++++
 spec/views/stop_areas/index.html.erb_spec.rb       | 53 ----------------------
 spec/views/stop_areas/index.html.slim_spec.rb      | 53 ++++++++++++++++++++++
 6 files changed, 97 insertions(+), 105 deletions(-)
 delete mode 100644 spec/views/connection_links/show.html.erb_spec.rb
 create mode 100644 spec/views/connection_links/show.html.slim_spec.rb
 delete mode 100644 spec/views/stop_areas/index.html.erb_spec.rb
 create mode 100644 spec/views/stop_areas/index.html.slim_spec.rb
diff --git a/spec/support/integration_spec_helper.rb b/spec/support/integration_spec_helper.rb
index 958aab9d5..182cadf24 100644
--- a/spec/support/integration_spec_helper.rb
+++ b/spec/support/integration_spec_helper.rb
@@ -1,17 +1,12 @@
 module IntegrationSpecHelper
-  extend ActiveSupport::Concern
-
-  included do
-    def self.with_permission permission, &block
-      context "with permission #{permission}" do
-        let(:permissions){ [permission] }
-        context('', &block) if block_given?
-      end
+  def with_permission permission, &block
+    context "with permission #{permission}" do
+      let(:permissions){ [permission] }
+      context('', &block) if block_given?
     end
   end
 end
 
-
 RSpec.configure do |config|
-  config.include IntegrationSpecHelper, type: :view
+  config.extend IntegrationSpecHelper, type: :view
 end
diff --git a/spec/support/pundit/pundit_view_policy.rb b/spec/support/pundit/pundit_view_policy.rb
index 6a663a471..91be0624c 100644
--- a/spec/support/pundit/pundit_view_policy.rb
+++ b/spec/support/pundit/pundit_view_policy.rb
@@ -1,15 +1,12 @@
 module Pundit
   module PunditViewPolicy
-    extend ActiveSupport::Concern
-
-    included do
-
-      let(:permissions){ nil }
-      let(:organisation){ referential.try(:organisation) }
-      let(:current_referential){ referential || build_stubbed(:referential) }
-      let(:current_user){ build_stubbed :user, permissions: permissions, organisation: organisation }
-      let(:pundit_user){ UserContext.new(current_user, referential: current_referential) }
-      before do
+    def self.included into
+      into.let(:permissions){ nil }
+      into.let(:organisation){ referential.try(:organisation) }
+      into.let(:current_referential){ referential || build_stubbed(:referential) }
+      into.let(:current_user){ build_stubbed :user, permissions: permissions, organisation: organisation }
+      into.let(:pundit_user){ UserContext.new(current_user, referential: current_referential) }
+      into.before do
         allow(view).to receive(:pundit_user) { pundit_user }
 
         allow(view).to receive(:policy) do |instance|
diff --git a/spec/views/connection_links/show.html.erb_spec.rb b/spec/views/connection_links/show.html.erb_spec.rb
deleted file mode 100644
index afe94fc6c..000000000
--- a/spec/views/connection_links/show.html.erb_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'spec_helper'
-
-describe "/connection_links/show", :type => :view do
-
-  assign_referential
-  let!(:connection_link) { assign(:connection_link, create(:connection_link)) }
-  let!(:map) { assign(:map, double(:to_html => ''.html_safe)) }
-
-  before do
-    allow(view).to receive_messages(current_organisation: referential.organisation)
-  end
-
-  it "should render h2 with the connection_link name" do
-    render
-    expect(rendered).to have_selector("h2", :text => Regexp.new(connection_link.name))
-  end
-
-  with_permission "connection_links.update" do
-    it "should render a link to edit the connection_link" do
-      render
-      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.edit_referential_connection_link_path(referential, connection_link)}']")
-    end
-  end
-
-  with_permission "connection_links.destroy" do
-    it "should render a link to remove the connection_link" do
-      render
-      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.referential_connection_link_path(referential, connection_link)}'][class='remove']")
-    end
-  end
-
-end
diff --git a/spec/views/connection_links/show.html.slim_spec.rb b/spec/views/connection_links/show.html.slim_spec.rb
new file mode 100644
index 000000000..afe94fc6c
--- /dev/null
+++ b/spec/views/connection_links/show.html.slim_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe "/connection_links/show", :type => :view do
+
+  assign_referential
+  let!(:connection_link) { assign(:connection_link, create(:connection_link)) }
+  let!(:map) { assign(:map, double(:to_html => ''.html_safe)) }
+
+  before do
+    allow(view).to receive_messages(current_organisation: referential.organisation)
+  end
+
+  it "should render h2 with the connection_link name" do
+    render
+    expect(rendered).to have_selector("h2", :text => Regexp.new(connection_link.name))
+  end
+
+  with_permission "connection_links.update" do
+    it "should render a link to edit the connection_link" do
+      render
+      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.edit_referential_connection_link_path(referential, connection_link)}']")
+    end
+  end
+
+  with_permission "connection_links.destroy" do
+    it "should render a link to remove the connection_link" do
+      render
+      expect(view.content_for(:sidebar)).to have_selector(".actions a[href='#{view.referential_connection_link_path(referential, connection_link)}'][class='remove']")
+    end
+  end
+
+end
diff --git a/spec/views/stop_areas/index.html.erb_spec.rb b/spec/views/stop_areas/index.html.erb_spec.rb
deleted file mode 100644
index e0c50685c..000000000
--- a/spec/views/stop_areas/index.html.erb_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require 'spec_helper'
-
-RSpec::Matchers.define :have_link_for_each_stop_area do |stop_areas, name, href|
-  match do |actual|
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{href.call(stop_area)}']", count: 1)
-    end
-  end
-  description { "have #{name} link for each stop area" }
-end
-
-RSpec::Matchers.define :have_the_right_number_of_links do |stop_areas, count|
-  match do |actual|
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: count)
-    end
-  end
-  description { "have #{count} links for each stop area" }
-end
-
-describe "/stop_areas/index", :type => :view do
-
-  let!(:stop_area_referential) { assign :stop_area_referential, create(:stop_area_referential) }
-  let!(:stop_areas) do
-    2.times { create(:stop_area, stop_area_referential: stop_area_referential) }
-    assign :stop_areas, ModelDecorator.decorate( Chouette::StopArea.page(1), with: StopAreaDecorator )
-  end
-  let!(:q) { assign :q, Ransack::Search.new(Chouette::StopArea) }
-
-  before :each do
-    allow(view).to receive(:link_with_search).and_return("#")
-    allow(view).to receive(:collection).and_return(stop_areas)
-    allow(view).to receive(:current_referential).and_return(stop_area_referential)
-    controller.request.path_parameters[:stop_area_referential_id] = stop_area_referential.id
-    render
-  end
-
-  it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
-  it { should have_the_right_number_of_links(stop_areas, 1) }
-
-  with_permission "stop_areas.create" do
-    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
-    it { should have_link_for_each_stop_area(stop_areas, "create", -> (stop_area){ view.new_stop_area_referential_stop_area_path(stop_area_referential) }) }
-    it { should have_the_right_number_of_links(stop_areas, 2) }
-  end
-
-  with_permission "stop_areas.update" do
-    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
-    it { should have_link_for_each_stop_area(stop_areas, "edit", -> (stop_area){ view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
-    it { should have_the_right_number_of_links(stop_areas, 2) }
-  end
-
-end
diff --git a/spec/views/stop_areas/index.html.slim_spec.rb b/spec/views/stop_areas/index.html.slim_spec.rb
new file mode 100644
index 000000000..e0c50685c
--- /dev/null
+++ b/spec/views/stop_areas/index.html.slim_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+RSpec::Matchers.define :have_link_for_each_stop_area do |stop_areas, name, href|
+  match do |actual|
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{href.call(stop_area)}']", count: 1)
+    end
+  end
+  description { "have #{name} link for each stop area" }
+end
+
+RSpec::Matchers.define :have_the_right_number_of_links do |stop_areas, count|
+  match do |actual|
+    stop_areas.each do |stop_area|
+      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: count)
+    end
+  end
+  description { "have #{count} links for each stop area" }
+end
+
+describe "/stop_areas/index", :type => :view do
+
+  let!(:stop_area_referential) { assign :stop_area_referential, create(:stop_area_referential) }
+  let!(:stop_areas) do
+    2.times { create(:stop_area, stop_area_referential: stop_area_referential) }
+    assign :stop_areas, ModelDecorator.decorate( Chouette::StopArea.page(1), with: StopAreaDecorator )
+  end
+  let!(:q) { assign :q, Ransack::Search.new(Chouette::StopArea) }
+
+  before :each do
+    allow(view).to receive(:link_with_search).and_return("#")
+    allow(view).to receive(:collection).and_return(stop_areas)
+    allow(view).to receive(:current_referential).and_return(stop_area_referential)
+    controller.request.path_parameters[:stop_area_referential_id] = stop_area_referential.id
+    render
+  end
+
+  it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+  it { should have_the_right_number_of_links(stop_areas, 1) }
+
+  with_permission "stop_areas.create" do
+    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_stop_area(stop_areas, "create", -> (stop_area){ view.new_stop_area_referential_stop_area_path(stop_area_referential) }) }
+    it { should have_the_right_number_of_links(stop_areas, 2) }
+  end
+
+  with_permission "stop_areas.update" do
+    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_stop_area(stop_areas, "edit", -> (stop_area){ view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_the_right_number_of_links(stop_areas, 2) }
+  end
+
+end
-- 
cgit v1.2.3
From fe2351168962eba58fb140abe490490daa1739cf Mon Sep 17 00:00:00 2001
From: Alban Peignier
Date: Mon, 18 Dec 2017 19:18:31 +0100
Subject: Fix link use in StopArea name into stop_areas#index. Refs #5287
---
 app/views/stop_areas/index.html.slim | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/stop_areas/index.html.slim b/app/views/stop_areas/index.html.slim
index 99b399f5c..dbf3b848d 100644
--- a/app/views/stop_areas/index.html.slim
+++ b/app/views/stop_areas/index.html.slim
@@ -24,7 +24,7 @@
                 key: :name, \
                 attribute: 'name', \
                 link_to: lambda do |stop_area| \
-                  referential_stop_area_path( \
+                  stop_area_referential_stop_area_path( \
                     @stop_area_referential, \
                     stop_area \
                   ) \
-- 
cgit v1.2.3
From b67027e412aa731059e2783b8eccdece295b3240 Mon Sep 17 00:00:00 2001
From: Zog
Date: Tue, 19 Dec 2017 13:09:47 +0100
Subject: Refs #5287@0.5h; Use I18n in dashboard
For calendars panel, instead of hardcoded string
---
 app/assets/stylesheets/components/_panels.sass | 1 +
 app/views/dashboards/_dashboard.html.slim      | 2 +-
 config/locales/calendars.en.yml                | 5 +++--
 config/locales/calendars.fr.yml                | 5 +++--
 4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/app/assets/stylesheets/components/_panels.sass b/app/assets/stylesheets/components/_panels.sass
index e9f615081..ab25d8184 100644
--- a/app/assets/stylesheets/components/_panels.sass
+++ b/app/assets/stylesheets/components/_panels.sass
@@ -34,6 +34,7 @@
         a
           text-decoration: none
           color: $blue
+          text-transform: capitalize
 
           &:hover, &:focus
             color: $darkblue
diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim
index e5aa5093a..7d547bf4c 100644
--- a/app/views/dashboards/_dashboard.html.slim
+++ b/app/views/dashboards/_dashboard.html.slim
@@ -22,7 +22,7 @@
     .panel.panel-default
       .panel-heading
         h3.panel-title.with_actions
-          = link_to "Modèles de calendrier", calendars_path
+          = link_to I18n.t("activerecord.models.calendar", count: @dashboard.current_organisation.calendars.size), calendars_path
           div
             = link_to '', calendars_path, class: ' fa fa-chevron-right pull-right'
       - if @dashboard.current_organisation.calendars.present?
diff --git a/config/locales/calendars.en.yml b/config/locales/calendars.en.yml
index 0076e5207..d3cc57677 100644
--- a/config/locales/calendars.en.yml
+++ b/config/locales/calendars.en.yml
@@ -56,8 +56,9 @@ en:
           end: End
   activerecord:
     models:
-      one: calendar
-      other: calendars
+      calendar:
+        one: calendar
+        other: calendars
     attributes:
       calendar:
         name: Name
diff --git a/config/locales/calendars.fr.yml b/config/locales/calendars.fr.yml
index fddb47d64..fc895bf89 100644
--- a/config/locales/calendars.fr.yml
+++ b/config/locales/calendars.fr.yml
@@ -56,8 +56,9 @@ fr:
           end: Fin
   activerecord:
     models:
-      one: "calendrier"
-      other: "calendriers"
+      calendar:
+        one: "calendrier"
+        other: "calendriers"
     attributes:
       calendar:
         name: Nom
-- 
cgit v1.2.3
From 892f3448bc65358ce2ab3f1ef83888a25b8524e9 Mon Sep 17 00:00:00 2001
From: Alban Peignier
Date: Tue, 12 Dec 2017 21:24:24 +0100
Subject: Move logic to ReferentialCloning. Improve specs. Refs #5283
---
 app/models/referential_cloning.rb               | 21 ++++++--
 app/workers/referential_cloning_worker.rb       | 29 ++---------
 spec/models/referential_cloning_spec.rb         | 64 ++++++++++++++++++++++++-
 spec/workers/referential_cloning_worker_spec.rb | 53 +++++++-------------
 4 files changed, 100 insertions(+), 67 deletions(-)
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/workers/referential_cloning_worker.rb b/app/workers/referential_cloning_worker.rb
index 6592160ec..60dc1a4bc 100644
--- a/app/workers/referential_cloning_worker.rb
+++ b/app/workers/referential_cloning_worker.rb
@@ -1,32 +1,9 @@
 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
+    if operation = ReferentialCloning.find(id)
+      operation.clone!
+    end
   end
 end
diff --git a/spec/models/referential_cloning_spec.rb b/spec/models/referential_cloning_spec.rb
index 5acd433ec..c01be20a9 100644
--- a/spec/models/referential_cloning_spec.rb
+++ b/spec/models/referential_cloning_spec.rb
@@ -1,6 +1,8 @@
 require 'spec_helper'
 
 RSpec.describe ReferentialCloning, :type => :model do
+  alias_method :referential_cloning, :subject
+
   it 'should have a valid factory' do
     expect(FactoryGirl.build(:referential_cloning)).to be_valid
   end
@@ -8,11 +10,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
-- 
cgit v1.2.3
From 24df9992da672f84ec22435449bcd985fb2d3ed0 Mon Sep 17 00:00:00 2001
From: Alban Peignier
Date: Wed, 13 Dec 2017 09:30:11 +0100
Subject: Use ReferentialCloning.find result without test on
 ReferentialCloningWorker#perform. Refs #5283
---
 app/workers/referential_cloning_worker.rb | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/app/workers/referential_cloning_worker.rb b/app/workers/referential_cloning_worker.rb
index 60dc1a4bc..e20148055 100644
--- a/app/workers/referential_cloning_worker.rb
+++ b/app/workers/referential_cloning_worker.rb
@@ -2,8 +2,6 @@ class ReferentialCloningWorker
   include Sidekiq::Worker
 
   def perform(id)
-    if operation = ReferentialCloning.find(id)
-      operation.clone!
-    end
+    ReferentialCloning.find(id).clone!
   end
 end
-- 
cgit v1.2.3
From a8dee986c3b9666c1727c1a65e4bcc6a20deed6b Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Thu, 14 Dec 2017 11:54:40 +0100
Subject: Fix duplicate link on dropdown menu & label
Refs #5300
---
 app/decorators/company_decorator.rb | 2 +-
 app/views/companies/index.html.slim | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/decorators/company_decorator.rb b/app/decorators/company_decorator.rb
index 9416c73ae..96a5175bc 100644
--- a/app/decorators/company_decorator.rb
+++ b/app/decorators/company_decorator.rb
@@ -37,7 +37,7 @@ class CompanyDecorator < Draper::Decorator
 
     if h.policy(object).destroy?
       links << Link.new(
-        content: t('companies.actions.destroy'),
+        content: h.t('companies.actions.destroy'),
         href: h.line_referential_company_path(
           context[:referential],
           object
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'
-- 
cgit v1.2.3
From 8ca8824b490d139e9eafce439688aaf3c6658b13 Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Thu, 14 Dec 2017 14:12:12 +0100
Subject: Enable unaccent extension
Refs #5305
---
 db/migrate/20171214130636_enable_unaccent_extension.rb | 9 +++++++++
 db/schema.rb                                           | 3 ++-
 2 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 db/migrate/20171214130636_enable_unaccent_extension.rb
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
-- 
cgit v1.2.3
From c8ae1cde1def7f1765e3cc7bc1a20689ae605521 Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Thu, 14 Dec 2017 14:12:50 +0100
Subject: Autocomplete stop area, use unaccent in query search
Refs #5305
---
 app/controllers/autocomplete_stop_areas_controller.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
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
 
-- 
cgit v1.2.3
From b05efc905c3acc6fcc72cf5135799d692c80593e Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Fri, 15 Dec 2017 16:22:55 +0100
Subject: Remove edit duplicate edit link
Refs #5300
---
 app/views/referential_companies/index.html.slim | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
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'
-- 
cgit v1.2.3
From 49952f6be36a59f167310db6f902a84a165150a0 Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Fri, 15 Dec 2017 16:24:10 +0100
Subject: Refactoring use destroy_link_content & remove create link
Refs #5300
---
 app/decorators/company_decorator.rb | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/app/decorators/company_decorator.rb b/app/decorators/company_decorator.rb
index 96a5175bc..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: h.t('companies.actions.destroy'),
+        content: h.destroy_link_content('companies.actions.destroy'),
         href: h.line_referential_company_path(
           context[:referential],
           object
-- 
cgit v1.2.3
From aef2f87d6a64072bab3766094f483127d2e7bb38 Mon Sep 17 00:00:00 2001
From: Alban Peignier
Date: Mon, 18 Dec 2017 11:08:02 +0100
Subject: Remove unless subject alias_method. Use be_nil when possible. Refs
 #5283
---
 spec/models/referential_cloning_spec.rb | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/spec/models/referential_cloning_spec.rb b/spec/models/referential_cloning_spec.rb
index c01be20a9..4327c98aa 100644
--- a/spec/models/referential_cloning_spec.rb
+++ b/spec/models/referential_cloning_spec.rb
@@ -1,7 +1,6 @@
 require 'spec_helper'
 
 RSpec.describe ReferentialCloning, :type => :model do
-  alias_method :referential_cloning, :subject
 
   it 'should have a valid factory' do
     expect(FactoryGirl.build(:referential_cloning)).to be_valid
@@ -66,12 +65,12 @@ RSpec.describe ReferentialCloning, :type => :model do
 
     it "defines started_at" do
       referential_cloning.clone!
-      expect(referential_cloning.started_at).not_to be(nil)
+      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)
+      expect(referential_cloning.ended_at).not_to be_nil
     end
 
   end
-- 
cgit v1.2.3
From 69271aaae3df5fb50249dd0428945804135b1f8e Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 11:19:05 +0100
Subject: Refs #5231@0.1h; Fix wrong I18n
Fix wrong french translation for Line.number
---
 config/locales/lines.fr.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/locales/lines.fr.yml b/config/locales/lines.fr.yml
index 35f8792f4..36254d754 100644
--- a/config/locales/lines.fr.yml
+++ b/config/locales/lines.fr.yml
@@ -74,7 +74,7 @@ fr:
         deactivated: "Activé"
         name: "Nom de la ligne"
         published_name: "Nom public"
-        number: "Nom court"
+        number: "Numéro"
         transport_mode: "Mode de transport"
         transport_submode: "Sous mode de transport"
         seasonal: "Saisonnière"
-- 
cgit v1.2.3
From b97d6c4af9f3d9f4f9be82031557c05b83e3b1d4 Mon Sep 17 00:00:00 2001
From: Teddy Wing
Date: Mon, 18 Dec 2017 12:53:48 +0100
Subject: Imports#create: Add flash message
Add a message to let users know that the import has started and to be
patient while it does its thing.
Refs #5317
---
 config/locales/imports.en.yml               |  4 ++++
 config/locales/imports.fr.yml               |  4 ++++
 spec/controllers/imports_controller_spec.rb | 14 ++++++++++++++
 3 files changed, 22 insertions(+)
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/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
-- 
cgit v1.2.3
From cdfd4e184be3cb84400bb26b313d92384332123b Mon Sep 17 00:00:00 2001
From: Teddy Wing
Date: Mon, 18 Dec 2017 13:36:29 +0100
Subject: Referentials#validate: Update flash message
* Luc specified a new flash message string to use here. Update the old
  one with the new version.
* Move the translation key to `notice.referentials.validate` because we
  have multiple "operation_in_progress" messages (this one for
  validation, and another for referential cloning/duplication).
* Add a test to confirm that the flash message is set.
Refs #5317
---
 app/controllers/referentials_controller.rb       |  2 +-
 config/locales/referentials.en.yml               |  2 +-
 config/locales/referentials.fr.yml               |  2 +-
 spec/controllers/referentials_controller_spec.rb | 12 ++++++++++++
 4 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb
index ee1236912..f97e2c211 100644
--- a/app/controllers/referentials_controller.rb
+++ b/app/controllers/referentials_controller.rb
@@ -60,7 +60,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] = I18n.t('notice.referentials.validate')
     redirect_to(referential_path)
   end
 
diff --git a/config/locales/referentials.en.yml b/config/locales/referentials.en.yml
index 8420e9539..f3a9cdfd1 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,7 @@ en:
   notice:
     referentials:
       deleted: "Datasets has been successfully destroyed"
+      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..7f986ed93 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,7 @@ fr:
   notice:
     referentials:
       deleted: "Les jeux de données on été supprimés"
+      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/spec/controllers/referentials_controller_spec.rb b/spec/controllers/referentials_controller_spec.rb
index fba063085..dad2b3c8f 100644
--- a/spec/controllers/referentials_controller_spec.rb
+++ b/spec/controllers/referentials_controller_spec.rb
@@ -30,4 +30,16 @@ 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
 end
-- 
cgit v1.2.3
From 75f583ab29ebc29ad6b51f02f93b02c193e1a601 Mon Sep 17 00:00:00 2001
From: Teddy Wing
Date: Mon, 18 Dec 2017 13:42:57 +0100
Subject: Referentials#validate: Remove `I18n.` prefix
Call `#t` directly since we can and because the rest of the controller
does this without the `I18n.` prefix.
Refs #5317
---
 app/controllers/referentials_controller.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb
index f97e2c211..773de04fd 100644
--- a/app/controllers/referentials_controller.rb
+++ b/app/controllers/referentials_controller.rb
@@ -60,7 +60,7 @@ class ReferentialsController < ChouetteController
 
   def validate
     ComplianceControlSetCopyWorker.perform_async(params[:compliance_control_set], params[:id])
-    flash[:notice] = I18n.t('notice.referentials.validate')
+    flash[:notice] = t('notice.referentials.validate')
     redirect_to(referential_path)
   end
 
-- 
cgit v1.2.3
From f5ea5fc7d198eb0c183d76e06582909150befc40 Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 14:23:36 +0100
Subject: Refs #5331; Show user's name ...
... instead of user's username in the top bar
---
 app/views/layouts/navigation/_main_nav_top.html.slim | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
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
 
 
-- 
cgit v1.2.3
From 3fdd836fc62ef3164569e322b789cbe096226c04 Mon Sep 17 00:00:00 2001
From: Teddy Wing
Date: Mon, 18 Dec 2017 17:23:04 +0100
Subject: Referentials#create: Add flash message on referential duplication
When a "duplicate referential" action is initiated, show a flash message
to let users know that it started and is in progress (and will take a
while since it's an asynchronous task).
Refs #5317
---
 app/controllers/referentials_controller.rb       |  2 ++
 config/locales/referentials.en.yml               |  1 +
 config/locales/referentials.fr.yml               |  1 +
 spec/controllers/referentials_controller_spec.rb | 17 +++++++++++++++++
 4 files changed, 21 insertions(+)
diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb
index 773de04fd..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
diff --git a/config/locales/referentials.en.yml b/config/locales/referentials.en.yml
index f3a9cdfd1..f41e35446 100644
--- a/config/locales/referentials.en.yml
+++ b/config/locales/referentials.en.yml
@@ -125,6 +125,7 @@ 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"
diff --git a/config/locales/referentials.fr.yml b/config/locales/referentials.fr.yml
index 7f986ed93..9250a033c 100644
--- a/config/locales/referentials.fr.yml
+++ b/config/locales/referentials.fr.yml
@@ -123,6 +123,7 @@ 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é"
diff --git a/spec/controllers/referentials_controller_spec.rb b/spec/controllers/referentials_controller_spec.rb
index dad2b3c8f..4050a8812 100644
--- a/spec/controllers/referentials_controller_spec.rb
+++ b/spec/controllers/referentials_controller_spec.rb
@@ -42,4 +42,21 @@ describe ReferentialsController, :type => :controller do
       )
     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
-- 
cgit v1.2.3
From 4084c176a305cfed393f8090d3ec8d998865ea4a Mon Sep 17 00:00:00 2001
From: Xinhui
Date: Tue, 19 Dec 2017 12:02:06 +0100
Subject: Controller spec AutocompleteStopAreas
Refs #5305
---
 .../autocomplete_stop_areas_controller_spec.rb     | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 spec/controllers/autocomplete_stop_areas_controller_spec.rb
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
-- 
cgit v1.2.3
From 74a601f6f35e0a547d3cde0501081e6e9f509959 Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 15 Dec 2017 17:01:49 +0100
Subject: Ref #5291@2h; Specs setup
- Refactor specs helper to be more generic
- Write missing specs for the Workbenches#show view
We now have failing tests highlighting the bug
---
 app/helpers/table_builder_helper.rb                | 18 ++++++++--
 spec/support/integration_spec_helper.rb            | 30 ++++++++++++++++
 spec/views/offer_workbenches/show.html.erb_spec.rb | 41 ++++++++++++++++++++--
 spec/views/stop_areas/index.html.slim_spec.rb      | 31 ++++------------
 4 files changed, 91 insertions(+), 29 deletions(-)
diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb
index 37f01ce0d..59906dc87 100644
--- a/app/helpers/table_builder_helper.rb
+++ b/app/helpers/table_builder_helper.rb
@@ -95,6 +95,18 @@ module TableBuilderHelper
       class: cls
   end
 
+  def self.item_row_class_name collection
+    if collection.respond_to?(:model)
+      model_name = collection.model.name
+    elsif collection.respond_to?(:first)
+      model_name = collection.first.class.name
+    else
+      model_name = "item"
+    end
+
+    model_name.split("::").last.parameterize
+  end
+
   private
 
   def thead(collection, columns, sortable, selectable, has_links, overhead, model )
@@ -188,10 +200,12 @@ module TableBuilderHelper
   end
 
   def tbody(collection, columns, selectable, links, overhead)
+    model_name = TableBuilderHelper.item_row_class_name collection
+
     content_tag :tbody do
       collection.map do |item|
-
-        content_tag :tr do
+        klass = "#{model_name}-#{item.id}"
+        content_tag :tr, class: klass do
           bcont = []
 
           if selectable
diff --git a/spec/support/integration_spec_helper.rb b/spec/support/integration_spec_helper.rb
index 182cadf24..5bcf0bd3a 100644
--- a/spec/support/integration_spec_helper.rb
+++ b/spec/support/integration_spec_helper.rb
@@ -4,9 +4,39 @@ module IntegrationSpecHelper
       let(:permissions){ [permission] }
       context('', &block) if block_given?
     end
+
+    def paginate_collection klass, decorator, page=1
+      ModelDecorator.decorate( klass.page(page), with: decorator )
+    end
+
+    def build_paginated_collection factory, decorator, opts={}
+      count = opts.delete(:count) || 2
+      page = opts.delete(:page) || 1
+      klass = nil
+      count.times { klass ||= create(factory, opts).class }
+      paginate_collection klass, decorator, page
+    end
   end
 end
 
 RSpec.configure do |config|
   config.extend IntegrationSpecHelper, type: :view
 end
+
+RSpec::Matchers.define :have_link_for_each_item do |collection, name, href|
+  match do |actual|
+    collection.each do |item|
+      expect(rendered).to have_selector("tr.#{TableBuilderHelper.item_row_class_name(collection)}-#{item.id} .actions a[href='#{href.call(item)}']", count: 1)
+    end
+  end
+  description { "have #{name} link for each item" }
+end
+
+RSpec::Matchers.define :have_the_right_number_of_links do |collection, count|
+  match do |actual|
+    collection.each do |item|
+      expect(rendered).to have_selector("tr.#{TableBuilderHelper.item_row_class_name(collection)}-#{item.id} .actions a", count: count)
+    end
+  end
+  description { "have #{count} links for each item" }
+end
diff --git a/spec/views/offer_workbenches/show.html.erb_spec.rb b/spec/views/offer_workbenches/show.html.erb_spec.rb
index 40b09268a..597335166 100644
--- a/spec/views/offer_workbenches/show.html.erb_spec.rb
+++ b/spec/views/offer_workbenches/show.html.erb_spec.rb
@@ -1,5 +1,42 @@
-require 'rails_helper'
+require 'spec_helper'
 
-RSpec.describe "workbenches/show.html.erb", :type => :view do
+describe "workbenches/show", :type => :view do
+  let!(:ids) { ['STIF:CODIFLIGNE:Line:C00840', 'STIF:CODIFLIGNE:Line:C00086'] }
+  let!(:lines) {
+    ids.map do |id|
+      create :line, objectid: id, line_referential: workbench.line_referential
+    end
+  }
 
+  let!(:workbench){ assign :workbench, create(:workbench) }
+  let!(:same_organisation_referential){ create :workbench_referential, workbench: workbench, metadatas: [create(:referential_metadata, lines: lines)] }
+  let!(:different_organisation_referential){ create :workbench_referential, metadatas: [create(:referential_metadata, lines: lines)] }
+  let!(:referentials){
+    same_organisation_referential && different_organisation_referential
+    assign :wbench_refs, paginate_collection(Referential, ReferentialDecorator)
+  }
+  let!(:q) { assign :q_for_form, Ransack::Search.new(Referential) }
+  before :each do
+
+    lines
+    controller.request.path_parameters[:id] = workbench.id
+    expect(workbench.referentials).to include same_organisation_referential
+    expect(workbench.referentials).to_not include different_organisation_referential
+    expect(workbench.all_referentials).to include same_organisation_referential
+    expect(workbench.all_referentials).to include different_organisation_referential
+    render
+  end
+
+  it { should have_link_for_each_item(referentials, "show", -> (referential){ view.referential_path(referential) }) }
+  it "should enable the checkbox for the referential which belongs to the same organisation" do
+    klass = "#{TableBuilderHelper.item_row_class_name(referentials)}-#{same_organisation_referential.id}"
+    selector = "tr.#{klass} [type=checkbox][value='#{same_organisation_referential.id}']:not([disabled])"
+    expect(rendered).to have_selector(selector, count: 1)
+  end
+
+  it "should disable the checkbox for the referential which does not belong to the same organisation" do
+    klass = "#{TableBuilderHelper.item_row_class_name(referentials)}-#{different_organisation_referential.id}"
+    selector = "tr.#{klass} [type=checkbox][disabled][value='#{different_organisation_referential.id}']"
+    expect(rendered).to have_selector(selector, count: 1)
+  end
 end
diff --git a/spec/views/stop_areas/index.html.slim_spec.rb b/spec/views/stop_areas/index.html.slim_spec.rb
index e0c50685c..ecd76fb03 100644
--- a/spec/views/stop_areas/index.html.slim_spec.rb
+++ b/spec/views/stop_areas/index.html.slim_spec.rb
@@ -1,29 +1,10 @@
 require 'spec_helper'
 
-RSpec::Matchers.define :have_link_for_each_stop_area do |stop_areas, name, href|
-  match do |actual|
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a[href='#{href.call(stop_area)}']", count: 1)
-    end
-  end
-  description { "have #{name} link for each stop area" }
-end
-
-RSpec::Matchers.define :have_the_right_number_of_links do |stop_areas, count|
-  match do |actual|
-    stop_areas.each do |stop_area|
-      expect(rendered).to have_selector("tr.stoparea-#{stop_area.id} .actions a", count: count)
-    end
-  end
-  description { "have #{count} links for each stop area" }
-end
-
 describe "/stop_areas/index", :type => :view do
 
   let!(:stop_area_referential) { assign :stop_area_referential, create(:stop_area_referential) }
   let!(:stop_areas) do
-    2.times { create(:stop_area, stop_area_referential: stop_area_referential) }
-    assign :stop_areas, ModelDecorator.decorate( Chouette::StopArea.page(1), with: StopAreaDecorator )
+    assign :stop_areas, build_paginated_collection(:stop_area, StopAreaDecorator, stop_area_referential: stop_area_referential)
   end
   let!(:q) { assign :q, Ransack::Search.new(Chouette::StopArea) }
 
@@ -35,18 +16,18 @@ describe "/stop_areas/index", :type => :view do
     render
   end
 
-  it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+  it { should have_link_for_each_item(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
   it { should have_the_right_number_of_links(stop_areas, 1) }
 
   with_permission "stop_areas.create" do
-    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
-    it { should have_link_for_each_stop_area(stop_areas, "create", -> (stop_area){ view.new_stop_area_referential_stop_area_path(stop_area_referential) }) }
+    it { should have_link_for_each_item(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_item(stop_areas, "create", -> (stop_area){ view.new_stop_area_referential_stop_area_path(stop_area_referential) }) }
     it { should have_the_right_number_of_links(stop_areas, 2) }
   end
 
   with_permission "stop_areas.update" do
-    it { should have_link_for_each_stop_area(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
-    it { should have_link_for_each_stop_area(stop_areas, "edit", -> (stop_area){ view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_item(stop_areas, "show", -> (stop_area){ view.stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
+    it { should have_link_for_each_item(stop_areas, "edit", -> (stop_area){ view.edit_stop_area_referential_stop_area_path(stop_area_referential, stop_area) }) }
     it { should have_the_right_number_of_links(stop_areas, 2) }
   end
 
-- 
cgit v1.2.3
From 3a78b0d44affe79ec297f1a25ee3cfe4ecd32a74 Mon Sep 17 00:00:00 2001
From: Zog
Date: Fri, 15 Dec 2017 17:54:31 +0100
Subject: Refs: #5291@1h; Update TableBuilderHelper
Update TableBuilderHelper to allow the `selectable` param to be a
lambda, thus allowing us to have row-based granularity.
---
 app/helpers/table_builder_helper.rb                | 131 +++++++++++----------
 spec/helpers/table_builder_helper_spec.rb          |  81 +++++++++++++
 spec/views/offer_workbenches/show.html.erb_spec.rb |   2 -
 3 files changed, 149 insertions(+), 65 deletions(-)
diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb
index 59906dc87..de78e903d 100644
--- a/app/helpers/table_builder_helper.rb
+++ b/app/helpers/table_builder_helper.rb
@@ -199,88 +199,92 @@ module TableBuilderHelper
     end
   end
 
-  def tbody(collection, columns, selectable, links, overhead)
-    model_name = TableBuilderHelper.item_row_class_name collection
-
-    content_tag :tbody do
-      collection.map do |item|
-        klass = "#{model_name}-#{item.id}"
-        content_tag :tr, class: klass do
-          bcont = []
-
-          if selectable
-            bcont << content_tag(
-              :td,
-              checkbox(id_name: item.try(:id), value: item.try(:id))
-            )
-          end
-
-          columns.each do |column|
-            value = column.value(item)
-
-            if column.linkable?
-              path = column.link_to(item)
-              link = link_to(value, path)
+  def tr item, columns, selectable, links, overhead, model_name
+    klass = "#{model_name}-#{item.id}"
+    content_tag :tr, class: klass do
+      bcont = []
+      if selectable
+        disabled = selectable.respond_to?(:call) && !selectable.call(item)
+        bcont << content_tag(
+          :td,
+          checkbox(id_name: item.try(:id), value: item.try(:id), disabled: disabled)
+        )
+      end
 
-              if overhead.empty?
-                bcont << content_tag(:td, link, title: 'Voir')
+      columns.each do |column|
+        value = column.value(item)
 
-              else
-                i = columns.index(column)
+        if column.linkable?
+          path = column.link_to(item)
+          link = link_to(value, path)
 
-                if overhead[i].blank?
-                  if (i > 0) && (overhead[i - 1][:width] > 1)
-                    clsArrayAlt = overhead[i - 1][:cls].split
+          if overhead.empty?
+            bcont << content_tag(:td, link, title: 'Voir')
 
-                    bcont << content_tag(:td, link, title: 'Voir', class: td_cls(clsArrayAlt))
+          else
+            i = columns.index(column)
 
-                  else
-                    bcont << content_tag(:td, link, title: 'Voir')
-                  end
+            if overhead[i].blank?
+              if (i > 0) && (overhead[i - 1][:width] > 1)
+                clsArrayAlt = overhead[i - 1][:cls].split
 
-                else
-                  clsArray = overhead[columns.index(column)][:cls].split
+                bcont << content_tag(:td, link, title: 'Voir', class: td_cls(clsArrayAlt))
 
-                  bcont << content_tag(:td, link, title: 'Voir', class: td_cls(clsArray))
-                end
+              else
+                bcont << content_tag(:td, link, title: 'Voir')
               end
 
             else
-              if overhead.empty?
-                bcont << content_tag(:td, value)
+              clsArray = overhead[columns.index(column)][:cls].split
 
-              else
-                i = columns.index(column)
+              bcont << content_tag(:td, link, title: 'Voir', class: td_cls(clsArray))
+            end
+          end
 
-                if overhead[i].blank?
-                  if (i > 0) && (overhead[i - 1][:width] > 1)
-                    clsArrayAlt = overhead[i - 1][:cls].split
+        else
+          if overhead.empty?
+            bcont << content_tag(:td, value)
 
-                    bcont << content_tag(:td, value, class: td_cls(clsArrayAlt))
+          else
+            i = columns.index(column)
 
-                  else
-                    bcont << content_tag(:td, value)
-                  end
+            if overhead[i].blank?
+              if (i > 0) && (overhead[i - 1][:width] > 1)
+                clsArrayAlt = overhead[i - 1][:cls].split
 
-                else
-                  clsArray = overhead[i][:cls].split
+                bcont << content_tag(:td, value, class: td_cls(clsArrayAlt))
 
-                  bcont << content_tag(:td, value, class: td_cls(clsArray))
-                end
+              else
+                bcont << content_tag(:td, value)
               end
+
+            else
+              clsArray = overhead[i][:cls].split
+
+              bcont << content_tag(:td, value, class: td_cls(clsArray))
             end
           end
+        end
+      end
 
-          if links.any? || item.try(:action_links).try(:any?)
-            bcont << content_tag(
-              :td,
-              build_links(item, links),
-              class: 'actions'
-            )
-          end
+      if links.any? || item.try(:action_links).try(:any?)
+        bcont << content_tag(
+          :td,
+          build_links(item, links),
+          class: 'actions'
+        )
+      end
 
-          bcont.join.html_safe
-        end
+      bcont.join.html_safe
+    end
+  end
+
+  def tbody(collection, columns, selectable, links, overhead)
+    model_name = TableBuilderHelper.item_row_class_name collection
+
+    content_tag :tbody do
+      collection.map do |item|
+        tr item, columns, selectable, links, overhead, model_name
       end.join.html_safe
     end
   end
@@ -355,13 +359,14 @@ module TableBuilderHelper
     end
   end
 
-  def checkbox(id_name:, value:)
+  def checkbox(id_name:, value:, disabled: false)
     content_tag :div, '', class: 'checkbox' do
-      check_box_tag(id_name, value).concat(
+      check_box_tag(id_name, value, nil, disabled: disabled).concat(
         content_tag(:label, '', for: id_name)
       )
     end
   end
+
   def gear_menu_link(link)
     content_tag(
       :li,
diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb
index 3b0a18379..8c77bd465 100644
--- a/spec/helpers/table_builder_helper_spec.rb
+++ b/spec/helpers/table_builder_helper_spec.rb
@@ -381,5 +381,86 @@ describe TableBuilderHelper, type: :helper do
 
       expect(beautified_html).to eq(expected.chomp)
     end
+
+    context "on a single row" do
+      let(:referential){ build_stubbed :referential }
+      let(:other_referential){ build_stubbed :referential }
+      let(:user_context){
+        UserContext.new(
+          build_stubbed(
+            :user,
+            organisation: referential.organisation,
+            permissions: [
+              'referentials.create',
+              'referentials.update',
+              'referentials.destroy',
+            ]
+          ),
+          referential: referential
+        )
+      }
+      let(:columns){
+        [
+          TableBuilderHelper::Column.new(
+            key: :name,
+            attribute: 'name'
+          ),
+        ]
+      }
+      let(:item){ referential.decorate }
+      let(:other_item){ other_referential.decorate }
+      let(:selectable){ false }
+      let(:links){ [:show] }
+      let(:overhead){ [] }
+      let(:model_name){ "referential" }
+      let(:other_tr){ helper.send(:tr, other_item, columns, selectable, links, overhead, model_name) }
+      let(:items){ [item, other_item] }
+
+      before(:each){
+        allow(helper).to receive(:current_user).and_return(user_context)
+      }
+
+      context "with all rows non-selectable" do
+        let(:selectable){ false }
+        it "sets all rows as non selectable" do
+          items.each do |i|
+            tr = helper.send(:tr, i, columns, selectable, links, overhead, model_name)
+            klass = "#{TableBuilderHelper.item_row_class_name([referential])}-#{i.id}"
+            selector = "tr.#{klass} [type=checkbox]"
+            expect(tr).to_not have_selector selector
+          end
+        end
+      end
+
+      context "with all rows selectable" do
+        let(:selectable){ true }
+        it "adds a checkbox in all rows" do
+          items.each do |i|
+            tr = helper.send(:tr, i, columns, selectable, links, overhead, model_name)
+            klass = "#{TableBuilderHelper.item_row_class_name([referential])}-#{i.id}"
+            selector = "tr.#{klass} [type=checkbox]"
+            expect(tr).to have_selector selector
+          end
+        end
+      end
+
+      context "with THIS row non selectable" do
+        let(:selectable){ ->(i){ i.id != item.id } }
+        it "adds a checkbox in all rows" do
+          items.each do |i|
+            tr = helper.send(:tr, i, columns, selectable, links, overhead, model_name)
+            klass = "#{TableBuilderHelper.item_row_class_name([referential])}-#{i.id}"
+            selector = "tr.#{klass} [type=checkbox]"
+            expect(tr).to have_selector selector
+          end
+        end
+        it "disables this rows checkbox" do
+          tr = helper.send(:tr, item, columns, selectable, links, overhead, model_name)
+          klass = "#{TableBuilderHelper.item_row_class_name([referential])}-#{item.id}"
+          selector = "tr.#{klass} [type=checkbox][disabled]"
+          expect(tr).to have_selector selector
+        end
+      end
+    end
   end
 end
diff --git a/spec/views/offer_workbenches/show.html.erb_spec.rb b/spec/views/offer_workbenches/show.html.erb_spec.rb
index 597335166..44dfe88f1 100644
--- a/spec/views/offer_workbenches/show.html.erb_spec.rb
+++ b/spec/views/offer_workbenches/show.html.erb_spec.rb
@@ -7,7 +7,6 @@ describe "workbenches/show", :type => :view do
       create :line, objectid: id, line_referential: workbench.line_referential
     end
   }
-
   let!(:workbench){ assign :workbench, create(:workbench) }
   let!(:same_organisation_referential){ create :workbench_referential, workbench: workbench, metadatas: [create(:referential_metadata, lines: lines)] }
   let!(:different_organisation_referential){ create :workbench_referential, metadatas: [create(:referential_metadata, lines: lines)] }
@@ -17,7 +16,6 @@ describe "workbenches/show", :type => :view do
   }
   let!(:q) { assign :q_for_form, Ransack::Search.new(Referential) }
   before :each do
-
     lines
     controller.request.path_parameters[:id] = workbench.id
     expect(workbench.referentials).to include same_organisation_referential
-- 
cgit v1.2.3
From 0403917aab03cfc3200f62e70f255bc7887cdcdf Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 08:52:18 +0100
Subject: Refs #5291@0.5h; Update view
Update the view to match the actual controller behaviour.
---
 app/views/workbenches/show.html.slim               |  2 +-
 spec/views/offer_workbenches/show.html.erb_spec.rb | 35 ++++++++++++++++------
 2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim
index af312fc08..1c82c34b7 100644
--- a/app/views/workbenches/show.html.slim
+++ b/app/views/workbenches/show.html.slim
@@ -57,7 +57,7 @@
                   attribute: '' \
                 ) \
               ],
-              selectable: true,
+              selectable: ->(ref){ @workbench.referentials.include?(ref) },
               links: [:show, :edit],
               cls: 'table has-filter has-search'
 
diff --git a/spec/views/offer_workbenches/show.html.erb_spec.rb b/spec/views/offer_workbenches/show.html.erb_spec.rb
index 44dfe88f1..cc01c9d0e 100644
--- a/spec/views/offer_workbenches/show.html.erb_spec.rb
+++ b/spec/views/offer_workbenches/show.html.erb_spec.rb
@@ -1,5 +1,18 @@
 require 'spec_helper'
 
+RSpec::Matchers.define :have_box_for_item do |item, disabled|
+  match do |actual|
+    klass = "#{TableBuilderHelper.item_row_class_name([item])}-#{item.id}"
+    if disabled
+      selector = "tr.#{klass} [type=checkbox][disabled][value='#{item.id}']"
+    else
+      selector = "tr.#{klass} [type=checkbox][value='#{item.id}']:not([disabled])"
+    end
+    expect(actual).to have_selector(selector, count: 1)
+  end
+  description { "have a #{disabled ? "disabled ": ""}box for the item ##{item.id}" }
+end
+
 describe "workbenches/show", :type => :view do
   let!(:ids) { ['STIF:CODIFLIGNE:Line:C00840', 'STIF:CODIFLIGNE:Line:C00086'] }
   let!(:lines) {
@@ -18,7 +31,7 @@ describe "workbenches/show", :type => :view do
   before :each do
     lines
     controller.request.path_parameters[:id] = workbench.id
-    expect(workbench.referentials).to include same_organisation_referential
+    expect(workbench.referentials).to     include same_organisation_referential
     expect(workbench.referentials).to_not include different_organisation_referential
     expect(workbench.all_referentials).to include same_organisation_referential
     expect(workbench.all_referentials).to include different_organisation_referential
@@ -26,15 +39,19 @@ describe "workbenches/show", :type => :view do
   end
 
   it { should have_link_for_each_item(referentials, "show", -> (referential){ view.referential_path(referential) }) }
-  it "should enable the checkbox for the referential which belongs to the same organisation" do
-    klass = "#{TableBuilderHelper.item_row_class_name(referentials)}-#{same_organisation_referential.id}"
-    selector = "tr.#{klass} [type=checkbox][value='#{same_organisation_referential.id}']:not([disabled])"
-    expect(rendered).to have_selector(selector, count: 1)
+
+  context "without permission" do
+    it "should disable all the checkboxes" do
+      expect(rendered).to have_box_for_item same_organisation_referential, false
+      expect(rendered).to have_box_for_item different_organisation_referential, true
+    end
   end
 
-  it "should disable the checkbox for the referential which does not belong to the same organisation" do
-    klass = "#{TableBuilderHelper.item_row_class_name(referentials)}-#{different_organisation_referential.id}"
-    selector = "tr.#{klass} [type=checkbox][disabled][value='#{different_organisation_referential.id}']"
-    expect(rendered).to have_selector(selector, count: 1)
+  with_permission "referentials.destroy" do
+    it "should enable the checkbox for the referential which belongs to the same organisation and disable the other one" do
+      expect(rendered).to have_box_for_item same_organisation_referential, false
+      expect(rendered).to have_box_for_item different_organisation_referential, true
+    end
   end
+
 end
-- 
cgit v1.2.3
From f875a1b07db4f877f406952ef9074d7ed54f5a6d Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 09:11:03 +0100
Subject: Refs #5291@0.1h; Add missing styles
Add missing styles for disabled checkboxes
---
 app/assets/stylesheets/base/_config.sass      | 1 +
 app/assets/stylesheets/components/_forms.sass | 7 +++++++
 2 files changed, 8 insertions(+)
diff --git a/app/assets/stylesheets/base/_config.sass b/app/assets/stylesheets/base/_config.sass
index 65444479f..ec1c43e7f 100644
--- a/app/assets/stylesheets/base/_config.sass
+++ b/app/assets/stylesheets/base/_config.sass
@@ -16,6 +16,7 @@ $blue: #007fbb
 
 $darkgrey: #4b4b4b
 $grey: #a4a4a4
+$lightgrey: rgba($grey, 0.15)
 
 $green: #70b12b
 $red: #da2f36
diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass
index 9a363ab97..47faf19b1 100644
--- a/app/assets/stylesheets/components/_forms.sass
+++ b/app/assets/stylesheets/components/_forms.sass
@@ -229,6 +229,13 @@ $cbx-size-xs: 15px
     &[type='checkbox']:checked + label:before
       background-color: $blue
 
+    &[type='checkbox']:disabled + label
+      &:before
+        border-color: $grey
+        background-color: $lightgrey
+        cursor: not-allowed
+      &:after
+        display: none
 // Table adjustments
 table, .table
   .td, td, .th, th
-- 
cgit v1.2.3
From 3aa5ff0d1f5e74b4c46c14e6240e7def82f0451d Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 09:34:15 +0100
Subject: Refs #5291@0.1h; Fix rebase
Fix integration_spec_helper after rebase
---
 spec/support/integration_spec_helper.rb | 37 ++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/spec/support/integration_spec_helper.rb b/spec/support/integration_spec_helper.rb
index 5bcf0bd3a..78efb9027 100644
--- a/spec/support/integration_spec_helper.rb
+++ b/spec/support/integration_spec_helper.rb
@@ -1,26 +1,33 @@
 module IntegrationSpecHelper
-  def with_permission permission, &block
-    context "with permission #{permission}" do
-      let(:permissions){ [permission] }
-      context('', &block) if block_given?
-    end
 
-    def paginate_collection klass, decorator, page=1
-      ModelDecorator.decorate( klass.page(page), with: decorator )
-    end
+  def paginate_collection klass, decorator, page=1
+    ModelDecorator.decorate( klass.page(page), with: decorator )
+  end
 
-    def build_paginated_collection factory, decorator, opts={}
-      count = opts.delete(:count) || 2
-      page = opts.delete(:page) || 1
-      klass = nil
-      count.times { klass ||= create(factory, opts).class }
-      paginate_collection klass, decorator, page
+  def build_paginated_collection factory, decorator, opts={}
+    count = opts.delete(:count) || 2
+    page = opts.delete(:page) || 1
+    klass = nil
+    count.times { klass ||= create(factory, opts).class }
+    paginate_collection klass, decorator, page
+  end
+
+  module Methods
+    def with_permission permission, &block
+      context "with permission #{permission}" do
+        let(:permissions){ [permission] }
+        context('', &block) if block_given?
+      end
     end
   end
+
+  def self.included into
+    into.extend Methods
+  end
 end
 
 RSpec.configure do |config|
-  config.extend IntegrationSpecHelper, type: :view
+  config.include IntegrationSpecHelper, type: :view
 end
 
 RSpec::Matchers.define :have_link_for_each_item do |collection, name, href|
-- 
cgit v1.2.3
From 98c08c6fae5b0bf59231b3e402ca91307c200297 Mon Sep 17 00:00:00 2001
From: Zog
Date: Mon, 18 Dec 2017 17:18:25 +0100
Subject: Refs #5333@1.5h; Use permissions to sync StopAreas and Lines
- add missing policies
- update permissions translator
- update views to check for the permission
- update views helper to check for the permission
- uipdate controllers to check for the permission
---
 app/controllers/line_referentials_controller.rb    |  1 +
 .../stop_area_referentials_controller.rb           |  1 +
 app/helpers/application_helper.rb                  | 16 +++++++++++-----
 app/models/user.rb                                 |  2 +-
 app/policies/calendar_policy.rb                    | 17 +++++++----------
 app/policies/line_referential_policy.rb            | 14 ++++++++++++++
 app/policies/stop_area_referential_policy.rb       | 14 ++++++++++++++
 app/views/line_referentials/show.html.slim         |  5 +++--
 app/views/stop_area_referentials/show.html.slim    |  5 +++--
 lib/stif/permission_translator.rb                  | 15 +++++++++++----
 .../line_referentials_controller_spec.rb           | 14 ++++++++++++++
 .../stop_area_referentials_controller_spec.rb      | 17 +++++++++++++++++
 spec/lib/stif/permission_translator_spec.rb        | 15 +++++++++++++++
 spec/policies/calendar_policy_spec.rb              |  3 +++
 spec/policies/line_referential_policy_spec.rb      |  9 +++++++++
 spec/policies/sto_area_referential_policy_spec.rb  |  9 +++++++++
 spec/support/controller_spec_helper.rb             | 18 ++++++++++++++++++
 .../views/line_referentials/show.html.slim_spec.rb | 22 ++++++++++++++++++++++
 .../stop_area_referentials/show.html.slim_spec.rb  | 22 ++++++++++++++++++++++
 19 files changed, 195 insertions(+), 24 deletions(-)
 create mode 100644 app/policies/line_referential_policy.rb
 create mode 100644 app/policies/stop_area_referential_policy.rb
 create mode 100644 spec/controllers/stop_area_referentials_controller_spec.rb
 create mode 100644 spec/policies/line_referential_policy_spec.rb
 create mode 100644 spec/policies/sto_area_referential_policy_spec.rb
 create mode 100644 spec/support/controller_spec_helper.rb
 create mode 100644 spec/views/line_referentials/show.html.slim_spec.rb
 create mode 100644 spec/views/line_referentials/stop_area_referentials/show.html.slim_spec.rb
diff --git a/app/controllers/line_referentials_controller.rb b/app/controllers/line_referentials_controller.rb
index 39c2cdb89..03dab3f8f 100644
--- a/app/controllers/line_referentials_controller.rb
+++ b/app/controllers/line_referentials_controller.rb
@@ -3,6 +3,7 @@ class LineReferentialsController < ChouetteController
   defaults :resource_class => LineReferential
 
   def sync
+    authorize resource, :synchronize?
     @sync = resource.line_referential_syncs.build
     if @sync.save
       flash[:notice] = t('notice.line_referential_sync.created')
diff --git a/app/controllers/stop_area_referentials_controller.rb b/app/controllers/stop_area_referentials_controller.rb
index 85541230d..f2d375e49 100644
--- a/app/controllers/stop_area_referentials_controller.rb
+++ b/app/controllers/stop_area_referentials_controller.rb
@@ -2,6 +2,7 @@ class StopAreaReferentialsController < ChouetteController
 
   defaults :resource_class => StopAreaReferential
   def sync
+    authorize resource, :synchronize?
     @sync = resource.stop_area_referential_syncs.build
     if @sync.save
       flash[:notice] = t('notice.stop_area_referential_sync.created')
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 124604cd9..713542ff4 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -23,12 +23,18 @@ module ApplicationHelper
   end
 
   def page_header_meta(object)
-    info = t('last_update', time: l(object.updated_at, format: :short))
-    if object.try(:versions)
-      author = object.versions.try(:last).try(:whodunnit) || t('default_whodunnit')
-      info   = "#{info} | 
 #{t('whodunnit', author: author)}"
+    out = ""
+    display = true
+    display = policy(object).synchronize? if policy(object).respond_to?(:synchronize?) rescue false
+    if display
+      info = t('last_update', time: l(object.updated_at, format: :short))
+      if object.try(:versions)
+        author = object.versions.try(:last).try(:whodunnit) || t('default_whodunnit')
+        info   = "#{info} 
 #{t('whodunnit', author: author)}"
+      end
+      out += content_tag :div, info.html_safe, class: 'small last-update'
     end
-    content_tag :div, info.html_safe, class: 'small'
+    out.html_safe
   end
 
   def page_header_content_for(object)
diff --git a/app/models/user.rb b/app/models/user.rb
index 37d35209a..1342f60ed 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -36,7 +36,7 @@ class User < ActiveRecord::Base
     self.name         = extra[:full_name]
     self.email        = extra[:email]
     self.organisation = Organisation.sync_update extra[:organisation_code], extra[:organisation_name], extra[:functional_scope]
-    self.permissions  = Stif::PermissionTranslator.translate(extra[:permissions])
+    self.permissions  = Stif::PermissionTranslator.translate(extra[:permissions], self.organisation)
   end
 
   def self.portail_api_request
diff --git a/app/policies/calendar_policy.rb b/app/policies/calendar_policy.rb
index 074c41d8d..3ba708ec9 100644
--- a/app/policies/calendar_policy.rb
+++ b/app/policies/calendar_policy.rb
@@ -5,18 +5,15 @@ class CalendarPolicy < ApplicationPolicy
     end
   end
 
-  def create? 
+  def create?
     !archived? && user.has_permission?('calendars.create')
   end
-  def destroy?
-    !archived? & organisation_match? && user.has_permission?('calendars.destroy')
-  end
-  def update?
-    !archived? && organisation_match? && user.has_permission?('calendars.update')
-  end
+  def destroy?; instance_permission("destroy") end
+  def update?; instance_permission("update") end
+  def share?; instance_permission("share") end
 
-  def share?
-    user.organisation.name == 'STIF' # FIXME
+  private
+  def instance_permission permission
+    !archived? & organisation_match? && user.has_permission?("calendars.#{permission}")
   end
-
 end
diff --git a/app/policies/line_referential_policy.rb b/app/policies/line_referential_policy.rb
new file mode 100644
index 000000000..ee742a083
--- /dev/null
+++ b/app/policies/line_referential_policy.rb
@@ -0,0 +1,14 @@
+class LineReferentialPolicy < ApplicationPolicy
+  class Scope < Scope
+    def resolve
+      scope
+    end
+  end
+
+  def synchronize?; instance_permission("synchronize") end
+
+  private
+  def instance_permission permission
+    user.has_permission?("line_referentials.#{permission}")
+  end
+end
diff --git a/app/policies/stop_area_referential_policy.rb b/app/policies/stop_area_referential_policy.rb
new file mode 100644
index 000000000..e370babf8
--- /dev/null
+++ b/app/policies/stop_area_referential_policy.rb
@@ -0,0 +1,14 @@
+class StopAreaReferentialPolicy < ApplicationPolicy
+  class Scope < Scope
+    def resolve
+      scope
+    end
+  end
+
+  def synchronize?; instance_permission("synchronize") end
+
+  private
+  def instance_permission permission
+    user.has_permission?("stop_area_referentials.#{permission}")
+  end
+end
diff --git a/app/views/line_referentials/show.html.slim b/app/views/line_referentials/show.html.slim
index b4b32bc52..763eb076e 100644
--- a/app/views/line_referentials/show.html.slim
+++ b/app/views/line_referentials/show.html.slim
@@ -1,7 +1,8 @@
 - breadcrumb :line_referential, @line_referential
 - page_header_content_for @line_referential
-- content_for :page_header_actions do
-  = link_to(t('actions.sync'), sync_line_referential_path(@line_referential), method: :post, class: 'btn btn-default')
+- if policy(@line_referential).synchronize?
+  - content_for :page_header_actions do
+    = link_to(t('actions.sync'), sync_line_referential_path(@line_referential), method: :post, class: 'btn btn-default')
 
 - content_for :page_header_content do
   .row.mb-md
diff --git a/app/views/stop_area_referentials/show.html.slim b/app/views/stop_area_referentials/show.html.slim
index d43333fd9..f66db89f4 100644
--- a/app/views/stop_area_referentials/show.html.slim
+++ b/app/views/stop_area_referentials/show.html.slim
@@ -1,6 +1,7 @@
 - breadcrumb :stop_area_referential, @stop_area_referential
-- content_for :page_header_actions do
-  = link_to(t('actions.sync'), sync_stop_area_referential_path(@stop_area_referential), method: :post, class: 'btn btn-default')
+- if policy(@stop_area_referential).synchronize?
+  - content_for :page_header_actions do
+    = link_to(t('actions.sync'), sync_stop_area_referential_path(@stop_area_referential), method: :post, class: 'btn btn-default')
 
 - content_for :page_header_content do
   .row.mb-md
diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb
index 2d267bc7b..78a4bac18 100644
--- a/lib/stif/permission_translator.rb
+++ b/lib/stif/permission_translator.rb
@@ -1,11 +1,11 @@
 module Stif
   module PermissionTranslator extend self
 
-    def translate(sso_extra_permissions)
-      sso_extra_permissions
-        .sort
+    def translate(sso_extra_permissions, organisation=nil)
+      permissions = sso_extra_permissions.sort
         .flat_map(&method(:extra_permission_translation))
-        .uniq
+      permissions += extra_organisation_permissions(organisation)
+      permissions.uniq
     end
 
     private
@@ -49,5 +49,12 @@ module Stif
         "boiv:edit-offer" => all_destructive_permissions + %w{sessions.create},
       }
     end
+
+    def extra_organisation_permissions organisation
+      if organisation&.name&.downcase == "stif"
+        return %w{calendars.share stop_area_referentials.synchronize line_referentials.synchronize} 
+      end
+      []
+    end
   end
 end
diff --git a/spec/controllers/line_referentials_controller_spec.rb b/spec/controllers/line_referentials_controller_spec.rb
index aee24b0fa..380fe32fd 100644
--- a/spec/controllers/line_referentials_controller_spec.rb
+++ b/spec/controllers/line_referentials_controller_spec.rb
@@ -1,3 +1,17 @@
 RSpec.describe LineReferentialsController, :type => :controller do
+  login_user
 
+  let(:line_referential) { create :line_referential }
+
+  describe 'PUT sync' do
+    let(:request){ put :sync, id: line_referential.id }
+
+    it { request.should redirect_to "/403" }
+
+    with_permission "line_referentials.synchronize" do
+      it 'returns HTTP success' do
+        expect(request).to redirect_to [line_referential]
+      end
+    end
+  end
 end
diff --git a/spec/controllers/stop_area_referentials_controller_spec.rb b/spec/controllers/stop_area_referentials_controller_spec.rb
new file mode 100644
index 000000000..c8d7e1736
--- /dev/null
+++ b/spec/controllers/stop_area_referentials_controller_spec.rb
@@ -0,0 +1,17 @@
+RSpec.describe StopAreaReferentialsController, :type => :controller do
+  login_user
+
+  let(:stop_area_referential) { create :stop_area_referential }
+
+  describe 'PUT sync' do
+    let(:request){ put :sync, id: stop_area_referential.id }
+
+    it { request.should redirect_to "/403" }
+
+    with_permission "stop_area_referentials.synchronize" do
+      it 'returns HTTP success' do
+        expect(request).to redirect_to [stop_area_referential]
+      end
+    end
+  end
+end
diff --git a/spec/lib/stif/permission_translator_spec.rb b/spec/lib/stif/permission_translator_spec.rb
index ae1a2d1d5..04fc1c6f3 100644
--- a/spec/lib/stif/permission_translator_spec.rb
+++ b/spec/lib/stif/permission_translator_spec.rb
@@ -42,4 +42,19 @@ RSpec.describe Stif::PermissionTranslator do
       ).to match_array(Support::Permissions.all_permissions)
     end
   end
+
+  context "For the STIF organisation" do
+    let(:organisation){ build_stubbed :organisation, name: "STIF" }
+    let(:permissions){ %w{calendars.share stop_area_referentials.synchronize line_referentials.synchronize}.sort }
+    it "adds the calendars.share permission" do
+      expect(described_class.translate([], organisation).sort).to eq permissions
+    end
+
+    context "with the case changed" do
+      let(:organisation){ build_stubbed :organisation, name: "StiF" }
+      it "adds the calendars.share permission" do
+        expect(described_class.translate([], organisation).sort).to eq permissions
+      end
+    end
+  end
 end
diff --git a/spec/policies/calendar_policy_spec.rb b/spec/policies/calendar_policy_spec.rb
index 294be8198..8b1facc71 100644
--- a/spec/policies/calendar_policy_spec.rb
+++ b/spec/policies/calendar_policy_spec.rb
@@ -7,6 +7,9 @@ RSpec.describe CalendarPolicy, type: :policy do
   permissions :create? do
     it_behaves_like 'permitted policy', 'calendars.create', archived: true
   end
+  permissions :share? do
+    it_behaves_like 'permitted policy and same organisation', 'calendars.share', archived: true
+  end
   permissions :destroy? do
     it_behaves_like 'permitted policy and same organisation', 'calendars.destroy', archived: true
   end
diff --git a/spec/policies/line_referential_policy_spec.rb b/spec/policies/line_referential_policy_spec.rb
new file mode 100644
index 000000000..7e0a9da8e
--- /dev/null
+++ b/spec/policies/line_referential_policy_spec.rb
@@ -0,0 +1,9 @@
+RSpec.describe LineReferentialPolicy, type: :policy do
+
+  let( :record ){ build_stubbed :line_referential }
+  before { stub_policy_scope(record) }
+
+  permissions :synchronize? do
+    it_behaves_like 'permitted policy', 'line_referentials.synchronize'
+  end
+end
diff --git a/spec/policies/sto_area_referential_policy_spec.rb b/spec/policies/sto_area_referential_policy_spec.rb
new file mode 100644
index 000000000..5bd6da427
--- /dev/null
+++ b/spec/policies/sto_area_referential_policy_spec.rb
@@ -0,0 +1,9 @@
+RSpec.describe StopAreaReferentialPolicy, type: :policy do
+
+  let( :record ){ build_stubbed :stop_area_referential }
+  before { stub_policy_scope(record) }
+
+  permissions :synchronize? do
+    it_behaves_like 'permitted policy', 'stop_area_referentials.synchronize'
+  end
+end
diff --git a/spec/support/controller_spec_helper.rb b/spec/support/controller_spec_helper.rb
new file mode 100644
index 000000000..1d0288dea
--- /dev/null
+++ b/spec/support/controller_spec_helper.rb
@@ -0,0 +1,18 @@
+module ControllerSpecHelper
+  def with_permission permission, &block
+    context "with permission #{permission}" do
+      login_user
+      before(:each) do
+        @user.permissions << permission
+        @user.save!
+        sign_in @user
+      end
+      context('', &block) if block_given?
+    end
+  end
+
+end
+
+RSpec.configure do |config|
+  config.extend ControllerSpecHelper, type: :controller
+end
diff --git a/spec/views/line_referentials/show.html.slim_spec.rb b/spec/views/line_referentials/show.html.slim_spec.rb
new file mode 100644
index 000000000..0516677cb
--- /dev/null
+++ b/spec/views/line_referentials/show.html.slim_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe "/line_referentials/show", :type => :view do
+
+  let!(:line_referential) { assign :line_referential, create(:line_referential) }
+
+  before :each do
+    render
+  end
+
+  it "should not present syncing infos and button" do
+    expect(view.content_for(:page_header_actions)).to_not have_selector("a[href=\"#{view.sync_line_referential_path(line_referential)}\"]")
+    expect(view.content_for(:page_header_meta)).to_not have_selector(".last-update")
+  end
+
+  with_permission "line_referentials.synchronize" do
+    it "should present syncing infos and button" do
+      expect(view.content_for(:page_header_actions)).to have_selector("a[href=\"#{view.sync_line_referential_path(line_referential)}\"]", count: 1)
+      expect(view.content_for(:page_header_meta)).to have_selector(".last-update", count: 1)
+    end
+  end
+end
diff --git a/spec/views/line_referentials/stop_area_referentials/show.html.slim_spec.rb b/spec/views/line_referentials/stop_area_referentials/show.html.slim_spec.rb
new file mode 100644
index 000000000..71a8d16f5
--- /dev/null
+++ b/spec/views/line_referentials/stop_area_referentials/show.html.slim_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe "/stop_area_referentials/show", :type => :view do
+
+  let!(:stop_area_referential) { assign :stop_area_referential, create(:stop_area_referential) }
+
+  before :each do
+    render
+  end
+
+  it "should not present syncing infos and button" do
+    expect(view.content_for(:page_header_actions)).to_not have_selector("a[href=\"#{view.sync_stop_area_referential_path(stop_area_referential)}\"]")
+    expect(view.content_for(:page_header_meta)).to_not have_selector(".last-update")
+  end
+
+  with_permission "stop_area_referentials.synchronize" do
+    it "should present syncing infos and button" do
+      expect(view.content_for(:page_header_actions)).to have_selector("a[href=\"#{view.sync_stop_area_referential_path(stop_area_referential)}\"]", count: 1)
+      expect(view.content_for(:page_header_meta)).to have_selector(".last-update", count: 1)
+    end
+  end
+end
-- 
cgit v1.2.3
From 023fdab6840c7bb2d87d8ffee2df478574158d6e Mon Sep 17 00:00:00 2001
From: Zog
Date: Tue, 19 Dec 2017 14:24:10 +0100
Subject: Refs #5333; Minor CR improvement
---
 spec/controllers/line_referentials_controller_spec.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/spec/controllers/line_referentials_controller_spec.rb b/spec/controllers/line_referentials_controller_spec.rb
index 380fe32fd..17ffb670d 100644
--- a/spec/controllers/line_referentials_controller_spec.rb
+++ b/spec/controllers/line_referentials_controller_spec.rb
@@ -6,7 +6,9 @@ RSpec.describe LineReferentialsController, :type => :controller do
   describe 'PUT sync' do
     let(:request){ put :sync, id: line_referential.id }
 
-    it { request.should redirect_to "/403" }
+    it 'should redirect to 403' do
+       expect(request).to redirect_to "/403"
+    end
 
     with_permission "line_referentials.synchronize" do
       it 'returns HTTP success' do
-- 
cgit v1.2.3