strongbolt 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.editorconfig +33 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +22 -0
- data/README.md +182 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/strongbolt.js +1 -0
- data/app/assets/javascripts/strongbolt/role-capabilities.js +80 -0
- data/app/controllers/strongbolt/capabilities_controller.rb +77 -0
- data/app/controllers/strongbolt/roles_controller.rb +92 -0
- data/app/controllers/strongbolt/security_controller.rb +8 -0
- data/app/controllers/strongbolt/user_groups_controller.rb +76 -0
- data/app/controllers/strongbolt/user_groups_users_controller.rb +35 -0
- data/app/controllers/strongbolt_controller.rb +2 -0
- data/app/views/strongbolt/_menu.html.erb +13 -0
- data/app/views/strongbolt/capabilities/index.html.erb +53 -0
- data/app/views/strongbolt/capabilities/show.html.erb +53 -0
- data/app/views/strongbolt/roles/_capabilities.html.erb +47 -0
- data/app/views/strongbolt/roles/_capability.html.erb +21 -0
- data/app/views/strongbolt/roles/_form.html.erb +12 -0
- data/app/views/strongbolt/roles/edit.html.erb +14 -0
- data/app/views/strongbolt/roles/index.html.erb +54 -0
- data/app/views/strongbolt/roles/new.html.erb +11 -0
- data/app/views/strongbolt/roles/show.html.erb +52 -0
- data/app/views/strongbolt/user_groups/_form.html.erb +12 -0
- data/app/views/strongbolt/user_groups/edit.html.erb +14 -0
- data/app/views/strongbolt/user_groups/index.html.erb +46 -0
- data/app/views/strongbolt/user_groups/new.html.erb +13 -0
- data/app/views/strongbolt/user_groups/show.html.erb +88 -0
- data/lib/generators/strongbolt/fix_generator.rb +23 -0
- data/lib/generators/strongbolt/indexes_generator.rb +19 -0
- data/lib/generators/strongbolt/install_generator.rb +29 -0
- data/lib/generators/strongbolt/templates/fix.rb +5 -0
- data/lib/generators/strongbolt/templates/indexes.rb +21 -0
- data/lib/generators/strongbolt/templates/migration.rb +73 -0
- data/lib/generators/strongbolt/templates/strongbolt.rb +45 -0
- data/lib/generators/strongbolt/views_generator.rb +26 -0
- data/lib/strongbolt.rb +219 -0
- data/lib/strongbolt/base.rb +7 -0
- data/lib/strongbolt/bolted.rb +125 -0
- data/lib/strongbolt/bolted_controller.rb +297 -0
- data/lib/strongbolt/capabilities_role.rb +15 -0
- data/lib/strongbolt/capability.rb +165 -0
- data/lib/strongbolt/configuration.rb +111 -0
- data/lib/strongbolt/controllers/url_helpers.rb +37 -0
- data/lib/strongbolt/engine.rb +44 -0
- data/lib/strongbolt/errors.rb +38 -0
- data/lib/strongbolt/generators/migration.rb +35 -0
- data/lib/strongbolt/helpers.rb +18 -0
- data/lib/strongbolt/rails/routes.rb +20 -0
- data/lib/strongbolt/role.rb +46 -0
- data/lib/strongbolt/roles_user_group.rb +15 -0
- data/lib/strongbolt/rspec.rb +29 -0
- data/lib/strongbolt/rspec/user.rb +90 -0
- data/lib/strongbolt/tenantable.rb +304 -0
- data/lib/strongbolt/user_abilities.rb +292 -0
- data/lib/strongbolt/user_group.rb +24 -0
- data/lib/strongbolt/user_groups_user.rb +16 -0
- data/lib/strongbolt/users_tenant.rb +12 -0
- data/lib/strongbolt/version.rb +3 -0
- data/lib/tasks/strongbolt_tasks.rake +29 -0
- data/spec/controllers/strongbolt/capabilities_controller_spec.rb +254 -0
- data/spec/controllers/strongbolt/roles_controller_spec.rb +228 -0
- data/spec/controllers/strongbolt/user_groups_controller_spec.rb +216 -0
- data/spec/controllers/strongbolt/user_groups_users_controller_spec.rb +69 -0
- data/spec/controllers/without_authorization_controller_spec.rb +20 -0
- data/spec/dummy/.rspec +2 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/posts_controller.rb +18 -0
- data/spec/dummy/app/controllers/test_controller.rb +3 -0
- data/spec/dummy/app/controllers/without_authorization_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/strongbolt.rb +32 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20150630212236_create_strongbolt_tables.rb +54 -0
- data/spec/dummy/db/migrate/20150630212251_create_strongbolt_tables_indexes.rb +21 -0
- data/spec/dummy/db/schema.rb +84 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/fabricators/capability_fabricator.rb +4 -0
- data/spec/fabricators/role_fabricator.rb +9 -0
- data/spec/fabricators/user_fabricator.rb +3 -0
- data/spec/fabricators/user_group_fabricator.rb +9 -0
- data/spec/fixtures/application.rb +28 -0
- data/spec/fixtures/controllers.rb +5 -0
- data/spec/spec_helper.rb +89 -0
- data/spec/strongbolt/bolted_controller_spec.rb +706 -0
- data/spec/strongbolt/bolted_spec.rb +136 -0
- data/spec/strongbolt/capability_spec.rb +251 -0
- data/spec/strongbolt/configuration_spec.rb +119 -0
- data/spec/strongbolt/controllers/url_helpers_spec.rb +34 -0
- data/spec/strongbolt/helpers_spec.rb +43 -0
- data/spec/strongbolt/role_spec.rb +90 -0
- data/spec/strongbolt/tenantable_spec.rb +281 -0
- data/spec/strongbolt/user_abilities_spec.rb +509 -0
- data/spec/strongbolt/user_group_spec.rb +37 -0
- data/spec/strongbolt/users_tenant_spec.rb +36 -0
- data/spec/strongbolt_spec.rb +274 -0
- data/spec/support/controller_macros.rb +11 -0
- data/spec/support/db_setup.rb +134 -0
- data/spec/support/helpers.rb +62 -0
- data/spec/support/transactional_specs.rb +17 -0
- data/strongbolt.gemspec +32 -0
- metadata +407 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
|
|
3
|
+
module Configuration
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# A placeholder class for logger when not defined
|
|
7
|
+
# Just print what's given
|
|
8
|
+
#
|
|
9
|
+
class DefaultLogger
|
|
10
|
+
def method_missing method_name, text = nil, &block
|
|
11
|
+
puts "[#{method_name}] #{block.present? ? block.call : text}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Sets the class name of the user if different then default 'User'
|
|
17
|
+
#
|
|
18
|
+
mattr_accessor :user_class
|
|
19
|
+
@@user_class = 'User'
|
|
20
|
+
|
|
21
|
+
#
|
|
22
|
+
# Returns the constantize version of user class
|
|
23
|
+
#
|
|
24
|
+
def self.user_class_constant() self.user_class.constantize; end
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Sets the logger used by Strongbolt
|
|
28
|
+
#
|
|
29
|
+
mattr_accessor :logger
|
|
30
|
+
@@logger = DefaultLogger.new
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# Sets the tenants of the application
|
|
34
|
+
#
|
|
35
|
+
@@tenants = []
|
|
36
|
+
def self.tenants= tenants
|
|
37
|
+
@@tenants = []
|
|
38
|
+
[*tenants].each {|t| add_tenant t}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Returns the tenants
|
|
43
|
+
#
|
|
44
|
+
def self.tenants() @@tenants; end
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Adds a tenant if not in the list
|
|
48
|
+
#
|
|
49
|
+
def self.add_tenant tenant
|
|
50
|
+
tenant = tenant.constantize if tenant.is_a? String
|
|
51
|
+
unless @@tenants.any? { |m| m.name == tenant.name }
|
|
52
|
+
tenant.send :tenant
|
|
53
|
+
@@tenants << tenant
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# Allows to configure what happens when the access is denied,
|
|
60
|
+
# or call the block that has been given
|
|
61
|
+
#
|
|
62
|
+
# The block access denied receives as arguments:
|
|
63
|
+
# user, instance, action, request_path
|
|
64
|
+
#
|
|
65
|
+
def self.access_denied *args, &block
|
|
66
|
+
if block.present?
|
|
67
|
+
@@access_denied_block = block
|
|
68
|
+
else
|
|
69
|
+
@@access_denied_block.call(*args) if defined?(@@access_denied_block)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Allows to set Capability Models list
|
|
75
|
+
#
|
|
76
|
+
def self.models= models
|
|
77
|
+
Strongbolt::Capability.add_models models
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
# Controllers to skip controller authorization check ups
|
|
82
|
+
#
|
|
83
|
+
def self.skip_controller_authorization_for *controllers
|
|
84
|
+
ActiveSupport.on_load :action_controller do
|
|
85
|
+
controllers.each do |controller|
|
|
86
|
+
begin
|
|
87
|
+
"#{controller.camelize}Controller".constantize.send :skip_controller_authorization
|
|
88
|
+
rescue NameError => e
|
|
89
|
+
raise NameError, "Controller #{controller} doesn't correspond to a valid controller name"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# Default permissions
|
|
97
|
+
#
|
|
98
|
+
@@default_capabilities = []
|
|
99
|
+
def self.default_capabilities= list
|
|
100
|
+
@@default_capabilities = list.inject([]) do |capabilities, hash|
|
|
101
|
+
capabilities.concat Capability.from_hash(hash)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.default_capabilities
|
|
106
|
+
@@default_capabilities
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'active_support/inflector'
|
|
2
|
+
|
|
3
|
+
module Strongbolt
|
|
4
|
+
module Controllers
|
|
5
|
+
#
|
|
6
|
+
# Creates the url helpers without the 'strongbolt_' prefix,
|
|
7
|
+
# that both Strongbolt views and the app views can use
|
|
8
|
+
#
|
|
9
|
+
# It's not very nice like that but would be too complicated to do like Devise for now...
|
|
10
|
+
#
|
|
11
|
+
module UrlHelpers
|
|
12
|
+
URLS = %w{role user_group user_group_user role_capability}
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# Creates the url helpers for the specific url and scope
|
|
16
|
+
#
|
|
17
|
+
def self.create_url_helper url, scope=nil
|
|
18
|
+
[:path, :url].each do |path_or_url|
|
|
19
|
+
class_eval <<-URL_HELPERS
|
|
20
|
+
def #{scope.present? ? "#{scope}_" : ''}#{url}_#{path_or_url} *args
|
|
21
|
+
send(:main_app).send("#{scope.present? ? "#{scope}_" : ''}strongbolt_#{url}_#{path_or_url}", *args)
|
|
22
|
+
end
|
|
23
|
+
URL_HELPERS
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# Loads all the required helpers
|
|
29
|
+
#
|
|
30
|
+
URLS.each do |url|
|
|
31
|
+
create_url_helper url
|
|
32
|
+
create_url_helper url.pluralize
|
|
33
|
+
[:new, :edit].each { |scope| create_url_helper url, scope }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "strongbolt/rails/routes"
|
|
2
|
+
|
|
3
|
+
require "strongbolt/helpers"
|
|
4
|
+
require "strongbolt/controllers/url_helpers"
|
|
5
|
+
|
|
6
|
+
module Strongbolt
|
|
7
|
+
class Engine < ::Rails::Engine
|
|
8
|
+
|
|
9
|
+
initializer 'strongbolt.assets.precompile' do |app|
|
|
10
|
+
%w(javascripts).each do |sub|
|
|
11
|
+
app.config.assets.paths << root.join('app', 'assets', sub).to_s
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
initializer "strongbolt.helpers" do
|
|
16
|
+
ActionView::Base.send :include, Strongbolt::Helpers
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
# Session Store should be accessible anytime
|
|
21
|
+
#
|
|
22
|
+
initializer "strongbolt.session" do
|
|
23
|
+
if defined? ActiveRecord::SessionStore::Session
|
|
24
|
+
ActiveRecord::SessionStore::Session.grant(:find, :create, :update, :destroy) { true }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Avoids authorization checking in the middleware
|
|
30
|
+
#
|
|
31
|
+
initializer "strongbolt.devise_integration" do
|
|
32
|
+
if defined?(Warden) && defined?(Warden::SessionSerializer)
|
|
33
|
+
Warden::SessionSerializer.perform_without_authorization :store, :fetch, :delete
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Initialize our custom url helpers
|
|
39
|
+
#
|
|
40
|
+
initializer "strongbolt.url_helpers" do
|
|
41
|
+
Strongbolt.include_helpers Strongbolt::Controllers
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
StrongboltError = Class.new StandardError
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Copy & Paste of Grant Error
|
|
6
|
+
#
|
|
7
|
+
class Unauthorized < StrongboltError
|
|
8
|
+
attr_reader :user, :action, :model
|
|
9
|
+
|
|
10
|
+
def initialize(*args)
|
|
11
|
+
if args.size == 3
|
|
12
|
+
@user, @action, @model = args
|
|
13
|
+
else
|
|
14
|
+
@message = args[0]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
if @message
|
|
20
|
+
@message
|
|
21
|
+
else
|
|
22
|
+
user_str = user == nil ? 'Anonymous' : "#{user.try(:class).try(:name)}:#{user.try :id}"
|
|
23
|
+
model_str = model.is_a?(Class) ? "#{model.try :name}" : "#{model.try(:class).try(:name)}:#{model.try :id}"
|
|
24
|
+
"#{action} permission not granted to #{user_str} for resource #{model_str}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
ModelNotFound = Class.new StrongboltError
|
|
30
|
+
ActionNotConfigured = Class.new StrongboltError
|
|
31
|
+
|
|
32
|
+
WrongUserClass = Class.new StrongboltError
|
|
33
|
+
ModelNotOwned = Class.new StrongboltError
|
|
34
|
+
|
|
35
|
+
TenantError = Class.new StrongboltError
|
|
36
|
+
InverseAssociationNotConfigured = Class.new TenantError
|
|
37
|
+
DirectAssociationNotConfigured = Class.new TenantError
|
|
38
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'rails/generators/active_record'
|
|
2
|
+
|
|
3
|
+
module Strongbolt
|
|
4
|
+
module Generators
|
|
5
|
+
module Migration
|
|
6
|
+
def self.included receiver
|
|
7
|
+
receiver.send :include, Rails::Generators::Migration
|
|
8
|
+
receiver.send :include, InstanceMethods
|
|
9
|
+
receiver.extend ClassMethods
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
#
|
|
14
|
+
# Need to add this here... Don't know why it's not in a Rails module
|
|
15
|
+
#
|
|
16
|
+
def next_migration_number(dirname)
|
|
17
|
+
next_migration_number = current_migration_number(dirname) + 1
|
|
18
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module InstanceMethods
|
|
24
|
+
|
|
25
|
+
def copy_migration(source, target)
|
|
26
|
+
if self.class.migration_exists?("db/migrate", "#{target}")
|
|
27
|
+
say_status "skipped", "Migration #{target}.rb already exists"
|
|
28
|
+
else
|
|
29
|
+
migration_template "#{source}.rb", "db/migrate/#{target}.rb"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
module Helpers
|
|
3
|
+
def can? *args, &block
|
|
4
|
+
# Block can be used when testing an instance
|
|
5
|
+
Strongbolt.without_authorization do
|
|
6
|
+
if block.present?
|
|
7
|
+
args.insert 1, block.call
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
return current_user.can? *args
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def cannot? *args, &block
|
|
15
|
+
! can? *args, &block
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ActionDispatch::Routing
|
|
2
|
+
#
|
|
3
|
+
# Creates the strongbolt route helper method
|
|
4
|
+
#
|
|
5
|
+
class Mapper
|
|
6
|
+
def strongbolt
|
|
7
|
+
scope :module => :strongbolt do
|
|
8
|
+
resources :user_groups do
|
|
9
|
+
resources :user_groups_users, as: :users, path: 'users', only: [:create, :destroy]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
resources :roles do
|
|
13
|
+
resources :capabilities, only: [:create, :destroy] do
|
|
14
|
+
delete :destroy, on: :collection
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
class Role < Base
|
|
3
|
+
|
|
4
|
+
acts_as_nested_set
|
|
5
|
+
|
|
6
|
+
validates :name, presence: true
|
|
7
|
+
|
|
8
|
+
has_many :roles_user_groups,
|
|
9
|
+
:class_name => "Strongbolt::RolesUserGroup",
|
|
10
|
+
:dependent => :restrict_with_exception,
|
|
11
|
+
:inverse_of => :role
|
|
12
|
+
has_many :user_groups, :through => :roles_user_groups
|
|
13
|
+
|
|
14
|
+
has_many :users, through: :user_groups
|
|
15
|
+
|
|
16
|
+
has_many :capabilities_roles,
|
|
17
|
+
:class_name => "Strongbolt::CapabilitiesRole",
|
|
18
|
+
:dependent => :delete_all,
|
|
19
|
+
:inverse_of => :role
|
|
20
|
+
has_many :capabilities, :through => :capabilities_roles
|
|
21
|
+
|
|
22
|
+
before_destroy :should_not_have_children
|
|
23
|
+
|
|
24
|
+
# We SHOULD NOT destroy descendants in our case
|
|
25
|
+
skip_callback :destroy, :before, :destroy_descendants
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# Returns inherited capabilities
|
|
29
|
+
#
|
|
30
|
+
def inherited_capabilities
|
|
31
|
+
Strongbolt::Capability.joins(:roles)
|
|
32
|
+
.where("strongbolt_roles.lft < :lft AND strongbolt_roles.rgt > :rgt", lft: lft, rgt: rgt)
|
|
33
|
+
.distinct
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def should_not_have_children
|
|
39
|
+
if children.count > 0
|
|
40
|
+
raise ActiveRecord::DeleteRestrictionError.new :children
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
Role = Strongbolt::Role unless defined? Role
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
class RolesUserGroup < Base
|
|
3
|
+
authorize_as "Strongbolt::UserGroup"
|
|
4
|
+
|
|
5
|
+
belongs_to :user_group,
|
|
6
|
+
:class_name => "Strongbolt::UserGroup",
|
|
7
|
+
:inverse_of => :roles_user_groups
|
|
8
|
+
|
|
9
|
+
belongs_to :role,
|
|
10
|
+
:class_name => "Strongbolt::Role",
|
|
11
|
+
:inverse_of => :roles_user_groups
|
|
12
|
+
|
|
13
|
+
validates_presence_of :user_group, :role
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Setups Rspec related stuff to handle correctly Strongbolt
|
|
3
|
+
#
|
|
4
|
+
require 'strongbolt'
|
|
5
|
+
|
|
6
|
+
Strongbolt.switch_to_multithread
|
|
7
|
+
|
|
8
|
+
if defined?(RSpec)
|
|
9
|
+
# We load the class that overrides user behavior,
|
|
10
|
+
# more convenient for tests
|
|
11
|
+
require 'strongbolt/rspec/user'
|
|
12
|
+
|
|
13
|
+
RSpec.configure do |config|
|
|
14
|
+
#
|
|
15
|
+
# When creating stuff in before :all, avoid leaks
|
|
16
|
+
#
|
|
17
|
+
config.before(:all) do
|
|
18
|
+
Strongbolt.current_user = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
config.around(:each) do |example|
|
|
22
|
+
Strongbolt.without_authorization &example
|
|
23
|
+
# Clear all the User authorizations that could have been defined
|
|
24
|
+
User.clear_authorizations
|
|
25
|
+
# Removes the user from current_user to avoid leaks
|
|
26
|
+
Strongbolt.current_user = nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require 'rspec/mocks'
|
|
2
|
+
#
|
|
3
|
+
# We define a can! that allows to quickly stub a user authorization
|
|
4
|
+
#
|
|
5
|
+
Strongbolt.user_class_constant.class_eval do
|
|
6
|
+
#
|
|
7
|
+
# Best to use a class context and use class instance variables
|
|
8
|
+
#
|
|
9
|
+
class << self
|
|
10
|
+
|
|
11
|
+
def authorizations
|
|
12
|
+
@authorizations ||= {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def set_authorization_for user, authorized, *args
|
|
16
|
+
return if user.new_record?
|
|
17
|
+
|
|
18
|
+
self.authorizations[user.id] ||= {}
|
|
19
|
+
self.authorizations[user.id][key_for(*args)] = authorized
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def clear_authorizations
|
|
23
|
+
@authorizations = {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def authorized? user, *args
|
|
27
|
+
# Cannot do if user not saved
|
|
28
|
+
return false if user.new_record?
|
|
29
|
+
key = key_for(*args)
|
|
30
|
+
if self.authorizations[user.id].present? && self.authorizations[user.id][key].present?
|
|
31
|
+
return self.authorizations[user.id][key]
|
|
32
|
+
else
|
|
33
|
+
user._can? *args
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def key_for *args
|
|
38
|
+
action = args[0]
|
|
39
|
+
instance = args[1]
|
|
40
|
+
attrs = args[2] || :any
|
|
41
|
+
all_instances = (args[3] || false) ? "all" : "tenanted"
|
|
42
|
+
if instance.is_a?(ActiveRecord::Base)
|
|
43
|
+
model = instance.class.name
|
|
44
|
+
if instance.new_record?
|
|
45
|
+
"#{action}-#{model}-#{attrs}-#{all_instances}"
|
|
46
|
+
else
|
|
47
|
+
"#{action}-#{model}-#{attrs}-#{instance.id}"
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
model = instance.class.name
|
|
51
|
+
"#{action}-#{model}-#{attrs}-#{all_instances}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# 2 methods to setup mocking and stubs
|
|
59
|
+
#
|
|
60
|
+
def init
|
|
61
|
+
if RSpec::Mocks::Version::STRING >= "3.0"
|
|
62
|
+
require "rspec/mocks/standalone"
|
|
63
|
+
else
|
|
64
|
+
RSpec::Mocks::setup(self) unless self.respond_to? :allow
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def setup_stub authorized, arguments
|
|
69
|
+
init
|
|
70
|
+
# Set the authorizations on a class level
|
|
71
|
+
self.class.set_authorization_for self, authorized, *arguments
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#
|
|
75
|
+
# Mocked methods
|
|
76
|
+
#
|
|
77
|
+
alias_method :_can?, :can?
|
|
78
|
+
|
|
79
|
+
def can? *args
|
|
80
|
+
self.class.authorized? self, *args
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def can! *args
|
|
84
|
+
setup_stub true, args
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def cannot! *args
|
|
88
|
+
setup_stub false, args
|
|
89
|
+
end
|
|
90
|
+
end
|