diff options
| -rw-r--r-- | app/helpers/newapplication_helper.rb | 5 | ||||
| -rw-r--r-- | app/helpers/table_builder_helper/custom_links.rb | 14 | ||||
| -rw-r--r-- | app/models/chouette/stop_point.rb | 5 | ||||
| -rw-r--r-- | app/models/user.rb | 2 | ||||
| -rw-r--r-- | app/policies/application_policy.rb | 2 | ||||
| -rw-r--r-- | app/policies/boiv_policy.rb | 4 | ||||
| -rw-r--r-- | app/policies/default_policy.rb | 11 | ||||
| -rw-r--r-- | app/policies/line_policy.rb | 5 | ||||
| -rw-r--r-- | app/policies/time_table_policy.rb | 4 | ||||
| -rw-r--r-- | config/environments/development.rb | 10 | ||||
| -rw-r--r-- | spec/features/lines_spec.rb | 144 | ||||
| -rw-r--r-- | spec/features/routes_spec.rb | 193 | ||||
| -rw-r--r-- | spec/features/workbenches_spec.rb | 7 | ||||
| -rw-r--r-- | spec/support/pundit/policies.rb | 14 | 
14 files changed, 232 insertions, 188 deletions
| diff --git a/app/helpers/newapplication_helper.rb b/app/helpers/newapplication_helper.rb index edcad76c3..ac57997d1 100644 --- a/app/helpers/newapplication_helper.rb +++ b/app/helpers/newapplication_helper.rb @@ -155,7 +155,10 @@ module NewapplicationHelper              content_tag :li, link_to(t("actions.#{action}"), polymorph_url, method: :put)            end          else -          content_tag :li, link_to(t("actions.#{action}"), polymorph_url) +          permission = "#{action}?" +          if !policy(item).respond_to?(permission) || policy(item).public_send(permission) +            content_tag :li, link_to(t("actions.#{action}"), polymorph_url) +          end          end        end.join.html_safe      end diff --git a/app/helpers/table_builder_helper/custom_links.rb b/app/helpers/table_builder_helper/custom_links.rb index abb907678..e185bf77b 100644 --- a/app/helpers/table_builder_helper/custom_links.rb +++ b/app/helpers/table_builder_helper/custom_links.rb @@ -40,6 +40,14 @@ module TableBuilderHelper      def actions_after_policy_check        @actions.select do |action| +        # TODO: My idea would be to push authorization logic into policies +        #       Eventually the code should look like: +        #       select do |action| +        #         Pundit.policy(@user_context, @obj).send("#{action}?") +        #       end +        #       This puts the responsability where it belongs to and allows +        #       for easy and fast unit testing of the BL, always a goos sign. +          # Has policy and can destroy          (action == :delete &&              Pundit.policy(@user_context, @obj).present? && @@ -64,6 +72,10 @@ module TableBuilderHelper            # Object is archived            (action == :unarchive && @obj.archived?) || +          !Pundit.policy(@user_context, @obj).respond_to?("#{action}?") || +          Pundit.policy(@user_context, @obj).public_send("#{action}?") || +             +            action_is_allowed_regardless_of_policy(action)        end      end @@ -71,7 +83,7 @@ module TableBuilderHelper      private      def action_is_allowed_regardless_of_policy(action) -      ![:delete, :edit, :archive, :unarchive].include?(action) +      ![:delete, :edit, :archive, :unarchive, :duplicate, :actualize].include?(action)      end    end  end diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb index e0f947487..1cc1ed7a3 100644 --- a/app/models/chouette/stop_point.rb +++ b/app/models/chouette/stop_point.rb @@ -1,5 +1,10 @@  module Chouette    class StopPoint < TridentActiveRecord + +    def self.policy_class +      DefaultPolicy +    end +      include ForBoardingEnumerations      include ForAlightingEnumerations diff --git a/app/models/user.rb b/app/models/user.rb index 4ba05b164..31fc4ef78 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -31,7 +31,7 @@ class User < ActiveRecord::Base    @@edit_offer_permissions = ['routes.create', 'routes.edit', 'routes.destroy', 'journey_patterns.create', 'journey_patterns.edit', 'journey_patterns.destroy',      'vehicle_journeys.create', 'vehicle_journeys.edit', 'vehicle_journeys.destroy', 'time_tables.create', 'time_tables.edit', 'time_tables.destroy',      'footnotes.edit', 'footnotes.create', 'footnotes.destroy', 'routing_constraint_zones.create', 'routing_constraint_zones.edit', -    'routing_constraint_zones.destroy', 'referentials.create', 'referentials.edit', 'referentials.destroy', 'boiv:edit-offer'] +    'routing_constraint_zones.destroy', 'referentials.create', 'referentials.edit', 'referentials.destroy', 'boiv:edit-offer', 'boiv:read-offer']    mattr_reader :edit_offer_permissions    def self.all_permissions diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index f2521fa44..e2c0acd8e 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -53,7 +53,7 @@ class ApplicationPolicy    end    def boiv_read_offer? -    organisation_match? && user.has_permission?('boiv:read-offer') +    organisation_match? && !(user.permissions || []).grep(%r{\Aboiv:.}).empty?    end    def organisation_match? diff --git a/app/policies/boiv_policy.rb b/app/policies/boiv_policy.rb index 444006aa4..aa3ecc50d 100644 --- a/app/policies/boiv_policy.rb +++ b/app/policies/boiv_policy.rb @@ -1,10 +1,6 @@  class BoivPolicy < ApplicationPolicy -  def boiv_read_offer? -    organisation_match? && user.has_permission?('boiv:read-offer') -  end -    def index?      boiv_read_offer?    end diff --git a/app/policies/default_policy.rb b/app/policies/default_policy.rb new file mode 100644 index 000000000..efdac1575 --- /dev/null +++ b/app/policies/default_policy.rb @@ -0,0 +1,11 @@ +class DefaultPolicy +   +  def initialize(*args); end + +  def create?;   true end +  def destroy?;  true end +  def edit?;     true end +  def index?;    true end +  def show?;     true end +  def update?;   true end +end diff --git a/app/policies/line_policy.rb b/app/policies/line_policy.rb index b829040af..1b0d00cc5 100644 --- a/app/policies/line_policy.rb +++ b/app/policies/line_policy.rb @@ -6,9 +6,8 @@ class LinePolicy < BoivPolicy      end    end -  def create? -    false -  end +  def show?; true end +  def create?; false end    def update?  ; false end    def new?     ; create? end    def edit?    ; false end diff --git a/app/policies/time_table_policy.rb b/app/policies/time_table_policy.rb index e915ede6a..a8f54ad48 100644 --- a/app/policies/time_table_policy.rb +++ b/app/policies/time_table_policy.rb @@ -6,6 +6,10 @@ class TimeTablePolicy < BoivPolicy      end    end +  def actualize? +    !archived? && organisation_match? && edit? +  end +    def create?      !archived? && user.has_permission?('time_tables.create') # organisation match via referential is checked in the view    end diff --git a/config/environments/development.rb b/config/environments/development.rb index 0b4eab7d2..c0531594c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -60,13 +60,13 @@ Rails.application.configure do    config.reflex_api_url = "https://pprod.reflex.stif.info/ws/reflex/V1/service=getData"    config.codifligne_api_url = "https://pprod.codifligne.stif.info/rest/v1/lc/getlist" -  # config.chouette_authentication_settings = { -  #   type: "database" -  # }    config.chouette_authentication_settings = { -    type: "cas", -    cas_server: "http://stif-portail-dev.af83.priv/sessions" +    type: "database"    } +  # config.chouette_authentication_settings = { +    # type: "cas", +    # cas_server: "http://stif-portail-dev.af83.priv/sessions" +  # }    config.stif_portail_api =    {      key: "Ohphie1Voo6the5hohpi", diff --git a/spec/features/lines_spec.rb b/spec/features/lines_spec.rb index a55f30ebc..2a442bd2f 100644 --- a/spec/features/lines_spec.rb +++ b/spec/features/lines_spec.rb @@ -8,89 +8,91 @@ describe "Lines", type: :feature do    let!(:group_of_line) { create(:group_of_line) }    subject { lines.first } -  describe "index" do -    before(:each) { visit line_referential_lines_path(line_referential) } +  with_permissions "boiv:read" do +    describe "index" do +      before(:each) { visit line_referential_lines_path(line_referential) } -    it "displays lines" do -      expect(page).to have_content(lines.first.name) -      expect(page).to have_content(lines.last.name) -    end - -    it 'allows only R in CRUD' do -      expect(page).to have_link(I18n.t('actions.show')) -      expect(page).not_to have_link(I18n.t('actions.edit'), href: edit_referential_line_path(referential, lines.first)) -      expect(page).not_to have_link(I18n.t('actions.destroy'), href: referential_line_path(referential, lines.first)) -      expect(page).not_to have_link(I18n.t('actions.add'), href: new_referential_line_path(referential)) -    end - -    context 'filtering' do -      it 'supports filtering by name' do -        fill_in 'q[name_or_number_or_objectid_cont]', with: lines.first.name -        click_button 'search-btn' +      it "displays lines" do          expect(page).to have_content(lines.first.name) -        expect(page).not_to have_content(lines.last.name) +        expect(page).to have_content(lines.last.name)        end -      it 'supports filtering by number' do -        fill_in 'q[name_or_number_or_objectid_cont]', with: lines.first.number -        click_button 'search-btn' -        expect(page).to have_content(lines.first.name) -        expect(page).not_to have_content(lines.last.name) +      it 'allows only R in CRUD' do +        expect(page).to have_link(I18n.t('actions.show')) +        expect(page).not_to have_link(I18n.t('actions.edit'), href: edit_referential_line_path(referential, lines.first)) +        expect(page).not_to have_link(I18n.t('actions.destroy'), href: referential_line_path(referential, lines.first)) +        expect(page).not_to have_link(I18n.t('actions.add'), href: new_referential_line_path(referential))        end -      it 'supports filtering by objectid' do -        fill_in 'q[name_or_number_or_objectid_cont]', with: lines.first.objectid -        click_button 'search-btn' -        expect(page).to have_content(lines.first.name) -        expect(page).not_to have_content(lines.last.name) +      context 'filtering' do +        it 'supports filtering by name' do +          fill_in 'q[name_or_number_or_objectid_cont]', with: lines.first.name +          click_button 'search-btn' +          expect(page).to have_content(lines.first.name) +          expect(page).not_to have_content(lines.last.name) +        end + +        it 'supports filtering by number' do +          fill_in 'q[name_or_number_or_objectid_cont]', with: lines.first.number +          click_button 'search-btn' +          expect(page).to have_content(lines.first.name) +          expect(page).not_to have_content(lines.last.name) +        end + +        it 'supports filtering by objectid' do +          fill_in 'q[name_or_number_or_objectid_cont]', with: lines.first.objectid +          click_button 'search-btn' +          expect(page).to have_content(lines.first.name) +          expect(page).not_to have_content(lines.last.name) +        end        end      end -  end -  describe "show" do -    it "displays line" do -      visit line_referential_line_path(line_referential, lines.first) -      expect(page).to have_content(lines.first.name) +    describe "show" do +      it "displays line" do +        visit line_referential_line_path(line_referential, lines.first) +        expect(page).to have_content(lines.first.name) +      end      end -  end -  # Fixme #1780 -  # describe "new" do -  #   it "creates line and return to show" do -  #     visit line_referential_lines_path(line_referential) -  #     click_link "Ajouter une ligne" -  #     fill_in "line_name", :with => "Line 1" -  #     fill_in "Numéro d'enregistrement", :with => "1" -  #     fill_in "Identifiant Neptune", :with => "chouette:test:Line:999" -  #     click_button("Créer ligne") -  #     expect(page).to have_content("Line 1") -  #   end -  # end +    # Fixme #1780 +    # describe "new" do +    #   it "creates line and return to show" do +    #     visit line_referential_lines_path(line_referential) +    #     click_link "Ajouter une ligne" +    #     fill_in "line_name", :with => "Line 1" +    #     fill_in "Numéro d'enregistrement", :with => "1" +    #     fill_in "Identifiant Neptune", :with => "chouette:test:Line:999" +    #     click_button("Créer ligne") +    #     expect(page).to have_content("Line 1") +    #   end +    # end -  # Fixme #1780 -  # describe "new with group of line", :js => true do -  #   it "creates line and return to show" do -  #     visit new_line_referential_line_path(line_referential) -  #     fill_in "line_name", :with => "Line 1" -  #     fill_in "Numéro d'enregistrement", :with => "1" -  #     fill_in "Identifiant Neptune", :with => "test:Line:999" -  #     fill_in_token_input('line_group_of_line_tokens', :with => "#{group_of_line.name}") -  #     find_button("Créer ligne").trigger("click") -  #     expect(page).to have_text("Line 1") -  #     expect(page).to have_text("#{group_of_line.name}") -  #   end -  # end +    # Fixme #1780 +    # describe "new with group of line", :js => true do +    #   it "creates line and return to show" do +    #     visit new_line_referential_line_path(line_referential) +    #     fill_in "line_name", :with => "Line 1" +    #     fill_in "Numéro d'enregistrement", :with => "1" +    #     fill_in "Identifiant Neptune", :with => "test:Line:999" +    #     fill_in_token_input('line_group_of_line_tokens', :with => "#{group_of_line.name}") +    #     find_button("Créer ligne").trigger("click") +    #     expect(page).to have_text("Line 1") +    #     expect(page).to have_text("#{group_of_line.name}") +    #   end +    # end -  # Fixme #1780 -  # describe "edit and return to show" do -  #   it "edit line" do -  #     visit line_referential_line_path(line_referential, subject) -  #     click_link "Editer cette ligne" -  #     fill_in "line_name", :with => "Line Modified" -  #     fill_in "Numéro d'enregistrement", :with => "test-1" -  #     click_button("Editer ligne") -  #     expect(page).to have_content("Line Modified") -  #   end -  # end +    # Fixme #1780 +    # describe "edit and return to show" do +    #   it "edit line" do +    #     visit line_referential_line_path(line_referential, subject) +    #     click_link "Editer cette ligne" +    #     fill_in "line_name", :with => "Line Modified" +    #     fill_in "Numéro d'enregistrement", :with => "test-1" +    #     click_button("Editer ligne") +    #     expect(page).to have_content("Line Modified") +    #   end +    # end +  end  end diff --git a/spec/features/routes_spec.rb b/spec/features/routes_spec.rb index 28015f011..561725ddd 100644 --- a/spec/features/routes_spec.rb +++ b/spec/features/routes_spec.rb @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -require 'spec_helper' -  describe "Routes", :type => :feature do    login_user @@ -13,130 +10,132 @@ describe "Routes", :type => :feature do    before { @user.update(organisation: referential.organisation) } -  describe "from lines page to a line page" do -    it "display line's routes" do -      visit referential_lines_path(referential) -      first(:link, 'Consulter').click -      expect(page).to have_content(route.name) -      expect(page).to have_content(route2.name) +  with_permissions "boiv:read" do +    context "from lines page to a line page" do +      it "display line's routes" do +        visit referential_lines_path(referential) +        first(:link, 'Consulter').click +        expect(page).to have_content(route.name) +        expect(page).to have_content(route2.name) +      end      end -  end -  describe "from line's page to route's page" do -    it "display route properties" do -      visit referential_line_path(referential, line) -      click_link "#{route.name}" -      expect(page).to have_content(route.name) -      expect(page).to have_content(route.number) +    describe "from line's page to route's page" do +      it "display route properties" do +        visit referential_line_path(referential, line) +        click_link "#{route.name}" +        expect(page).to have_content(route.name) +        expect(page).to have_content(route.number) +      end      end -  end -  describe "from line's page, create a new route" do -    it "return to line's page that display new route" do -      visit referential_line_path(referential, line) -      click_link "Ajouter un itinéraire" -      fill_in "route_name", :with => "A to B" -      fill_in "route_published_name", :with => "Published A to B" -      # select 'Aller', :from => "route_direction" -      check('route[wayback]') -      click_button("Valider") -      expect(page).to have_content("A to B") -      expect(page).to have_content("Published A to B") -       +    describe "from line's page, create a new route" do +      it "return to line's page that display new route" do +        visit referential_line_path(referential, line) +        click_link "Ajouter un itinéraire" +        fill_in "route_name", :with => "A to B" +        fill_in "route_published_name", :with => "Published A to B" +        # select 'Aller', :from => "route_direction" +        check('route[wayback]') +        click_button("Valider") +        expect(page).to have_content("A to B") +        expect(page).to have_content("Published A to B") + +      end      end -  end -  describe "Modifies boarding/alighting properties on route stops" do -    xit "Puts (http) an update request" do -      #visit edit_boarding_alighting_referential_line_route_path(referential, line, route) -      visit referential_line_route_path(referential, line, route) - -      click_link I18n.t('routes.actions.edit_boarding_alighting') -      #select('', :from => '') -      # Changes the boarding of the first stop -      # Changes the alighting of the last stop -      # save -      #click_button(I18n.t('helpers.submit.update', model: I18n.t('activerecord.models.route.one'))) -      click_button(I18n.t('helpers.submit.update', model: I18n.t('activerecord.models.route.one'))) +    describe "Modifies boarding/alighting properties on route stops" do +      xit "Puts (http) an update request" do +        #visit edit_boarding_alighting_referential_line_route_path(referential, line, route) +        visit referential_line_route_path(referential, line, route) + +        click_link I18n.t('routes.actions.edit_boarding_alighting') +        #select('', :from => '') +        # Changes the boarding of the first stop +        # Changes the alighting of the last stop +        # save +        #click_button(I18n.t('helpers.submit.update', model: I18n.t('activerecord.models.route.one'))) +        click_button(I18n.t('helpers.submit.update', model: I18n.t('activerecord.models.route.one'))) +      end      end -  end -  describe 'show' do -    before(:each) { visit referential_line_route_path(referential, line, route) } +    describe 'show' do +      before(:each) { visit referential_line_route_path(referential, line, route) } -    context 'user has permission to edit journey patterns' do -      skip "not sure the spec is correct or the code" do -        it 'shows edit links for journey patterns' do -          expect(page).to have_link(I18n.t('actions.edit'), href: edit_referential_line_route_journey_pattern_path(referential, line, route, journey_pattern)) +      context 'user has permission to edit journey patterns' do +        skip "not sure the spec is correct or the code" do +          it 'shows edit links for journey patterns' do +            expect(page).to have_link(I18n.t('actions.edit'), href: edit_referential_line_route_journey_pattern_path(referential, line, route, journey_pattern)) +          end          end        end -    end -    context 'user does not have permission to edit journey patterns' do -      it 'does not show edit links for journey patterns' do -        @user.update_attribute(:permissions, []) -        visit referential_line_route_path(referential, line, route) -        expect(page).not_to have_link(I18n.t('actions.edit'), href: edit_referential_line_route_journey_pattern_path(referential, line, route, journey_pattern)) +      context 'user does not have permission to edit journey patterns' do +        it 'does not show edit links for journey patterns' do +          @user.update_attribute(:permissions, []) +          visit referential_line_route_path(referential, line, route) +          expect(page).not_to have_link(I18n.t('actions.edit'), href: edit_referential_line_route_journey_pattern_path(referential, line, route, journey_pattern)) +        end        end -    end -    context 'user has permission to destroy journey patterns' do -      it 'shows destroy links for journey patterns' do -        expect(page).to have_content(I18n.t('actions.destroy')) +      context 'user has permission to destroy journey patterns' do +        it 'shows destroy links for journey patterns' do +          expect(page).to have_content(I18n.t('actions.destroy')) +        end        end -    end -    context 'user does not have permission to destroy journey patterns' do -      it 'does not show destroy links for journey patterns' do -        @user.update_attribute(:permissions, []) -        visit referential_line_route_path(referential, line, route) -        expect(page).not_to have_link(I18n.t('actions.destroy'), href: referential_line_route_journey_pattern_path(referential, line, route, journey_pattern)) +      context 'user does not have permission to destroy journey patterns' do +        it 'does not show destroy links for journey patterns' do +          @user.update_attribute(:permissions, []) +          visit referential_line_route_path(referential, line, route) +          expect(page).not_to have_link(I18n.t('actions.destroy'), href: referential_line_route_journey_pattern_path(referential, line, route, journey_pattern)) +        end        end      end -  end -  describe 'referential line show' do -    before(:each) { visit referential_line_path(referential, line) } +    describe 'referential line show' do +      before(:each) { visit referential_line_path(referential, line) } -    context 'user has permission to edit routes' do -      it 'shows edit buttons for routes' do -        expect(page).to have_content(I18n.t('actions.edit')) +      context 'user has permission to edit routes' do +        it 'shows edit buttons for routes' do +          expect(page).to have_content(I18n.t('actions.edit')) +        end        end -    end -    context 'user does not have permission to edit routes' do -      it 'does not show edit buttons for routes' do -        @user.update_attribute(:permissions, []) -        visit referential_line_path(referential, line) -        expect(page).not_to have_link(I18n.t('actions.edit'), href: edit_referential_line_route_path(referential, line, route)) +      context 'user does not have permission to edit routes' do +        it 'does not show edit buttons for routes' do +          @user.update_attribute(:permissions, []) +          visit referential_line_path(referential, line) +          expect(page).not_to have_link(I18n.t('actions.edit'), href: edit_referential_line_route_path(referential, line, route)) +        end        end -    end -    context 'user has permission to create routes' do -      it 'shows link to a create route page' do -        expect(page).to have_content(I18n.t('routes.actions.new')) +      context 'user has permission to create routes' do +        it 'shows link to a create route page' do +          expect(page).to have_content(I18n.t('routes.actions.new')) +        end        end -    end -    context 'user belongs to another organisation' do -      xit 'does not show link to a create route page' do -        expect(page).not_to have_content(I18n.t('routes.actions.new')) +      context 'user belongs to another organisation' do +        xit 'does not show link to a create route page' do +          expect(page).not_to have_content(I18n.t('routes.actions.new')) +        end        end -    end -    context 'user does not have permission to create routes' do -      it 'does not show link to a create route page' do -        @user.update_attribute(:permissions, []) -        visit referential_line_path(referential, line) -        expect(page).not_to have_content(I18n.t('routes.actions.new')) +      context 'user does not have permission to create routes' do +        it 'does not show link to a create route page' do +          @user.update_attribute(:permissions, []) +          visit referential_line_path(referential, line) +          expect(page).not_to have_content(I18n.t('routes.actions.new')) +        end        end -    end -    context 'user does not have permission to destroy routes' do -      it 'does not show destroy buttons for routes' do -        @user.update_attribute(:permissions, []) -        visit referential_line_path(referential, line) -        expect(page).not_to have_link(I18n.t('actions.destroy'), href: referential_line_route_path(referential, line, route)) +      context 'user does not have permission to destroy routes' do +        it 'does not show destroy buttons for routes' do +          @user.update_attribute(:permissions, []) +          visit referential_line_path(referential, line) +          expect(page).not_to have_link(I18n.t('actions.destroy'), href: referential_line_route_path(referential, line, route)) +        end        end      end    end diff --git a/spec/features/workbenches_spec.rb b/spec/features/workbenches_spec.rb index 9a40a8376..cad70624f 100644 --- a/spec/features/workbenches_spec.rb +++ b/spec/features/workbenches_spec.rb @@ -156,7 +156,6 @@ describe 'Workbenches', type: :feature do            end          end        end -    end      context 'permissions' do        before(:each) do @@ -177,7 +176,6 @@ describe 'Workbenches', type: :feature do          end        end      end -  end    describe 'create new Referential' do      it "create a new Referential with a specifed line and period" do @@ -188,8 +186,9 @@ describe 'Workbenches', type: :feature do        fill_in "referential[name]", with: "Referential to test creation"        select workbench.lines.first.id, from: 'referential[metadatas_attributes][0][lines][]' -      click_button "Valider" -      expect(page).to have_css("h1", text: "Referential to test creation") +        click_button "Valider" +        expect(page).to have_css("h1", text: "Referential to test creation") +      end      end    end  end diff --git a/spec/support/pundit/policies.rb b/spec/support/pundit/policies.rb index 02fea2944..d5bb63243 100644 --- a/spec/support/pundit/policies.rb +++ b/spec/support/pundit/policies.rb @@ -35,10 +35,24 @@ module Support          end        end      end + +    module FeaturePermissionMacros +      def with_permissions(*permissions, &blk) +        perms, options = permissions.partition{|x| String === x} +        context "with permissions #{perms.inspect}...", *options do +          before do +            add_permissions(*permissions, for_user: @user) +          end +          instance_eval(&blk) +        end +      end +    end    end  end  RSpec.configure do | c |    c.include Support::Pundit::Policies, type: :policy    c.extend Support::Pundit::PoliciesMacros, type: :policy +  c.include Support::Pundit::Policies, type: :feature +  c.extend Support::Pundit::FeaturePermissionMacros, type: :feature  end | 
