aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlban Peignier2017-12-20 21:30:22 +0100
committerGitHub2017-12-20 21:30:22 +0100
commit6b4b00a57d2c96ea9f2c663dd9892ccdd4fdbd29 (patch)
treea7f69ebd48e32bf14d2da6ba47c84a8e2e57aae2
parent0a1e40a31c27c59018cbdb8821b530ccfd59b878 (diff)
parent462c1c257e954c77f1dedfc770d3c78111c1b499 (diff)
downloadchouette-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.rb1
-rw-r--r--app/controllers/concerns/feature_checker.rb42
-rw-r--r--app/controllers/workbenches_controller.rb3
-rw-r--r--app/models/organisation.rb5
-rw-r--r--config/application.rb4
-rw-r--r--db/migrate/20171219170128_add_features_to_organisations.rb5
-rw-r--r--db/schema.rb48
-rw-r--r--spec/controllers/concerns/feature_checker_spec.rb37
-rw-r--r--spec/models/organisation_spec.rb22
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