diff options
65 files changed, 1062 insertions, 558 deletions
| diff --git a/DEVNOTES.md b/DEVNOTES.md new file mode 100644 index 000000000..2a3915ed2 --- /dev/null +++ b/DEVNOTES.md @@ -0,0 +1,61 @@ + +# 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. + +They are overriden as follows + +```ruby +      def <destructive>? +        !archived? && organisation_match? && user.has_permission('<resource in plural form>.<action>') +      end +``` + +**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` +  - `ConnectionLink` +  - `JourneyPattern` +  - `Referential` + custom +  - `Route` (used by `StopPoint` too) +  - `RoutingConstraintZone` +  - `TimeTable` + custom + + + + + 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/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/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/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/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/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/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/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 39cffd2cd..4e385b266 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), @@ -32,8 +34,8 @@ module TableBuilderHelper        end        polymorph_url += URL.polymorphic_url_parts( -        @obj, -        @user_context.context[:referential] +        object, +        user_context.context[:referential]        )      end @@ -41,40 +43,14 @@ module TableBuilderHelper        ACTIONS_TO_HTTP_METHODS[action]      end -    def actions_after_policy_check -      @actions.select do |action| -        # Has policy and can destroy -        (action == :delete && -            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 -          (action == :edit && -            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?) || - -          # Object is archived -          (action == :unarchive && @obj.archived?) || - -          action_is_allowed_regardless_of_policy(action) -      end +    def authorized_actions +      actions.select(&policy.method(:authorizes_action?))      end      private -    def action_is_allowed_regardless_of_policy(action) -      ![:delete, :edit, :archive, :unarchive].include?(action) +    def policy +      @__policy__ ||= Pundit.policy(user_context, object)      end    end  end 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/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb index e0f947487..3dbf6be0d 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 +      RoutePolicy +    end +      include ForBoardingEnumerations      include ForAlightingEnumerations diff --git a/app/models/user.rb b/app/models/user.rb index 4ba05b164..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 @@ -44,8 +55,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 +83,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 deleted file mode 100644 index 08af5981a..000000000 --- a/app/policies/acces_point_policy.rb +++ /dev/null @@ -1,22 +0,0 @@ -class AccessPointPolicy < BoivPolicy -  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 edit? -    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 654739d06..1f1147f60 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 @@ -6,17 +6,14 @@ class AccessLinkPolicy < BoivPolicy    end    def create? -    user.has_permission?('access_links.create') # organisation match via referential is checked in the view +    !archived? && organisation_match? && user.has_permission?('access_links.create')    end -  def edit? -    organisation_match? && user.has_permission?('access_links.edit') +  def update? +    !archived? && organisation_match? && user.has_permission?('access_links.update')    end    def destroy? -    organisation_match? && user.has_permission?('access_links.destroy') +    !archived? && organisation_match? && user.has_permission?('access_links.destroy')    end - -  def update?  ; edit? end -  def new?     ; create? end  end diff --git a/app/policies/access_point_policy.rb b/app/policies/access_point_policy.rb new file mode 100644 index 000000000..41436e77c --- /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? +    !archived? && organisation_match? && user.has_permission?('access_points.create') +  end + +  def update? +    !archived? && organisation_match? && user.has_permission?('access_points.update') +  end + +  def destroy? +    !archived? && 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 a863404ae..dbe4542e7 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -1,70 +1,107 @@  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) +  # 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 -  def referential -    @referential ||= record_referential +  # Make authorization by action easier +  def delete? +    destroy?    end -  def record_referential -    record.referential if record.respond_to?(:referential) +  def authorizes_action?(action) +    public_send("#{action}?") +  rescue NoMethodError +    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 new? and create? together, do not override #new?, +  # unless you want to break this tie on purpose +  def new? +    create?    end + +  # +  # Permissions for undestructive actions +  # ------------------------------------- +    def index? -    false +    true    end    def show?      scope.where(:id => record.id).exists?    end + +  # +  # Permissions for destructive actions +  # ----------------------------------- +    def create?      false    end -  def new? -    create? +  def destroy? +    false    end    def update?      false    end -  def edit? -    update? -  end - -  def destroy? -    false -  end -  def scope -    Pundit.policy_scope!(user, record.class) -  end +  # +  #  Custom Permissions +  #  ------------------ -  def boiv_read_offer? -    organisation_match? && user.has_permission?('boiv:read-offer') +  def archived? +    return @is_archived if instance_variable_defined?(:@is_archived) +    @is_archived = is_archived    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 + + +  # +  #  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 @@ -77,4 +114,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 diff --git a/app/policies/boiv_policy.rb b/app/policies/boiv_policy.rb deleted file mode 100644 index 444006aa4..000000000 --- a/app/policies/boiv_policy.rb +++ /dev/null @@ -1,15 +0,0 @@ -class BoivPolicy < ApplicationPolicy - - -  def boiv_read_offer? -    organisation_match? && user.has_permission?('boiv:read-offer') -  end - -  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..d3c715d70 100644 --- a/app/policies/calendar_policy.rb +++ b/app/policies/calendar_policy.rb @@ -1,27 +1,22 @@ -class CalendarPolicy < BoivPolicy +class CalendarPolicy < ApplicationPolicy    class Scope < Scope      def resolve        scope      end    end -  def show? -    organisation_match? || record.shared +  def create?  +    !archived? && organisation_match? && user.has_permission?('calendars.create') +  end +  def destroy? +    !archived? && organisation_match? && user.has_permission?('calendars.destroy') +  end +  def update? +    !archived? && organisation_match? && user.has_permission?('calendars.update')    end - -  def 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 95d607f3d..6106798be 100644 --- a/app/policies/company_policy.rb +++ b/app/policies/company_policy.rb @@ -1,15 +1,7 @@ -class CompanyPolicy < BoivPolicy +class CompanyPolicy < ApplicationPolicy    class Scope < Scope      def resolve        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/connection_link_policy.rb b/app/policies/connection_link_policy.rb index 21414efb9..240c2a804 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 @@ -6,17 +6,14 @@ class ConnectionLinkPolicy < BoivPolicy    end    def create? -    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') +    !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?  ; edit? end -  def new?     ; create? end +  def update? +    !archived? && organisation_match? && user.has_permission?('connection_links.update') +  end  end diff --git a/app/policies/group_of_line_policy.rb b/app/policies/group_of_line_policy.rb index 86d522545..03e94449d 100644 --- a/app/policies/group_of_line_policy.rb +++ b/app/policies/group_of_line_policy.rb @@ -1,15 +1,7 @@ -class GroupOfLinePolicy < BoivPolicy +class GroupOfLinePolicy < ApplicationPolicy    class Scope < Scope      def resolve        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 01ce2cbbb..507a364b6 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 @@ -7,19 +7,15 @@ class JourneyPatternPolicy < BoivPolicy    end    def create? -    # organisation match via referential is checked in the view -    user.has_permission?('journey_patterns.create') -  end - -  def edit? -    organisation_match? && user.has_permission?('journey_patterns.edit') +    !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?  ; edit? end -  def new?     ; create? end +  def update? +    !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 b829040af..acb0d79e7 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 @@ -6,24 +6,16 @@ class LinePolicy < BoivPolicy      end    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') +    !archived? && organisation_match? && user.has_permission?('footnotes.create')    end    def edit_footnote? -    !archived? && user.has_permission?('footnotes.edit') +    !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/network_policy.rb b/app/policies/network_policy.rb index 4c1ea1090..9f86451a5 100644 --- a/app/policies/network_policy.rb +++ b/app/policies/network_policy.rb @@ -1,15 +1,7 @@ -class NetworkPolicy < BoivPolicy +class NetworkPolicy < ApplicationPolicy    class Scope < Scope      def resolve        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 e531c6c19..bf970c2b8 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 @@ -9,20 +9,26 @@ class ReferentialPolicy < BoivPolicy      user.has_permission?('referentials.create')    end -  def edit? -    organisation_match? && user.has_permission?('referentials.edit') +  def destroy? +    !archived? && organisation_match? && user.has_permission?('referentials.destroy')    end -  def destroy? -    organisation_match? && user.has_permission?('referentials.destroy') +  def update? +    !archived? && organisation_match? && user.has_permission?('referentials.update') +  end + + + +  def clone? +    !archived? && organisation_match? && create?    end    def archive? -    edit? +    record.archived_at.nil? && user.has_permission?('referentials.update')    end -  def clone? -    organisation_match? && create? +  def unarchive? +    !record.archived_at.nil? && user.has_permission?('referentials.update')    end    def common_lines? @@ -30,9 +36,6 @@ class ReferentialPolicy < BoivPolicy      true    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 ca9b02164..786b0acf4 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 @@ -6,17 +6,14 @@ class RoutePolicy < BoivPolicy    end    def create? -    !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') +    !archived? && organisation_match? && user.has_permission?('routes.create')    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.update') +  end  end diff --git a/app/policies/routing_constraint_zone_policy.rb b/app/policies/routing_constraint_zone_policy.rb index da311bc03..3cfcf46ff 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 @@ -6,17 +6,14 @@ class RoutingConstraintZonePolicy < BoivPolicy    end    def create? -    !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') +    !archived? && organisation_match? && user.has_permission?('routing_constraint_zones.create')    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.update') +  end  end diff --git a/app/policies/stop_area_policy.rb b/app/policies/stop_area_policy.rb index 79b7178ce..de8ecda8d 100644 --- a/app/policies/stop_area_policy.rb +++ b/app/policies/stop_area_policy.rb @@ -1,15 +1,7 @@ -class StopAreaPolicy < BoivPolicy +class StopAreaPolicy < ApplicationPolicy    class Scope < Scope      def resolve        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 e915ede6a..c9f3a3ec6 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 @@ -7,21 +7,22 @@ class TimeTablePolicy < BoivPolicy    end    def create? -    !archived? && user.has_permission?('time_tables.create') # organisation match via referential is checked in the view -  end - -  def edit? -    !archived? && organisation_match? && user.has_permission?('time_tables.edit') +    !archived? && organisation_match? && user.has_permission?('time_tables.create')    end    def destroy?      !archived? && organisation_match? && user.has_permission?('time_tables.destroy')    end +  def update? +    !archived? && organisation_match? && user.has_permission?('time_tables.update') +  end + +  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 de6dd7088..24040455f 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 @@ -6,17 +6,14 @@ class VehicleJourneyPolicy < BoivPolicy    end    def create? -    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') +    !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?  ; edit? end -  def new?     ; create? end +  def update? +    !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/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/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 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/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/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/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/features/workbenches_spec.rb b/spec/features/workbenches_spec.rb index 9a40a8376..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,47 +149,47 @@ 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            end          end        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 -  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  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..4b07922a7 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,19 +6,17 @@ describe TableBuilderHelper::CustomLinks do          build_stubbed(            :user,            organisation: referential.organisation, -          permissions: [ -            'boiv:read-offer' -          ]          ),          referential: referential        ) +      stub_policy_scope(referential)        expect(          TableBuilderHelper::CustomLinks.new(            referential,            user_context,            [:show] -        ).actions_after_policy_check +        ).authorized_actions        ).to eq([:show])      end    end diff --git a/spec/helpers/table_builder_helper_spec.rb b/spec/helpers/table_builder_helper_spec.rb index d90c14204..4f7c1bd69 100644 --- a/spec/helpers/table_builder_helper_spec.rb +++ b/spec/helpers/table_builder_helper_spec.rb @@ -16,8 +16,8 @@ describe TableBuilderHelper, type: :helper do            organisation: referential.organisation,            permissions: [              'referentials.create', -            'referentials.edit', -            'referentials.destroy' +            'referentials.update', +            'referentials.destroy',            ]          ),          referential: referential @@ -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,6 +194,7 @@ describe TableBuilderHelper, type: :helper do          companies,          with: CompanyDecorator        ) +      stub_policy_scope(company)        expected = <<-HTML  <table class="table has-search"> @@ -299,8 +301,10 @@ describe TableBuilderHelper, type: :helper do        companies = ModelDecorator.decorate(          companies, -        with: CompanyDecorator +        with: CompanyDecorator, +        context: {line_referential: line_referential}        ) +      stub_policy_scope(company)        expected = <<-HTML  <table class="table has-search"> 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/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 diff --git a/spec/policies/calendar_policy_spec.rb b/spec/policies/calendar_policy_spec.rb new file mode 100644 index 000000000..57f771c54 --- /dev/null +++ b/spec/policies/calendar_policy_spec.rb @@ -0,0 +1,22 @@ +RSpec.describe CalendarPolicy, type: :policy do + +  let( :record ){ build_stubbed :calendar } +  before { stub_policy_scope(record) } + + +  permissions :create? do +    it_behaves_like 'permitted policy and same organisation', 'calendars.create', archived: true +  end +  permissions :destroy? do +    it_behaves_like 'permitted policy and same organisation', 'calendars.destroy', archived: true +  end +  permissions :edit? do +    it_behaves_like 'permitted policy and same organisation', 'calendars.update', archived: true +  end +  permissions :new? do +    it_behaves_like 'permitted policy and same organisation', 'calendars.create', archived: true +  end +  permissions :update? do +    it_behaves_like 'permitted policy and same organisation', '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..334073506 100644 --- a/spec/policies/line_policy_spec.rb +++ b/spec/policies/line_policy_spec.rb @@ -1,21 +1,59 @@  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 +    it_behaves_like 'permitted policy and same organisation', 'footnotes.create', archived: true    end -  permissions :new_footnote? do -    it_behaves_like 'permitted policy', 'footnotes.create', archived: true +  permissions :destroy_footnote? do +    it_behaves_like 'permitted policy and same organisation', 'footnotes.destroy', archived: true    end    permissions :update_footnote? do -    it_behaves_like 'permitted policy', 'footnotes.edit', archived: true +    it_behaves_like 'permitted policy and same organisation', 'footnotes.update', archived: true    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..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 @@ -11,14 +11,14 @@ 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 -    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 -    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 2508b49f9..2ef15fa95 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 @@ -12,14 +12,14 @@ 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 -    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 -    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/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/policies/time_table_policy_spec.rb b/spec/policies/time_table_policy_spec.rb index 90e6600ea..dad3c13bc 100644 --- a/spec/policies/time_table_policy_spec.rb +++ b/spec/policies/time_table_policy_spec.rb @@ -2,20 +2,23 @@ RSpec.describe TimeTablePolicy, type: :policy do    let( :record ){ build_stubbed :time_table } - -  permissions :duplicate? do +  permissions :create? do      it_behaves_like 'permitted policy and same organisation', 'time_tables.create', 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 :destroy? do +    it_behaves_like 'permitted policy and same organisation', 'time_tables.destroy', archived: true    end -  permissions :create? do -    it_behaves_like 'permitted policy', 'time_tables.create', archived: true +  permissions :edit? do +    it_behaves_like 'permitted policy and same organisation', 'time_tables.update', 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/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 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/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 diff --git a/spec/support/pundit/shared_examples.rb b/spec/support/pundit/shared_examples.rb index 33ed1ffae..b91caa479 100644 --- a/spec/support/pundit/shared_examples.rb +++ b/spec/support/pundit/shared_examples.rb @@ -1,57 +1,100 @@ -RSpec.shared_examples 'permitted policy and same organisation' 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) +RSpec.shared_examples 'always allowed' do +  | permission, archived: false| +  context 'same organisation →' do +    before do +      user.organisation_id = referential.organisation_id      end -    it 'and also a user with the same organisation' do -      user.organisation = referential.organisation -      expect_it.not_to permit(user_context, record) +    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 'permission present → '  do + +  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 -    it 'denies a user with a different organisation' do +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 - -    it 'but allows it for a user with the same organisation' do -      user.organisation = referential.organisation -      expect_it.to permit(user_context, record) +    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 'removes the permission for archived referentials' do -        user.organisation = referential.organisation +      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' do +j +RSpec.shared_examples 'permitted policy and same organisation' 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 +    it 'and also a user with the same organisation' do +      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)      end -    it 'allows a user with a different organisation' do + +    it 'denies a user with a different organisation' do +      expect_it.not_to permit(user_context, record) +    end + +    it 'but allows it for a user with the same organisation' do +      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_id = referential.organisation_id          referential.archived_at = 42.seconds.ago          expect_it.not_to permit(user_context, record)        end | 
