diff options
| author | Alban Peignier | 2017-12-21 21:27:51 +0100 | 
|---|---|---|
| committer | GitHub | 2017-12-21 21:27:51 +0100 | 
| commit | 01b2d2b785d99c9b031269fc741b70ee9c248f16 (patch) | |
| tree | 5660c31a263a7a71d4bdb4bb68159b9479ca8a00 | |
| parent | 8cd9b9ee5fc127b2f39a9c89c71327ab8d5e9cec (diff) | |
| parent | 4be4d378d15ad24c8ca0cd43befb25d94cd093de (diff) | |
| download | chouette-core-01b2d2b785d99c9b031269fc741b70ee9c248f16.tar.bz2 | |
Merge pull request #165 from af83/5340-deactivate-lines
Deactivate lines instead of destroying them. Refs #5340 
| -rw-r--r-- | app/assets/stylesheets/components/_buttons.sass | 7 | ||||
| -rw-r--r-- | app/controllers/lines_controller.rb | 8 | ||||
| -rw-r--r-- | app/decorators/line_decorator.rb | 20 | ||||
| -rw-r--r-- | app/decorators/referential_line_decorator.rb | 9 | ||||
| -rw-r--r-- | app/helpers/links_helper.rb | 15 | ||||
| -rw-r--r-- | app/helpers/table_builder_helper.rb | 6 | ||||
| -rw-r--r-- | app/models/chouette/line.rb | 11 | ||||
| -rw-r--r-- | app/policies/line_policy.rb | 8 | ||||
| -rw-r--r-- | config/locales/actions.en.yml | 2 | ||||
| -rw-r--r-- | config/locales/actions.fr.yml | 2 | ||||
| -rw-r--r-- | config/locales/lines.en.yml | 8 | ||||
| -rw-r--r-- | config/locales/lines.fr.yml | 4 | ||||
| -rw-r--r-- | config/routes.rb | 5 | ||||
| -rw-r--r-- | lib/link.rb | 5 | ||||
| -rw-r--r-- | spec/controllers/lines_controller_spec.rb | 38 | ||||
| -rw-r--r-- | spec/controllers/stop_area_referentials_controller_spec.rb | 2 | ||||
| -rw-r--r-- | spec/support/integration_spec_helper.rb | 34 | ||||
| -rw-r--r-- | spec/views/lines/index.html.erb_spec.rb | 27 | ||||
| -rw-r--r-- | spec/views/lines/index.html.slim_spec.rb | 71 | 
19 files changed, 228 insertions, 54 deletions
| diff --git a/app/assets/stylesheets/components/_buttons.sass b/app/assets/stylesheets/components/_buttons.sass index a59699383..a649a07ef 100644 --- a/app/assets/stylesheets/components/_buttons.sass +++ b/app/assets/stylesheets/components/_buttons.sass @@ -165,6 +165,13 @@ table, .table              .fa:first-child                margin-right: 0.5em +          & + li.delete-action +            > a, > button +              margin-top: 0 +              &:before +                display: none + +    &.table-2entries .t2e-item      > .th        position: relative diff --git a/app/controllers/lines_controller.rb b/app/controllers/lines_controller.rb index 571c73f4a..676581076 100644 --- a/app/controllers/lines_controller.rb +++ b/app/controllers/lines_controller.rb @@ -50,6 +50,14 @@ class LinesController < ChouetteController      super    end +  %w(activate deactivate).each do |action| +    define_method action do +      authorize resource, "#{action}?" +      resource.send "#{action}!" +      redirect_to request.referer || [resource.line_referential, resource] +    end +  end +    # overwrite inherited resources to use delete instead of destroy    # foreign keys will propagate deletion)    def destroy_resource(object) diff --git a/app/decorators/line_decorator.rb b/app/decorators/line_decorator.rb index ede670cbd..fe0750b05 100644 --- a/app/decorators/line_decorator.rb +++ b/app/decorators/line_decorator.rb @@ -41,6 +41,26 @@ class LineDecorator < Draper::Decorator        )      end +    if h.policy(object).deactivate? +      links << Link.new( +        content: h.deactivate_link_content('lines.actions.deactivate'), +        href: h.deactivate_line_referential_line_path(context[:line_referential], object), +        method: :put, +        data: {confirm: h.t('lines.actions.deactivate_confirm')}, +        extra_class: "delete-action" +      ) +    end + +    if h.policy(object).activate? +      links << Link.new( +        content: h.activate_link_content('lines.actions.activate'), +        href: h.activate_line_referential_line_path(context[:line_referential], object), +        method: :put, +        data: {confirm: h.t('lines.actions.activate_confirm')}, +        extra_class: "delete-action" +      ) +    end +      if h.policy(object).destroy?        links << Link.new(          content: h.destroy_link_content('lines.actions.destroy'), diff --git a/app/decorators/referential_line_decorator.rb b/app/decorators/referential_line_decorator.rb index 654f68bf5..dceb3e2a9 100644 --- a/app/decorators/referential_line_decorator.rb +++ b/app/decorators/referential_line_decorator.rb @@ -24,15 +24,6 @@ class ReferentialLineDecorator < Draper::Decorator        )      ) -    if h.policy(object).destroy? -      links << Link.new( -        content: h.destroy_link_content('actions.destroy'), -        href: h.referential_line_path(context[:referential], object), -        method: :delete, -        data: { confirm: t('lines.actions.destroy_confirm') } -      ) -    end -      if !object.hub_restricted? ||          (object.hub_restricted? && object.routes.size < 2)        if h.policy(Chouette::Route).create? && diff --git a/app/helpers/links_helper.rb b/app/helpers/links_helper.rb index 4fb7a797d..088415dc3 100644 --- a/app/helpers/links_helper.rb +++ b/app/helpers/links_helper.rb @@ -1,5 +1,18 @@  module LinksHelper +  def custom_link_content(translation_key, klass, extra_class: nil) +    klass = ["fa", "fa-#{klass}", "mr-xs", extra_class].compact.join(" ") +    content_tag(:span, nil, class: klass) + t(translation_key) +  end +    def destroy_link_content(translation_key = 'actions.destroy') -    content_tag(:span, nil, class: 'fa fa-trash mr-xs') + t(translation_key) +    custom_link_content translation_key, 'trash' +  end + +  def deactivate_link_content(translation_key = 'actions.deactivate') +    custom_link_content translation_key, 'power-off', extra_class: "text-danger" +  end + +  def activate_link_content(translation_key = 'actions.activate') +    custom_link_content translation_key, 'power-off', extra_class: "text-success"    end  end diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb index de78e903d..96b2889da 100644 --- a/app/helpers/table_builder_helper.rb +++ b/app/helpers/table_builder_helper.rb @@ -368,6 +368,10 @@ module TableBuilderHelper    end    def gear_menu_link(link) +    klass = [link.extra_class] +    klass << 'delete-action' if link.method == :delete +    klass = klass.compact.join(' ') +    klass = nil unless klass.present?      content_tag(        :li,        link_to( @@ -377,7 +381,7 @@ module TableBuilderHelper        ) do          link.content        end, -      class: ('delete-action' if link.method == :delete) +      class: klass      )    end diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb index 93d4f5e8b..2d776e94b 100644 --- a/app/models/chouette/line.rb +++ b/app/models/chouette/line.rb @@ -79,5 +79,16 @@ module Chouette        line_referential.companies.where(id: ([company_id] + Array(secondary_company_ids)).compact)      end +    def deactivate! +      update_attribute :deactivated, true +    end + +    def activate! +      update_attribute :deactivated, false +    end + +    def activated? +      !deactivated +    end    end  end diff --git a/app/policies/line_policy.rb b/app/policies/line_policy.rb index 67ea0b611..e5674fbe2 100644 --- a/app/policies/line_policy.rb +++ b/app/policies/line_policy.rb @@ -14,6 +14,14 @@ class LinePolicy < ApplicationPolicy      user.has_permission?('lines.destroy')    end +  def deactivate? +    !record.deactivated? && user.has_permission?('lines.change_status') +  end + +  def activate? +    record.deactivated? && user.has_permission?('lines.change_status') +  end +    def update?      user.has_permission?('lines.update')    end diff --git a/config/locales/actions.en.yml b/config/locales/actions.en.yml index 2706ba69d..f5f48db22 100644 --- a/config/locales/actions.en.yml +++ b/config/locales/actions.en.yml @@ -1,6 +1,8 @@  en:    actions:      edit: "Edit" +    activate: 'Activate' +    deactivate: 'Deactivate'      destroy: "Destroy"      delete: "Delete"      search: "Search" diff --git a/config/locales/actions.fr.yml b/config/locales/actions.fr.yml index e796017c7..4b3ac6901 100644 --- a/config/locales/actions.fr.yml +++ b/config/locales/actions.fr.yml @@ -1,6 +1,8 @@  fr:    actions:      edit: 'Editer' +    activate: 'Activer' +    deactivate: 'Désactiver'      destroy: 'Supprimer'      delete: 'Supprimer'      search: "Chercher" diff --git a/config/locales/lines.en.yml b/config/locales/lines.en.yml index 78d5c36be..0bbe1b30d 100644 --- a/config/locales/lines.en.yml +++ b/config/locales/lines.en.yml @@ -6,8 +6,12 @@ en:        edit: "Edit this line"        edit_footnotes: "Edit line footnotes"        destroy: "Remove this line" -      destroy_confirm: "Are you sure you want destroy this line?" -      destroy_selection_confirm: "Are you sure you want destroy those lines?" +      activate: "Activate this line" +      deactivate: "Deactivate this line" +      activate_confirm: "Are you sure you want to activate this line ?" +      deactivate_confirm: "Are you sure you want tode activate this line ?" +      destroy_confirm: "Are you sure you want to destroy this line ?" +      destroy_selection_confirm: "Are you sure you want to destroy those lines ?"        import: "Import lines"        export_kml: "Export KML line"        export_kml_all: "Export KML lines" diff --git a/config/locales/lines.fr.yml b/config/locales/lines.fr.yml index 36254d754..9397f6989 100644 --- a/config/locales/lines.fr.yml +++ b/config/locales/lines.fr.yml @@ -6,6 +6,10 @@ fr:        edit: "Editer cette ligne"        edit_footnotes: "Editer notes en bas de page"        destroy: "Supprimer cette ligne" +      activate: "Activer cette ligne" +      deactivate: "Désactiver cette ligne" +      activate_confirm: "Etes vous sûr d'activer cette ligne ?" +      deactivate_confirm: "Etes vous sûr de désactiver cette ligne ?"        destroy_confirm: "Etes vous sûr de supprimer cette ligne ?"        destroy_selection_confirm: "Etes vous sûr de supprimer cette sélection de lignes ?"        import: "Importer des lignes" diff --git a/config/routes.rb b/config/routes.rb index d097d2d71..a36ecc36e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -93,7 +93,10 @@ ChouetteIhm::Application.routes.draw do    resources :line_referentials, :only => [:show, :edit, :update] do      post :sync, on: :member -    resources :lines +    resources :lines do +      put :deactivate, on: :member +      put :activate, on: :member +    end      resources :group_of_lines      resources :companies      resources :networks diff --git a/lib/link.rb b/lib/link.rb index 7683a808f..d34c5c59a 100644 --- a/lib/link.rb +++ b/lib/link.rb @@ -1,10 +1,11 @@  class Link -  attr_reader :content, :href, :method, :data +  attr_reader :content, :href, :method, :data, :extra_class -  def initialize(content: nil, href:, method: nil, data: nil) +  def initialize(content: nil, href:, method: nil, data: nil, extra_class: nil)      @content = content      @href = href      @method = method      @data = data +    @extra_class = extra_class    end  end diff --git a/spec/controllers/lines_controller_spec.rb b/spec/controllers/lines_controller_spec.rb new file mode 100644 index 000000000..ce5adbbdd --- /dev/null +++ b/spec/controllers/lines_controller_spec.rb @@ -0,0 +1,38 @@ +RSpec.describe LinesController, :type => :controller do +  login_user + +  let(:line_referential) { create :line_referential } +  let(:line) { create :line, line_referential: line_referential } + +  describe 'PUT deactivate' do +    let(:request){ put :deactivate, id: line.id, line_referential_id: line_referential.id } + +    it 'should redirect to 403' do +       expect(request).to redirect_to "/403" +    end + +    with_permission "lines.change_status" do +      it 'returns HTTP success' do +        expect(request).to redirect_to [line_referential, line] +        expect(line.reload).to be_deactivated +      end +    end +  end + +  describe 'PUT activate' do +    let(:request){ put :activate, id: line.id, line_referential_id: line_referential.id } +    before(:each){ +      line.deactivate! +    } +    it 'should redirect to 403' do +       expect(request).to redirect_to "/403" +    end + +    with_permission "lines.change_status" do +      it 'returns HTTP success' do +        expect(request).to redirect_to [line_referential, line] +        expect(line.reload).to be_activated +      end +    end +  end +end diff --git a/spec/controllers/stop_area_referentials_controller_spec.rb b/spec/controllers/stop_area_referentials_controller_spec.rb index c8d7e1736..384323334 100644 --- a/spec/controllers/stop_area_referentials_controller_spec.rb +++ b/spec/controllers/stop_area_referentials_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe StopAreaReferentialsController, :type => :controller do    describe 'PUT sync' do      let(:request){ put :sync, id: stop_area_referential.id } -    it { request.should redirect_to "/403" } +    it { expect(request).to redirect_to "/403" }      with_permission "stop_area_referentials.synchronize" do        it 'returns HTTP success' do diff --git a/spec/support/integration_spec_helper.rb b/spec/support/integration_spec_helper.rb index 1bf211fe1..36306559d 100644 --- a/spec/support/integration_spec_helper.rb +++ b/spec/support/integration_spec_helper.rb @@ -1,19 +1,20 @@  module IntegrationSpecHelper -  def paginate_collection klass, decorator, page=1 -    coll = klass.page(page) +  def paginate_collection klass, decorator, page=1, context={} +    collection = klass.page(page)      if decorator -      coll = ModelDecorator.decorate( coll, with: decorator ) +      collection = ModelDecorator.decorate(collection, with: decorator, context: context)      end -    coll +    collection    end    def build_paginated_collection factory, decorator, opts={} +    context = opts.delete(:context) || {}      count = opts.delete(:count) || 2      page = opts.delete(:page) || 1      klass = nil -    count.times { klass ||= create(factory, opts).class } -    paginate_collection klass, decorator, page +    count.times { klass = create(factory, opts).class } +    paginate_collection klass, decorator, page, context    end    module Methods @@ -34,20 +35,33 @@ RSpec.configure do |config|    config.include IntegrationSpecHelper, type: :view  end -RSpec::Matchers.define :have_link_for_each_item do |collection, name, href| +RSpec::Matchers.define :have_link_for_each_item do |collection, name, opts| +  opts = {href: opts} unless opts.is_a? Hash +  href = opts[:href] +  method = opts[:method] +  method_selector = method.present? ? "[data-method='#{method.downcase}']": ""    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) +      @selector = "tr.#{TableBuilderHelper.item_row_class_name(collection)}-#{item.id} .actions a[href='#{href.call(item)}']#{method_selector}" +      expect(rendered).to have_selector(@selector, count: 1)      end    end    description { "have #{name} link for each item" } +  failure_message do +    "expected view to have #{name} link for each item, failed with selector: \"#{@selector}\"" +  end  end  RSpec::Matchers.define :have_the_right_number_of_links do |collection, count| -  match do |actual| +  match do      collection.each do |item| -      expect(rendered).to have_selector("tr.#{TableBuilderHelper.item_row_class_name(collection)}-#{item.id} .actions a", count: count) +      @selector = "tr.#{TableBuilderHelper.item_row_class_name(collection)}-#{item.id} .actions a" +      expect(rendered).to have_selector(@selector, count: count)      end    end    description { "have #{count} links for each item" } +  failure_message do +    actual = Capybara::Node::Simple.new(rendered).all(@selector).count +    "expected #{count} links for each item, got #{actual} for \"#{@selector}\"" +  end  end diff --git a/spec/views/lines/index.html.erb_spec.rb b/spec/views/lines/index.html.erb_spec.rb deleted file mode 100644 index dbc3cbdb7..000000000 --- a/spec/views/lines/index.html.erb_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' - -describe "/lines/index", :type => :view do - -  let!(:line_referential) { assign :line_referential, create(:line_referential) } -  let!(:network) { create :network } -  let!(:company) { create :company } -  let!(:lines) { assign :lines, Array.new(2) { create(:line, line_referential: line_referential, network: network, company: company) }.paginate } -  let!(:q) { assign :q, Ransack::Search.new(Chouette::Line) } - -  before :each do -    allow(view).to receive(:link_with_search).and_return("#") -  end - -  # it "should render a show link for each group" do -  #   render -  #   lines.each do |line| -  #     expect(rendered).to have_selector(".line a[href='#{view.line_referential_line_path(line_referential, line)}']", :text => line.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_line_referential_line_path(line_referential)}']") -  # end - -end diff --git a/spec/views/lines/index.html.slim_spec.rb b/spec/views/lines/index.html.slim_spec.rb new file mode 100644 index 000000000..498784912 --- /dev/null +++ b/spec/views/lines/index.html.slim_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe "/lines/index", :type => :view do +  let(:deactivated_line){ nil } +  let(:line_referential) { assign :line_referential, create(:line_referential) } +  let(:current_organisation) { current_user.organisation } +  let(:context) { +     { +       current_organisation: current_organisation, +       line_referential: line_referential +     } +   } +  let(:lines) do +    assign :lines, build_paginated_collection(:line, LineDecorator, line_referential: line_referential, context: context) +  end +  let!(:q) {  assign :q, Ransack::Search.new(Chouette::Line) } + +  before :each do +    deactivated_line +    allow(view).to receive(:collection).and_return(lines) +    allow(view).to receive(:current_referential).and_return(line_referential) +    controller.request.path_parameters[:line_referential_id] = line_referential.id +    render +  end + +  common_items = ->{ +    it { should have_link_for_each_item(lines, "show", -> (line){ view.line_referential_line_path(line_referential, line) }) } +    it { should have_link_for_each_item(lines, "network", -> (line){ view.line_referential_network_path(line_referential, line.network) }) } +    it { should have_link_for_each_item(lines, "company", -> (line){ view.line_referential_company_path(line_referential, line.company) }) } +  } + +  common_items.call() +  it { should have_the_right_number_of_links(lines, 3) } + +  with_permission "lines.change_status" do +    common_items.call() +    it { should have_link_for_each_item(lines, "deactivate", -> (line){ view.deactivate_line_referential_line_path(line_referential, line) }) } +    it { should have_the_right_number_of_links(lines, 4) } +  end + +  with_permission "lines.destroy" do +    common_items.call() +    it { +      should have_link_for_each_item(lines, "destroy", { +        href: ->(line){ view.line_referential_line_path(line_referential, line)}, +        method: :delete +      }) +    } +    it { should have_the_right_number_of_links(lines, 4) } +  end + +  context "with a deactivated item" do +    with_permission "lines.change_status" do +      let(:deactivated_line){ create :line, deactivated: true } + +      common_items.call() +      it "should display an activate link for the deactivated one" do +        lines.each do |line| +          if line == deactivated_line +            href = view.activate_line_referential_line_path(line_referential, line) +          else +            href = view.deactivate_line_referential_line_path(line_referential, line) +          end +          selector = "tr.#{TableBuilderHelper.item_row_class_name(lines)}-#{line.id} .actions a[href='#{href}']" +          expect(rendered).to have_selector(selector, count: 1) +        end +      end +      it { should have_the_right_number_of_links(lines, 4) } +    end +  end +end | 
