diff options
| author | Alban Peignier | 2017-12-20 21:30:22 +0100 | 
|---|---|---|
| committer | GitHub | 2017-12-20 21:30:22 +0100 | 
| commit | 6b4b00a57d2c96ea9f2c663dd9892ccdd4fdbd29 (patch) | |
| tree | a7f69ebd48e32bf14d2da6ba47c84a8e2e57aae2 | |
| parent | 0a1e40a31c27c59018cbdb8821b530ccfd59b878 (diff) | |
| parent | 462c1c257e954c77f1dedfc770d3c78111c1b499 (diff) | |
| download | chouette-core-6b4b00a57d2c96ea9f2c663dd9892ccdd4fdbd29.tar.bz2 | |
Merge pull request #164 from af83/5339-organisation-and-features
Create Organisation#features and FeatureChecker. Refs #5339 
| -rw-r--r-- | app/controllers/application_controller.rb | 1 | ||||
| -rw-r--r-- | app/controllers/concerns/feature_checker.rb | 42 | ||||
| -rw-r--r-- | app/controllers/workbenches_controller.rb | 3 | ||||
| -rw-r--r-- | app/models/organisation.rb | 5 | ||||
| -rw-r--r-- | config/application.rb | 4 | ||||
| -rw-r--r-- | db/migrate/20171219170128_add_features_to_organisations.rb | 5 | ||||
| -rw-r--r-- | db/schema.rb | 48 | ||||
| -rw-r--r-- | spec/controllers/concerns/feature_checker_spec.rb | 37 | ||||
| -rw-r--r-- | spec/models/organisation_spec.rb | 22 | 
9 files changed, 155 insertions, 12 deletions
| diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 97f5548ae..474277da1 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,7 @@  class ApplicationController < ActionController::Base    include PaperTrailSupport    include Pundit +  include FeatureChecker    rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized diff --git a/app/controllers/concerns/feature_checker.rb b/app/controllers/concerns/feature_checker.rb new file mode 100644 index 000000000..9ca5ed0a7 --- /dev/null +++ b/app/controllers/concerns/feature_checker.rb @@ -0,0 +1,42 @@ +# Check availability of optional features +# +# In your controller, use : +# +#   requires_feature :test +#   requires_feature :test, only: [:show] +# +# In your view, use : +# +#   has_feature? :test +# +module FeatureChecker +  extend ActiveSupport::Concern + +  module ClassMethods +    def requires_feature(feature, options = {}) +      before_action options do +        check_feature! feature +      end +    end +  end + +  included do +    helper_method :has_feature? +  end + +  protected + +  def has_feature?(*features) +    features.all? do |feature| +      current_organisation.has_feature? feature +    end +  end + +  def check_feature!(*features) +    unless has_feature?(*features) +      raise NotAuthorizedError, "Feature not autorized" +    end +  end + +  class NotAuthorizedError < StandardError; end +end diff --git a/app/controllers/workbenches_controller.rb b/app/controllers/workbenches_controller.rb index b2dac9e67..4da95df7a 100644 --- a/app/controllers/workbenches_controller.rb +++ b/app/controllers/workbenches_controller.rb @@ -5,6 +5,9 @@ class WorkbenchesController < ChouetteController    defaults resource_class: Workbench    respond_to :html, only: [:show, :index] +  include FeatureChecker +  requires_feature :test, only: :index +    def index      redirect_to dashboard_path    end diff --git a/app/models/organisation.rb b/app/models/organisation.rb index 4343c87af..da7d1fcf3 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -1,3 +1,4 @@ +# coding: utf-8  class Organisation < ActiveRecord::Base    include DataFormatEnumerations @@ -75,4 +76,8 @@ class Organisation < ActiveRecord::Base      STIF::CodifligneLineId.lines_set_from_functional_scope( functional_scope )    end +  def has_feature?(feature) +    features && features.include?(feature.to_s) +  end +  end diff --git a/config/application.rb b/config/application.rb index 169c13e10..bda582610 100644 --- a/config/application.rb +++ b/config/application.rb @@ -35,6 +35,10 @@ module ChouetteIhm      config.active_job.queue_adapter = :sidekiq +    config.action_dispatch.rescue_responses.merge!( +      'FeatureChecker::NotAuthorizedError' => :unauthorized +    ) +      unless Rails.env.production?          # Work around sprockets+teaspoon mismatch:          Rails.application.config.assets.precompile += %w(spec_helper.js) diff --git a/db/migrate/20171219170128_add_features_to_organisations.rb b/db/migrate/20171219170128_add_features_to_organisations.rb new file mode 100644 index 000000000..bbec3297b --- /dev/null +++ b/db/migrate/20171219170128_add_features_to_organisations.rb @@ -0,0 +1,5 @@ +class AddFeaturesToOrganisations < ActiveRecord::Migration +  def change +    add_column :organisations, :features, :string, array: true, default: [] +  end +end diff --git a/db/schema.rb b/db/schema.rb index f2642f8fc..e19a40aab 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@  #  # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171214130636) do +ActiveRecord::Schema.define(version: 20171219170128) do    # These are extensions that must be enabled in order to support this database    enable_extension "plpgsql" @@ -281,6 +281,22 @@ ActiveRecord::Schema.define(version: 20171214130636) do    add_index "connection_links", ["objectid"], name: "connection_links_objectid_key", unique: true, using: :btree +  create_table "delayed_jobs", id: :bigserial, force: :cascade do |t| +    t.integer  "priority",               default: 0 +    t.integer  "attempts",               default: 0 +    t.text     "handler" +    t.text     "last_error" +    t.datetime "run_at" +    t.datetime "locked_at" +    t.datetime "failed_at" +    t.string   "locked_by",  limit: 255 +    t.string   "queue",      limit: 255 +    t.datetime "created_at" +    t.datetime "updated_at" +  end + +  add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree +    create_table "exports", id: :bigserial, force: :cascade do |t|      t.integer  "referential_id",  limit: 8      t.string   "status" @@ -400,12 +416,12 @@ ActiveRecord::Schema.define(version: 20171214130636) do      t.datetime "started_at"      t.datetime "ended_at"      t.string   "token_download" -    t.string   "type" +    t.string   "type",                  limit: 255      t.integer  "parent_id",             limit: 8      t.string   "parent_type" +    t.integer  "current_step",                      default: 0 +    t.integer  "total_steps",                       default: 0      t.datetime "notified_parent_at" -    t.integer  "current_step",                    default: 0 -    t.integer  "total_steps",                     default: 0      t.string   "creator"    end @@ -543,6 +559,11 @@ ActiveRecord::Schema.define(version: 20171214130636) do    add_index "networks", ["objectid"], name: "networks_objectid_key", unique: true, using: :btree    add_index "networks", ["registration_number"], name: "networks_registration_number_key", using: :btree +  create_table "object_id_factories", id: :bigserial, force: :cascade do |t| +    t.datetime "created_at", null: false +    t.datetime "updated_at", null: false +  end +    create_table "organisations", id: :bigserial, force: :cascade do |t|      t.string   "name"      t.datetime "created_at" @@ -552,6 +573,7 @@ ActiveRecord::Schema.define(version: 20171214130636) do      t.datetime "synced_at"      t.hstore   "sso_attributes"      t.string   "custom_view" +    t.string   "features",       default: [],        array: true    end    add_index "organisations", ["code"], name: "index_organisations_on_code", unique: true, using: :btree @@ -709,7 +731,7 @@ ActiveRecord::Schema.define(version: 20171214130636) do    create_table "stop_areas", id: :bigserial, force: :cascade do |t|      t.integer  "parent_id",                       limit: 8 -    t.string   "objectid",                                                            null: false +    t.string   "objectid",                                                              null: false      t.integer  "object_version",                  limit: 8      t.string   "name"      t.string   "comment" @@ -717,8 +739,8 @@ ActiveRecord::Schema.define(version: 20171214130636) do      t.string   "registration_number"      t.string   "nearest_topic_name"      t.integer  "fare_code" -    t.decimal  "longitude",                                 precision: 19, scale: 16 -    t.decimal  "latitude",                                  precision: 19, scale: 16 +    t.decimal  "longitude",                                   precision: 19, scale: 16 +    t.decimal  "latitude",                                    precision: 19, scale: 16      t.string   "long_lat_type"      t.string   "country_code"      t.string   "street_name" @@ -736,7 +758,7 @@ ActiveRecord::Schema.define(version: 20171214130636) do      t.datetime "deleted_at"      t.datetime "created_at"      t.datetime "updated_at" -    t.string   "stif_type" +    t.string   "stif_type",                       limit: 255    end    add_index "stop_areas", ["name"], name: "index_stop_areas_on_name", using: :btree @@ -806,17 +828,17 @@ ActiveRecord::Schema.define(version: 20171214130636) do    add_index "time_table_periods", ["time_table_id"], name: "index_time_table_periods_on_time_table_id", using: :btree    create_table "time_tables", id: :bigserial, force: :cascade do |t| -    t.string   "objectid",                              null: false -    t.integer  "object_version",  limit: 8, default: 1 +    t.string   "objectid",                                null: false +    t.integer  "object_version",  limit: 8,   default: 1      t.string   "version"      t.string   "comment" -    t.integer  "int_day_types",             default: 0 +    t.integer  "int_day_types",               default: 0      t.date     "start_date"      t.date     "end_date"      t.integer  "calendar_id",     limit: 8      t.datetime "created_at"      t.datetime "updated_at" -    t.string   "color" +    t.string   "color",           limit: 255      t.integer  "created_from_id", limit: 8      t.string   "checksum"      t.text     "checksum_source" @@ -971,7 +993,9 @@ ActiveRecord::Schema.define(version: 20171214130636) do    add_foreign_key "compliance_controls", "compliance_control_blocks"    add_foreign_key "compliance_controls", "compliance_control_sets"    add_foreign_key "group_of_lines_lines", "group_of_lines", name: "groupofline_group_fkey", on_delete: :cascade +  add_foreign_key "journey_frequencies", "timebands", name: "journey_frequencies_timeband_id_fk", on_delete: :nullify    add_foreign_key "journey_frequencies", "timebands", on_delete: :nullify +  add_foreign_key "journey_frequencies", "vehicle_journeys", name: "journey_frequencies_vehicle_journey_id_fk", on_delete: :nullify    add_foreign_key "journey_frequencies", "vehicle_journeys", on_delete: :nullify    add_foreign_key "journey_patterns", "routes", name: "jp_route_fkey", on_delete: :cascade    add_foreign_key "journey_patterns", "stop_points", column: "arrival_stop_point_id", name: "arrival_point_fkey", on_delete: :nullify diff --git a/spec/controllers/concerns/feature_checker_spec.rb b/spec/controllers/concerns/feature_checker_spec.rb new file mode 100644 index 000000000..1d289bb15 --- /dev/null +++ b/spec/controllers/concerns/feature_checker_spec.rb @@ -0,0 +1,37 @@ +require "rails_helper" + +RSpec.describe "FeatureChecker", type: :controller do +  login_user + +  controller do +    include FeatureChecker +    requires_feature :test, only: :protected + +    def protected; render text: "protected"; end +    def not_protected; render text: "not protected"; end + +    def current_organisation +      @organisation ||= Organisation.new +    end +  end + +  before do +    routes.draw do +      get "protected" => "anonymous#protected" +      get "not_protected" => "anonymous#not_protected" +    end +  end + +  it "refuse access when organisation does not have the feature" do +    expect{ get(:protected) }.to raise_error(FeatureChecker::NotAuthorizedError) +  end + +  it "accept access on unprotected action" do +    get :not_protected +  end + +  it 'accept access when organisation has feature' do +    controller.current_organisation.features << "test" +    get :protected +  end +end diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb index 359417d88..595b08058 100644 --- a/spec/models/organisation_spec.rb +++ b/spec/models/organisation_spec.rb @@ -62,4 +62,26 @@ describe Organisation, :type => :model do        expect{Organisation.portail_sync}.to change{ Organisation.count }.by(4)      end    end + +  describe "#has_feature?" do + +    let(:organisation) { Organisation.new } + +    it 'return false if Organisation features is nil' do +      organisation.features = nil +      expect(organisation.has_feature?(:dummy)).to be_falsy +    end + +    it 'return true if Organisation features contains given feature' do +      organisation.features = %w{present} +      expect(organisation.has_feature?(:present)).to be_truthy +    end + +    it "return false if Organisation features doesn't contains given feature" do +      organisation.features = %w{other} +      expect(organisation.has_feature?(:absent)).to be_falsy +    end + +  end +  end | 
