From 747d333ffbcc8ee0c9f1daf93ccca32799434e04 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 3 Jul 2017 08:27:45 +0200 Subject: Refs: #3478@2h Access correct referential in line_footnotes Ctrl + ApplicationController provides Pundit's UserContext's referential with `@referential` instead of `current_referential`, (`@referential` is computed from the URL, while `current_referential` was aliased to different methods, **not always** pointing to `Referential` instances) + ApplicationPolicy uses the record's referential in its `referential method` iff it is an instance of `Referential` else it uses the abovely provided referential, locally named `@current_referential` (as it should be named in the Ctrl too) This assures, in combination with the Ctrl Change, that `referential` **always** returns an instance of `Referential`! - TODO: Review my understanding of _Referential Setup_ inside the Ctrls --- app/controllers/application_controller.rb | 2 +- app/controllers/line_footnotes_controller.rb | 2 +- app/policies/application_policy.rb | 23 +++++++++++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 42b7c2a25..8fcaa3b1b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -19,7 +19,7 @@ class ApplicationController < ActionController::Base end def pundit_user - UserContext.new(current_user, referential: self.try(:current_referential)) + UserContext.new(current_user, referential: @referential) end protected diff --git a/app/controllers/line_footnotes_controller.rb b/app/controllers/line_footnotes_controller.rb index c42aa785b..6a9048392 100644 --- a/app/controllers/line_footnotes_controller.rb +++ b/app/controllers/line_footnotes_controller.rb @@ -34,7 +34,7 @@ class LineFootnotesController < BreadcrumbController private def resource @referential = Referential.find params[:referential_id] - @line = @referential.lines.find params[:line_id] + @line = @referential.lines.find params[:line_id] end def line_params diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index a863404ae..f2521fa44 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -1,18 +1,19 @@ class ApplicationPolicy - attr_reader :user, :record + attr_reader :current_referential, :record, :user def initialize(user_context, record) - @user = user_context.user - @referential = user_context.context[:referential] - @record = record + @user = user_context.user + @current_referential = user_context.context[:referential] + @record = record end def archived? - !!referential.try(:archived_at) + return @is_archived if instance_variable_defined?(:@is_archived) + @is_archived = is_archived end def referential - @referential ||= record_referential + @referential ||= current_referential || record_referential end def record_referential @@ -77,4 +78,14 @@ class ApplicationPolicy scope end end + + private + def is_archived + !!case referential + when Referential + referential.archived_at + else + current_referential.try(:archived_at) + end + end end -- cgit v1.2.3 From c48ad4fde3056ef04645b73f7eab54ff867d370c Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 3 Jul 2017 15:34:11 +0200 Subject: Refs: #3478@1h newapplication helper default authorization, (no if) -> * DefaultPolicy (all true) * Add some policies (LinePolicy) * Use `boiv:read` pour show, index * Adapted `table_builder` --- app/helpers/newapplication_helper.rb | 5 +- app/helpers/table_builder_helper/custom_links.rb | 14 +- app/models/chouette/stop_point.rb | 5 + app/models/user.rb | 2 +- app/policies/application_policy.rb | 2 +- app/policies/boiv_policy.rb | 4 - app/policies/default_policy.rb | 11 ++ app/policies/line_policy.rb | 5 +- app/policies/time_table_policy.rb | 4 + config/environments/development.rb | 10 +- spec/features/lines_spec.rb | 144 ++++++++--------- spec/features/routes_spec.rb | 193 +++++++++++------------ spec/features/workbenches_spec.rb | 7 +- spec/support/pundit/policies.rb | 14 ++ 14 files changed, 232 insertions(+), 188 deletions(-) create mode 100644 app/policies/default_policy.rb 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 -- cgit v1.2.3 From cce302f6ea2252deb09973c8df8842c50349eb79 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 4 Jul 2017 15:01:12 +0200 Subject: Refs: #3478@1h; adapted table builder spex --- app/decorators/company_decorator.rb | 2 ++ app/helpers/table_builder_helper/custom_links.rb | 19 +++++++------------ app/policies/application_policy.rb | 7 +++++++ app/policies/company_policy.rb | 13 ++++++------- spec/decorators/company_decorator_spec.rb | 2 -- spec/helpers/table_builder_helper_spec.rb | 5 +++-- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/decorators/company_decorator.rb b/app/decorators/company_decorator.rb index 51c1f3c61..030952483 100644 --- a/app/decorators/company_decorator.rb +++ b/app/decorators/company_decorator.rb @@ -19,6 +19,8 @@ class CompanyDecorator < Draper::Decorator links = [] if h.policy(Chouette::Company).create? + require 'pry' + binding.pry links << Link.new( content: h.t('companies.actions.new'), href: h.new_line_referential_company_path(context[:line_referential]) diff --git a/app/helpers/table_builder_helper/custom_links.rb b/app/helpers/table_builder_helper/custom_links.rb index e185bf77b..6f2234948 100644 --- a/app/helpers/table_builder_helper/custom_links.rb +++ b/app/helpers/table_builder_helper/custom_links.rb @@ -48,24 +48,19 @@ module TableBuilderHelper # This puts the responsability where it belongs to and allows # for easy and fast unit testing of the BL, always a goos sign. + # N.B. Does not have policy shall not apply in the future anymore + # Has policy and can destroy + # Doesn't have policy or is autorized (action == :delete && - Pundit.policy(@user_context, @obj).present? && + !Pundit.policy(@user_context, @obj).present? || Pundit.policy(@user_context, @obj).destroy?) || - # Doesn't have policy - (action == :delete && - !Pundit.policy(@user_context, @obj).present?) || - - # Has policy and can update + # Doesn't have policy or is autorized (action == :edit && - Pundit.policy(@user_context, @obj).present? && + !Pundit.policy(@user_context, @obj).present? || Pundit.policy(@user_context, @obj).update?) || - # Doesn't have policy - (action == :edit && - !Pundit.policy(@user_context, @obj).present?) || - # Object isn't archived (action == :archive && !@obj.archived?) || @@ -74,7 +69,7 @@ module TableBuilderHelper !Pundit.policy(@user_context, @obj).respond_to?("#{action}?") || Pundit.policy(@user_context, @obj).public_send("#{action}?") || - + action_is_allowed_regardless_of_policy(action) end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index e2c0acd8e..532004296 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -1,6 +1,13 @@ class ApplicationPolicy attr_reader :current_referential, :record, :user + # Make authorization by action easier + def delete? + destroy? + end + + + def initialize(user_context, record) @user = user_context.user @current_referential = user_context.context[:referential] diff --git a/app/policies/company_policy.rb b/app/policies/company_policy.rb index 95d607f3d..2983c6acc 100644 --- a/app/policies/company_policy.rb +++ b/app/policies/company_policy.rb @@ -5,11 +5,10 @@ class CompanyPolicy < BoivPolicy end end - def create? - false - end - def update? ; create? end - def new? ; create? end - def edit? ; create? end - def destroy? ; create? end + def create?; false end + def destroy?; false end + def edit?; false end + def new?; false end + def show?; true end + def update?; false end end diff --git a/spec/decorators/company_decorator_spec.rb b/spec/decorators/company_decorator_spec.rb index 42ed6a408..a1df03449 100644 --- a/spec/decorators/company_decorator_spec.rb +++ b/spec/decorators/company_decorator_spec.rb @@ -1,4 +1,2 @@ -require 'spec_helper' - describe CompanyDecorator do end diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb index 67980fc2c..6d7b60366 100644 --- a/spec/helpers/table_builder_helper_spec.rb +++ b/spec/helpers/table_builder_helper_spec.rb @@ -17,7 +17,7 @@ describe TableBuilderHelper, type: :helper do permissions: [ 'referentials.create', 'referentials.edit', - 'referentials.destroy' + 'referentials.destroy', ] ), referential: referential @@ -299,7 +299,8 @@ describe TableBuilderHelper, type: :helper do companies = ModelDecorator.decorate( companies, - with: CompanyDecorator + with: CompanyDecorator, + context: {line_referential: line_referential} ) expected = <<-HTML -- cgit v1.2.3 From cf546740389e782b17278259369e0d288dbf2653 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 4 Jul 2017 15:21:31 +0200 Subject: Refs: #3478@0.5h; refactored table_builder_helper/custom_links.rb, according to moving authoriation BL into policies --- app/helpers/table_builder_helper/custom_links.rb | 61 ++++++++-------------- app/policies/referential_policy.rb | 4 ++ .../table_builder_helper/custom_links_spec.rb | 2 +- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/app/helpers/table_builder_helper/custom_links.rb b/app/helpers/table_builder_helper/custom_links.rb index 6f2234948..7890f3d35 100644 --- a/app/helpers/table_builder_helper/custom_links.rb +++ b/app/helpers/table_builder_helper/custom_links.rb @@ -8,14 +8,16 @@ module TableBuilderHelper unarchive: :put } - def initialize(obj, user_context, actions) - @obj = obj + attr_reader :actions, :object, :user_context + + def initialize(object, user_context, actions) + @object = object @user_context = user_context - @actions = actions + @actions = actions end def links - actions_after_policy_check.map do |action| + authorized_actions.map do |action| Link.new( content: I18n.t("actions.#{action}"), href: polymorphic_url(action), @@ -31,48 +33,23 @@ module TableBuilderHelper polymorph_url << action end - polymorph_url += URL.polymorphic_url_parts(@obj) + polymorph_url += URL.polymorphic_url_parts(@object) end def method_for_action(action) ACTIONS_TO_HTTP_METHODS[action] end - 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. - - # N.B. Does not have policy shall not apply in the future anymore - - # Has policy and can destroy - # Doesn't have policy or is autorized - (action == :delete && - !Pundit.policy(@user_context, @obj).present? || - Pundit.policy(@user_context, @obj).destroy?) || - - # Doesn't have policy or is autorized - (action == :edit && - !Pundit.policy(@user_context, @obj).present? || - Pundit.policy(@user_context, @obj).update?) || - - # Object isn't archived - (action == :archive && !@obj.archived?) || - - # 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 + def authorized_actions + @actions.select(&method(:action_authorized?)) + end + def action_authorized?(action) + # TODO: Remove this guard when all resources have policies associated to them + return true unless policy + policy.public_send("#{action}?") + rescue NoMethodError + # TODO: When all action permissions are implemented for all policies remove this rescue clause + action_is_allowed_regardless_of_policy(action) end private @@ -80,5 +57,9 @@ module TableBuilderHelper def action_is_allowed_regardless_of_policy(action) ![:delete, :edit, :archive, :unarchive, :duplicate, :actualize].include?(action) end + + def policy + @__policy__ ||= Pundit.policy(user_context, object) + end end end diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index e531c6c19..88847a212 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -30,6 +30,10 @@ class ReferentialPolicy < BoivPolicy true end + def show? + true + end + def unarchive? ; archive? end def update? ; edit? end def new? ; create? end diff --git a/spec/helpers/table_builder_helper/custom_links_spec.rb b/spec/helpers/table_builder_helper/custom_links_spec.rb index b64e97527..c1038b7f1 100644 --- a/spec/helpers/table_builder_helper/custom_links_spec.rb +++ b/spec/helpers/table_builder_helper/custom_links_spec.rb @@ -20,7 +20,7 @@ describe TableBuilderHelper::CustomLinks do referential, user_context, [:show] - ).actions_after_policy_check + ).authorized_actions ).to eq([:show]) end end -- cgit v1.2.3 From 16423b19122eefed728fc71e52d5c1660ff5575a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 4 Jul 2017 17:28:51 +0200 Subject: Refs: #3478@1h removed boiv-read-offer and BoivPolicy --- app/models/user.rb | 6 +-- app/policies/acces_point_policy.rb | 2 +- app/policies/access_link_policy.rb | 2 +- app/policies/application_policy.rb | 18 +++++--- app/policies/boiv_policy.rb | 11 ----- app/policies/calendar_policy.rb | 2 +- app/policies/company_policy.rb | 2 +- app/policies/connection_link_policy.rb | 2 +- app/policies/group_of_line_policy.rb | 2 +- app/policies/journey_pattern_policy.rb | 2 +- app/policies/line_policy.rb | 2 +- app/policies/network_policy.rb | 2 +- app/policies/referential_policy.rb | 2 +- app/policies/route_policy.rb | 2 +- app/policies/routing_constraint_zone_policy.rb | 2 +- app/policies/stop_area_policy.rb | 2 +- app/policies/time_table_policy.rb | 2 +- app/policies/vehicle_journey_policy.rb | 2 +- spec/features/workbenches_spec.rb | 51 +++++++++++----------- .../table_builder_helper/custom_links_spec.rb | 5 --- spec/policies/boiv_policy_spec.rb | 16 ------- 21 files changed, 55 insertions(+), 82 deletions(-) delete mode 100644 app/policies/boiv_policy.rb delete mode 100644 spec/policies/boiv_policy_spec.rb diff --git a/app/models/user.rb b/app/models/user.rb index 31fc4ef78..9cd4f64d6 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', 'boiv:read-offer'] + 'routing_constraint_zones.destroy', 'referentials.create', 'referentials.edit', 'referentials.destroy', 'boiv:edit-offer'] mattr_reader :edit_offer_permissions def self.all_permissions @@ -44,8 +44,6 @@ 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] - # TODO: Discuss the following behavior in the light of how the portal's permissions will evolve - # boiv:edit-offer does not imply boiv:read-offer, which needs to be provided specifically for any connection rights self.permissions = extra[:permissions].include?('boiv:edit-offer') ? @@edit_offer_permissions : [] end @@ -74,8 +72,6 @@ class User < ActiveRecord::Base user.locked_at = el['locked_at'] user.organisation = Organisation.sync_update el['organization_code'], el['organization_name'], el['functional_scope'] user.synced_at = Time.now - # TODO: Discuss the following behavior in the light of how the portal's permissions will evolve - # boiv:edit-offer does not imply boiv:read-offer, which needs to be provided specifically for any connection rights user.permissions = el['permissions'].include?('boiv:edit-offer') ? @@edit_offer_permissions : [] user.save end diff --git a/app/policies/acces_point_policy.rb b/app/policies/acces_point_policy.rb index 08af5981a..904b7a242 100644 --- a/app/policies/acces_point_policy.rb +++ b/app/policies/acces_point_policy.rb @@ -1,4 +1,4 @@ -class AccessPointPolicy < BoivPolicy +class AccessPointPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/access_link_policy.rb b/app/policies/access_link_policy.rb index 654739d06..73b2d1baa 100644 --- a/app/policies/access_link_policy.rb +++ b/app/policies/access_link_policy.rb @@ -1,4 +1,4 @@ -class AccessLinkPolicy < BoivPolicy +class AccessLinkPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index 532004296..e8d7f5f30 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -6,6 +6,18 @@ class ApplicationPolicy destroy? end + # Tie edit and update together, #edit?, do not override #edit?, + # unless you want to break this tie on purpose + def edit? + update? + end + + # Tie new and create together, do not override #new?, + # unless you want to break this tie on purpose + def new? + create? + end + def initialize(user_context, record) @@ -28,7 +40,7 @@ class ApplicationPolicy end def index? - false + show? end def show? @@ -59,10 +71,6 @@ class ApplicationPolicy Pundit.policy_scope!(user, record.class) end - def boiv_read_offer? - organisation_match? && !(user.permissions || []).grep(%r{\Aboiv:.}).empty? - end - def organisation_match? user.organisation == organisation end diff --git a/app/policies/boiv_policy.rb b/app/policies/boiv_policy.rb deleted file mode 100644 index aa3ecc50d..000000000 --- a/app/policies/boiv_policy.rb +++ /dev/null @@ -1,11 +0,0 @@ -class BoivPolicy < ApplicationPolicy - - - def index? - boiv_read_offer? - end - - def show? - boiv_read_offer? - end -end diff --git a/app/policies/calendar_policy.rb b/app/policies/calendar_policy.rb index 9d6b09a9b..4248bccc7 100644 --- a/app/policies/calendar_policy.rb +++ b/app/policies/calendar_policy.rb @@ -1,4 +1,4 @@ -class CalendarPolicy < BoivPolicy +class CalendarPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/company_policy.rb b/app/policies/company_policy.rb index 2983c6acc..3cc7822a3 100644 --- a/app/policies/company_policy.rb +++ b/app/policies/company_policy.rb @@ -1,4 +1,4 @@ -class CompanyPolicy < BoivPolicy +class CompanyPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/connection_link_policy.rb b/app/policies/connection_link_policy.rb index 21414efb9..abefd741c 100644 --- a/app/policies/connection_link_policy.rb +++ b/app/policies/connection_link_policy.rb @@ -1,4 +1,4 @@ -class ConnectionLinkPolicy < BoivPolicy +class ConnectionLinkPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/group_of_line_policy.rb b/app/policies/group_of_line_policy.rb index 86d522545..5d42a23bd 100644 --- a/app/policies/group_of_line_policy.rb +++ b/app/policies/group_of_line_policy.rb @@ -1,4 +1,4 @@ -class GroupOfLinePolicy < BoivPolicy +class GroupOfLinePolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/journey_pattern_policy.rb b/app/policies/journey_pattern_policy.rb index 01ce2cbbb..7ce2da561 100644 --- a/app/policies/journey_pattern_policy.rb +++ b/app/policies/journey_pattern_policy.rb @@ -1,4 +1,4 @@ -class JourneyPatternPolicy < BoivPolicy +class JourneyPatternPolicy < ApplicationPolicy class Scope < Scope def resolve diff --git a/app/policies/line_policy.rb b/app/policies/line_policy.rb index 1b0d00cc5..a557b496c 100644 --- a/app/policies/line_policy.rb +++ b/app/policies/line_policy.rb @@ -1,4 +1,4 @@ -class LinePolicy < BoivPolicy +class LinePolicy < ApplicationPolicy class Scope < Scope def resolve diff --git a/app/policies/network_policy.rb b/app/policies/network_policy.rb index 4c1ea1090..427eace93 100644 --- a/app/policies/network_policy.rb +++ b/app/policies/network_policy.rb @@ -1,4 +1,4 @@ -class NetworkPolicy < BoivPolicy +class NetworkPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index 88847a212..8e2a8f7f7 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -1,4 +1,4 @@ -class ReferentialPolicy < BoivPolicy +class ReferentialPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/route_policy.rb b/app/policies/route_policy.rb index ca9b02164..a12055aa6 100644 --- a/app/policies/route_policy.rb +++ b/app/policies/route_policy.rb @@ -1,4 +1,4 @@ -class RoutePolicy < BoivPolicy +class RoutePolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/routing_constraint_zone_policy.rb b/app/policies/routing_constraint_zone_policy.rb index da311bc03..1e7535475 100644 --- a/app/policies/routing_constraint_zone_policy.rb +++ b/app/policies/routing_constraint_zone_policy.rb @@ -1,4 +1,4 @@ -class RoutingConstraintZonePolicy < BoivPolicy +class RoutingConstraintZonePolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/stop_area_policy.rb b/app/policies/stop_area_policy.rb index 79b7178ce..4fa426ff6 100644 --- a/app/policies/stop_area_policy.rb +++ b/app/policies/stop_area_policy.rb @@ -1,4 +1,4 @@ -class StopAreaPolicy < BoivPolicy +class StopAreaPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/app/policies/time_table_policy.rb b/app/policies/time_table_policy.rb index a8f54ad48..30df8939b 100644 --- a/app/policies/time_table_policy.rb +++ b/app/policies/time_table_policy.rb @@ -1,4 +1,4 @@ -class TimeTablePolicy < BoivPolicy +class TimeTablePolicy < ApplicationPolicy class Scope < Scope def resolve diff --git a/app/policies/vehicle_journey_policy.rb b/app/policies/vehicle_journey_policy.rb index de6dd7088..ae3680adf 100644 --- a/app/policies/vehicle_journey_policy.rb +++ b/app/policies/vehicle_journey_policy.rb @@ -1,4 +1,4 @@ -class VehicleJourneyPolicy < BoivPolicy +class VehicleJourneyPolicy < ApplicationPolicy class Scope < Scope def resolve scope diff --git a/spec/features/workbenches_spec.rb b/spec/features/workbenches_spec.rb index cad70624f..9141b5673 100644 --- a/spec/features/workbenches_spec.rb +++ b/spec/features/workbenches_spec.rb @@ -121,7 +121,7 @@ describe 'Workbenches', type: :feature do expect(page).to_not have_content(other_referential.name) end - it 'should keep filtering on sort' do + it 'should keep filtering on sort' do dates = referential.validity_period.to_a fill_validity_field dates[0], 'begin_gteq' fill_validity_field dates[1], 'end_lteq' @@ -149,7 +149,7 @@ describe 'Workbenches', type: :feature do end click_button 'Filtrer' - ['begin_gteq', 'end_lteq'].each_with_index do |field, index| + ['begin_gteq', 'end_lteq'].each_with_index do |field, index| expect(find("#q_validity_period_#{field}_3i").value).to eq dates[index].day.to_s expect(find("#q_validity_period_#{field}_2i").value).to eq dates[index].month.to_s expect(find("#q_validity_period_#{field}_1i").value).to eq dates[index].year.to_s @@ -157,37 +157,38 @@ describe 'Workbenches', type: :feature do end end - context 'permissions' do - before(:each) do - visit workbench_path(workbench) - end + context 'permissions' do + before(:each) do + visit workbench_path(workbench) + end - context 'user has the permission to create referentials' do - it 'shows the link for a new referetnial' do - expect(page).to have_link(I18n.t('actions.add'), href: new_referential_path(workbench_id: workbench.id)) + context 'user has the permission to create referentials' do + it 'shows the link for a new referetnial' do + expect(page).to have_link(I18n.t('actions.add'), href: new_referential_path(workbench_id: workbench.id)) + end end - end - context 'user does not have the permission to create referentials' do - it 'does not show the clone link for referential' do - @user.update_attribute(:permissions, []) - visit referential_path(referential) - expect(page).not_to have_link(I18n.t('actions.add'), href: new_referential_path(workbench_id: workbench.id)) + context 'user does not have the permission to create referentials' do + it 'does not show the clone link for referential' do + @user.update_attribute(:permissions, []) + visit referential_path(referential) + expect(page).not_to have_link(I18n.t('actions.add'), href: new_referential_path(workbench_id: workbench.id)) + end end end - end - describe 'create new Referential' do - it "create a new Referential with a specifed line and period" do - referential.destroy + describe 'create new Referential' do + it "create a new Referential with a specifed line and period" do + referential.destroy - visit workbench_path(workbench) - click_link I18n.t('actions.add') - fill_in "referential[name]", with: "Referential to test creation" - select workbench.lines.first.id, from: 'referential[metadatas_attributes][0][lines][]' + visit workbench_path(workbench) + click_link I18n.t('actions.add') + 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/helpers/table_builder_helper/custom_links_spec.rb b/spec/helpers/table_builder_helper/custom_links_spec.rb index c1038b7f1..bd0bd4fcf 100644 --- a/spec/helpers/table_builder_helper/custom_links_spec.rb +++ b/spec/helpers/table_builder_helper/custom_links_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - describe TableBuilderHelper::CustomLinks do describe "#actions_after_policy_check" do it "includes :show" do @@ -8,9 +6,6 @@ describe TableBuilderHelper::CustomLinks do build_stubbed( :user, organisation: referential.organisation, - permissions: [ - 'boiv:read-offer' - ] ), referential: referential ) diff --git a/spec/policies/boiv_policy_spec.rb b/spec/policies/boiv_policy_spec.rb deleted file mode 100644 index 6787ab2ac..000000000 --- a/spec/policies/boiv_policy_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -RSpec.describe BoivPolicy, type: :policy do - - let( :record ){ nil } - - permissions :index? do - it_behaves_like 'permitted policy and same organisation', 'boiv:read-offer' - end - - permissions :boiv_read_offer? do - it_behaves_like 'permitted policy and same organisation', 'boiv:read-offer' - end - - permissions :show? do - it_behaves_like 'permitted policy and same organisation', 'boiv:read-offer' - end -end -- cgit v1.2.3 From 9d52ccea7b00b957bf6cf67a44029912ee6b171f Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 4 Jul 2017 18:59:26 +0200 Subject: Refs: #3478@3h; Policy Cleanup and Providing Policy and permissions for all models and actions - ApplicationPolicy nondestructive permission depend on model existance - ApplicationPolicy destructive permission default to `false` - Tied Policy permissions at ApplicationPolicy Level: edit? → update?, new? → create?, index? → show? - ApplicationPolicy convenience methods `delete?` & `authorizes_action?(action)` - Refactoring of `spec/helpers/table_builder_helper_spec.rb` accordingly - Stubbing scope in specs (cannot switch to referential with a `build_stubbed` instance) --- app/helpers/table_builder_helper/custom_links.rb | 14 +-------- app/policies/acces_point_policy.rb | 5 +--- app/policies/access_link_policy.rb | 5 +--- app/policies/application_policy.rb | 36 ++++++++++++------------ app/policies/calendar_policy.rb | 21 ++++++-------- app/policies/company_policy.rb | 7 ----- app/policies/connection_link_policy.rb | 9 ++---- app/policies/default_policy.rb | 6 ---- app/policies/group_of_line_policy.rb | 8 ------ app/policies/journey_pattern_policy.rb | 9 ++---- app/policies/line_policy.rb | 7 ----- app/policies/network_policy.rb | 8 ------ app/policies/referential_policy.rb | 11 ++++---- app/policies/route_policy.rb | 9 ++---- app/policies/routing_constraint_zone_policy.rb | 9 ++---- app/policies/stop_area_policy.rb | 8 ------ app/policies/time_table_policy.rb | 17 +++++------ app/policies/vehicle_journey_policy.rb | 9 ++---- spec/helpers/table_builder_helper_spec.rb | 2 ++ 19 files changed, 58 insertions(+), 142 deletions(-) diff --git a/app/helpers/table_builder_helper/custom_links.rb b/app/helpers/table_builder_helper/custom_links.rb index 7890f3d35..68cb24c7a 100644 --- a/app/helpers/table_builder_helper/custom_links.rb +++ b/app/helpers/table_builder_helper/custom_links.rb @@ -41,23 +41,11 @@ module TableBuilderHelper end def authorized_actions - @actions.select(&method(:action_authorized?)) - end - def action_authorized?(action) - # TODO: Remove this guard when all resources have policies associated to them - return true unless policy - policy.public_send("#{action}?") - rescue NoMethodError - # TODO: When all action permissions are implemented for all policies remove this rescue clause - action_is_allowed_regardless_of_policy(action) + @actions.select(&policy.method(:authorizes_action?)) end private - def action_is_allowed_regardless_of_policy(action) - ![:delete, :edit, :archive, :unarchive, :duplicate, :actualize].include?(action) - end - def policy @__policy__ ||= Pundit.policy(user_context, object) end diff --git a/app/policies/acces_point_policy.rb b/app/policies/acces_point_policy.rb index 904b7a242..4e017eae4 100644 --- a/app/policies/acces_point_policy.rb +++ b/app/policies/acces_point_policy.rb @@ -9,14 +9,11 @@ class AccessPointPolicy < ApplicationPolicy user.has_permission?('access_points.create') # organisation match via referential is checked in the view end - def edit? + def update? organisation_match? && user.has_permission?('access_points.edit') end def destroy? organisation_match? && user.has_permission?('access_points.destroy') end - - def update? ; edit? end - def new? ; create? end end diff --git a/app/policies/access_link_policy.rb b/app/policies/access_link_policy.rb index 73b2d1baa..4c6473f18 100644 --- a/app/policies/access_link_policy.rb +++ b/app/policies/access_link_policy.rb @@ -9,14 +9,11 @@ class AccessLinkPolicy < ApplicationPolicy user.has_permission?('access_links.create') # organisation match via referential is checked in the view end - def edit? + def update? organisation_match? && user.has_permission?('access_links.edit') end def destroy? organisation_match? && user.has_permission?('access_links.destroy') end - - def update? ; edit? end - def new? ; create? end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index e8d7f5f30..b23d9e0cf 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -6,13 +6,25 @@ class ApplicationPolicy destroy? end - # Tie edit and update together, #edit?, do not override #edit?, + def authorizes_action?(action) + public_send("#{action}?") + rescue NoMethodError + false + end + + # Tie edit? and update? together, #edit?, do not override #edit?, # unless you want to break this tie on purpose def edit? update? end - # Tie new and create together, do not override #new?, + # Tie index? and show? together, do not override #new?, + # unless you want to break this tie on purpose + def index? + show? + end + + # Tie new? and create? together, do not override #new?, # unless you want to break this tie on purpose def new? create? @@ -39,31 +51,19 @@ class ApplicationPolicy record.referential if record.respond_to?(:referential) end - def index? - show? - end - - def show? - scope.where(:id => record.id).exists? - end - def create? false end - def new? - create? - end - - def update? + def destroy? false end - def edit? - update? + def show? + scope.where(:id => record.id).exists? end - def destroy? + def update? false end diff --git a/app/policies/calendar_policy.rb b/app/policies/calendar_policy.rb index 4248bccc7..927a985b3 100644 --- a/app/policies/calendar_policy.rb +++ b/app/policies/calendar_policy.rb @@ -5,23 +5,18 @@ class CalendarPolicy < ApplicationPolicy end end - def show? - organisation_match? || record.shared + def create? + organisation_match? + end + def destroy? + organisation_match? + end + def update? + organisation_match? end - - def new? ; modify? end - def create? ; new? end - - def edit? ; modify? end - def update? ; edit? end - - def destroy? ; modify? end def share? user.organisation.name == 'STIF' # FIXME end - def modify? - organisation_match? - end end diff --git a/app/policies/company_policy.rb b/app/policies/company_policy.rb index 3cc7822a3..6106798be 100644 --- a/app/policies/company_policy.rb +++ b/app/policies/company_policy.rb @@ -4,11 +4,4 @@ class CompanyPolicy < ApplicationPolicy scope end end - - def create?; false end - def destroy?; false end - def edit?; false end - def new?; false end - def show?; true end - def update?; false end end diff --git a/app/policies/connection_link_policy.rb b/app/policies/connection_link_policy.rb index abefd741c..7dccd30a9 100644 --- a/app/policies/connection_link_policy.rb +++ b/app/policies/connection_link_policy.rb @@ -9,14 +9,11 @@ class ConnectionLinkPolicy < ApplicationPolicy user.has_permission?('connection_links.create') # organisation match via referential is checked in the view end - def edit? - organisation_match? && user.has_permission?('connection_links.edit') - end - def destroy? organisation_match? && user.has_permission?('connection_links.destroy') end - def update? ; edit? end - def new? ; create? end + def update? + organisation_match? && user.has_permission?('connection_links.edit') + end end diff --git a/app/policies/default_policy.rb b/app/policies/default_policy.rb index efdac1575..1858fbe7c 100644 --- a/app/policies/default_policy.rb +++ b/app/policies/default_policy.rb @@ -2,10 +2,4 @@ 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/group_of_line_policy.rb b/app/policies/group_of_line_policy.rb index 5d42a23bd..03e94449d 100644 --- a/app/policies/group_of_line_policy.rb +++ b/app/policies/group_of_line_policy.rb @@ -4,12 +4,4 @@ class GroupOfLinePolicy < ApplicationPolicy scope end end - - def create? - false - end - def update? ; create? end - def new? ; create? end - def edit? ; create? end - def destroy? ; create? end end diff --git a/app/policies/journey_pattern_policy.rb b/app/policies/journey_pattern_policy.rb index 7ce2da561..99e39eeff 100644 --- a/app/policies/journey_pattern_policy.rb +++ b/app/policies/journey_pattern_policy.rb @@ -11,15 +11,12 @@ class JourneyPatternPolicy < ApplicationPolicy user.has_permission?('journey_patterns.create') end - def edit? - organisation_match? && user.has_permission?('journey_patterns.edit') - end - def destroy? organisation_match? && user.has_permission?('journey_patterns.destroy') end - def update? ; edit? end - def new? ; create? end + def update? + organisation_match? && user.has_permission?('journey_patterns.edit') + end end diff --git a/app/policies/line_policy.rb b/app/policies/line_policy.rb index a557b496c..674ed9b8d 100644 --- a/app/policies/line_policy.rb +++ b/app/policies/line_policy.rb @@ -6,13 +6,6 @@ class LinePolicy < ApplicationPolicy end end - def show?; true end - def create?; false end - def update? ; false end - def new? ; create? end - def edit? ; false end - def destroy? ; create? end - def create_footnote? !archived? && user.has_permission?('footnotes.create') end diff --git a/app/policies/network_policy.rb b/app/policies/network_policy.rb index 427eace93..9f86451a5 100644 --- a/app/policies/network_policy.rb +++ b/app/policies/network_policy.rb @@ -4,12 +4,4 @@ class NetworkPolicy < ApplicationPolicy scope end end - - def create? - false - end - def update? ; create? end - def new? ; create? end - def edit? ; create? end - def destroy? ; create? end end diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index 8e2a8f7f7..371cae218 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -9,14 +9,15 @@ class ReferentialPolicy < ApplicationPolicy user.has_permission?('referentials.create') end - def edit? - organisation_match? && user.has_permission?('referentials.edit') - end - def destroy? organisation_match? && user.has_permission?('referentials.destroy') end + def update? + organisation_match? && user.has_permission?('referentials.edit') + end + + def archive? edit? end @@ -35,8 +36,6 @@ class ReferentialPolicy < ApplicationPolicy end def unarchive? ; archive? end - def update? ; edit? end - def new? ; create? end end diff --git a/app/policies/route_policy.rb b/app/policies/route_policy.rb index a12055aa6..a33551737 100644 --- a/app/policies/route_policy.rb +++ b/app/policies/route_policy.rb @@ -9,14 +9,11 @@ class RoutePolicy < ApplicationPolicy !archived? && user.has_permission?('routes.create') # organisation match via referential is checked in the view end - def edit? - !archived? && organisation_match? && user.has_permission?('routes.edit') - end - def destroy? !archived? && organisation_match? && user.has_permission?('routes.destroy') end - def update? ; edit? end - def new? ; create? end + def update? + !archived? && organisation_match? && user.has_permission?('routes.edit') + end end diff --git a/app/policies/routing_constraint_zone_policy.rb b/app/policies/routing_constraint_zone_policy.rb index 1e7535475..a10a2c909 100644 --- a/app/policies/routing_constraint_zone_policy.rb +++ b/app/policies/routing_constraint_zone_policy.rb @@ -9,14 +9,11 @@ class RoutingConstraintZonePolicy < ApplicationPolicy !archived? && user.has_permission?('routing_constraint_zones.create') # organisation match via referential is checked in the view end - def edit? - !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.edit') - end - def destroy? !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.destroy') end - def update? ; edit? end - def new? ; create? end + def update? + !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.edit') + end end diff --git a/app/policies/stop_area_policy.rb b/app/policies/stop_area_policy.rb index 4fa426ff6..de8ecda8d 100644 --- a/app/policies/stop_area_policy.rb +++ b/app/policies/stop_area_policy.rb @@ -4,12 +4,4 @@ class StopAreaPolicy < ApplicationPolicy scope end end - - def create? - false - end - def update? ; create? end - def new? ; create? end - def edit? ; create? end - def destroy? ; create? end end diff --git a/app/policies/time_table_policy.rb b/app/policies/time_table_policy.rb index 30df8939b..acd31e9b1 100644 --- a/app/policies/time_table_policy.rb +++ b/app/policies/time_table_policy.rb @@ -6,26 +6,23 @@ class TimeTablePolicy < ApplicationPolicy 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 - def edit? + def destroy? + !archived? && organisation_match? && user.has_permission?('time_tables.destroy') + end + + def update? !archived? && organisation_match? && user.has_permission?('time_tables.edit') end - def destroy? - !archived? && organisation_match? && user.has_permission?('time_tables.destroy') + def actualize? + !archived? && organisation_match? && edit? end def duplicate? !archived? && organisation_match? && create? end - - def update? ; edit? end - def new? ; create? end end diff --git a/app/policies/vehicle_journey_policy.rb b/app/policies/vehicle_journey_policy.rb index ae3680adf..7737f6d7e 100644 --- a/app/policies/vehicle_journey_policy.rb +++ b/app/policies/vehicle_journey_policy.rb @@ -9,14 +9,11 @@ class VehicleJourneyPolicy < ApplicationPolicy user.has_permission?('vehicle_journeys.create') # organisation match via referential is checked in the view end - def edit? - organisation_match? && user.has_permission?('vehicle_journeys.edit') - end - def destroy? organisation_match? && user.has_permission?('vehicle_journeys.destroy') end - def update? ; edit? end - def new? ; create? end + def update? + organisation_match? && user.has_permission?('vehicle_journeys.edit') + end end diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb index 6d7b60366..6b505c940 100644 --- a/spec/helpers/table_builder_helper_spec.rb +++ b/spec/helpers/table_builder_helper_spec.rb @@ -193,6 +193,7 @@ describe TableBuilderHelper, type: :helper do companies, with: CompanyDecorator ) + allow(CompanyDecorator).to receive(:where).with(id: company.id).and_return double.as_null_object expected = <<-HTML @@ -302,6 +303,7 @@ describe TableBuilderHelper, type: :helper do with: CompanyDecorator, context: {line_referential: line_referential} ) + allow(CompanyDecorator).to receive(:where).with(id: company.id).and_return double.as_null_object expected = <<-HTML -- cgit v1.2.3 From 841bd65847066e92bf5a4d6de112fed1ada73c1c Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 5 Jul 2017 08:13:14 +0200 Subject: Refs: #3478@1.5h; - PolicyChecker authorizes(*) all now - Untied ApplicationPolicy#index? from show? - mv access_point_policy.rb to access_point_policy.rb fixing an invisible name curruption (local problem?) * to authorize: to allow (not here), to undergo the process of authorization (here) --- app/controllers/concerns/policy_checker.rb | 9 +++- app/controllers/referentials_controller.rb | 1 - app/models/chouette/access_point.rb | 1 - app/policies/acces_point_policy.rb | 19 -------- app/policies/access_point_policy.rb | 19 ++++++++ app/policies/application_policy.rb | 72 +++++++++++++++++++----------- config/environments/test.rb | 2 - 7 files changed, 73 insertions(+), 50 deletions(-) delete mode 100644 app/policies/acces_point_policy.rb create mode 100644 app/policies/access_point_policy.rb diff --git a/app/controllers/concerns/policy_checker.rb b/app/controllers/concerns/policy_checker.rb index 72c18c64f..c8a821cf7 100644 --- a/app/controllers/concerns/policy_checker.rb +++ b/app/controllers/concerns/policy_checker.rb @@ -2,11 +2,16 @@ module PolicyChecker extend ActiveSupport::Concern included do - before_action :check_policy, only: [:edit, :update, :destroy] + before_action :authorize_resource, except: [:create, :index, :new] + before_action :authorize_resource_class, only: [:create, :index, :new] end protected - def check_policy + def authorize_resource authorize resource end + + def authorize_resource_class + authorize resource_class + end end diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index 1239d512f..31b953ace 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -1,7 +1,6 @@ class ReferentialsController < BreadcrumbController defaults :resource_class => Referential include PolicyChecker - before_action :check_policy, :only => [:edit, :update, :destroy, :archive, :unarchive] # overrides default respond_to :html respond_to :json, :only => :show diff --git a/app/models/chouette/access_point.rb b/app/models/chouette/access_point.rb index 3cae07b8e..da1f9524a 100644 --- a/app/models/chouette/access_point.rb +++ b/app/models/chouette/access_point.rb @@ -1,4 +1,3 @@ - require 'geokit' require 'geo_ruby' diff --git a/app/policies/acces_point_policy.rb b/app/policies/acces_point_policy.rb deleted file mode 100644 index 4e017eae4..000000000 --- a/app/policies/acces_point_policy.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AccessPointPolicy < ApplicationPolicy - class Scope < Scope - def resolve - scope - end - end - - def create? - user.has_permission?('access_points.create') # organisation match via referential is checked in the view - end - - def update? - organisation_match? && user.has_permission?('access_points.edit') - end - - def destroy? - organisation_match? && user.has_permission?('access_points.destroy') - end -end diff --git a/app/policies/access_point_policy.rb b/app/policies/access_point_policy.rb new file mode 100644 index 000000000..4e017eae4 --- /dev/null +++ b/app/policies/access_point_policy.rb @@ -0,0 +1,19 @@ +class AccessPointPolicy < ApplicationPolicy + class Scope < Scope + def resolve + scope + end + end + + def create? + user.has_permission?('access_points.create') # organisation match via referential is checked in the view + end + + def update? + organisation_match? && user.has_permission?('access_points.edit') + end + + def destroy? + organisation_match? && user.has_permission?('access_points.destroy') + end +end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index b23d9e0cf..d5c1039fd 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -1,5 +1,17 @@ class ApplicationPolicy + attr_reader :current_referential, :record, :user + def initialize(user_context, record) + @user = user_context.user + @current_referential = user_context.context[:referential] + @record = record + end + + # HMMM: Maybe one can tie index? to show? again by replacing record.class as follows: + # Class === record ? record : record.class + def scope + Pundit.policy_scope!(user, record.class) + end # Make authorization by action easier def delete? @@ -12,18 +24,17 @@ class ApplicationPolicy false end + + # + # Tied permissions + # ---------------- + # Tie edit? and update? together, #edit?, do not override #edit?, # unless you want to break this tie on purpose def edit? update? end - # Tie index? and show? together, do not override #new?, - # unless you want to break this tie on purpose - def index? - show? - end - # Tie new? and create? together, do not override #new?, # unless you want to break this tie on purpose def new? @@ -31,25 +42,22 @@ class ApplicationPolicy end + # + # Permissions for undestructive actions + # ------------------------------------- - def initialize(user_context, record) - @user = user_context.user - @current_referential = user_context.context[:referential] - @record = record + def index? + true end - def archived? - return @is_archived if instance_variable_defined?(:@is_archived) - @is_archived = is_archived + def show? + scope.where(:id => record.id).exists? end - def referential - @referential ||= current_referential || record_referential - end - def record_referential - record.referential if record.respond_to?(:referential) - end + # + # Permissions for destructive actions + # ----------------------------------- def create? false @@ -59,16 +67,18 @@ class ApplicationPolicy false end - def show? - scope.where(:id => record.id).exists? - end - def update? false end - def scope - Pundit.policy_scope!(user, record.class) + + # + # Custom Permissions + # ------------------ + + def archived? + return @is_archived if instance_variable_defined?(:@is_archived) + @is_archived = is_archived end def organisation_match? @@ -81,6 +91,18 @@ class ApplicationPolicy organisation or referential.try :organisation end + + # + # Helpers + # ------- + + def referential + @referential ||= current_referential || record_referential + end + + def record_referential + record.referential if record.respond_to?(:referential) + end class Scope attr_reader :user, :scope diff --git a/config/environments/test.rb b/config/environments/test.rb index d83b4fd85..80ed940ca 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,8 +1,6 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - config.eager_load = false - # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped -- cgit v1.2.3 From e53aa88c442bd0057c4e0ae66e2684d62d3193ed Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 5 Jul 2017 11:54:33 +0200 Subject: Refs: #3478@1h; - All permissions tied to `!archived?` - Tests adapted - Policies refactored ? Is `create?` permission bound to `organisation_match?` --- app/helpers/table_builder_helper/custom_links.rb | 4 ++-- app/policies/acces_point_policy.rb | 25 ++++++++++++++++++++++ app/policies/access_link_policy.rb | 6 +++--- app/policies/access_point_policy.rb | 6 +++--- app/policies/calendar_policy.rb | 6 +++--- app/policies/connection_link_policy.rb | 6 +++--- app/policies/journey_pattern_policy.rb | 7 +++--- app/policies/referential_policy.rb | 20 ++++++++--------- app/policies/routing_constraint_zone_policy.rb | 2 +- app/policies/time_table_policy.rb | 2 +- app/policies/vehicle_journey_policy.rb | 6 +++--- .../table_builder_helper/custom_links_spec.rb | 1 + spec/helpers/table_builder_helper_spec.rb | 5 +++-- .../routing_constraint_zone_policy_spec.rb | 4 ++-- spec/policies/time_table_policy_spec.rb | 11 ++++------ spec/support/apartment_stubbing.rb | 14 ++++++++++++ 16 files changed, 81 insertions(+), 44 deletions(-) create mode 100644 app/policies/acces_point_policy.rb create mode 100644 spec/support/apartment_stubbing.rb diff --git a/app/helpers/table_builder_helper/custom_links.rb b/app/helpers/table_builder_helper/custom_links.rb index 68cb24c7a..e3ffb18ac 100644 --- a/app/helpers/table_builder_helper/custom_links.rb +++ b/app/helpers/table_builder_helper/custom_links.rb @@ -33,7 +33,7 @@ module TableBuilderHelper polymorph_url << action end - polymorph_url += URL.polymorphic_url_parts(@object) + polymorph_url += URL.polymorphic_url_parts(object) end def method_for_action(action) @@ -41,7 +41,7 @@ module TableBuilderHelper end def authorized_actions - @actions.select(&policy.method(:authorizes_action?)) + actions.select(&policy.method(:authorizes_action?)) end private diff --git a/app/policies/acces_point_policy.rb b/app/policies/acces_point_policy.rb new file mode 100644 index 000000000..ce3a8a1ef --- /dev/null +++ b/app/policies/acces_point_policy.rb @@ -0,0 +1,25 @@ +class AccessPointPolicy < ApplicationPolicy + class Scope < Scope + def resolve + scope + end + end + + def create? + !archived? && + organisation_match? && + user.has_permission?('access_points.create') + end + + def update? + !archived? && + organisation_match? && + user.has_permission?('access_points.edit') + end + + def destroy? + !archived? && + organisation_match? + && user.has_permission?('access_points.destroy') + end +end diff --git a/app/policies/access_link_policy.rb b/app/policies/access_link_policy.rb index 4c6473f18..a4f0e40e8 100644 --- a/app/policies/access_link_policy.rb +++ b/app/policies/access_link_policy.rb @@ -6,14 +6,14 @@ class AccessLinkPolicy < ApplicationPolicy end def create? - user.has_permission?('access_links.create') # organisation match via referential is checked in the view + !archived? && oragnisation_mathc? && user.has_permission?('access_links.create') end def update? - organisation_match? && user.has_permission?('access_links.edit') + !archived? && organisation_match? && user.has_permission?('access_links.edit') end def destroy? - organisation_match? && user.has_permission?('access_links.destroy') + !archived? && organisation_match? && user.has_permission?('access_links.destroy') end end diff --git a/app/policies/access_point_policy.rb b/app/policies/access_point_policy.rb index 4e017eae4..a1b57a3e5 100644 --- a/app/policies/access_point_policy.rb +++ b/app/policies/access_point_policy.rb @@ -6,14 +6,14 @@ class AccessPointPolicy < ApplicationPolicy end def create? - user.has_permission?('access_points.create') # organisation match via referential is checked in the view + !archived? && organisation_match? && user.has_permission?('access_points.create') end def update? - organisation_match? && user.has_permission?('access_points.edit') + !archived? && organisation_match? && user.has_permission?('access_points.edit') end def destroy? - organisation_match? && user.has_permission?('access_points.destroy') + !archived? && organisation_match? && user.has_permission?('access_points.destroy') end end diff --git a/app/policies/calendar_policy.rb b/app/policies/calendar_policy.rb index 927a985b3..3353988bd 100644 --- a/app/policies/calendar_policy.rb +++ b/app/policies/calendar_policy.rb @@ -6,13 +6,13 @@ class CalendarPolicy < ApplicationPolicy end def create? - organisation_match? + !archived? && organisation_match? end def destroy? - organisation_match? + !archived? && organisation_match? end def update? - organisation_match? + !archived? && organisation_match? end def share? diff --git a/app/policies/connection_link_policy.rb b/app/policies/connection_link_policy.rb index 7dccd30a9..acadc807d 100644 --- a/app/policies/connection_link_policy.rb +++ b/app/policies/connection_link_policy.rb @@ -6,14 +6,14 @@ class ConnectionLinkPolicy < ApplicationPolicy end def create? - user.has_permission?('connection_links.create') # organisation match via referential is checked in the view + !archived? && organisation_match? && user.has_permission?('connection_links.create') end def destroy? - organisation_match? && user.has_permission?('connection_links.destroy') + !archived? && organisation_match? && user.has_permission?('connection_links.destroy') end def update? - organisation_match? && user.has_permission?('connection_links.edit') + !archived? && organisation_match? && user.has_permission?('connection_links.edit') end end diff --git a/app/policies/journey_pattern_policy.rb b/app/policies/journey_pattern_policy.rb index 99e39eeff..810ead170 100644 --- a/app/policies/journey_pattern_policy.rb +++ b/app/policies/journey_pattern_policy.rb @@ -7,16 +7,15 @@ class JourneyPatternPolicy < ApplicationPolicy end def create? - # organisation match via referential is checked in the view - user.has_permission?('journey_patterns.create') + !archived? && organisation_match? && user.has_permission?('journey_patterns.create') end def destroy? - organisation_match? && user.has_permission?('journey_patterns.destroy') + !archived? && organisation_match? && user.has_permission?('journey_patterns.destroy') end def update? - organisation_match? && user.has_permission?('journey_patterns.edit') + !archived? && organisation_match? && user.has_permission?('journey_patterns.edit') end end diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index 371cae218..7f8c9e939 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -10,20 +10,25 @@ class ReferentialPolicy < ApplicationPolicy end def destroy? - organisation_match? && user.has_permission?('referentials.destroy') + !archived? && organisation_match? && user.has_permission?('referentials.destroy') end def update? - organisation_match? && user.has_permission?('referentials.edit') + !archived? && organisation_match? && user.has_permission?('referentials.edit') end + + def clone? + !archived? && organisation_match? && create? + end + def archive? - edit? + !archived? && update? end - def clone? - organisation_match? && create? + def unarchive? + archived? && update? end def common_lines? @@ -31,11 +36,6 @@ class ReferentialPolicy < ApplicationPolicy true end - def show? - true - end - - def unarchive? ; archive? end end diff --git a/app/policies/routing_constraint_zone_policy.rb b/app/policies/routing_constraint_zone_policy.rb index a10a2c909..3f2ad99a9 100644 --- a/app/policies/routing_constraint_zone_policy.rb +++ b/app/policies/routing_constraint_zone_policy.rb @@ -6,7 +6,7 @@ class RoutingConstraintZonePolicy < ApplicationPolicy end def create? - !archived? && user.has_permission?('routing_constraint_zones.create') # organisation match via referential is checked in the view + !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.create') end def destroy? diff --git a/app/policies/time_table_policy.rb b/app/policies/time_table_policy.rb index acd31e9b1..acdc2d13c 100644 --- a/app/policies/time_table_policy.rb +++ b/app/policies/time_table_policy.rb @@ -7,7 +7,7 @@ class TimeTablePolicy < ApplicationPolicy end def create? - !archived? && user.has_permission?('time_tables.create') # organisation match via referential is checked in the view + !archived? && organisation_match? && user.has_permission?('time_tables.create') end def destroy? diff --git a/app/policies/vehicle_journey_policy.rb b/app/policies/vehicle_journey_policy.rb index 7737f6d7e..27d96e43b 100644 --- a/app/policies/vehicle_journey_policy.rb +++ b/app/policies/vehicle_journey_policy.rb @@ -6,14 +6,14 @@ class VehicleJourneyPolicy < ApplicationPolicy end def create? - user.has_permission?('vehicle_journeys.create') # organisation match via referential is checked in the view + !archived? && organisation_match? && user.has_permission?('vehicle_journeys.create') end def destroy? - organisation_match? && user.has_permission?('vehicle_journeys.destroy') + !archived? && organisation_match? && user.has_permission?('vehicle_journeys.destroy') end def update? - organisation_match? && user.has_permission?('vehicle_journeys.edit') + !archived? && organisation_match? && user.has_permission?('vehicle_journeys.edit') end end diff --git a/spec/helpers/table_builder_helper/custom_links_spec.rb b/spec/helpers/table_builder_helper/custom_links_spec.rb index bd0bd4fcf..4b07922a7 100644 --- a/spec/helpers/table_builder_helper/custom_links_spec.rb +++ b/spec/helpers/table_builder_helper/custom_links_spec.rb @@ -10,6 +10,7 @@ describe TableBuilderHelper::CustomLinks do referential: referential ) + stub_policy_scope(referential) expect( TableBuilderHelper::CustomLinks.new( referential, diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb index 6b505c940..4afd0774c 100644 --- a/spec/helpers/table_builder_helper_spec.rb +++ b/spec/helpers/table_builder_helper_spec.rb @@ -27,6 +27,7 @@ describe TableBuilderHelper, type: :helper do referentials = [referential] allow(referentials).to receive(:model).and_return(Referential) + stub_policy_scope(referential) allow(helper).to receive(:params).and_return({ controller: 'workbenches', @@ -193,7 +194,7 @@ describe TableBuilderHelper, type: :helper do companies, with: CompanyDecorator ) - allow(CompanyDecorator).to receive(:where).with(id: company.id).and_return double.as_null_object + stub_policy_scope(company) expected = <<-HTML @@ -303,7 +304,7 @@ describe TableBuilderHelper, type: :helper do with: CompanyDecorator, context: {line_referential: line_referential} ) - allow(CompanyDecorator).to receive(:where).with(id: company.id).and_return double.as_null_object + stub_policy_scope(company) expected = <<-HTML diff --git a/spec/policies/routing_constraint_zone_policy_spec.rb b/spec/policies/routing_constraint_zone_policy_spec.rb index 2508b49f9..f91313390 100644 --- a/spec/policies/routing_constraint_zone_policy_spec.rb +++ b/spec/policies/routing_constraint_zone_policy_spec.rb @@ -4,7 +4,7 @@ RSpec.describe RoutingConstraintZonePolicy, type: :policy do permissions :create? do - it_behaves_like 'permitted policy', 'routing_constraint_zones.create', archived: true + it_behaves_like 'permitted policy and same organisation', 'routing_constraint_zones.create', archived: true end permissions :destroy? do @@ -16,7 +16,7 @@ RSpec.describe RoutingConstraintZonePolicy, type: :policy do end permissions :new? do - it_behaves_like 'permitted policy', 'routing_constraint_zones.create', archived: true + it_behaves_like 'permitted policy and same organisation', 'routing_constraint_zones.create', archived: true end permissions :update? do diff --git a/spec/policies/time_table_policy_spec.rb b/spec/policies/time_table_policy_spec.rb index 90e6600ea..6c19362d2 100644 --- a/spec/policies/time_table_policy_spec.rb +++ b/spec/policies/time_table_policy_spec.rb @@ -3,8 +3,10 @@ RSpec.describe TimeTablePolicy, type: :policy do let( :record ){ build_stubbed :time_table } - permissions :duplicate? do - it_behaves_like 'permitted policy and same organisation', 'time_tables.create', archived: true + %w{create duplicate}.each do | permission | + permissions "#{permission}?".to_sym do + it_behaves_like 'permitted policy and same organisation', 'time_tables.create', archived: true + end end %w{destroy edit}.each do | permission | @@ -13,9 +15,4 @@ RSpec.describe TimeTablePolicy, type: :policy do end end - permissions :create? do - it_behaves_like 'permitted policy', 'time_tables.create', archived: true - end - - end diff --git a/spec/support/apartment_stubbing.rb b/spec/support/apartment_stubbing.rb new file mode 100644 index 000000000..408d3b878 --- /dev/null +++ b/spec/support/apartment_stubbing.rb @@ -0,0 +1,14 @@ +module Support + # This is needed for referentials that are stubbed with `build_stubbed` + # As one cannot switch to such referentials (obviously the schema does not exist) + # we provide a stub for `scope.where(...` needed in ApplicationPolicy#show + module ApartmentStubbing + def stub_policy_scope(model) + allow(model.class).to receive(:where).with(id: model.id).and_return double("instance of #{model.class}").as_null_object + end + end +end + +RSpec.configure do | conf | + conf.include Support::ApartmentStubbing +end -- cgit v1.2.3 From b09994a4ee79f735f9b3f43535c6d138c4b68a56 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 5 Jul 2017 16:52:44 +0200 Subject: Refs:#3478@10h; Policy Refactoring and Policy Test Completion - All policies (and all permissions) under test. - Common patterns and potential problems identified... - ... and documented in DEVNOTES.md - some simply refactorings --- DEVNOTES.md | 62 +++++++++ .../journey_patterns_collections_controller.rb | 9 +- app/controllers/time_tables_controller.rb | 1 - app/controllers/vehicle_journeys_controller.rb | 9 +- app/models/user.rb | 19 ++- app/policies/acces_point_policy.rb | 25 ---- app/policies/access_link_policy.rb | 4 +- app/policies/access_point_policy.rb | 2 +- app/policies/application_policy.rb | 7 +- app/policies/connection_link_policy.rb | 2 +- app/policies/journey_pattern_policy.rb | 2 +- app/policies/line_policy.rb | 2 +- app/policies/referential_policy.rb | 6 +- app/policies/route_policy.rb | 2 +- app/policies/routing_constraint_zone_policy.rb | 2 +- app/policies/time_table_policy.rb | 2 +- app/policies/vehicle_journey_policy.rb | 2 +- app/views/time_tables/show.html.slim | 1 + ...journey_patterns_collections_controller_spec.rb | 2 - spec/controllers/routes_controller_spec.rb | 4 +- spec/features/time_tables_spec.rb | 5 +- spec/features/vehicle_journeys_spec.rb | 2 +- spec/helpers/table_builder_helper_spec.rb | 2 +- spec/policies/access_link_policy_spec.rb | 20 +++ spec/policies/access_point_policy_spec.rb | 20 +++ spec/policies/calendar_policy_spec.rb | 47 +++++++ spec/policies/company_policy_spec.rb | 42 ++++++ spec/policies/connection_link_policy_spec.rb | 20 +++ spec/policies/group_of_line_policy_spec.rb | 42 ++++++ spec/policies/journey_pattern_policy_spec.rb | 20 +++ spec/policies/line_policy_spec.rb | 154 ++++++++++++++++++++- spec/policies/network_policy_spec.rb | 42 ++++++ spec/policies/referential_policy_spec.rb | 102 ++++++++++++++ spec/policies/route_policy_spec.rb | 4 +- .../routing_constraint_zone_policy_spec.rb | 4 +- spec/policies/stop_area_policy_spec.rb | 42 ++++++ spec/policies/time_table_policy_spec.rb | 22 +-- spec/support/devise.rb | 43 ++++-- spec/support/pundit/shared_examples.rb | 74 +++++++++- 39 files changed, 769 insertions(+), 103 deletions(-) create mode 100644 DEVNOTES.md delete mode 100644 app/policies/acces_point_policy.rb create mode 100644 spec/policies/access_link_policy_spec.rb create mode 100644 spec/policies/access_point_policy_spec.rb create mode 100644 spec/policies/calendar_policy_spec.rb create mode 100644 spec/policies/company_policy_spec.rb create mode 100644 spec/policies/connection_link_policy_spec.rb create mode 100644 spec/policies/group_of_line_policy_spec.rb create mode 100644 spec/policies/journey_pattern_policy_spec.rb create mode 100644 spec/policies/network_policy_spec.rb create mode 100644 spec/policies/referential_policy_spec.rb create mode 100644 spec/policies/stop_area_policy_spec.rb diff --git a/DEVNOTES.md b/DEVNOTES.md new file mode 100644 index 000000000..01f58fa0f --- /dev/null +++ b/DEVNOTES.md @@ -0,0 +1,62 @@ + +# Authorization Logic in Policies + +## Base Rules + +### ApplicationPolicy + +Policies inheriting from the `ApplicationPolicy` authorize _Undestructive_ _Permissions_ whiche are `index?` and +`show?`. And forbid _Destructive_ _Permissions_ which are `create?`, `destroy?` & `update`. + +These _CRUD_ permissions are tied to to _Action_ permissions, `delete?`→ `destroy?`, `edit?` → `update? and `new?`→ `create?`. + +These three _Action_ permissions are not supposed to be overriden in `ApplicationPolicy` subclasses. + + +### Common Policy Types + +There are two common policy types. + +#### Read Only Type Policy + +This corresponds to inheriting from `ApplicationPolicy` without overriding one of the five aforementioned _CRUD_ permissions. + +The following Policies are of this type. + + - `Company` + - `GroupOfLine` + - `Line` + custom + - `Network` + - `StopArea` + +#### Standard Type Policy + +The standard type policy inherits from `ApplicationPolicy` does not override any _Undesructive_ _Pemission_ but overrides the _Destructive_ ones. + +Normally, but not always they are overriden as follows + +```ruby + def ? + !archived? && organisation_match? && user.has_permission('.') + end +``` + +There are some variations (**TO BE CLARIFIED**) concerning `organisation_match?`. + +The following Policies are of this type. + + - `AccessLink` + - `AccessPoint` + - `Calendar` (*) + - `ConnectionLink` + - `JourneyPattern` + - `Referential` + custom + - `Route` + - `RoutingConstraintZone` + - `TimeTable` + custom + +`Calendar` is a strange exception where no user permission is checked for the _destructive_ _permissions_. + + + + diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb index 7b97e1408..837ac65e7 100644 --- a/app/controllers/journey_patterns_collections_controller.rb +++ b/app/controllers/journey_patterns_collections_controller.rb @@ -49,11 +49,10 @@ class JourneyPatternsCollectionsController < ChouetteController end def user_permissions - @perms = {}.tap do |perm| - ['journey_patterns.create', 'journey_patterns.edit', 'journey_patterns.destroy'].each do |name| - perm[name] = policy(:journey_pattern).send("#{name.split('.').last}?") - end - end.to_json + @perms = + %w{create destroy edit}.inject({}) do | permissions, action | + permissions.merge( "journey_patterns.#{action}" => policy.authorizes_action?(action) ) + end.to_json end def update diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb index 6d2639981..0e0cade56 100644 --- a/app/controllers/time_tables_controller.rb +++ b/app/controllers/time_tables_controller.rb @@ -17,7 +17,6 @@ class TimeTablesController < ChouetteController @time_table = @time_table.decorate(context: { referential: @referential }) - build_breadcrumb :show end end diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb index fe2e2137f..f7e2fcdc1 100644 --- a/app/controllers/vehicle_journeys_controller.rb +++ b/app/controllers/vehicle_journeys_controller.rb @@ -159,11 +159,10 @@ class VehicleJourneysController < ChouetteController end def user_permissions - @perms = {}.tap do |perm| - ['vehicle_journeys.create', 'vehicle_journeys.edit', 'vehicle_journeys.destroy'].each do |name| - perm[name] = policy(:vehicle_journey).send("#{name.split('.').last}?") - end - end.to_json + @perms = + %w{create destroy update}.inject({}) do | permissions, action | + permissions.merge( "vehicle_journeys.#{action}" => policy.authorizes_action?(action) ) + end.to_json end private diff --git a/app/models/user.rb b/app/models/user.rb index 9cd4f64d6..1d9e435d5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -28,10 +28,21 @@ class User < ActiveRecord::Base end after_destroy :check_destroy_organisation - @@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'] + def self.destructive_permissions_for(models) + models.product( %w{create destroy update} ).map{ |model_action| model_action.join('.') } + end + + @@edit_offer_permissions = + destructive_permissions_for( %w[ + footnotes + journey_patterns + referentials + routes + routing_constraint_zones + time_tables + vehicle_journeys + ]) << 'boiv:edit-offer' + mattr_reader :edit_offer_permissions def self.all_permissions diff --git a/app/policies/acces_point_policy.rb b/app/policies/acces_point_policy.rb deleted file mode 100644 index ce3a8a1ef..000000000 --- a/app/policies/acces_point_policy.rb +++ /dev/null @@ -1,25 +0,0 @@ -class AccessPointPolicy < ApplicationPolicy - class Scope < Scope - def resolve - scope - end - end - - def create? - !archived? && - organisation_match? && - user.has_permission?('access_points.create') - end - - def update? - !archived? && - organisation_match? && - user.has_permission?('access_points.edit') - end - - def destroy? - !archived? && - organisation_match? - && user.has_permission?('access_points.destroy') - end -end diff --git a/app/policies/access_link_policy.rb b/app/policies/access_link_policy.rb index a4f0e40e8..1f1147f60 100644 --- a/app/policies/access_link_policy.rb +++ b/app/policies/access_link_policy.rb @@ -6,11 +6,11 @@ class AccessLinkPolicy < ApplicationPolicy end def create? - !archived? && oragnisation_mathc? && user.has_permission?('access_links.create') + !archived? && organisation_match? && user.has_permission?('access_links.create') end def update? - !archived? && organisation_match? && user.has_permission?('access_links.edit') + !archived? && organisation_match? && user.has_permission?('access_links.update') end def destroy? diff --git a/app/policies/access_point_policy.rb b/app/policies/access_point_policy.rb index a1b57a3e5..41436e77c 100644 --- a/app/policies/access_point_policy.rb +++ b/app/policies/access_point_policy.rb @@ -10,7 +10,7 @@ class AccessPointPolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('access_points.edit') + !archived? && organisation_match? && user.has_permission?('access_points.update') end def destroy? diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index d5c1039fd..dbe4542e7 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -82,13 +82,12 @@ class ApplicationPolicy end def organisation_match? - user.organisation == organisation + user.organisation_id == organisation_id end - def organisation + def organisation_id # When sending permission to react UI, we don't have access to record object for edit & destroy.. actions - organisation = record.is_a?(Symbol) ? nil : record.try(:organisation) - organisation or referential.try :organisation + referential.try(:organisation_id) || record.try(:organisation_id) end diff --git a/app/policies/connection_link_policy.rb b/app/policies/connection_link_policy.rb index acadc807d..240c2a804 100644 --- a/app/policies/connection_link_policy.rb +++ b/app/policies/connection_link_policy.rb @@ -14,6 +14,6 @@ class ConnectionLinkPolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('connection_links.edit') + !archived? && organisation_match? && user.has_permission?('connection_links.update') end end diff --git a/app/policies/journey_pattern_policy.rb b/app/policies/journey_pattern_policy.rb index 810ead170..507a364b6 100644 --- a/app/policies/journey_pattern_policy.rb +++ b/app/policies/journey_pattern_policy.rb @@ -15,7 +15,7 @@ class JourneyPatternPolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('journey_patterns.edit') + !archived? && organisation_match? && user.has_permission?('journey_patterns.update') end end diff --git a/app/policies/line_policy.rb b/app/policies/line_policy.rb index 674ed9b8d..b84c7a69f 100644 --- a/app/policies/line_policy.rb +++ b/app/policies/line_policy.rb @@ -11,7 +11,7 @@ class LinePolicy < ApplicationPolicy end def edit_footnote? - !archived? && user.has_permission?('footnotes.edit') + !archived? && user.has_permission?('footnotes.update') end def destroy_footnote? diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb index 7f8c9e939..bf970c2b8 100644 --- a/app/policies/referential_policy.rb +++ b/app/policies/referential_policy.rb @@ -14,7 +14,7 @@ class ReferentialPolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('referentials.edit') + !archived? && organisation_match? && user.has_permission?('referentials.update') end @@ -24,11 +24,11 @@ class ReferentialPolicy < ApplicationPolicy end def archive? - !archived? && update? + record.archived_at.nil? && user.has_permission?('referentials.update') end def unarchive? - archived? && update? + !record.archived_at.nil? && user.has_permission?('referentials.update') end def common_lines? diff --git a/app/policies/route_policy.rb b/app/policies/route_policy.rb index a33551737..be3ffce4d 100644 --- a/app/policies/route_policy.rb +++ b/app/policies/route_policy.rb @@ -14,6 +14,6 @@ class RoutePolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('routes.edit') + !archived? && organisation_match? && user.has_permission?('routes.update') end end diff --git a/app/policies/routing_constraint_zone_policy.rb b/app/policies/routing_constraint_zone_policy.rb index 3f2ad99a9..3cfcf46ff 100644 --- a/app/policies/routing_constraint_zone_policy.rb +++ b/app/policies/routing_constraint_zone_policy.rb @@ -14,6 +14,6 @@ class RoutingConstraintZonePolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.edit') + !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.update') end end diff --git a/app/policies/time_table_policy.rb b/app/policies/time_table_policy.rb index acdc2d13c..c9f3a3ec6 100644 --- a/app/policies/time_table_policy.rb +++ b/app/policies/time_table_policy.rb @@ -15,7 +15,7 @@ class TimeTablePolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('time_tables.edit') + !archived? && organisation_match? && user.has_permission?('time_tables.update') end def actualize? diff --git a/app/policies/vehicle_journey_policy.rb b/app/policies/vehicle_journey_policy.rb index 27d96e43b..24040455f 100644 --- a/app/policies/vehicle_journey_policy.rb +++ b/app/policies/vehicle_journey_policy.rb @@ -14,6 +14,6 @@ class VehicleJourneyPolicy < ApplicationPolicy end def update? - !archived? && organisation_match? && user.has_permission?('vehicle_journeys.edit') + !archived? && organisation_match? && user.has_permission?('vehicle_journeys.update') end end diff --git a/app/views/time_tables/show.html.slim b/app/views/time_tables/show.html.slim index f596fd480..36b79cc25 100644 --- a/app/views/time_tables/show.html.slim +++ b/app/views/time_tables/show.html.slim @@ -1,6 +1,7 @@ - require 'calendar_helper' / PageHeader + = pageheader 'map-marker', @time_table.comment, '', diff --git a/spec/controllers/journey_patterns_collections_controller_spec.rb b/spec/controllers/journey_patterns_collections_controller_spec.rb index 888281036..442d73fb7 100644 --- a/spec/controllers/journey_patterns_collections_controller_spec.rb +++ b/spec/controllers/journey_patterns_collections_controller_spec.rb @@ -1,5 +1,3 @@ -require 'rails_helper' - RSpec.describe JourneyPatternsCollectionsController, :type => :controller do end diff --git a/spec/controllers/routes_controller_spec.rb b/spec/controllers/routes_controller_spec.rb index 18067dec7..000b799db 100644 --- a/spec/controllers/routes_controller_spec.rb +++ b/spec/controllers/routes_controller_spec.rb @@ -1,6 +1,4 @@ -require 'spec_helper' - -describe RoutesController, :type => :controller do +RSpec.describe RoutesController, :type => :controller do login_user let!(:route) { create(:route) } diff --git a/spec/features/time_tables_spec.rb b/spec/features/time_tables_spec.rb index 58a1dc98f..0fb4bb30d 100644 --- a/spec/features/time_tables_spec.rb +++ b/spec/features/time_tables_spec.rb @@ -1,7 +1,4 @@ -# -*- coding: utf-8 -*- -require 'spec_helper' - -describe "TimeTables", :type => :feature do +RSpec.describe "TimeTables", :type => :feature do login_user let!(:time_tables) { Array.new(2) { create(:time_table) } } diff --git a/spec/features/vehicle_journeys_spec.rb b/spec/features/vehicle_journeys_spec.rb index 5a3a9ad7d..16a79e2c5 100644 --- a/spec/features/vehicle_journeys_spec.rb +++ b/spec/features/vehicle_journeys_spec.rb @@ -43,7 +43,7 @@ describe 'VehicleJourneys', type: :feature do context 'user does not have permission to edit vehicle journeys' do it 'does not show an edit link for vehicle journeys' do - @user.tap { |u| u.permissions.delete('vehicle_journeys.edit') }.save + @user.tap { |u| u.permissions.delete('vehicle_journeys.update') }.save visit referential_line_route_vehicle_journey_path(referential, line, route, vehicle_journey) expect(page).not_to have_content(I18n.t('vehicle_journeys.actions.edit')) end diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb index 4afd0774c..c2c287b99 100644 --- a/spec/helpers/table_builder_helper_spec.rb +++ b/spec/helpers/table_builder_helper_spec.rb @@ -16,7 +16,7 @@ describe TableBuilderHelper, type: :helper do organisation: referential.organisation, permissions: [ 'referentials.create', - 'referentials.edit', + 'referentials.update', 'referentials.destroy', ] ), diff --git a/spec/policies/access_link_policy_spec.rb b/spec/policies/access_link_policy_spec.rb new file mode 100644 index 000000000..6194ae55c --- /dev/null +++ b/spec/policies/access_link_policy_spec.rb @@ -0,0 +1,20 @@ +RSpec.describe AccessLinkPolicy, type: :policy do + + let( :record ){ build_stubbed :access_link } + + permissions :create? do + it_behaves_like 'permitted policy and same organisation', "access_links.create", archived: true + end + permissions :destroy? do + it_behaves_like 'permitted policy and same organisation', "access_links.destroy", archived: true + end + permissions :edit? do + it_behaves_like 'permitted policy and same organisation', "access_links.update", archived: true + end + permissions :new? do + it_behaves_like 'permitted policy and same organisation', "access_links.create", archived: true + end + permissions :update? do + it_behaves_like 'permitted policy and same organisation', "access_links.update", archived: true + end +end diff --git a/spec/policies/access_point_policy_spec.rb b/spec/policies/access_point_policy_spec.rb new file mode 100644 index 000000000..b6bc46eb4 --- /dev/null +++ b/spec/policies/access_point_policy_spec.rb @@ -0,0 +1,20 @@ +RSpec.describe AccessPointPolicy, type: :policy do + + let( :record ){ build_stubbed :access_point } + + permissions :create? do + it_behaves_like 'permitted policy and same organisation', "access_points.create", archived: true + end + permissions :destroy? do + it_behaves_like 'permitted policy and same organisation', "access_points.destroy", archived: true + end + permissions :edit? do + it_behaves_like 'permitted policy and same organisation', "access_points.update", archived: true + end + permissions :new? do + it_behaves_like 'permitted policy and same organisation', "access_points.create", archived: true + end + permissions :update? do + it_behaves_like 'permitted policy and same organisation', "access_points.update", archived: true + end +end diff --git a/spec/policies/calendar_policy_spec.rb b/spec/policies/calendar_policy_spec.rb new file mode 100644 index 000000000..f4423fb82 --- /dev/null +++ b/spec/policies/calendar_policy_spec.rb @@ -0,0 +1,47 @@ +RSpec.describe CalendarPolicy, type: :policy do + + let( :record ){ build_stubbed :calendar } + + shared_examples 'authorizes on archived and same organisation only' do + | permission, archived: false| + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "allows a user with the same organisation" do + expect_it.to permit(user_context, record) + end + if archived + it 'removes permission for archived referentials' do + referential.archived_at = 42.seconds.ago + expect_it.not_to permit(user_context, record) + end + end + end + + context 'different organisations →' do + before do + add_permissions(permission, for_user: user) + end + it "denies a user with a different organisation" do + expect_it.not_to permit(user_context, record) + end + end + end + + permissions :create? do + it_behaves_like 'authorizes on archived and same organisation only', 'calendars.create', archived: true + end + permissions :destroy? do + it_behaves_like 'authorizes on archived and same organisation only', 'calendars.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'authorizes on archived and same organisation only', 'calendars.update', archived: true + end + permissions :new? do + it_behaves_like 'authorizes on archived and same organisation only', 'calendars.create', archived: true + end + permissions :update? do + it_behaves_like 'authorizes on archived and same organisation only', 'calendars.update', archived: true + end +end diff --git a/spec/policies/company_policy_spec.rb b/spec/policies/company_policy_spec.rb new file mode 100644 index 000000000..2d249a2be --- /dev/null +++ b/spec/policies/company_policy_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe CompanyPolicy, type: :policy do + + let( :record ){ build_stubbed :company } + before { stub_policy_scope(record) } + + + # + # Non Destructive + # --------------- + + context 'Non Destructive actions →' do + permissions :index? do + it_behaves_like 'always allowed', 'anything', archived: true + end + permissions :show? do + it_behaves_like 'always allowed', 'anything', archived: true + end + end + + + # + # Destructive + # ----------- + + context 'Destructive actions →' do + permissions :create? do + it_behaves_like 'always forbidden', 'companies.create', archived: true + end + permissions :destroy? do + it_behaves_like 'always forbidden', 'companies.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'always forbidden', 'companies.update', archived: true + end + permissions :new? do + it_behaves_like 'always forbidden', 'companies.create', archived: true + end + permissions :update? do + it_behaves_like 'always forbidden', 'companies.update', archived: true + end + end +end diff --git a/spec/policies/connection_link_policy_spec.rb b/spec/policies/connection_link_policy_spec.rb new file mode 100644 index 000000000..23e40abe3 --- /dev/null +++ b/spec/policies/connection_link_policy_spec.rb @@ -0,0 +1,20 @@ +RSpec.describe ConnectionLinkPolicy, type: :policy do + + let( :record ){ build_stubbed :connection_link } + + permissions :create? do + it_behaves_like 'permitted policy and same organisation', "connection_links.create", archived: true + end + permissions :destroy? do + it_behaves_like 'permitted policy and same organisation', "connection_links.destroy", archived: true + end + permissions :edit? do + it_behaves_like 'permitted policy and same organisation', "connection_links.update", archived: true + end + permissions :new? do + it_behaves_like 'permitted policy and same organisation', "connection_links.create", archived: true + end + permissions :update? do + it_behaves_like 'permitted policy and same organisation', "connection_links.update", archived: true + end +end diff --git a/spec/policies/group_of_line_policy_spec.rb b/spec/policies/group_of_line_policy_spec.rb new file mode 100644 index 000000000..29fbb1bfb --- /dev/null +++ b/spec/policies/group_of_line_policy_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe GroupOfLinePolicy, type: :policy do + + let( :record ){ build_stubbed :group_of_line } + before { stub_policy_scope(record) } + + + # + # Non Destructive + # --------------- + + context 'Non Destructive actions →' do + permissions :index? do + it_behaves_like 'always allowed', 'anything', archived: true + end + permissions :show? do + it_behaves_like 'always allowed', 'anything', archived: true + end + end + + + # + # Destructive + # ----------- + + context 'Destructive actions →' do + permissions :create? do + it_behaves_like 'always forbidden', 'group_of_lines.create', archived: true + end + permissions :destroy? do + it_behaves_like 'always forbidden', 'group_of_lines.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'always forbidden', 'group_of_lines.update', archived: true + end + permissions :new? do + it_behaves_like 'always forbidden', 'group_of_lines.create', archived: true + end + permissions :update? do + it_behaves_like 'always forbidden', 'group_of_lines.update', archived: true + end + end +end diff --git a/spec/policies/journey_pattern_policy_spec.rb b/spec/policies/journey_pattern_policy_spec.rb new file mode 100644 index 000000000..39f849277 --- /dev/null +++ b/spec/policies/journey_pattern_policy_spec.rb @@ -0,0 +1,20 @@ +RSpec.describe JourneyPatternPolicy, type: :policy do + + let( :record ){ build_stubbed :journey_pattern } + + permissions :create? do + it_behaves_like 'permitted policy and same organisation', "journey_patterns.create", archived: true + end + permissions :destroy? do + it_behaves_like 'permitted policy and same organisation', "journey_patterns.destroy", archived: true + end + permissions :edit? do + it_behaves_like 'permitted policy and same organisation', "journey_patterns.update", archived: true + end + permissions :new? do + it_behaves_like 'permitted policy and same organisation', "journey_patterns.create", archived: true + end + permissions :update? do + it_behaves_like 'permitted policy and same organisation', "journey_patterns.update", archived: true + end +end diff --git a/spec/policies/line_policy_spec.rb b/spec/policies/line_policy_spec.rb index e720b2bc7..d9e684847 100644 --- a/spec/policies/line_policy_spec.rb +++ b/spec/policies/line_policy_spec.rb @@ -1,21 +1,163 @@ RSpec.describe LinePolicy, type: :policy do let( :record ){ build_stubbed :line } + before { stub_policy_scope(record) } - %w{create destroy edit}.each do | permission | - footnote_permission = "#{permission}_footnote" - permissions "#{footnote_permission}?".to_sym do - it_behaves_like 'permitted policy', "footnotes.#{permission}", archived: true + # + # Non Destructive + # --------------- + + context 'Non Destructive actions →' do + permissions :index? do + it_behaves_like 'always allowed', 'anything', archived: true + end + permissions :show? do + it_behaves_like 'always allowed', 'anything', archived: true + end + end + + + # + # Destructive + # ----------- + + context 'Destructive actions →' do + permissions :create? do + it_behaves_like 'always forbidden', 'lines.create', archived: true + end + permissions :destroy? do + it_behaves_like 'always forbidden', 'lines.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'always forbidden', 'lines.update', archived: true + end + permissions :new? do + it_behaves_like 'always forbidden', 'lines.create', archived: true + end + permissions :update? do + it_behaves_like 'always forbidden', 'lines.update', archived: true + end + end + + + # + # Custom Footnote Permissions + # --------------------------- + + permissions :create_footnote? do + context 'permission present →' do + before do + add_permissions('footnotes.create', for_user: user) + end + + it 'authorized for unarchived referentials' do + expect_it.to permit(user_context, record) + end + + it 'forbidden for archived referentials' do + referential.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + expect_it.not_to permit(user_context, record) + end + end + end + + permissions :destroy_footnote? do + context 'permission present →' do + before do + add_permissions('footnotes.destroy', for_user: user) + end + + it 'authorized for unarchived referentials' do + expect_it.to permit(user_context, record) + end + + it 'forbidden for archived referentials' do + referential.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + expect_it.not_to permit(user_context, record) + end + end + end + + permissions :edit_footnote? do + context 'permission present →' do + before do + add_permissions('footnotes.update', for_user: user) + end + + it 'authorized for unarchived referentials' do + expect_it.to permit(user_context, record) + end + + it 'forbidden for archived referentials' do + referential.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + expect_it.not_to permit(user_context, record) + end end end permissions :new_footnote? do - it_behaves_like 'permitted policy', 'footnotes.create', archived: true + context 'permission present →' do + before do + add_permissions('footnotes.create', for_user: user) + end + + it 'authorized for unarchived referentials' do + expect_it.to permit(user_context, record) + end + + it 'forbidden for archived referentials' do + referential.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + expect_it.not_to permit(user_context, record) + end + end end permissions :update_footnote? do - it_behaves_like 'permitted policy', 'footnotes.edit', archived: true + context 'permission present →' do + before do + add_permissions('footnotes.update', for_user: user) + end + + it 'authorized for unarchived referentials' do + expect_it.to permit(user_context, record) + end + + it 'forbidden for archived referentials' do + referential.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + expect_it.not_to permit(user_context, record) + end + end end end diff --git a/spec/policies/network_policy_spec.rb b/spec/policies/network_policy_spec.rb new file mode 100644 index 000000000..ae4ffa03a --- /dev/null +++ b/spec/policies/network_policy_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe NetworkPolicy, type: :policy do + + let( :record ){ build_stubbed :network } + before { stub_policy_scope(record) } + + + # + # Non Destructive + # --------------- + + context 'Non Destructive actions →' do + permissions :index? do + it_behaves_like 'always allowed', 'anything', archived: true + end + permissions :show? do + it_behaves_like 'always allowed', 'anything', archived: true + end + end + + + # + # Destructive + # ----------- + + context 'Destructive actions →' do + permissions :create? do + it_behaves_like 'always forbidden', 'networks.create', archived: true + end + permissions :destroy? do + it_behaves_like 'always forbidden', 'networks.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'always forbidden', 'networks.update', archived: true + end + permissions :new? do + it_behaves_like 'always forbidden', 'networks.create', archived: true + end + permissions :update? do + it_behaves_like 'always forbidden', 'networks.update', archived: true + end + end +end diff --git a/spec/policies/referential_policy_spec.rb b/spec/policies/referential_policy_spec.rb new file mode 100644 index 000000000..d060317f9 --- /dev/null +++ b/spec/policies/referential_policy_spec.rb @@ -0,0 +1,102 @@ +RSpec.describe ReferentialPolicy, type: :policy do + + let( :record ){ build_stubbed :referential } + + + # + # Collection Based Permissions differ from standard as there is no referential yet + # -------------------------------------------------------------------------------- + + permissions :create? do + it 'permissions present → allowed' do + add_permissions('referentials.create', for_user: user) + expect_it.to permit(user_context, record) + end + it 'permissions absent → forbidden' do + expect_it.not_to permit(user_context, record) + end + end + + permissions :new? do + it 'permissions present → allowed' do + add_permissions('referentials.create', for_user: user) + expect_it.to permit(user_context, record) + end + it 'permissions absent → forbidden' do + expect_it.not_to permit(user_context, record) + end + end + + # + # Standard Destructive Action Permissions + # --------------------------------------- + + permissions :destroy? do + it_behaves_like 'permitted policy and same organisation', 'referentials.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'permitted policy and same organisation', 'referentials.update', archived: true + end + permissions :update? do + it_behaves_like 'permitted policy and same organisation', 'referentials.update', archived: true + end + + # + # Custom Permissions + # ------------------ + + permissions :clone? do + it_behaves_like 'permitted policy and same organisation', 'referentials.create', archived: true + end + + permissions :archive? do + + context 'permission present →' do + before do + add_permissions('referentials.update', for_user: user) + end + + it 'allowed for unarchived referentials' do + expect_it.to permit(user_context, record) + end + + it 'forbidden for archived referentials' do + record.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + expect_it.not_to permit(user_context, record) + end + end + + end + + permissions :unarchive? do + + context 'permission present →' do + before do + add_permissions('referentials.update', for_user: user) + end + + it 'forbidden for unarchived referentials' do + expect_it.not_to permit(user_context, record) + end + + it 'allowed for archived referentials' do + record.archived_at = 1.second.ago + expect_it.to permit(user_context, record) + end + end + + context 'permission absent →' do + it 'is forbidden' do + record.archived_at = 1.second.ago + expect_it.not_to permit(user_context, record) + end + end + + end +end diff --git a/spec/policies/route_policy_spec.rb b/spec/policies/route_policy_spec.rb index cc949ff45..6be517048 100644 --- a/spec/policies/route_policy_spec.rb +++ b/spec/policies/route_policy_spec.rb @@ -11,7 +11,7 @@ RSpec.describe RoutePolicy, type: :policy do end permissions :edit? do - it_behaves_like 'permitted policy and same organisation', 'routes.edit', archived: true + it_behaves_like 'permitted policy and same organisation', 'routes.update', archived: true end permissions :new? do @@ -19,6 +19,6 @@ RSpec.describe RoutePolicy, type: :policy do end permissions :update? do - it_behaves_like 'permitted policy and same organisation', 'routes.edit', archived: true + it_behaves_like 'permitted policy and same organisation', 'routes.update', archived: true end end diff --git a/spec/policies/routing_constraint_zone_policy_spec.rb b/spec/policies/routing_constraint_zone_policy_spec.rb index f91313390..2ef15fa95 100644 --- a/spec/policies/routing_constraint_zone_policy_spec.rb +++ b/spec/policies/routing_constraint_zone_policy_spec.rb @@ -12,7 +12,7 @@ RSpec.describe RoutingConstraintZonePolicy, type: :policy do end permissions :edit? do - it_behaves_like 'permitted policy and same organisation', 'routing_constraint_zones.edit', archived: true + it_behaves_like 'permitted policy and same organisation', 'routing_constraint_zones.update', archived: true end permissions :new? do @@ -20,6 +20,6 @@ RSpec.describe RoutingConstraintZonePolicy, type: :policy do end permissions :update? do - it_behaves_like 'permitted policy and same organisation', 'routing_constraint_zones.edit', archived: true + it_behaves_like 'permitted policy and same organisation', 'routing_constraint_zones.update', archived: true end end diff --git a/spec/policies/stop_area_policy_spec.rb b/spec/policies/stop_area_policy_spec.rb new file mode 100644 index 000000000..8fe59c8e3 --- /dev/null +++ b/spec/policies/stop_area_policy_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe StopAreaPolicy, type: :policy do + + let( :record ){ build_stubbed :stop_area } + before { stub_policy_scope(record) } + + + # + # Non Destructive + # --------------- + + context 'Non Destructive actions →' do + permissions :index? do + it_behaves_like 'always allowed', 'anything', archived: true + end + permissions :show? do + it_behaves_like 'always allowed', 'anything', archived: true + end + end + + + # + # Destructive + # ----------- + + context 'Destructive actions →' do + permissions :create? do + it_behaves_like 'always forbidden', 'stop_areas.create', archived: true + end + permissions :destroy? do + it_behaves_like 'always forbidden', 'stop_areas.destroy', archived: true + end + permissions :edit? do + it_behaves_like 'always forbidden', 'stop_areas.update', archived: true + end + permissions :new? do + it_behaves_like 'always forbidden', 'stop_areas.create', archived: true + end + permissions :update? do + it_behaves_like 'always forbidden', 'stop_areas.update', archived: true + end + end +end diff --git a/spec/policies/time_table_policy_spec.rb b/spec/policies/time_table_policy_spec.rb index 6c19362d2..dad3c13bc 100644 --- a/spec/policies/time_table_policy_spec.rb +++ b/spec/policies/time_table_policy_spec.rb @@ -2,17 +2,23 @@ RSpec.describe TimeTablePolicy, type: :policy do let( :record ){ build_stubbed :time_table } + permissions :create? do + it_behaves_like 'permitted policy and same organisation', 'time_tables.create', archived: true + end + + permissions :destroy? do + it_behaves_like 'permitted policy and same organisation', 'time_tables.destroy', archived: true + end - %w{create duplicate}.each do | permission | - permissions "#{permission}?".to_sym do - it_behaves_like 'permitted policy and same organisation', 'time_tables.create', archived: true - end + permissions :edit? do + it_behaves_like 'permitted policy and same organisation', 'time_tables.update', archived: true end - %w{destroy edit}.each do | permission | - permissions "#{permission}?".to_sym do - it_behaves_like 'permitted policy and same organisation', "time_tables.#{permission}", archived: true - end + permissions :new? do + it_behaves_like 'permitted policy and same organisation', 'time_tables.create', archived: true end + permissions :update? do + it_behaves_like 'permitted policy and same organisation', 'time_tables.update', archived: true + end end diff --git a/spec/support/devise.rb b/spec/support/devise.rb index d4a279a41..28703c072 100644 --- a/spec/support/devise.rb +++ b/spec/support/devise.rb @@ -4,12 +4,12 @@ module DeviseRequestHelper def login_user organisation = Organisation.where(:code => "first").first_or_create(attributes_for(:organisation)) @user ||= create(:user, :organisation => organisation, - :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', - 'access_points.create', 'access_points.edit', 'access_points.destroy', 'access_links.create', 'access_links.edit', 'access_links.destroy', - 'connection_links.create', 'connection_links.edit', 'connection_links.destroy', 'route_sections.create', 'route_sections.edit', 'route_sections.destroy', - 'referentials.create', 'referentials.edit', 'referentials.destroy']) + :permissions => ['routes.create', 'routes.update', 'routes.destroy', 'journey_patterns.create', 'journey_patterns.update', 'journey_patterns.destroy', + 'vehicle_journeys.create', 'vehicle_journeys.update', 'vehicle_journeys.destroy', 'time_tables.create', 'time_tables.update', 'time_tables.destroy', + 'footnotes.update', 'footnotes.create', 'footnotes.destroy', 'routing_constraint_zones.create', 'routing_constraint_zones.update', 'routing_constraint_zones.destroy', + 'access_points.create', 'access_points.update', 'access_points.destroy', 'access_links.create', 'access_links.update', 'access_links.destroy', + 'connection_links.create', 'connection_links.update', 'connection_links.destroy', 'route_sections.create', 'route_sections.update', 'route_sections.destroy', + 'referentials.create', 'referentials.update', 'referentials.destroy']) login_as @user, :scope => :user # post_via_redirect user_session_path, 'user[email]' => @user.email, 'user[password]' => @user.password end @@ -36,25 +36,42 @@ module DeviseRequestHelper end module DeviseControllerHelper + def setup_user + _all_actions = %w{create destroy update} + _all_resources = %w{ access_links + access_points + connection_links + footnotes + journey_patterns + referentials + route_sections + routes + routing_constraint_zones + time_tables + vehicle_journeys } + join_with = -> (separator) do + -> (ary) { ary.join(separator) } + end + before do @request.env["devise.mapping"] = Devise.mappings[:user] organisation = Organisation.where(:code => "first").first_or_create(attributes_for(:organisation)) - @user = create(:user, :organisation => organisation, - :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', - 'access_points.create', 'access_points.edit', 'access_points.destroy', 'access_links.create', 'access_links.edit', 'access_links.destroy', - 'connection_links.create', 'connection_links.edit', 'connection_links.destroy', 'route_sections.create', 'route_sections.edit', 'route_sections.destroy', - 'referentials.create', 'referentials.edit', 'referentials.destroy']) + @user = create(:user, + organisation: organisation, + permissions: _all_resources.product( _all_actions ).map(&join_with.('.'))) end end + def login_user() setup_user before do sign_in @user end end + + private + end RSpec.configure do |config| diff --git a/spec/support/pundit/shared_examples.rb b/spec/support/pundit/shared_examples.rb index 33ed1ffae..357004f4e 100644 --- a/spec/support/pundit/shared_examples.rb +++ b/spec/support/pundit/shared_examples.rb @@ -1,3 +1,69 @@ + +RSpec.shared_examples 'always allowed' do + | permission, archived: false| + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "allows a user with the same organisation" do + expect_it.to permit(user_context, record) + end + if archived + it 'does not remove permission for archived referentials' do + referential.archived_at = 42.seconds.ago + expect_it.to permit(user_context, record) + end + end + end + + context 'different organisations →' do + before do + add_permissions(permission, for_user: user) + end + it "allows a user with a different organisation" do + expect_it.to permit(user_context, record) + end + if archived + it 'does not remove permission for archived referentials' do + referential.archived_at = 42.seconds.ago + expect_it.to permit(user_context, record) + end + end + end +end + +RSpec.shared_examples 'always forbidden' do + | permission, archived: false| + context 'same organisation →' do + before do + user.organisation_id = referential.organisation_id + end + it "allows a user with the same organisation" do + expect_it.not_to permit(user_context, record) + end + if archived + it 'still no permission for archived referentials' do + referential.archived_at = 42.seconds.ago + expect_it.not_to permit(user_context, record) + end + end + end + + context 'different organisations →' do + before do + add_permissions(permission, for_user: user) + end + it "denies a user with a different organisation" do + expect_it.not_to permit(user_context, record) + end + if archived + it 'still no permission for archived referentials' do + referential.archived_at = 42.seconds.ago + expect_it.not_to permit(user_context, record) + end + end + end +end RSpec.shared_examples 'permitted policy and same organisation' do | permission, archived: false| @@ -6,11 +72,11 @@ RSpec.shared_examples 'permitted policy and same organisation' do expect_it.not_to permit(user_context, record) end it 'and also a user with the same organisation' do - user.organisation = referential.organisation + user.organisation_id = referential.organisation_id expect_it.not_to permit(user_context, record) end end - + context 'permission present → ' do before do add_permissions(permission, for_user: user) @@ -21,13 +87,13 @@ RSpec.shared_examples 'permitted policy and same organisation' do end it 'but allows it for a user with the same organisation' do - user.organisation = referential.organisation + user.organisation_id = referential.organisation_id expect_it.to permit(user_context, record) end if archived it 'removes the permission for archived referentials' do - user.organisation = referential.organisation + user.organisation_id = referential.organisation_id referential.archived_at = 42.seconds.ago expect_it.not_to permit(user_context, record) end -- cgit v1.2.3 From 1b5b681603f629b901deabffc4c55f654bbcfe14 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 6 Jul 2017 11:40:03 +0200 Subject: Fixes: #3478@1.5h - Fixes remaining issues with LinePolicy, CalenderPolicy & RoutePolicy - Dead Code elimination --- DEVNOTES.md | 9 ++- app/models/chouette/stop_point.rb | 2 +- app/policies/calendar_policy.rb | 6 +- app/policies/default_policy.rb | 5 -- app/policies/line_policy.rb | 6 +- app/policies/route_policy.rb | 2 +- spec/policies/calendar_policy_spec.rb | 37 ++--------- spec/policies/line_policy_spec.rb | 110 +------------------------------- spec/policies/route_policy_spec.rb | 4 +- spec/policies/stop_point_policy_spec.rb | 5 ++ spec/support/pundit/shared_examples.rb | 25 +------- 11 files changed, 29 insertions(+), 182 deletions(-) delete mode 100644 app/policies/default_policy.rb create mode 100644 spec/policies/stop_point_policy_spec.rb diff --git a/DEVNOTES.md b/DEVNOTES.md index 01f58fa0f..2a3915ed2 100644 --- a/DEVNOTES.md +++ b/DEVNOTES.md @@ -33,7 +33,7 @@ The following Policies are of this type. The standard type policy inherits from `ApplicationPolicy` does not override any _Undesructive_ _Pemission_ but overrides the _Destructive_ ones. -Normally, but not always they are overriden as follows +They are overriden as follows ```ruby def ? @@ -41,21 +41,20 @@ Normally, but not always they are overriden as follows end ``` -There are some variations (**TO BE CLARIFIED**) concerning `organisation_match?`. +**An exception** is `Referntial` which **cannot** check for `organisation_match?` for creation as there is no referential. The following Policies are of this type. - `AccessLink` - `AccessPoint` - - `Calendar` (*) + - `Calendar` - `ConnectionLink` - `JourneyPattern` - `Referential` + custom - - `Route` + - `Route` (used by `StopPoint` too) - `RoutingConstraintZone` - `TimeTable` + custom -`Calendar` is a strange exception where no user permission is checked for the _destructive_ _permissions_. diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb index 1cc1ed7a3..3dbf6be0d 100644 --- a/app/models/chouette/stop_point.rb +++ b/app/models/chouette/stop_point.rb @@ -2,7 +2,7 @@ module Chouette class StopPoint < TridentActiveRecord def self.policy_class - DefaultPolicy + RoutePolicy end include ForBoardingEnumerations diff --git a/app/policies/calendar_policy.rb b/app/policies/calendar_policy.rb index 3353988bd..d3c715d70 100644 --- a/app/policies/calendar_policy.rb +++ b/app/policies/calendar_policy.rb @@ -6,13 +6,13 @@ class CalendarPolicy < ApplicationPolicy end def create? - !archived? && organisation_match? + !archived? && organisation_match? && user.has_permission?('calendars.create') end def destroy? - !archived? && organisation_match? + !archived? && organisation_match? && user.has_permission?('calendars.destroy') end def update? - !archived? && organisation_match? + !archived? && organisation_match? && user.has_permission?('calendars.update') end def share? diff --git a/app/policies/default_policy.rb b/app/policies/default_policy.rb deleted file mode 100644 index 1858fbe7c..000000000 --- a/app/policies/default_policy.rb +++ /dev/null @@ -1,5 +0,0 @@ -class DefaultPolicy - - def initialize(*args); end - -end diff --git a/app/policies/line_policy.rb b/app/policies/line_policy.rb index b84c7a69f..acb0d79e7 100644 --- a/app/policies/line_policy.rb +++ b/app/policies/line_policy.rb @@ -7,15 +7,15 @@ class LinePolicy < ApplicationPolicy end def create_footnote? - !archived? && user.has_permission?('footnotes.create') + !archived? && organisation_match? && user.has_permission?('footnotes.create') end def edit_footnote? - !archived? && user.has_permission?('footnotes.update') + !archived? && organisation_match? && user.has_permission?('footnotes.update') end def destroy_footnote? - !archived? && user.has_permission?('footnotes.destroy') + !archived? && organisation_match? && user.has_permission?('footnotes.destroy') end def update_footnote? ; edit_footnote? end diff --git a/app/policies/route_policy.rb b/app/policies/route_policy.rb index be3ffce4d..786b0acf4 100644 --- a/app/policies/route_policy.rb +++ b/app/policies/route_policy.rb @@ -6,7 +6,7 @@ class RoutePolicy < ApplicationPolicy end def create? - !archived? && user.has_permission?('routes.create') # organisation match via referential is checked in the view + !archived? && organisation_match? && user.has_permission?('routes.create') end def destroy? diff --git a/spec/policies/calendar_policy_spec.rb b/spec/policies/calendar_policy_spec.rb index f4423fb82..57f771c54 100644 --- a/spec/policies/calendar_policy_spec.rb +++ b/spec/policies/calendar_policy_spec.rb @@ -1,47 +1,22 @@ RSpec.describe CalendarPolicy, type: :policy do let( :record ){ build_stubbed :calendar } + before { stub_policy_scope(record) } - shared_examples 'authorizes on archived and same organisation only' do - | permission, archived: false| - context 'same organisation →' do - before do - user.organisation_id = referential.organisation_id - end - it "allows a user with the same organisation" do - expect_it.to permit(user_context, record) - end - if archived - it 'removes permission for archived referentials' do - referential.archived_at = 42.seconds.ago - expect_it.not_to permit(user_context, record) - end - end - end - - context 'different organisations →' do - before do - add_permissions(permission, for_user: user) - end - it "denies a user with a different organisation" do - expect_it.not_to permit(user_context, record) - end - end - end permissions :create? do - it_behaves_like 'authorizes on archived and same organisation only', 'calendars.create', archived: true + it_behaves_like 'permitted policy and same organisation', 'calendars.create', archived: true end permissions :destroy? do - it_behaves_like 'authorizes on archived and same organisation only', 'calendars.destroy', archived: true + it_behaves_like 'permitted policy and same organisation', 'calendars.destroy', archived: true end permissions :edit? do - it_behaves_like 'authorizes on archived and same organisation only', 'calendars.update', archived: true + it_behaves_like 'permitted policy and same organisation', 'calendars.update', archived: true end permissions :new? do - it_behaves_like 'authorizes on archived and same organisation only', 'calendars.create', archived: true + it_behaves_like 'permitted policy and same organisation', 'calendars.create', archived: true end permissions :update? do - it_behaves_like 'authorizes on archived and same organisation only', 'calendars.update', archived: true + it_behaves_like 'permitted policy and same organisation', 'calendars.update', archived: true end end diff --git a/spec/policies/line_policy_spec.rb b/spec/policies/line_policy_spec.rb index d9e684847..334073506 100644 --- a/spec/policies/line_policy_spec.rb +++ b/spec/policies/line_policy_spec.rb @@ -46,118 +46,14 @@ RSpec.describe LinePolicy, type: :policy do # --------------------------- permissions :create_footnote? do - context 'permission present →' do - before do - add_permissions('footnotes.create', for_user: user) - end - - it 'authorized for unarchived referentials' do - expect_it.to permit(user_context, record) - end - - it 'forbidden for archived referentials' do - referential.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) - end - end - - context 'permission absent →' do - it 'is forbidden' do - expect_it.not_to permit(user_context, record) - end - end + it_behaves_like 'permitted policy and same organisation', 'footnotes.create', archived: true end permissions :destroy_footnote? do - context 'permission present →' do - before do - add_permissions('footnotes.destroy', for_user: user) - end - - it 'authorized for unarchived referentials' do - expect_it.to permit(user_context, record) - end - - it 'forbidden for archived referentials' do - referential.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) - end - end - - context 'permission absent →' do - it 'is forbidden' do - expect_it.not_to permit(user_context, record) - end - end - end - - permissions :edit_footnote? do - context 'permission present →' do - before do - add_permissions('footnotes.update', for_user: user) - end - - it 'authorized for unarchived referentials' do - expect_it.to permit(user_context, record) - end - - it 'forbidden for archived referentials' do - referential.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) - end - end - - context 'permission absent →' do - it 'is forbidden' do - expect_it.not_to permit(user_context, record) - end - end - end - - permissions :new_footnote? do - context 'permission present →' do - before do - add_permissions('footnotes.create', for_user: user) - end - - it 'authorized for unarchived referentials' do - expect_it.to permit(user_context, record) - end - - it 'forbidden for archived referentials' do - referential.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) - end - end - - context 'permission absent →' do - it 'is forbidden' do - expect_it.not_to permit(user_context, record) - end - end + it_behaves_like 'permitted policy and same organisation', 'footnotes.destroy', archived: true end permissions :update_footnote? do - context 'permission present →' do - before do - add_permissions('footnotes.update', for_user: user) - end - - it 'authorized for unarchived referentials' do - expect_it.to permit(user_context, record) - end - - it 'forbidden for archived referentials' do - referential.archived_at = 1.second.ago - expect_it.not_to permit(user_context, record) - end - end - - context 'permission absent →' do - it 'is forbidden' do - expect_it.not_to permit(user_context, record) - end - end + it_behaves_like 'permitted policy and same organisation', 'footnotes.update', archived: true end - end diff --git a/spec/policies/route_policy_spec.rb b/spec/policies/route_policy_spec.rb index 6be517048..243d85acb 100644 --- a/spec/policies/route_policy_spec.rb +++ b/spec/policies/route_policy_spec.rb @@ -3,7 +3,7 @@ RSpec.describe RoutePolicy, type: :policy do let( :record ){ build_stubbed :route } permissions :create? do - it_behaves_like 'permitted policy', 'routes.create', archived: true + it_behaves_like 'permitted policy and same organisation', 'routes.create', archived: true end permissions :destroy? do @@ -15,7 +15,7 @@ RSpec.describe RoutePolicy, type: :policy do end permissions :new? do - it_behaves_like 'permitted policy', 'routes.create', archived: true + it_behaves_like 'permitted policy and same organisation', 'routes.create', archived: true end permissions :update? do diff --git a/spec/policies/stop_point_policy_spec.rb b/spec/policies/stop_point_policy_spec.rb new file mode 100644 index 000000000..2a8b9b905 --- /dev/null +++ b/spec/policies/stop_point_policy_spec.rb @@ -0,0 +1,5 @@ +RSpec.describe Chouette::StopPoint do + describe "using RoutePolicy" do + it { expect( described_class.policy_class ).to eq(RoutePolicy) } + end +end diff --git a/spec/support/pundit/shared_examples.rb b/spec/support/pundit/shared_examples.rb index 357004f4e..b91caa479 100644 --- a/spec/support/pundit/shared_examples.rb +++ b/spec/support/pundit/shared_examples.rb @@ -64,6 +64,7 @@ RSpec.shared_examples 'always forbidden' do end end end +j RSpec.shared_examples 'permitted policy and same organisation' do | permission, archived: false| @@ -100,27 +101,3 @@ RSpec.shared_examples 'permitted policy and same organisation' do end end end - -RSpec.shared_examples 'permitted policy' do - | permission, archived: false| - context 'permission absent → ' do - it "denies a user with a different organisation" do - expect_it.not_to permit(user_context, record) - end - end - context 'permission present → ' do - before do - add_permissions(permission, for_user: user) - end - it 'allows a user with a different organisation' do - expect_it.to permit(user_context, record) - end - - if archived - it 'removes the permission for archived referentials' do - referential.archived_at = 42.seconds.ago - expect_it.not_to permit(user_context, record) - end - end - end -end -- cgit v1.2.3