strongbolt 0.3.12 → 0.3.13
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 +4 -4
- data/.rubocop.yml +56 -0
- data/.rubocop_todo.yml +91 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +18 -2
- data/Rakefile +1 -1
- data/app/controllers/strongbolt/capabilities_controller.rb +36 -45
- data/app/controllers/strongbolt/roles_controller.rb +39 -47
- data/app/controllers/strongbolt/security_controller.rb +2 -3
- data/app/controllers/strongbolt/user_groups_controller.rb +48 -54
- data/app/controllers/strongbolt/user_groups_users_controller.rb +2 -4
- data/app/controllers/strongbolt_controller.rb +1 -1
- data/circle.yml +13 -0
- data/lib/generators/strongbolt/fix_generator.rb +5 -6
- data/lib/generators/strongbolt/fix_unique_group_members_generator.rb +2 -3
- data/lib/generators/strongbolt/indexes_generator.rb +3 -4
- data/lib/generators/strongbolt/install_generator.rb +8 -9
- data/lib/generators/strongbolt/templates/fix_unique_group_members.rb +1 -1
- data/lib/generators/strongbolt/templates/indexes.rb +1 -1
- data/lib/generators/strongbolt/templates/migration.rb +11 -12
- data/lib/generators/strongbolt/templates/strongbolt.rb +1 -1
- data/lib/generators/strongbolt/views_generator.rb +4 -4
- data/lib/strongbolt.rb +51 -54
- data/lib/strongbolt/base.rb +1 -1
- data/lib/strongbolt/bolted.rb +12 -13
- data/lib/strongbolt/bolted_controller.rb +46 -57
- data/lib/strongbolt/capabilities_role.rb +5 -5
- data/lib/strongbolt/capability.rb +32 -31
- data/lib/strongbolt/configuration.rb +18 -19
- data/lib/strongbolt/controllers/url_helpers.rb +5 -5
- data/lib/strongbolt/engine.rb +9 -9
- data/lib/strongbolt/errors.rb +4 -4
- data/lib/strongbolt/generators/migration.rb +4 -6
- data/lib/strongbolt/helpers.rb +5 -7
- data/lib/strongbolt/rails/routes.rb +4 -4
- data/lib/strongbolt/role.rb +11 -12
- data/lib/strongbolt/roles_user_group.rb +5 -5
- data/lib/strongbolt/rspec.rb +2 -2
- data/lib/strongbolt/rspec/user.rb +13 -15
- data/lib/strongbolt/tenantable.rb +78 -80
- data/lib/strongbolt/user_abilities.rb +44 -54
- data/lib/strongbolt/user_group.rb +8 -10
- data/lib/strongbolt/user_groups_user.rb +6 -6
- data/lib/strongbolt/version.rb +1 -1
- data/lib/tasks/strongbolt_tasks.rake +4 -4
- data/spec/controllers/strongbolt/capabilities_controller_spec.rb +28 -45
- data/spec/controllers/strongbolt/roles_controller_spec.rb +39 -72
- data/spec/controllers/strongbolt/user_groups_controller_spec.rb +34 -65
- data/spec/controllers/strongbolt/user_groups_users_controller_spec.rb +11 -19
- data/spec/controllers/without_authorization_controller_spec.rb +5 -5
- data/spec/dummy/app/controllers/posts_controller.rb +2 -2
- data/spec/dummy/app/controllers/test_controller.rb +1 -1
- data/spec/dummy/app/controllers/without_authorization_controller.rb +1 -1
- data/spec/dummy/bin/rails +1 -1
- data/spec/dummy/config.ru +1 -1
- data/spec/dummy/config/application.rb +4 -5
- data/spec/dummy/config/initializers/cookies_serializer.rb +1 -1
- data/spec/dummy/config/initializers/strongbolt.rb +2 -2
- data/spec/dummy/config/routes.rb +1 -3
- data/spec/dummy/db/migrate/20150630212236_create_strongbolt_tables.rb +9 -10
- data/spec/dummy/db/migrate/20150630212251_create_strongbolt_tables_indexes.rb +2 -2
- data/spec/dummy/db/migrate/20160531110509_fix_unique_group_members.rb +1 -1
- data/spec/fabricators/capability_fabricator.rb +4 -4
- data/spec/fabricators/role_fabricator.rb +3 -3
- data/spec/fabricators/user_fabricator.rb +2 -2
- data/spec/fabricators/user_group_fabricator.rb +3 -3
- data/spec/fixtures/application.rb +6 -3
- data/spec/fixtures/controllers.rb +1 -1
- data/spec/spec_helper.rb +7 -8
- data/spec/strongbolt/bolted_controller_spec.rb +110 -208
- data/spec/strongbolt/bolted_spec.rb +26 -40
- data/spec/strongbolt/capability_spec.rb +72 -86
- data/spec/strongbolt/configuration_spec.rb +33 -46
- data/spec/strongbolt/controllers/url_helpers_spec.rb +7 -9
- data/spec/strongbolt/helpers_spec.rb +14 -16
- data/spec/strongbolt/role_spec.rb +32 -35
- data/spec/strongbolt/tenantable_spec.rb +88 -86
- data/spec/strongbolt/user_abilities_multiple_tenants_spec.rb +29 -34
- data/spec/strongbolt/user_abilities_spec.rb +142 -188
- data/spec/strongbolt/user_group_spec.rb +14 -14
- data/spec/strongbolt/users_tenant_spec.rb +10 -12
- data/spec/strongbolt_spec.rb +53 -73
- data/spec/support/controller_macros.rb +1 -3
- data/spec/support/db_setup.rb +31 -25
- data/spec/support/helpers.rb +12 -12
- data/spec/support/transactional_specs.rb +1 -3
- data/strongbolt.gemspec +14 -12
- metadata +20 -3
@@ -1,8 +1,9 @@
|
|
1
1
|
module Strongbolt
|
2
2
|
module Tenantable
|
3
3
|
module ClassMethods
|
4
|
-
|
5
|
-
|
4
|
+
def tenant?
|
5
|
+
(@tenant.present? && @tenant) || Strongbolt.tenants.include?(name)
|
6
|
+
end
|
6
7
|
|
7
8
|
private
|
8
9
|
|
@@ -12,6 +13,7 @@ module Strongbolt
|
|
12
13
|
def singular_association_name
|
13
14
|
@singular_association_name ||= self.name.demodulize.underscore.to_sym
|
14
15
|
end
|
16
|
+
|
15
17
|
def plural_association_name
|
16
18
|
@plural_association_name ||= self.name.demodulize.underscore.pluralize.to_sym
|
17
19
|
end
|
@@ -21,21 +23,21 @@ module Strongbolt
|
|
21
23
|
# It will traverse all the has_many relationships
|
22
24
|
# and add a has_one :tenant if not specified
|
23
25
|
#
|
24
|
-
def tenant
|
26
|
+
def tenant(_opts = {})
|
25
27
|
# Stops if already configured
|
26
28
|
return if tenant?
|
27
29
|
|
28
|
-
Strongbolt.logger.debug "-------------------------------------------------------------------\n"
|
29
|
-
|
30
|
-
|
30
|
+
Strongbolt.logger.debug "-------------------------------------------------------------------\n" \
|
31
|
+
"Configuring tenant #{self.name}\n" \
|
32
|
+
"-------------------------------------------------------------------\n\n"
|
31
33
|
#
|
32
34
|
# We're traversing using BFS the relationships
|
33
35
|
#
|
34
36
|
# Keep track of traversed models and their relationship to the tenant
|
35
|
-
@models_traversed = {self.name => self}
|
37
|
+
@models_traversed = { self.name => self }
|
36
38
|
# File of models/associations to traverse
|
37
39
|
models_to_traverse = reflect_on_all_associations
|
38
|
-
|
40
|
+
until models_to_traverse.empty?
|
39
41
|
# BFS search, shiftin first elt of array (older)
|
40
42
|
current_association = models_to_traverse.shift
|
41
43
|
# We don't check has_many :through association,
|
@@ -46,15 +48,14 @@ module Strongbolt
|
|
46
48
|
# So unless we've already traversed this model, or that's a through relationship
|
47
49
|
# or a polymorphic association
|
48
50
|
# Also we don't go following belongs_to relationship, it becomes crazy
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
51
|
+
next unless should_visit? current_association
|
52
|
+
# We setup the model using the association given
|
53
|
+
method = setup_model(current_association)
|
54
|
+
# We flag the model, storing the name of the method used to link to tenant
|
55
|
+
@models_traversed[current_association.klass.name] = method
|
56
|
+
# And add its relationships into the array, at the end, if method not nil
|
57
|
+
if method.present?
|
58
|
+
models_to_traverse.concat current_association.klass.reflect_on_all_associations
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -71,7 +72,7 @@ module Strongbolt
|
|
71
72
|
# Setup a model and returns the method name in symbol of the
|
72
73
|
# implemented link to the tenant
|
73
74
|
#
|
74
|
-
def setup_model
|
75
|
+
def setup_model(association)
|
75
76
|
# Source class
|
76
77
|
original_class = association.active_record
|
77
78
|
# Current class
|
@@ -104,11 +105,10 @@ module Strongbolt
|
|
104
105
|
# If no inverse, we cannot go further
|
105
106
|
if inverse.nil?
|
106
107
|
raise InverseAssociationNotConfigured, "Assocation #{association.name} on #{association.klass.name} could not be configured correctly as no inverse has been found"
|
107
|
-
elsif inverse.options.
|
108
|
+
elsif inverse.options.key? :polymorphic
|
108
109
|
return nil
|
109
110
|
end
|
110
111
|
|
111
|
-
|
112
112
|
# Common options
|
113
113
|
options = {
|
114
114
|
through: inverse.name,
|
@@ -145,22 +145,21 @@ module Strongbolt
|
|
145
145
|
scope "with_#{plur}", -> { includes assoc }
|
146
146
|
|
147
147
|
scope "where_#{plur}_among", ->(values) do
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
148
|
+
if values.is_a? Array
|
149
|
+
# If objects
|
150
|
+
values = values.map(&:id) if values.first.respond_to? :id
|
151
|
+
elsif values.respond_to?(:id)
|
152
|
+
# If object
|
153
|
+
values = values.id
|
154
|
+
end
|
155
|
+
|
156
|
+
includes(assoc).where(table_name => { id: values })
|
157
|
+
end
|
158
158
|
end
|
159
159
|
|
160
160
|
# And return name of association
|
161
|
-
|
162
|
-
end
|
163
|
-
|
161
|
+
assoc
|
162
|
+
end # /setup_model
|
164
163
|
|
165
164
|
#
|
166
165
|
# The initial idea of using a polymorphic association on UsersTenant
|
@@ -196,50 +195,48 @@ module Strongbolt
|
|
196
195
|
RUBY
|
197
196
|
Strongbolt.const_set users_tenants_subclass_name, users_tenant_subclass
|
198
197
|
end
|
199
|
-
end
|
198
|
+
end # /create_users_tenant_subclass
|
200
199
|
|
201
200
|
#
|
202
201
|
# Setups the has_many thru association on the User class
|
203
202
|
#
|
204
203
|
def setup_association_on_user
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
end
|
204
|
+
user_class = Configuration.user_class.constantize
|
205
|
+
|
206
|
+
# Setup the association
|
207
|
+
# The first one should never be there before
|
208
|
+
user_class.has_many :"users_#{plural_association_name}",
|
209
|
+
class_name: "Strongbolt::#{users_tenants_subclass_name}",
|
210
|
+
inverse_of: :user,
|
211
|
+
dependent: :delete_all,
|
212
|
+
foreign_key: :user_id
|
213
|
+
|
214
|
+
# This one may have been overriden by the developer
|
215
|
+
unless user_class.respond_to? plural_association_name
|
216
|
+
user_class.has_many plural_association_name,
|
217
|
+
source: :"#{singular_association_name}",
|
218
|
+
class_name: self.name,
|
219
|
+
through: :"users_#{plural_association_name}"
|
220
|
+
end
|
223
221
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
end
|
222
|
+
# Setup a quick method to get accessible clients directly
|
223
|
+
unless user_class.respond_to? "accessible_#{plural_association_name}"
|
224
|
+
user_class.class_exec(self, plural_association_name) do |klass, plur|
|
225
|
+
define_method "accessible_#{plur}" do
|
226
|
+
# If can find ALL the tenants
|
227
|
+
if can? :find, klass, :any, true
|
228
|
+
# Then it can access all of them
|
229
|
+
klass.all
|
230
|
+
else
|
231
|
+
# Otherwise, only the ones he manages
|
232
|
+
send plur
|
236
233
|
end
|
237
234
|
end
|
238
235
|
end
|
239
|
-
rescue NameError => e
|
240
|
-
Strongbolt.logger.error "User #{Configuration.user_class} could not have his association to tenant #{name} created"
|
241
236
|
end
|
242
|
-
|
237
|
+
rescue NameError
|
238
|
+
Strongbolt.logger.error "User #{Configuration.user_class} could not have his association to tenant #{name} created"
|
239
|
+
end # /setup_association_on_user
|
243
240
|
|
244
241
|
#
|
245
242
|
# returns the name of the subclass of Strongbolt::UsersTenant, containing
|
@@ -251,13 +248,13 @@ module Strongbolt
|
|
251
248
|
# The module name is left in the name, so that we won't have any collisions
|
252
249
|
# with the same class names in different modules.
|
253
250
|
"Users#{self.name.gsub('::', '')}"
|
254
|
-
end
|
251
|
+
end # /users_tenants_subclass_name
|
255
252
|
|
256
253
|
#
|
257
254
|
# Returns the inverse of specified association, using what's given
|
258
255
|
# as inverse_of or trying to guess it
|
259
256
|
#
|
260
|
-
def inverse_of
|
257
|
+
def inverse_of(association)
|
261
258
|
# If specified in association configuration
|
262
259
|
return association.inverse_of if association.has_inverse?
|
263
260
|
|
@@ -266,15 +263,17 @@ module Strongbolt
|
|
266
263
|
# Else we need to find it, using the class as reference
|
267
264
|
association.klass.reflect_on_all_associations.each do |assoc|
|
268
265
|
# If the association is polymorphic
|
269
|
-
if assoc.options.
|
266
|
+
if assoc.options.key? :polymorphic
|
267
|
+
if association.options && association.options[:as] == assoc.name
|
268
|
+
return assoc
|
269
|
+
end
|
270
270
|
polymorphic_associations << assoc
|
271
|
-
|
272
271
|
# If same class than the original source of the association
|
273
272
|
elsif assoc.klass == association.active_record
|
274
273
|
|
275
|
-
Strongbolt.logger.debug "Selected inverse of #{association.name} between #{association.active_record} "
|
276
|
-
|
277
|
-
|
274
|
+
Strongbolt.logger.debug "Selected inverse of #{association.name} between #{association.active_record} " \
|
275
|
+
"and #{association.klass} is #{assoc.name}.\n " \
|
276
|
+
"If not, please configure manually the inverse of #{association.name}\n"
|
278
277
|
|
279
278
|
return assoc
|
280
279
|
end
|
@@ -284,7 +283,7 @@ module Strongbolt
|
|
284
283
|
return polymorphic_associations.first
|
285
284
|
end
|
286
285
|
|
287
|
-
|
286
|
+
nil
|
288
287
|
end
|
289
288
|
|
290
289
|
#
|
@@ -296,13 +295,12 @@ module Strongbolt
|
|
296
295
|
# and not HasManyThrough, unless it's AR v >= 4.1.0 && < 4.2.0 where
|
297
296
|
# they define a HasManyAndBelongsTo as a HasManyThrough in the reflections
|
298
297
|
#
|
299
|
-
def should_visit?
|
300
|
-
!
|
298
|
+
def should_visit?(association)
|
299
|
+
!(association.is_a?(ActiveRecord::Reflection::ThroughReflection) ||
|
301
300
|
association.macro == :belongs_to ||
|
302
|
-
(@models_traversed.
|
303
|
-
@models_traversed[association.klass.name].present?)
|
301
|
+
(@models_traversed.key?(association.klass.name) &&
|
302
|
+
@models_traversed[association.klass.name].present?))
|
304
303
|
end
|
305
|
-
|
306
304
|
end
|
307
305
|
|
308
306
|
module InstanceMethods
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Strongbolt
|
2
2
|
module UserAbilities
|
3
3
|
module ClassMethods
|
4
|
-
|
5
4
|
end
|
6
5
|
|
7
6
|
module InstanceMethods
|
@@ -12,16 +11,16 @@ module Strongbolt
|
|
12
11
|
#----------------------------------------------------------#
|
13
12
|
def capabilities
|
14
13
|
@capabilities_cache ||= Strongbolt::Capability.unscoped.joins(:roles)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
.joins('INNER JOIN strongbolt_roles as children_roles ON strongbolt_roles.lft <= children_roles.lft AND children_roles.rgt <= strongbolt_roles.rgt')
|
15
|
+
.joins('INNER JOIN strongbolt_roles_user_groups rug ON rug.role_id = children_roles.id')
|
16
|
+
.joins('INNER JOIN strongbolt_user_groups_users ugu ON ugu.user_group_id = rug.user_group_id')
|
17
|
+
.where('ugu.user_id = ?', self.id).distinct.to_a.concat(Strongbolt.default_capabilities)
|
19
18
|
end
|
20
19
|
|
21
20
|
#
|
22
21
|
# Adds a managed tenant to the user
|
23
22
|
#
|
24
|
-
def add_tenant
|
23
|
+
def add_tenant(tenant)
|
25
24
|
sing_tenant_name = tenant.class.name.demodulize.underscore
|
26
25
|
send("users_#{sing_tenant_name.pluralize}").create! sing_tenant_name => tenant
|
27
26
|
# users_tenants.create! tenant: tenant
|
@@ -31,17 +30,16 @@ module Strongbolt
|
|
31
30
|
# Main method for user, used to check whether the user
|
32
31
|
# is authorized to perform a certain action on an instance/class
|
33
32
|
#
|
34
|
-
def can?
|
33
|
+
def can?(action, instance, attrs = :any, all_instance = false)
|
35
34
|
without_grant do
|
36
|
-
|
37
35
|
# Get the actual instance if we were given AR
|
38
36
|
instance = instance.try(:first) if instance.is_a?(ActiveRecord::Relation)
|
39
37
|
return false if instance.nil?
|
40
38
|
|
41
39
|
# We require this to be an *existing* user, that the action and attribute be symbols
|
42
40
|
# and that the instance is a class or a String
|
43
|
-
raise ArgumentError,
|
44
|
-
|
41
|
+
raise ArgumentError, 'Action must be a symbol and instance must be Class, String, Symbol or AR' unless self.id.present? && action.is_a?(Symbol) &&
|
42
|
+
(instance.is_a?(ActiveRecord::Base) || instance.is_a?(Class) || instance.is_a?(String)) && attrs.is_a?(Symbol)
|
45
43
|
|
46
44
|
# Pre-populate all the capabilities into a results cache for quick lookup. Permissions for all "non-owned" objects are
|
47
45
|
# immediately available; additional lookups are required for owned objects (e.g. User, CheckoutBag, etc.).
|
@@ -58,35 +56,33 @@ module Strongbolt
|
|
58
56
|
model_name = model.send(:name_for_authorization)
|
59
57
|
else
|
60
58
|
model = nil # We could do model_name.constantize, but there's a big cost to doing this
|
61
|
-
|
59
|
+
# if we don't need it, so just defer until we determine there's an actual need
|
62
60
|
model_name = instance
|
63
61
|
end
|
64
62
|
|
65
63
|
# Look up the various possible valid entries in the cache that would allow us to see this
|
66
64
|
return capability_in_cache?(action, instance, model_name, attrs, all_instance)
|
67
|
-
|
68
|
-
end #end w/o grant
|
65
|
+
end # end w/o grant
|
69
66
|
end
|
70
67
|
|
71
68
|
#
|
72
69
|
# Convenient method
|
73
70
|
#
|
74
|
-
def cannot?
|
75
|
-
!can?
|
71
|
+
def cannot?(*args)
|
72
|
+
!can?(*args)
|
76
73
|
end
|
77
74
|
|
78
75
|
#
|
79
76
|
# Checks if the user owns the instance given
|
80
77
|
#
|
81
|
-
def owns?
|
78
|
+
def owns?(instance)
|
82
79
|
raise ArgumentError unless instance.is_a?(Object) && !instance.is_a?(Class)
|
83
80
|
# If the user id is set, does this (a) user id match the user_id field of the instance
|
84
81
|
# or (b) if this is a User instance, does the user id match the instance id?
|
85
82
|
key = instance.is_a?(User) ? :id : :user_id
|
86
|
-
|
83
|
+
!id.nil? && instance.try(key) == id
|
87
84
|
end
|
88
85
|
|
89
|
-
|
90
86
|
private
|
91
87
|
|
92
88
|
#
|
@@ -99,14 +95,13 @@ module Strongbolt
|
|
99
95
|
@model_ancestor_cache ||= {}
|
100
96
|
|
101
97
|
# User can find itself by default
|
102
|
-
@results_cache[
|
98
|
+
@results_cache['findUserany-any'] = true
|
103
99
|
@results_cache["findUserany-#{id}"] = true
|
104
100
|
|
105
101
|
#
|
106
102
|
# Store every capability fetched
|
107
103
|
#
|
108
104
|
capabilities.each do |capability|
|
109
|
-
|
110
105
|
k = "#{capability.action}#{capability.model}"
|
111
106
|
attr_k = capability.attr || 'all'
|
112
107
|
|
@@ -137,14 +132,11 @@ module Strongbolt
|
|
137
132
|
end
|
138
133
|
end # End each capability
|
139
134
|
|
140
|
-
Strongbolt.logger.info "Populated capabilities in #{(Time.now - beginning)*1000}ms"
|
135
|
+
Strongbolt.logger.info "Populated capabilities in #{(Time.now - beginning) * 1000}ms"
|
141
136
|
|
142
137
|
@results_cache
|
143
138
|
end # End Populate capabilities Cache
|
144
139
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
140
|
#----------------------------------------------------------#
|
149
141
|
# #
|
150
142
|
# Checks if the user can perform 'action' on 'instance' #
|
@@ -154,20 +146,20 @@ module Strongbolt
|
|
154
146
|
def capability_in_cache?(action, instance, model_name, attrs = :any, all_instance = false)
|
155
147
|
action_model = "#{action}#{model_name}"
|
156
148
|
|
157
|
-
Strongbolt.logger.warn
|
149
|
+
Strongbolt.logger.warn 'User has no results cache' if @results_cache.empty?
|
158
150
|
Strongbolt.logger.debug { "Authorizing user to perform #{action} on #{instance.inspect}" }
|
159
151
|
|
160
152
|
# we don't know or care about tenants or if this is a new record
|
161
153
|
if instance.is_a?(ActiveRecord::Base) && !instance.new_record?
|
162
154
|
# First, check if we have a hash/cache hit for User being able to do this action to every instance of the model/class
|
163
|
-
return true if @results_cache["#{action_model}all-all"]
|
164
|
-
return true if @results_cache["#{action_model}#{attrs}-all"]
|
155
|
+
return true if @results_cache["#{action_model}all-all"] # Access to all attributes on ENTIRE class?
|
156
|
+
return true if @results_cache["#{action_model}#{attrs}-all"] # Access to this specific attribute on ENTIRE class?
|
165
157
|
|
166
158
|
# If we're checking on a specific instance of the class, not the general model,
|
167
159
|
# append the id to the key
|
168
160
|
id = instance.try(:id)
|
169
161
|
return true if @results_cache["#{action_model}all-#{id}"] # Access to all this instance's attributes?
|
170
|
-
return true if @results_cache["#{action_model}#{attrs}-#{id}"] #Access to this instance's attribute?
|
162
|
+
return true if @results_cache["#{action_model}#{attrs}-#{id}"] # Access to this instance's attribute?
|
171
163
|
|
172
164
|
# Checking ownership and tenant access
|
173
165
|
# Block access for non tenanted instance
|
@@ -187,30 +179,30 @@ module Strongbolt
|
|
187
179
|
end
|
188
180
|
|
189
181
|
# Finally we check for tenanted instances
|
190
|
-
@results_cache["#{action_model}all-#{id}"] = @results_cache["#{action_model}all-tenanted"] && valid_tenants
|
191
|
-
@results_cache["#{action_model}#{attrs}-#{id}"] =
|
182
|
+
@results_cache["#{action_model}all-#{id}"] = @results_cache["#{action_model}all-tenanted"] && valid_tenants # Access to all attributes on tenanted class?
|
183
|
+
@results_cache["#{action_model}#{attrs}-#{id}"] = @results_cache["#{action_model}#{attrs}-tenanted"] && valid_tenants # Access to this specific attribute on tenanted class?
|
192
184
|
return true if @results_cache["#{action_model}all-#{id}"] || @results_cache["#{action_model}#{attrs}-#{id}"]
|
193
185
|
elsif instance.is_a?(ActiveRecord::Base) && instance.new_record?
|
194
|
-
return true if @results_cache["#{action_model}all-all"]
|
195
|
-
return true if @results_cache["#{action_model}#{attrs}-all"]
|
186
|
+
return true if @results_cache["#{action_model}all-all"] # Access to all attributes on ENTIRE class?
|
187
|
+
return true if @results_cache["#{action_model}#{attrs}-all"] # Access to this specific attribute on ENTIRE class?
|
196
188
|
# Checking if the instance is from valid tenants (if necessary)
|
197
189
|
valid_tenants = has_access_to_tenants?(instance)
|
198
|
-
return true if @results_cache["#{action_model}all-tenanted"] && valid_tenants
|
199
|
-
return true if @results_cache["#{action_model}#{attrs}-tenanted"] && valid_tenants #Access to this specific attribute on tenanted class?
|
190
|
+
return true if @results_cache["#{action_model}all-tenanted"] && valid_tenants # Access to all attributes on tenanted class?
|
191
|
+
return true if @results_cache["#{action_model}#{attrs}-tenanted"] && valid_tenants # Access to this specific attribute on tenanted class?
|
200
192
|
|
201
193
|
# Finally, in the case where it's a non tenanted model (it still need to have valid_tenants == true)
|
202
194
|
return true if @results_cache["#{action_model}all-any"] && valid_tenants
|
203
195
|
return true if @results_cache["#{action_model}#{attrs}-any"] && valid_tenants
|
204
196
|
else
|
205
197
|
# First, check if we have a hash/cache hit for User being able to do this action to every instance of the model/class
|
206
|
-
return true if @results_cache["#{action_model}all-all"]
|
207
|
-
return true if @results_cache["#{action_model}#{attrs}-all"]
|
208
|
-
return true if @results_cache["#{action_model}all-any"] && !
|
209
|
-
return true if @results_cache["#{action_model}#{attrs}-any"] && !
|
198
|
+
return true if @results_cache["#{action_model}all-all"] # Access to all attributes on ENTIRE class?
|
199
|
+
return true if @results_cache["#{action_model}#{attrs}-all"] # Access to this specific attribute on ENTIRE class?
|
200
|
+
return true if @results_cache["#{action_model}all-any"] && !all_instance # Access to all attributes on at least once instance?
|
201
|
+
return true if @results_cache["#{action_model}#{attrs}-any"] && !all_instance # Access to this specific attribute on at least once instance?
|
210
202
|
end
|
211
|
-
#logger.info "Cache miss for checking access to #{key}"
|
203
|
+
# logger.info "Cache miss for checking access to #{key}"
|
212
204
|
|
213
|
-
|
205
|
+
false
|
214
206
|
end
|
215
207
|
|
216
208
|
#
|
@@ -218,7 +210,7 @@ module Strongbolt
|
|
218
210
|
#
|
219
211
|
# returns true even if instance has no relationship to any tenant
|
220
212
|
#
|
221
|
-
def has_access_to_tenants?
|
213
|
+
def has_access_to_tenants?(instance, tenants = nil)
|
222
214
|
# If no tenants list given, we take all
|
223
215
|
tenants ||= Strongbolt.tenants
|
224
216
|
# Populate the cache if needed
|
@@ -232,11 +224,11 @@ module Strongbolt
|
|
232
224
|
if instance.class == tenant
|
233
225
|
tenant_ids = [instance.id]
|
234
226
|
elsif instance.respond_to?(tenant.send(:singular_association_name))
|
235
|
-
if instance.send(tenant.send(:singular_association_name)).present?
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
227
|
+
tenant_ids = if instance.send(tenant.send(:singular_association_name)).present?
|
228
|
+
[instance.send(tenant.send(:singular_association_name)).id]
|
229
|
+
else
|
230
|
+
[]
|
231
|
+
end
|
240
232
|
elsif instance.respond_to?(tenant.send(:plural_association_name))
|
241
233
|
tenant_ids = instance.send("#{tenant.send(:singular_association_name)}_ids")
|
242
234
|
else
|
@@ -249,7 +241,7 @@ module Strongbolt
|
|
249
241
|
tenant_ids = []
|
250
242
|
end
|
251
243
|
found_any_tenant_relationship = true unless tenant_ids.empty?
|
252
|
-
has_access_to_current_tenant = (tenant_ids.
|
244
|
+
has_access_to_current_tenant = (!tenant_ids.empty? && (@tenants_cache[tenant.name] & tenant_ids).present?)
|
253
245
|
result || has_access_to_current_tenant
|
254
246
|
end
|
255
247
|
has_access_to_any_tenant || !found_any_tenant_relationship
|
@@ -270,8 +262,6 @@ module Strongbolt
|
|
270
262
|
Strongbolt.logger.debug "#{@tenants_cache[tenant.name].size} #{tenant.name}"
|
271
263
|
end
|
272
264
|
end
|
273
|
-
|
274
|
-
|
275
265
|
end # End InstanceMethods
|
276
266
|
|
277
267
|
def self.included(receiver)
|
@@ -280,11 +270,11 @@ module Strongbolt
|
|
280
270
|
|
281
271
|
receiver.class_eval do
|
282
272
|
has_many :user_groups_users,
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
has_many :user_groups, :
|
273
|
+
class_name: 'Strongbolt::UserGroupsUser',
|
274
|
+
dependent: :delete_all,
|
275
|
+
inverse_of: :user,
|
276
|
+
foreign_key: :user_id
|
277
|
+
has_many :user_groups, through: :user_groups_users
|
288
278
|
|
289
279
|
has_many :roles, through: :user_groups
|
290
280
|
end
|