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,297 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
module BoltedController
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Maps controller actions to CRUD operations
|
|
6
|
+
#
|
|
7
|
+
ACTIONS_MAPPING = {
|
|
8
|
+
:index => :find,
|
|
9
|
+
:show => :find,
|
|
10
|
+
:edit => :update,
|
|
11
|
+
:update => :update,
|
|
12
|
+
:new => :create,
|
|
13
|
+
:create => :create,
|
|
14
|
+
:destroy => :destroy
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module ClassMethods
|
|
18
|
+
#
|
|
19
|
+
# Allows defining a specific model for this controller,
|
|
20
|
+
# if it cannot be infer from the controller name
|
|
21
|
+
#
|
|
22
|
+
def model_for_authorization= model
|
|
23
|
+
@model_for_authorization = case model
|
|
24
|
+
when Class then model
|
|
25
|
+
when String then constantize_model(model)
|
|
26
|
+
when nil then nil
|
|
27
|
+
else
|
|
28
|
+
raise ArgumentError, "Model for authorization must be a Class or the name of the Class"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# Returns the model used for authorization,
|
|
34
|
+
# using controller name if not defined
|
|
35
|
+
#
|
|
36
|
+
def model_for_authorization
|
|
37
|
+
if @model_for_authorization.present?
|
|
38
|
+
@model_for_authorization
|
|
39
|
+
else
|
|
40
|
+
# We cannot just do controller_name.classify as it doesn't keep the modules
|
|
41
|
+
# We'll also check demoduling one module after the other for case when
|
|
42
|
+
# the controller and/or the model have different modules
|
|
43
|
+
full_name = name.sub("Controller", "").classify
|
|
44
|
+
# Split by ::
|
|
45
|
+
splits = full_name.split('::')
|
|
46
|
+
# While we still have modules to test
|
|
47
|
+
while splits.size >= 1
|
|
48
|
+
begin
|
|
49
|
+
return constantize_model splits.join('::')
|
|
50
|
+
rescue Strongbolt::ModelNotFound => e
|
|
51
|
+
ensure
|
|
52
|
+
# Removes first element
|
|
53
|
+
splits.shift
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
raise Strongbolt::ModelNotFound, "Model for controller #{controller_name} wasn't found"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Skips controller authorization check for this controller
|
|
62
|
+
# No argument given will skip for all actions,
|
|
63
|
+
# and can be passed only: [] or except: []
|
|
64
|
+
#
|
|
65
|
+
def skip_controller_authorization opts = {}
|
|
66
|
+
skip_before_action :check_authorization, opts
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#
|
|
70
|
+
# Skip all authorization checking for the controller,
|
|
71
|
+
# or a subset of actions
|
|
72
|
+
#
|
|
73
|
+
def skip_all_authorization opts = {}
|
|
74
|
+
skip_controller_authorization opts
|
|
75
|
+
around_action :disable_authorization, opts
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Sets what CRUD operation match a specific sets of non RESTful actions
|
|
80
|
+
#
|
|
81
|
+
[:find, :update, :create, :destroy].each do |operation|
|
|
82
|
+
define_method "authorize_as_#{operation}" do |*args|
|
|
83
|
+
args.each do |action|
|
|
84
|
+
actions_mapping[action] = operation
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Render without authorization, for better performance
|
|
91
|
+
#
|
|
92
|
+
def render_without_authorization *actions
|
|
93
|
+
self.actions_without_authorization = [*actions]
|
|
94
|
+
|
|
95
|
+
class_eval do
|
|
96
|
+
#
|
|
97
|
+
# It needs to be created afterward,
|
|
98
|
+
# No idea why
|
|
99
|
+
#
|
|
100
|
+
def render *args
|
|
101
|
+
if render_without_authorization?
|
|
102
|
+
Strongbolt.without_authorization { _render *args }
|
|
103
|
+
else
|
|
104
|
+
_render *args
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
#
|
|
111
|
+
# Render with authorization
|
|
112
|
+
#
|
|
113
|
+
def render_with_authorization
|
|
114
|
+
self.actions_without_authorization = nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# Returns the actions mapping of this controller
|
|
119
|
+
#
|
|
120
|
+
def actions_mapping
|
|
121
|
+
# Defaults to a duplicate of the standard mapping
|
|
122
|
+
@actions_mapping ||= ACTIONS_MAPPING.dup
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# Try to constantize a class
|
|
129
|
+
#
|
|
130
|
+
def constantize_model name
|
|
131
|
+
begin
|
|
132
|
+
name.constantize
|
|
133
|
+
rescue NameError
|
|
134
|
+
raise Strongbolt::ModelNotFound, "Model for controller #{controller_name} wasn't found"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
module InstanceMethods
|
|
141
|
+
|
|
142
|
+
def can? *args
|
|
143
|
+
Strongbolt.current_user.can? *args
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def cannot? *args
|
|
147
|
+
Strongbolt.current_user.cannot? *args
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
#
|
|
151
|
+
# Checks if the current action needs verification
|
|
152
|
+
#
|
|
153
|
+
def render_without_authorization?
|
|
154
|
+
self.class.actions_without_authorization.present? &&
|
|
155
|
+
self.class.actions_without_authorization.include?(params[:action].to_sym)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# We're aliasing render so we can trigger the without auth
|
|
160
|
+
#
|
|
161
|
+
# DOESN'T WORK WHEN DEFINED HERE?
|
|
162
|
+
#
|
|
163
|
+
def render *args
|
|
164
|
+
if render_without_authorization?
|
|
165
|
+
Strongbolt.without_authorization { _render *args }
|
|
166
|
+
else
|
|
167
|
+
_render *args
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
private
|
|
172
|
+
|
|
173
|
+
#
|
|
174
|
+
# Sets the current user using the :current_user method.
|
|
175
|
+
# Without Grant, as with it it would check if the user
|
|
176
|
+
# can find itself before having be assigned anything...
|
|
177
|
+
#
|
|
178
|
+
# Better than having to set an anymous method for granting
|
|
179
|
+
# find to anyone!
|
|
180
|
+
#
|
|
181
|
+
def set_current_user
|
|
182
|
+
# To be accessible in the model when not granted
|
|
183
|
+
$request = request
|
|
184
|
+
Grant::Status.without_grant do
|
|
185
|
+
Strongbolt.current_user = send(:current_user) if respond_to?(:current_user)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
#
|
|
190
|
+
# Unset the current user, by security (needed in some servers with only 1 thread)
|
|
191
|
+
#
|
|
192
|
+
def unset_current_user
|
|
193
|
+
Strongbolt.current_user = nil
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
#
|
|
197
|
+
# Checks authorization on the object, without fetching it
|
|
198
|
+
# so it can say yes to :index but won't authorize loading everything
|
|
199
|
+
# after, in the model by model authorization
|
|
200
|
+
#
|
|
201
|
+
def check_authorization
|
|
202
|
+
# If no user or disabled, no need
|
|
203
|
+
if Strongbolt.current_user.present? && Strongbolt.enabled?
|
|
204
|
+
begin
|
|
205
|
+
# Current model
|
|
206
|
+
# begin
|
|
207
|
+
obj = self.class.model_for_authorization
|
|
208
|
+
# rescue Strongbolt::ModelNotFound
|
|
209
|
+
# Strongbolt.logger.warn "No class found or defined for controller #{controller_name}"
|
|
210
|
+
# return
|
|
211
|
+
# end
|
|
212
|
+
|
|
213
|
+
# Unless it is authorized for this action
|
|
214
|
+
unless Strongbolt.current_user.can? crud_operation_of(action_name), obj
|
|
215
|
+
Strongbolt.access_denied current_user, obj, crud_operation_of(action_name), request.try(:fullpath)
|
|
216
|
+
raise Strongbolt::Unauthorized.new Strongbolt.current_user, action_name, obj
|
|
217
|
+
end
|
|
218
|
+
rescue Strongbolt::Unauthorized => e
|
|
219
|
+
raise e
|
|
220
|
+
rescue => e
|
|
221
|
+
raise e
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
Strongbolt.logger.warn "No authorization checking because no current user"
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
#
|
|
229
|
+
# Catch Grant::Error and send Strongbolt::Unauthorized instead
|
|
230
|
+
#
|
|
231
|
+
def catch_grant_error
|
|
232
|
+
begin
|
|
233
|
+
yield
|
|
234
|
+
rescue Grant::Error => e
|
|
235
|
+
raise Strongbolt::Unauthorized, e.to_s
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
#
|
|
240
|
+
# Returns the CRUD operations based on the action name
|
|
241
|
+
#
|
|
242
|
+
def crud_operation_of action
|
|
243
|
+
operation = self.class.actions_mapping[action.to_sym]
|
|
244
|
+
# If nothing find, we raise an error
|
|
245
|
+
if operation.nil?
|
|
246
|
+
raise Strongbolt::ActionNotConfigured, "Action #{action} on controller #{self.class.controller_name} not mapped to a CRUD operation"
|
|
247
|
+
end
|
|
248
|
+
# Else ok
|
|
249
|
+
operation
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
#
|
|
253
|
+
# CAREFUL: this skips authorization !
|
|
254
|
+
#
|
|
255
|
+
def disable_authorization
|
|
256
|
+
Strongbolt.without_authorization { yield }
|
|
257
|
+
Strongbolt.logger.warn "Authorization were disabled!"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def self.included(receiver)
|
|
263
|
+
receiver.class_eval do
|
|
264
|
+
# Compulsory filters
|
|
265
|
+
before_action :set_current_user
|
|
266
|
+
after_action :unset_current_user
|
|
267
|
+
|
|
268
|
+
# Catch Grant error
|
|
269
|
+
around_action :catch_grant_error
|
|
270
|
+
|
|
271
|
+
# Quick check of high level authorization
|
|
272
|
+
before_action :check_authorization
|
|
273
|
+
|
|
274
|
+
# A list storing actions that render without authorization
|
|
275
|
+
self.class.send :attr_accessor, :actions_without_authorization
|
|
276
|
+
|
|
277
|
+
# To allow render without authorization
|
|
278
|
+
alias_method :_render, :render
|
|
279
|
+
|
|
280
|
+
# Catch errors
|
|
281
|
+
rescue_from Strongbolt::Unauthorized, Grant::Error do |e|
|
|
282
|
+
if respond_to? :unauthorized
|
|
283
|
+
unauthorized e
|
|
284
|
+
else
|
|
285
|
+
raise Strongbolt::Unauthorized.new e.to_s
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end # End receiver class eval
|
|
290
|
+
|
|
291
|
+
receiver.extend ClassMethods
|
|
292
|
+
receiver.send :include, InstanceMethods
|
|
293
|
+
|
|
294
|
+
end # End self.included
|
|
295
|
+
|
|
296
|
+
end
|
|
297
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
class CapabilitiesRole < Base
|
|
3
|
+
authorize_as "Strongbolt::Role"
|
|
4
|
+
|
|
5
|
+
belongs_to :role,
|
|
6
|
+
:class_name => "Strongbolt::Role",
|
|
7
|
+
:inverse_of => :capabilities_roles
|
|
8
|
+
|
|
9
|
+
belongs_to :capability,
|
|
10
|
+
:class_name => "Strongbolt::Capability",
|
|
11
|
+
:inverse_of => :capabilities_roles
|
|
12
|
+
|
|
13
|
+
validates_presence_of :role, :capability
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
module Strongbolt
|
|
2
|
+
class Capability < Base
|
|
3
|
+
|
|
4
|
+
Actions = %w{find create update destroy}
|
|
5
|
+
|
|
6
|
+
DEFAULT_MODELS = ["Strongbolt::UserGroup",
|
|
7
|
+
"Strongbolt::Role",
|
|
8
|
+
"Strongbolt::Capability",
|
|
9
|
+
"Strongbolt::UsersTenant"]
|
|
10
|
+
|
|
11
|
+
has_many :capabilities_roles,
|
|
12
|
+
:class_name => "Strongbolt::CapabilitiesRole",
|
|
13
|
+
:dependent => :restrict_with_exception,
|
|
14
|
+
:inverse_of => :capability
|
|
15
|
+
|
|
16
|
+
has_many :roles, :through => :capabilities_roles
|
|
17
|
+
|
|
18
|
+
has_many :users, through: :roles
|
|
19
|
+
|
|
20
|
+
validates :model, :action, presence: true
|
|
21
|
+
validates :action, inclusion: Actions,
|
|
22
|
+
uniqueness: {scope: [:model, :require_ownership, :require_tenant_access]}
|
|
23
|
+
validate :model_exists?
|
|
24
|
+
|
|
25
|
+
before_validation :set_default
|
|
26
|
+
after_initialize :set_default
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# List all the models to be used in capabilities
|
|
30
|
+
#
|
|
31
|
+
def self.models() @models ||= DEFAULT_MODELS; end
|
|
32
|
+
def self.models=(models) @models = models; end
|
|
33
|
+
|
|
34
|
+
def self.add_models models
|
|
35
|
+
@models ||= DEFAULT_MODELS
|
|
36
|
+
@models |= [*models]
|
|
37
|
+
@models.sort!
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
scope :ordered, -> {
|
|
41
|
+
select("#{self.table_name}.*")
|
|
42
|
+
.select("CASE WHEN action = 'find' THEN 0 " +
|
|
43
|
+
"WHEN action = 'create' THEN 1 " +
|
|
44
|
+
"WHEN action = 'update' THEN 2 " +
|
|
45
|
+
"WHEN action = 'destroy' THEN 3 END AS action_id")
|
|
46
|
+
.order(:model, :require_ownership, :require_tenant_access, 'action_id')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#
|
|
50
|
+
# Group by model, ownership and tenant access
|
|
51
|
+
# and tells whether each action is set or not
|
|
52
|
+
#
|
|
53
|
+
def self.to_table
|
|
54
|
+
table = []
|
|
55
|
+
all.ordered.each do |capability|
|
|
56
|
+
if table.last.nil? ||
|
|
57
|
+
! (table.last[:model] == capability.model &&
|
|
58
|
+
table.last[:require_ownership] == capability.require_ownership &&
|
|
59
|
+
table.last[:require_tenant_access] == capability.require_tenant_access)
|
|
60
|
+
|
|
61
|
+
table << {
|
|
62
|
+
model: capability.model,
|
|
63
|
+
require_ownership: capability.require_ownership,
|
|
64
|
+
require_tenant_access: capability.require_tenant_access,
|
|
65
|
+
find: false,
|
|
66
|
+
create: false,
|
|
67
|
+
update: false,
|
|
68
|
+
destroy: false
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
table.last[capability.action.to_sym] = true
|
|
73
|
+
end
|
|
74
|
+
table
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Group by model, ownership and tenant access
|
|
79
|
+
# and tells whether each action is set or not
|
|
80
|
+
# in a hash
|
|
81
|
+
#
|
|
82
|
+
def self.to_hash
|
|
83
|
+
hash = {}
|
|
84
|
+
all.ordered.each do |capability|
|
|
85
|
+
key = {
|
|
86
|
+
model: capability.model,
|
|
87
|
+
require_ownership: capability.require_ownership,
|
|
88
|
+
require_tenant_access: capability.require_tenant_access
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
hash[key] ||= {
|
|
92
|
+
find: false,
|
|
93
|
+
create: false,
|
|
94
|
+
update: false,
|
|
95
|
+
destroy: false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
hash[key][capability.action.to_sym] = true
|
|
99
|
+
end
|
|
100
|
+
hash
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
#
|
|
106
|
+
# Create a set capabilities from a hash
|
|
107
|
+
# which has:
|
|
108
|
+
# {
|
|
109
|
+
# model: "ModelName",
|
|
110
|
+
# require_ownership: true,
|
|
111
|
+
# require_tenant_access: false,
|
|
112
|
+
# actions: [:find, :update]}
|
|
113
|
+
#
|
|
114
|
+
# Actions can be either one operation, an array of operations,
|
|
115
|
+
# or :all meaning all operations
|
|
116
|
+
#
|
|
117
|
+
def self.from_hash hash
|
|
118
|
+
hash.symbolize_keys!
|
|
119
|
+
actions_from_list(hash[:actions]).map do |action|
|
|
120
|
+
new :model => hash[:model],
|
|
121
|
+
:require_ownership => hash[:require_ownership],
|
|
122
|
+
:require_tenant_access => hash[:require_tenant_access],
|
|
123
|
+
:action => action
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# Virtual setter of actions
|
|
129
|
+
#
|
|
130
|
+
def self.actions_from_list actions
|
|
131
|
+
# Transform actions array
|
|
132
|
+
if actions.respond_to?(:to_sym) && actions.to_sym == :all
|
|
133
|
+
Actions # All actions
|
|
134
|
+
else
|
|
135
|
+
[*actions] # Transform into an array
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
#
|
|
142
|
+
# Checks that the model given as a string exists
|
|
143
|
+
#
|
|
144
|
+
def model_exists?
|
|
145
|
+
if model.present?
|
|
146
|
+
begin
|
|
147
|
+
model.constantize
|
|
148
|
+
rescue NameError => e
|
|
149
|
+
errors.add :model, "#{model} is not a valid model"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
#
|
|
155
|
+
# Default parameters
|
|
156
|
+
#
|
|
157
|
+
def set_default
|
|
158
|
+
self.require_ownership = true if require_ownership.nil?
|
|
159
|
+
self.require_tenant_access = true if require_tenant_access.nil?
|
|
160
|
+
true # Ensures it passes
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
Capability = Strongbolt::Capability unless defined? Capability
|