aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert2017-07-05 16:52:44 +0200
committerRobert2017-07-06 08:37:18 +0200
commitb09994a4ee79f735f9b3f43535c6d138c4b68a56 (patch)
tree92b244bc9d9d4d8e792d0129793ceb553738afd1
parente53aa88c442bd0057c4e0ae66e2684d62d3193ed (diff)
downloadchouette-core-b09994a4ee79f735f9b3f43535c6d138c4b68a56.tar.bz2
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
-rw-r--r--DEVNOTES.md62
-rw-r--r--app/controllers/journey_patterns_collections_controller.rb9
-rw-r--r--app/controllers/time_tables_controller.rb1
-rw-r--r--app/controllers/vehicle_journeys_controller.rb9
-rw-r--r--app/models/user.rb19
-rw-r--r--app/policies/acces_point_policy.rb25
-rw-r--r--app/policies/access_link_policy.rb4
-rw-r--r--app/policies/access_point_policy.rb2
-rw-r--r--app/policies/application_policy.rb7
-rw-r--r--app/policies/connection_link_policy.rb2
-rw-r--r--app/policies/journey_pattern_policy.rb2
-rw-r--r--app/policies/line_policy.rb2
-rw-r--r--app/policies/referential_policy.rb6
-rw-r--r--app/policies/route_policy.rb2
-rw-r--r--app/policies/routing_constraint_zone_policy.rb2
-rw-r--r--app/policies/time_table_policy.rb2
-rw-r--r--app/policies/vehicle_journey_policy.rb2
-rw-r--r--app/views/time_tables/show.html.slim1
-rw-r--r--spec/controllers/journey_patterns_collections_controller_spec.rb2
-rw-r--r--spec/controllers/routes_controller_spec.rb4
-rw-r--r--spec/features/time_tables_spec.rb5
-rw-r--r--spec/features/vehicle_journeys_spec.rb2
-rw-r--r--spec/helpers/table_builder_helper_spec.rb2
-rw-r--r--spec/policies/access_link_policy_spec.rb20
-rw-r--r--spec/policies/access_point_policy_spec.rb20
-rw-r--r--spec/policies/calendar_policy_spec.rb47
-rw-r--r--spec/policies/company_policy_spec.rb42
-rw-r--r--spec/policies/connection_link_policy_spec.rb20
-rw-r--r--spec/policies/group_of_line_policy_spec.rb42
-rw-r--r--spec/policies/journey_pattern_policy_spec.rb20
-rw-r--r--spec/policies/line_policy_spec.rb154
-rw-r--r--spec/policies/network_policy_spec.rb42
-rw-r--r--spec/policies/referential_policy_spec.rb102
-rw-r--r--spec/policies/route_policy_spec.rb4
-rw-r--r--spec/policies/routing_constraint_zone_policy_spec.rb4
-rw-r--r--spec/policies/stop_area_policy_spec.rb42
-rw-r--r--spec/policies/time_table_policy_spec.rb22
-rw-r--r--spec/support/devise.rb43
-rw-r--r--spec/support/pundit/shared_examples.rb74
39 files changed, 769 insertions, 103 deletions
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 <destructive>?
+ !archived? && organisation_match? && user.has_permission('<resource in plural form>.<action>')
+ 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