active_restrictors 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +11 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +39 -0
- data/README.rdoc +28 -6
- data/Rakefile +5 -0
- data/active_restrictors.gemspec +2 -1
- data/lib/active_restrictors/active_restrictor.rb +182 -104
- data/lib/active_restrictors/active_restrictor_views.rb +34 -31
- data/lib/active_restrictors/version.rb +1 -1
- data/spec/model_definitions.rb +116 -0
- data/spec/restrictor_spec.rb +386 -0
- data/spec/setup.rb +17 -0
- metadata +29 -9
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== v0.2.0
|
2
|
+
* Removed any remaining Rails 2 support
|
3
|
+
* Added new parameter structure for defining restrictors
|
4
|
+
* Added parameter mapping to allow old restrictor definitions to continue to function
|
5
|
+
* Renamed :basic restrictor to :basic_user
|
6
|
+
* Added two new restrictor types: basic_model and :implicit
|
7
|
+
* Cleaned up restrictor functionality from both model directions
|
8
|
+
* Updated #full_restrictors to provide all restrictors
|
9
|
+
* Updated view helpers to provide all restrictors
|
10
|
+
* Updated form building to use proper *_ids naming scheme
|
11
|
+
|
1
12
|
== v0.1.1
|
2
13
|
* Fixed class eval blocks
|
3
14
|
* Fixed hash variable naming
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activemodel (3.1.3)
|
5
|
+
activesupport (= 3.1.3)
|
6
|
+
builder (~> 3.0.0)
|
7
|
+
i18n (~> 0.6)
|
8
|
+
activerecord (3.1.3)
|
9
|
+
activemodel (= 3.1.3)
|
10
|
+
activesupport (= 3.1.3)
|
11
|
+
arel (~> 2.2.1)
|
12
|
+
tzinfo (~> 0.3.29)
|
13
|
+
activerecord-jdbc-adapter (1.2.1)
|
14
|
+
activerecord-jdbcsqlite3-adapter (1.2.1)
|
15
|
+
activerecord-jdbc-adapter (~> 1.2.1)
|
16
|
+
jdbc-sqlite3 (~> 3.7.2)
|
17
|
+
activesupport (3.1.3)
|
18
|
+
multi_json (~> 1.0)
|
19
|
+
arel (2.2.1)
|
20
|
+
builder (3.0.0)
|
21
|
+
i18n (0.6.0)
|
22
|
+
jdbc-sqlite3 (3.7.2)
|
23
|
+
minitest (2.10.0)
|
24
|
+
multi_json (1.0.4)
|
25
|
+
rake (0.9.2.2)
|
26
|
+
sqlite3 (1.3.5)
|
27
|
+
tzinfo (0.3.31)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
java
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
activerecord (~> 3.0)
|
35
|
+
activerecord-jdbcsqlite3-adapter
|
36
|
+
jdbc-sqlite3
|
37
|
+
minitest
|
38
|
+
rake
|
39
|
+
sqlite3
|
data/README.rdoc
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
== ActiveRestrictors
|
2
2
|
|
3
|
-
Chainable ActiveRecord
|
3
|
+
Chainable ActiveRecord restrictions.
|
4
|
+
|
5
|
+
{<img src="https://secure.travis-ci.org/chrisroberts/active_restrictors.png" />}[http://travis-ci.org/chrisroberts/active_restrictors]
|
4
6
|
|
5
7
|
=== Overview
|
6
8
|
|
@@ -47,10 +49,12 @@ Now, suppose a User should only be allowed to to see a Fubar instance if the Fub
|
|
47
49
|
|
48
50
|
add_restrictor(:permissions,
|
49
51
|
:enabled => lambda{ User.current_user.fubars_enabled? },
|
50
|
-
:
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
:views => {
|
53
|
+
:value => :name,
|
54
|
+
:multiple => true,
|
55
|
+
:default_view_all => true,
|
56
|
+
:user_values_only => lambda{ User.current_user }
|
57
|
+
}
|
54
58
|
)
|
55
59
|
end
|
56
60
|
|
@@ -95,7 +99,25 @@ The second is on Fubar instances:
|
|
95
99
|
%td= "#{pair.first}:"
|
96
100
|
%td= pair.last
|
97
101
|
|
98
|
-
==
|
102
|
+
== Restrictor Types
|
103
|
+
|
104
|
+
=== Basic User
|
105
|
+
|
106
|
+
- TODO
|
107
|
+
|
108
|
+
=== Basic Model
|
109
|
+
|
110
|
+
- TODO
|
111
|
+
|
112
|
+
=== Implicit
|
113
|
+
|
114
|
+
- TODO
|
115
|
+
|
116
|
+
=== Full
|
117
|
+
|
118
|
+
- TODO
|
119
|
+
|
120
|
+
== Custom Restrictors
|
99
121
|
|
100
122
|
=== User custom
|
101
123
|
|
data/Rakefile
ADDED
data/active_restrictors.gemspec
CHANGED
@@ -9,7 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = 'chrisroberts.code@gmail.com'
|
10
10
|
s.homepage = 'http://bitbucket.org/chrisroberts/active_restrictors'
|
11
11
|
s.description = 'Restrictors for Models'
|
12
|
+
s.add_dependency 'activerecord', '~> 3.0'
|
12
13
|
s.require_path = 'lib'
|
13
14
|
s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc']
|
14
|
-
s.files =
|
15
|
+
s.files = Dir.glob('**/*')
|
15
16
|
end
|
@@ -3,60 +3,86 @@ module ActiveRestrictor
|
|
3
3
|
|
4
4
|
# name:: Name of restrictor. For non-basic types this must be the name of the association.
|
5
5
|
# opts:: Options hash. Valid options:
|
6
|
-
# :type::
|
7
|
-
# :
|
8
|
-
# :class:: Class restriction is based on
|
9
|
-
# :value:: Attribute name of value to display
|
10
|
-
# :multiple:: Allow user to select multiple items for restriction
|
11
|
-
# :include_blank:: Include blank option in restriction selection
|
12
|
-
# :user_custom:: Block that returns User scope (passed: User scope, self instance)
|
13
|
-
# :user_association:: Name of association on user
|
14
|
-
# :model_custom:: Block that returns Model scope (passed: self instance, User instance)
|
6
|
+
# :type:: :full, :implicit, :basic_model, :basic_user
|
7
|
+
# :class:: Class restriction is based on if not guessable
|
15
8
|
# :enabled:: If restrictor is enabled. Must be boolean value or a callable object that returns boolean value
|
16
|
-
# :
|
17
|
-
# :
|
9
|
+
# :scope:: Scope or callable block returning scope
|
10
|
+
# :views =>
|
11
|
+
# :value:: Attribute name of value to display
|
12
|
+
# :multiple:: Multiple assignments allowed
|
13
|
+
# :include_blank:: Allow assignments to be unset
|
14
|
+
# :user_values_only:: User instance. Set this if you only want values set against user to be selectable
|
15
|
+
# :id:: Value method for selection (defaults to :id)
|
16
|
+
# :user_association:: Name of association on user (if different from restrictor name)
|
17
|
+
# :user_custom:: Block that returns User scope (passed: User scope, self instance) - Used when generic scope building is lacking
|
18
|
+
# :model_custom:: Block that returns Model scope (passed: self instance, User instance) - Used when generic scope building is lacking
|
19
|
+
# :default_allowed_all:: If source instance has no restriction assigned, it is viewable
|
20
|
+
# :default_view_all:: Alias for :default_allowed_all
|
18
21
|
# Adds restrictions to Model
|
19
|
-
# NOTE: Basic
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# are applied directly against the user model.
|
22
|
+
# NOTE: Basic types are run directly against the model culminating in a count to see if it is valid (ex for :basic_user: User.where(:allowed_to_do_stuff => true))
|
23
|
+
# Implicit type is run directly against the source model. (ex: Fubar.includes(:feebar).where(:feebars => {:user_id => User.current_user.id}))
|
24
|
+
# Full is a full restrictor using join tables and provides view helpers for management
|
23
25
|
def add_restrictor(name, opts={})
|
24
26
|
self.restrictors ||= []
|
25
|
-
new_opts = {:name => name, :
|
26
|
-
new_opts[:
|
27
|
-
new_opts
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
args = (args.is_a?(Array) ? args : Array(args)).find_all{|arg|arg.present?}
|
36
|
-
new_args = []
|
37
|
-
ids = []
|
38
|
-
args.each do |item|
|
39
|
-
if(item.is_a?(ActiveRecord::Base) || (defined?(ActiveRecord::Relation) && item.is_a?(ActiveRecord::Relation)))
|
40
|
-
new_args << item
|
41
|
-
else
|
42
|
-
ids << item.to_i
|
43
|
-
end
|
44
|
-
end
|
45
|
-
new_args += new_opts[:class].find(ids) unless ids.empty?
|
46
|
-
self.send("original_#{name}=".to_sym, new_args)
|
47
|
-
end
|
27
|
+
new_opts = {:name => name, :enabled => true, :type => :full, :scope => self.scoped, :default_allowed_all => false}.merge(opts)
|
28
|
+
new_opts[:views] ||= {}
|
29
|
+
new_opts = map_deprecated_hash(new_opts)
|
30
|
+
new_opts[:views][:id] ||= :id
|
31
|
+
new_opts[:class] = restrictor_class(new_opts)
|
32
|
+
if(new_opts[:type] == :full && new_opts[:views][:value].blank?)
|
33
|
+
if(new_opts[:class].column_names.include?('name'))
|
34
|
+
new_opts[:views][:value] = :name
|
35
|
+
else
|
36
|
+
raise 'Value must be defined for association to generate views'
|
48
37
|
end
|
49
38
|
end
|
39
|
+
self.restrictors.push(new_opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
# TODO: Add in proper mapping plus scope building
|
43
|
+
def map_deprecated_hash(hsh)
|
44
|
+
hsh[:type] = :basic_user if hsh[:type] == :basic
|
45
|
+
hsh[:scope] = self.class._restrictor_custom_user_class.where(hsh.delete(:condition)) if hsh[:condition].present?
|
46
|
+
[:value, :multiple, :include_blank, :user_values_only, :id].each do |v_opt|
|
47
|
+
hsh[:views][v_opt] = hsh.delete(v_opt) if hsh[v_opt].present?
|
48
|
+
end
|
49
|
+
hsh[:default_allowed_all] = hsh.delete(:default_view_all) if hsh.has_key?(:default_view_all)
|
50
|
+
hsh
|
50
51
|
end
|
51
52
|
|
52
|
-
# Returns restrictors
|
53
|
-
|
54
|
-
|
53
|
+
# Returns restrictors of type: :full
|
54
|
+
# NOTE: Returns enabled by default. Provide :include_disabled to get all
|
55
|
+
def full_restrictors(*args)
|
56
|
+
self.restrictors.find_all do |restrictor|
|
57
|
+
restrictor[:type] == :full &&
|
58
|
+
(args.include?(:include_disabled) || check_enabled(restrictor[:enabled]) == true)
|
59
|
+
end
|
55
60
|
end
|
56
61
|
|
57
|
-
# Returns restrictors of type :
|
58
|
-
|
59
|
-
|
62
|
+
# Returns restrictors of type :basic_model
|
63
|
+
# NOTE: Returns enabled by default. Provide :include_disabled to get all
|
64
|
+
def basic_model_restrictors(*args)
|
65
|
+
self.restrictors.find_all do |restrictor|
|
66
|
+
restrictor[:type] == :basic_model &&
|
67
|
+
(args.include?(:include_disabled) || check_enabled(restrictor[:enabled]) == true)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns restrictors of type :basic_user
|
72
|
+
# NOTE: Returns enabled by default. Provide :include_disabled to get all
|
73
|
+
def basic_user_restrictors(*args)
|
74
|
+
self.restrictors.find_all do |restrictor|
|
75
|
+
restrictor[:type] == :basic_user &&
|
76
|
+
(args.include?(:include_disabled) || check_enabled(restrictor[:enabled]) == true)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns restrictors of type :implicit
|
81
|
+
def implicit_restrictors(*args)
|
82
|
+
self.restrictors.find_all do |restrictor|
|
83
|
+
restrictor[:type] == :implicit &&
|
84
|
+
check_enabled(restrictor[:enabled]) == true
|
85
|
+
end
|
60
86
|
end
|
61
87
|
|
62
88
|
# Returns all restrictors that are currently in enabled state
|
@@ -70,8 +96,34 @@ module ActiveRestrictor
|
|
70
96
|
if(hash[:class].present?)
|
71
97
|
hash[:class]
|
72
98
|
else
|
73
|
-
|
99
|
+
if(hash[:type] == :basic_user)
|
100
|
+
_restrictor_custom_user_class
|
101
|
+
elsif(hash[:type] == :basic_model)
|
102
|
+
self
|
103
|
+
else
|
104
|
+
n = self.reflect_on_association(hash[:name]).try(:klass)
|
105
|
+
if(n.blank?)
|
106
|
+
raise "Failed to location association for restrictor. Given: #{hash[:name]}. Please check assocation name."
|
107
|
+
end
|
108
|
+
n
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def restrictor_user_scoping
|
114
|
+
user_scope = _restrictor_custom_user_class.scoped
|
115
|
+
basic_user_restrictors.each do |restrictor|
|
116
|
+
user_scope = user_scope.merge(restrictor[:scope].respond_to?(:call) ? restrictor[:scope].call : restrictor[:scope])
|
74
117
|
end
|
118
|
+
user_scope
|
119
|
+
end
|
120
|
+
|
121
|
+
def restrictor_klass_scoping
|
122
|
+
klass_scope = self.scoped
|
123
|
+
(implicit_restrictors + basic_model_restrictors).each do |restrictor|
|
124
|
+
klass_scope = klass_scope.merge(restrictor[:scope].respond_to?(:call) ? restrictor[:scope].call : restrictor[:scope])
|
125
|
+
end
|
126
|
+
klass_scope
|
75
127
|
end
|
76
128
|
|
77
129
|
private
|
@@ -89,6 +141,7 @@ module ActiveRestrictor
|
|
89
141
|
false
|
90
142
|
end
|
91
143
|
end
|
144
|
+
|
92
145
|
end
|
93
146
|
|
94
147
|
module InstanceMethods
|
@@ -100,13 +153,26 @@ module ActiveRestrictor
|
|
100
153
|
end
|
101
154
|
|
102
155
|
# Returns restrictors not of type :basic
|
103
|
-
|
104
|
-
|
156
|
+
# NOTE: Returns enabled by default. Provide :include_disabled to get all
|
157
|
+
def full_restrictors(*args)
|
158
|
+
self.class.full_restrictors(*args)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns restrictors of type :basic_user
|
162
|
+
# NOTE: Returns enabled by default. Provide :include_disabled to get all
|
163
|
+
def basic_user_restrictors(*args)
|
164
|
+
self.class.basic_user_restrictors(*args)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns restrictors of type :basic_model
|
168
|
+
# NOTE: Returns enabled by default. Provide :include_disabled to get all
|
169
|
+
def basic_model_restrictors(*args)
|
170
|
+
self.class.basic_model_restrictors(*args)
|
105
171
|
end
|
106
172
|
|
107
|
-
# Returns restrictors of type :
|
108
|
-
def
|
109
|
-
self.class.
|
173
|
+
# Returns restrictors of type :implict
|
174
|
+
def implicit_restrictors
|
175
|
+
self.class.implicit_restrictors
|
110
176
|
end
|
111
177
|
|
112
178
|
# Returns all restrictors taht are currently in enabled status
|
@@ -114,31 +180,43 @@ module ActiveRestrictor
|
|
114
180
|
self.class.enabled_restrictors
|
115
181
|
end
|
116
182
|
|
183
|
+
# Grabs customizable user class
|
184
|
+
def _restrictor_custom_user_class
|
185
|
+
self.class._restrictor_custom_user_class
|
186
|
+
end
|
187
|
+
|
117
188
|
# Returns User scope with all restrictors applied
|
118
189
|
def allowed_users
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
user_scope = user_scope.
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
190
|
+
klass_scope = self.class.restrictor_klass_scoping.where(:id => self.id)
|
191
|
+
user_scope = self.class.restrictor_user_scoping
|
192
|
+
if(klass_scope.count > 0)
|
193
|
+
full_restrictors.each do |restrictor|
|
194
|
+
user_scope = user_scope.includes(restrictor[:name])
|
195
|
+
unless(restrictor[:user_custom].present?)
|
196
|
+
rtable_name = restrictor[:table_name] || restrictor[:class].table_name
|
197
|
+
r_scope = self.send(restrictor[:name]).scoped.select("#{rtable_name}.id")
|
198
|
+
r_count = self.send(restrictor[:name]).scoped.select("count(*)")
|
199
|
+
# this next bit gets rid of the association_name.* rails insists upon and any extra cruft
|
200
|
+
r_scope.arel.ast.cores.first.projections.delete_if{|item| item != "#{rtable_name}.id"}
|
201
|
+
r_count.arel.ast.cores.first.projections.delete_if{|item| item != "count(*)"}
|
202
|
+
user_scope = user_scope.where(
|
203
|
+
"#{rtable_name}.id IN (#{r_scope.to_sql})#{
|
204
|
+
" OR (#{r_count.to_sql}) = 0" if restrictor[:default_allowed_all]
|
205
|
+
}"
|
206
|
+
)
|
207
|
+
else
|
208
|
+
user_scope = restrictor[:user_custom].call(user_scope, self)
|
209
|
+
end
|
133
210
|
end
|
134
|
-
|
135
|
-
|
211
|
+
if(Array(implicit_restrictors).size > 0)
|
212
|
+
if(r = _restrictor_custom_user_class.reflect_on_all_associations.detect{|r| r.klass == self.class})
|
213
|
+
user_scope = user_scope.includes(r.name).merge(klass_scope)
|
214
|
+
end
|
136
215
|
end
|
216
|
+
user_scope
|
217
|
+
else
|
218
|
+
user_scope.where('null')
|
137
219
|
end
|
138
|
-
if((methods = enabled_restrictors.find_all{|res| res[:user_custom]}).size > 0)
|
139
|
-
user_scope = methods.inject(user_scope){|result,func| func.call(result, self)}
|
140
|
-
end
|
141
|
-
user_scope
|
142
220
|
end
|
143
221
|
end
|
144
222
|
|
@@ -151,14 +229,28 @@ module ActiveRestrictor
|
|
151
229
|
extend ClassMethods
|
152
230
|
include InstanceMethods
|
153
231
|
|
232
|
+
unless(base.singleton_methods.map(&:to_sym).include?(:_restrictor_custom_user_class))
|
233
|
+
class << self
|
234
|
+
# This can be overridden for customization
|
235
|
+
def _restrictor_custom_user_class
|
236
|
+
User
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
154
240
|
scope :allowed_for, lambda{|*args|
|
155
241
|
user = args.detect{|item|item.is_a?(User)}
|
156
|
-
|
242
|
+
if(user.present?)
|
243
|
+
r_scope = user.send("allowed_#{base.name.tableize}").select("#{base.table_name}.id")
|
244
|
+
r_scope.arel.ast.cores.first.projections.delete_if{|item| item != "#{base.table_name}.id"}
|
245
|
+
where("#{table_name}.id IN (#{r_scope.to_sql})")
|
246
|
+
else
|
247
|
+
where('null')
|
248
|
+
end
|
157
249
|
}
|
158
250
|
end
|
159
251
|
end
|
160
252
|
# Patch up the user to provide restricted methods
|
161
|
-
([
|
253
|
+
([klass._restrictor_custom_user_class] + klass._restrictor_custom_user_class.descendants).compact.each do |user_klass|
|
162
254
|
user_klass.class_eval do
|
163
255
|
# This patches a method onto the User instance to
|
164
256
|
# provide access to the allowed instance of the model
|
@@ -168,45 +260,31 @@ module ActiveRestrictor
|
|
168
260
|
define_method("allowed_#{klass.name.tableize}") do
|
169
261
|
# First we perform a basic check against the User to see
|
170
262
|
# if this user instance is even allowed by default
|
171
|
-
user_scope =
|
172
|
-
klass.basic_restrictors.each do |restriction|
|
173
|
-
if(restriction[:condition].is_a?(ActiveRecord::Relation))
|
174
|
-
user_scope = user_scope.merge(restriction[:condition])
|
175
|
-
elsif(restriction[:condition].respond_to?(:call))
|
176
|
-
user_scope = user_scope.merge(restriction[:condition].call)
|
177
|
-
elsif(restriction[:condition].present?)
|
178
|
-
user_scope = user_scope.where(restriction[:condition])
|
179
|
-
end
|
180
|
-
if(restriction[:include].is_a?(ActiveRecord::Relation))
|
181
|
-
user_scope = user_scope.merge(restriction[:include])
|
182
|
-
elsif(restriction[:include].present?)
|
183
|
-
user_scope = user_scope.join(restriction[:include])
|
184
|
-
end
|
185
|
-
end
|
263
|
+
user_scope = klass.restrictor_user_scoping.where(:id => self.id)
|
186
264
|
if(user_scope.count > 0)
|
187
|
-
scope = klass.
|
265
|
+
scope = klass.restrictor_klass_scoping
|
188
266
|
klass.full_restrictors.each do |restrictor|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
267
|
+
scope = scope.includes(restrictor[:name])
|
268
|
+
if(restrictor[:scope].present?)
|
269
|
+
scope = scope.merge(restrictor[:scope].respond_to?(:call) ? restrictor[:scope].call : restrictor[:scope])
|
270
|
+
end
|
271
|
+
unless(restrictor[:model_custom].present?)
|
272
|
+
rtable_name = restrictor[:table_name] || restrictor[:class].table_name
|
273
|
+
r_scope = self.send(restrictor[:user_association] || restrictor[:name]).scoped.select("#{rtable_name}.id") # This gives us valid joiners!
|
274
|
+
# this next bit gets rid of the association_name.* rails insists upon and any extra cruft
|
275
|
+
r_scope.arel.ast.cores.first.projections.delete_if{|item| item != "#{rtable_name}.id"}
|
276
|
+
scope = scope.where(
|
277
|
+
"#{rtable_name}.id IN (#{r_scope.to_sql})#{
|
278
|
+
" OR #{rtable_name}.id IS NULL" if restrictor[:default_allowed_all]
|
279
|
+
}"
|
280
|
+
)
|
195
281
|
else
|
196
|
-
scope =
|
282
|
+
scope = restrictor[:model_custom].call(scope, self)
|
197
283
|
end
|
198
|
-
scope = scope.where(
|
199
|
-
"#{rtable_name}.id IN (#{r_scope.to_sql})#{
|
200
|
-
" OR #{rtable_name}.id IS NULL" if restrictor[:default_view_all]
|
201
|
-
}"
|
202
|
-
)
|
203
|
-
end
|
204
|
-
if((methods = klass.restrictors.map{|res| res[:model_custom]}.compact).size > 0)
|
205
|
-
scope = methods.inject(scope){|result,func| func.call(result, self)}
|
206
284
|
end
|
207
285
|
scope
|
208
286
|
else
|
209
|
-
klass.where('
|
287
|
+
klass.where('null')
|
210
288
|
end
|
211
289
|
end
|
212
290
|
end
|
@@ -1,57 +1,65 @@
|
|
1
1
|
module ActiveRestrictors
|
2
2
|
module View
|
3
|
+
|
3
4
|
# obj:: Instance with restrictors enabled
|
5
|
+
# args:: argument hash :
|
6
|
+
# :val_join:: string to join values with
|
7
|
+
# :include_disabled:: includes all restrictors
|
4
8
|
# val_join:: String to join restictor values together
|
5
9
|
# Provides array of enabled restrictors in the form of:
|
6
10
|
# [[restrictor_name_label, string_of_restriction_values]]
|
7
|
-
def display_full_restrictors(obj,
|
11
|
+
def display_full_restrictors(obj, *args)
|
12
|
+
arg_h = args.last.is_a?(Hash) ? args.last : {}
|
13
|
+
res = []
|
14
|
+
if(args.size == 1 && args.first.is_a?(String))
|
15
|
+
val_join = args.first
|
16
|
+
else
|
17
|
+
val_join = arg_h[:val_join] || '<br />'
|
18
|
+
end
|
8
19
|
if(obj.class.respond_to?(:full_restrictors))
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
obj.send(restrictor[:name]).map(&restrictor[:value].to_sym).join(val_join).html_safe
|
13
|
-
]
|
20
|
+
r_args = arg_h[:include_disabled] ? [:include_disabled] : []
|
21
|
+
res = obj.class.full_restrictors(*r_args).map do |restrictor|
|
22
|
+
[label(obj.class.name.camelize, restrictor[:name]),
|
23
|
+
obj.send(restrictor[:name]).map(&restrictor[:views][:value].to_sym).join(val_join).html_safe]
|
14
24
|
end
|
15
|
-
else
|
16
|
-
[]
|
17
25
|
end
|
18
|
-
|
19
|
-
|
20
|
-
def display_custom_restrictors(klass)
|
21
|
-
# Stub for now
|
22
|
-
[]
|
26
|
+
res
|
23
27
|
end
|
24
28
|
|
25
29
|
# obj:: Instance with restrictors enabled
|
26
30
|
# form:: Form object to attach restrictor fields to
|
31
|
+
# args:: Argument hash ->
|
32
|
+
# :include_disabled:: includes all restrictors
|
27
33
|
# Provides form items for restrictors in an array of format:
|
28
34
|
# [[restrictor_name_label, form_selection_string]]
|
29
|
-
def edit_full_restrictors(obj, form)
|
35
|
+
def edit_full_restrictors(obj, form, args={})
|
36
|
+
r_args = args[:include_disabled] ? [:include_disabled] : []
|
30
37
|
if(obj.class.respond_to?(:full_restrictors))
|
31
|
-
obj.class.full_restrictors.map do |restrictor|
|
32
|
-
if(restrictor[:user_values_only])
|
33
|
-
if(restrictor[:user_values_only].respond_to?(:call))
|
34
|
-
user = restrictor[:user_values_only].call
|
38
|
+
obj.class.full_restrictors(*r_args).map do |restrictor|
|
39
|
+
if(restrictor[:views][:user_values_only])
|
40
|
+
if(restrictor[:views][:user_values_only].respond_to?(:call))
|
41
|
+
user = restrictor[:views][:user_values_only].call
|
35
42
|
if(user)
|
36
43
|
values = user.send(restrictor[:name].to_sym).find(:all, :order => restrictor[:value])
|
37
44
|
else
|
38
|
-
values = restrictor[:user_values_only].send(restrictor[:name].to_sym).find(:all, :order => restrictor[:value])
|
45
|
+
values = restrictor[:views][:user_values_only].send(restrictor[:name].to_sym).find(:all, :order => restrictor[:views][:value])
|
39
46
|
end
|
40
47
|
end
|
41
48
|
end
|
42
|
-
|
49
|
+
@_restrictor_inflector_helper ||= Class.send(:include, ActiveSupport::Inflector).new
|
50
|
+
values = restrictor[:class].find(:all, :order => restrictor[:views][:value]) unless values
|
43
51
|
[
|
44
52
|
form.label(restrictor[:name]),
|
45
53
|
form.collection_select(
|
46
|
-
restrictor[:name],
|
54
|
+
"#{@_restrictor_inflector_helper.singularize(restrictor[:name])}_ids",
|
47
55
|
values,
|
48
|
-
restrictor[:id],
|
49
|
-
restrictor[:value],
|
56
|
+
restrictor[:views][:id],
|
57
|
+
restrictor[:views][:value],
|
50
58
|
{
|
51
|
-
:include_blank => restrictor[:include_blank],
|
52
|
-
:selected => Array(obj.send(restrictor[:name])).map(&restrictor[:id].to_sym)
|
59
|
+
:include_blank => restrictor[:views][:include_blank],
|
60
|
+
:selected => Array(obj.send(restrictor[:name])).map(&restrictor[:views][:id].to_sym)
|
53
61
|
},
|
54
|
-
:multiple => restrictor[:multiple]
|
62
|
+
:multiple => restrictor[:views][:multiple]
|
55
63
|
)
|
56
64
|
]
|
57
65
|
end
|
@@ -59,11 +67,6 @@ module ActiveRestrictors
|
|
59
67
|
[]
|
60
68
|
end
|
61
69
|
end
|
62
|
-
|
63
|
-
def edit_custom_restrictors(klass)
|
64
|
-
# Stub for now
|
65
|
-
[]
|
66
|
-
end
|
67
70
|
end
|
68
71
|
end
|
69
72
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/migration'
|
3
|
+
require 'benchmark'
|
4
|
+
class ModelSetup < ActiveRecord::Migration
|
5
|
+
def self.up
|
6
|
+
create_table :users do |t|
|
7
|
+
t.string :username
|
8
|
+
t.boolean :active
|
9
|
+
end
|
10
|
+
create_table :fubars do |t|
|
11
|
+
t.string :name
|
12
|
+
t.boolean :enabled
|
13
|
+
t.integer :user_id
|
14
|
+
end
|
15
|
+
create_table :permissions do |t|
|
16
|
+
t.string :name
|
17
|
+
end
|
18
|
+
create_table :groups do |t|
|
19
|
+
t.string :name
|
20
|
+
end
|
21
|
+
create_table :user_permissions do |t|
|
22
|
+
t.integer :user_id
|
23
|
+
t.integer :permission_id
|
24
|
+
end
|
25
|
+
create_table :fubar_permissions do |t|
|
26
|
+
t.integer :fubar_id
|
27
|
+
t.integer :permission_id
|
28
|
+
end
|
29
|
+
create_table :user_groups do |t|
|
30
|
+
t.integer :group_id
|
31
|
+
t.integer :user_id
|
32
|
+
end
|
33
|
+
create_table :fubar_groups do |t|
|
34
|
+
t.integer :group_id
|
35
|
+
t.integer :fubar_id
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ModelSetup.up
|
41
|
+
|
42
|
+
class User < ActiveRecord::Base
|
43
|
+
cattr_accessor :current_user
|
44
|
+
has_many :user_permissions, :dependent => :destroy
|
45
|
+
has_many :permissions, :through => :user_permissions
|
46
|
+
has_many :user_groups, :dependent => :destroy
|
47
|
+
has_many :groups, :through => :user_groups
|
48
|
+
has_many :fubars, :dependent => :destroy
|
49
|
+
end
|
50
|
+
|
51
|
+
class Permission < ActiveRecord::Base
|
52
|
+
has_many :user_permissions, :dependent => :destroy
|
53
|
+
has_many :users, :through => :user_permissions
|
54
|
+
has_many :fubar_permissions, :dependent => :destroy
|
55
|
+
has_many :fubars, :through => :fubar_permissions
|
56
|
+
end
|
57
|
+
|
58
|
+
class Group < ActiveRecord::Base
|
59
|
+
has_many :user_groups, :dependent => :destroy
|
60
|
+
has_many :users, :through => :user_groups
|
61
|
+
has_many :fubar_groups, :dependent => :destroy
|
62
|
+
has_many :fubars, :through => :fubar_groups
|
63
|
+
end
|
64
|
+
|
65
|
+
class Fubar < ActiveRecord::Base
|
66
|
+
include ActiveRestrictor
|
67
|
+
has_many :fubar_permissions, :dependent => :destroy
|
68
|
+
has_many :permissions, :through => :fubar_permissions
|
69
|
+
has_many :fubar_groups, :dependent => :destroy
|
70
|
+
has_many :groups, :through => :fubar_groups
|
71
|
+
belongs_to :user
|
72
|
+
end
|
73
|
+
|
74
|
+
class UserPermission < ActiveRecord::Base
|
75
|
+
belongs_to :user
|
76
|
+
belongs_to :permission
|
77
|
+
end
|
78
|
+
|
79
|
+
class FubarPermission < ActiveRecord::Base
|
80
|
+
belongs_to :fubar
|
81
|
+
belongs_to :permission
|
82
|
+
end
|
83
|
+
|
84
|
+
class FubarGroup < ActiveRecord::Base
|
85
|
+
belongs_to :fubar
|
86
|
+
belongs_to :group
|
87
|
+
end
|
88
|
+
|
89
|
+
class UserGroup < ActiveRecord::Base
|
90
|
+
belongs_to :user
|
91
|
+
belongs_to :group
|
92
|
+
end
|
93
|
+
|
94
|
+
def scrub_all
|
95
|
+
Fubar.restrictors.clear
|
96
|
+
UserGroup.delete_all
|
97
|
+
FubarGroup.delete_all
|
98
|
+
UserPermission.delete_all
|
99
|
+
FubarPermission.delete_all
|
100
|
+
User.current_user = nil
|
101
|
+
Fubar.update_all(:user_id => nil)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Setup our test models
|
105
|
+
10.times do |i|
|
106
|
+
User.create(:username => "user_#{i}", :active => i % 2 == 0)
|
107
|
+
Fubar.create(:name => "fubar_#{i}", :enabled => i % 2 == 0)
|
108
|
+
end
|
109
|
+
|
110
|
+
5.times do |i|
|
111
|
+
Permission.create(:name => "permission_#{i}")
|
112
|
+
end
|
113
|
+
|
114
|
+
5.times do |i|
|
115
|
+
Group.create(:name => "group_#{i}")
|
116
|
+
end
|
@@ -0,0 +1,386 @@
|
|
1
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), 'setup')
|
2
|
+
|
3
|
+
describe ActiveRestrictor do
|
4
|
+
# Check for proper setup at the start
|
5
|
+
describe 'after suite setup' do
|
6
|
+
it 'should have properly setup models' do
|
7
|
+
assert_equal 10, User.count
|
8
|
+
assert_equal 10, Fubar.count
|
9
|
+
assert_equal 5, Group.count
|
10
|
+
assert_equal 5, Permission.count
|
11
|
+
refute_equal User.count, User.where(:active => true).count
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
#!!!! basic_user type restrictions
|
17
|
+
describe 'when basic user restrictor only allows active users' do
|
18
|
+
before do
|
19
|
+
Fubar.class_eval do
|
20
|
+
add_restrictor(:active,
|
21
|
+
:type => :basic_user,
|
22
|
+
:scope => User.where(:active => true)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
after do
|
27
|
+
scrub_all
|
28
|
+
end
|
29
|
+
it 'should only allow active users access to fubars' do
|
30
|
+
u = User.where(:active => true).first
|
31
|
+
assert u.allowed_fubars.count > 0
|
32
|
+
u = User.where(:active => false).first
|
33
|
+
assert_equal 0, u.allowed_fubars.count
|
34
|
+
end
|
35
|
+
it 'should only show active users from fubars' do
|
36
|
+
Fubar.all.each do |fubar|
|
37
|
+
fubar.allowed_users.each do |user|
|
38
|
+
assert user.active
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'when basic user restrictor provide enabled block' do
|
45
|
+
before do
|
46
|
+
Fubar.class_eval do
|
47
|
+
add_restrictor(:active,
|
48
|
+
:type => :basic_user,
|
49
|
+
:scope => User.where(:active => true),
|
50
|
+
:enabled => lambda{ User.current_user.nil? || !User.current_user.username == 'user_1' }
|
51
|
+
)
|
52
|
+
end
|
53
|
+
u = User.find_by_username('user_1')
|
54
|
+
u.active = false
|
55
|
+
u.save!
|
56
|
+
end
|
57
|
+
after do
|
58
|
+
scrub_all
|
59
|
+
end
|
60
|
+
it 'should not allow fubars for user_1 when current_user is unset' do
|
61
|
+
assert_equal 0, User.find_by_username('user_1').allowed_fubars.count
|
62
|
+
end
|
63
|
+
it 'should allow fubars for user_1 when current_user is set' do
|
64
|
+
u = User.find_by_username('user_1')
|
65
|
+
User.current_user = u
|
66
|
+
assert u.allowed_fubars.count > 0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#!!! basic model type restrictions
|
71
|
+
describe 'when basic model restrictor only allows enabled fubars' do
|
72
|
+
before do
|
73
|
+
Fubar.class_eval do
|
74
|
+
add_restrictor(:enabled,
|
75
|
+
:type => :basic_model,
|
76
|
+
:scope => Fubar.where(:enabled => true)
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
after do
|
81
|
+
scrub_all
|
82
|
+
end
|
83
|
+
it 'should only allow users to access enabled fubars' do
|
84
|
+
User.all.each do |user|
|
85
|
+
user.allowed_fubars.each do |fubar|
|
86
|
+
assert fubar.enabled?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
it 'should not provide users from disabled fubars' do
|
91
|
+
assert Fubar.where(:enabled => false).count > 0
|
92
|
+
Fubar.where(:enabled => false).all.each do |fubar|
|
93
|
+
assert_equal 0, fubar.allowed_users.count
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
#!!! implicit model type restrictions
|
99
|
+
describe 'when implict restrictor only allows fubars belonging to users' do
|
100
|
+
before do
|
101
|
+
Fubar.class_eval do
|
102
|
+
add_restrictor(:user,
|
103
|
+
:type => :implicit,
|
104
|
+
:scope => lambda{ where(:user_id => User.current_user.id) }
|
105
|
+
)
|
106
|
+
end
|
107
|
+
u = User.find_by_username("user_1")
|
108
|
+
3.times do |i|
|
109
|
+
f = Fubar.find_by_name("fubar_#{i}")
|
110
|
+
f.user_id = u.id
|
111
|
+
f.save!
|
112
|
+
end
|
113
|
+
User.current_user = u
|
114
|
+
end
|
115
|
+
after do
|
116
|
+
scrub_all
|
117
|
+
end
|
118
|
+
it 'should show 3 fubars for user_1' do
|
119
|
+
assert_equal 3, User.find_by_username('user_1').fubars.count
|
120
|
+
end
|
121
|
+
it 'should show no fubars for users not user_1' do
|
122
|
+
User.where("username != 'user_1'").all.each do |user|
|
123
|
+
assert_equal 0, user.fubars.count
|
124
|
+
end
|
125
|
+
end
|
126
|
+
it 'should only show allowed users as assigned users' do
|
127
|
+
Fubar.all.each do |fubar|
|
128
|
+
if(fubar.user_id.nil?)
|
129
|
+
assert_equal 0, fubar.allowed_users.count
|
130
|
+
else
|
131
|
+
assert_equal 1, fubar.allowed_users.count
|
132
|
+
assert_equal 'user_1', fubar.allowed_users.first.username
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
#!!! full type restrictions
|
139
|
+
describe 'when full permission restrictor is applied' do
|
140
|
+
before do
|
141
|
+
Fubar.class_eval do
|
142
|
+
add_restrictor(:permissions,
|
143
|
+
:type => :full
|
144
|
+
)
|
145
|
+
end
|
146
|
+
3.times do |i|
|
147
|
+
perm = Permission.find_by_name("permission_#{i}")
|
148
|
+
user = User.find_by_username("user_#{i}")
|
149
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
150
|
+
user.permissions << perm
|
151
|
+
fubar.permissions << perm
|
152
|
+
end
|
153
|
+
end
|
154
|
+
after do
|
155
|
+
scrub_all
|
156
|
+
end
|
157
|
+
it 'should only allow users with matching permissions' do
|
158
|
+
3.times do |i|
|
159
|
+
user = User.find_by_username("user_#{i}")
|
160
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
161
|
+
assert_equal 1, user.allowed_fubars.count
|
162
|
+
assert_equal 1, fubar.allowed_users.count
|
163
|
+
assert_equal "fubar_#{i}", user.allowed_fubars.first.name
|
164
|
+
assert_equal "user_#{i}", fubar.allowed_users.first.username
|
165
|
+
end
|
166
|
+
end
|
167
|
+
it 'should not allow users without matching permissions' do
|
168
|
+
7.times do |i|
|
169
|
+
i = i + 3
|
170
|
+
user = User.find_by_username("user_#{i}")
|
171
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
172
|
+
assert_equal 0, user.allowed_fubars.count
|
173
|
+
assert_equal 0, fubar.allowed_users.count
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#!!! Stacked full restrictions
|
179
|
+
describe 'when full permission and full group restrictors are applied' do
|
180
|
+
before do
|
181
|
+
Fubar.class_eval do
|
182
|
+
add_restrictor(:permissions,
|
183
|
+
:type => :full
|
184
|
+
)
|
185
|
+
add_restrictor(:groups,
|
186
|
+
:type => :full
|
187
|
+
)
|
188
|
+
end
|
189
|
+
4.times do |i|
|
190
|
+
perm = Permission.find_by_name("permission_#{i}")
|
191
|
+
user = User.find_by_username("user_#{i}")
|
192
|
+
group = Group.find_by_name("group_#{i}")
|
193
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
194
|
+
if(i % 2 == 0 || i == 3)
|
195
|
+
user.permissions << perm
|
196
|
+
fubar.permissions << perm
|
197
|
+
end
|
198
|
+
if(i % 2 == 1 || i == 3)
|
199
|
+
user.groups << group
|
200
|
+
fubar.groups << group
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
after do
|
205
|
+
scrub_all
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should be setup correctly' do
|
209
|
+
3.times do |i|
|
210
|
+
u = User.find_by_username("user_#{i}")
|
211
|
+
if(u.groups.count > 0)
|
212
|
+
assert_equal(1, u.groups.count)
|
213
|
+
assert_equal(0, u.permissions.count)
|
214
|
+
elsif(u.permissions.count > 0)
|
215
|
+
assert_equal(1, u.permissions.count)
|
216
|
+
assert_equal(0, u.groups.count)
|
217
|
+
else
|
218
|
+
flunk "User should have one group or one permission assigned"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
assert_equal 1, User.find_by_username('user_3').groups.count
|
222
|
+
assert_equal 1, User.find_by_username('user_3').permissions.count
|
223
|
+
assert_equal 0, User.find_by_username('user_4').groups.count
|
224
|
+
assert_equal 0, User.find_by_username('user_5').permissions.count
|
225
|
+
end
|
226
|
+
it 'should allow not allow users with single matching permission or group only' do
|
227
|
+
3.times do |i|
|
228
|
+
user = User.find_by_username("user_#{i}")
|
229
|
+
assert_equal(0, user.allowed_fubars.count)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
it 'should allow users with both matching permission and group' do
|
233
|
+
assert_equal(1, User.find_by_username('user_3').allowed_fubars.count)
|
234
|
+
end
|
235
|
+
it 'should not allow users with no matching permission or group' do
|
236
|
+
assert_equal(0, User.find_by_username('user_4').allowed_fubars.count)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe 'when full permission and full group restrictors are applied using default_view_all' do
|
241
|
+
before do
|
242
|
+
Fubar.class_eval do
|
243
|
+
add_restrictor(:permissions,
|
244
|
+
:type => :full,
|
245
|
+
:default_view_all => true
|
246
|
+
)
|
247
|
+
add_restrictor(:groups,
|
248
|
+
:type => :full,
|
249
|
+
:default_view_all => true
|
250
|
+
)
|
251
|
+
end
|
252
|
+
4.times do |i|
|
253
|
+
perm = Permission.find_by_name("permission_#{i}")
|
254
|
+
user = User.find_by_username("user_#{i}")
|
255
|
+
group = Group.find_by_name("group_#{i}")
|
256
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
257
|
+
if(i % 2 == 0 || i == 3)
|
258
|
+
user.permissions << perm
|
259
|
+
fubar.permissions << perm
|
260
|
+
end
|
261
|
+
if(i % 2 == 1 || i == 3)
|
262
|
+
user.groups << group
|
263
|
+
fubar.groups << group
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
after do
|
268
|
+
scrub_all
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'should only provide fubars without assigned groups and permissions to users without assigned groups and permissions' do
|
272
|
+
User.includes(:groups, :permissions).where(:groups => {:id => nil}, :permissions => {:id => nil}).each do |user|
|
273
|
+
assert_equal(6, user.allowed_fubars.count)
|
274
|
+
user.allowed_fubars.each do |fubar|
|
275
|
+
assert_equal(0, fubar.groups.count)
|
276
|
+
assert_equal(0, fubar.permissions.count)
|
277
|
+
end
|
278
|
+
assert_equal(0, user.groups.count)
|
279
|
+
assert_equal(0, user.permissions.count)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
it 'should provide fubars with with matching group or permissions and fubars without assigned groups or permissions' do
|
283
|
+
4.times do |i|
|
284
|
+
user = User.find_by_username("user_#{i}")
|
285
|
+
assert_equal(7, user.allowed_fubars.count)
|
286
|
+
user.allowed_fubars.each do |fubar|
|
287
|
+
if(fubar.groups.count > 0)
|
288
|
+
assert_equal fubar.groups.first, user.groups.first
|
289
|
+
end
|
290
|
+
if(fubar.permissions.count > 0)
|
291
|
+
assert_equal fubar.permissions.first, user.permissions.first
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
it 'should allow all users when no permission and groups are defined' do
|
297
|
+
6.times do |i|
|
298
|
+
fubar = Fubar.find_by_name("fubar_#{i + 4}")
|
299
|
+
assert_equal(10, fubar.allowed_users.count)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
it 'should only allow users with matching permission or group' do
|
303
|
+
4.times do |i|
|
304
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
305
|
+
assert_equal(1, fubar.allowed_users.count)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
#!!! Stacked mixed restrictions
|
311
|
+
describe 'when basic and full restrictors are applied' do
|
312
|
+
before do
|
313
|
+
Fubar.class_eval do
|
314
|
+
add_restrictor(:enabled,
|
315
|
+
:type => :basic_user,
|
316
|
+
:scope => User.where(:active => true)
|
317
|
+
)
|
318
|
+
add_restrictor(:enabled,
|
319
|
+
:type => :basic_model,
|
320
|
+
:scope => where(:enabled => true)
|
321
|
+
)
|
322
|
+
add_restrictor(:permissions,
|
323
|
+
:type => :full
|
324
|
+
)
|
325
|
+
end
|
326
|
+
4.times do |i|
|
327
|
+
user = User.find_by_username("user_#{i}")
|
328
|
+
perm = Permission.find_by_name("permission_#{i}")
|
329
|
+
fubar = Fubar.find_by_name("fubar_#{i}")
|
330
|
+
user.permissions << perm
|
331
|
+
fubar.permissions << perm
|
332
|
+
end
|
333
|
+
end
|
334
|
+
after do
|
335
|
+
scrub_all
|
336
|
+
end
|
337
|
+
|
338
|
+
it "should have disabled and enabled users and fubars setup" do
|
339
|
+
users = 4.times.map{|i| User.find_by_username("user_#{i}")}
|
340
|
+
fubars = 4.times.map{|i| Fubar.find_by_name("fubar_#{i}")}
|
341
|
+
assert users.detect(&:active?), 'Expecting active users'
|
342
|
+
assert users.detect{|u| !u.active?}, 'Expecting inactive users'
|
343
|
+
assert fubars.detect(&:enabled?), 'Expecting enabled fubars'
|
344
|
+
assert fubars.detect{|f| !f.enabled?}, 'Expecting disabled fubars'
|
345
|
+
end
|
346
|
+
it "should not show any allowed users when fubar is disabled" do
|
347
|
+
fubar = Fubar.where(:name => 4.times.map{|i|"fubar_#{i}"}, :enabled => false).first
|
348
|
+
assert fubar, "Expecting Fubar instance to be found"
|
349
|
+
assert_equal 0, fubar.allowed_users.count
|
350
|
+
end
|
351
|
+
it "should only show active users when fubar is enabled" do
|
352
|
+
fubar = Fubar.where(:name => 4.times.map{|i|"fubar_#{i}"}, :enabled => true).first
|
353
|
+
assert fubar, "Expecting Fubar instance to be found"
|
354
|
+
assert fubar.allowed_users.count > 0, 'Expecting allowed users to be found'
|
355
|
+
fubar.allowed_users.each do |user|
|
356
|
+
assert user.active?, 'Expecting user to be active'
|
357
|
+
end
|
358
|
+
end
|
359
|
+
it "should not show any allowed fubars when user is inactive" do
|
360
|
+
user = User.where(:username => 4.times.map{|i|"user_#{i}"}, :active => false).first
|
361
|
+
assert user, "Expecting User instance to be found"
|
362
|
+
assert_equal(0, user.allowed_fubars.count)
|
363
|
+
end
|
364
|
+
it "should only show enabled fubars when user is active" do
|
365
|
+
user = User.where(:username => 4.times.map{|i|"user_#{i}"}, :active => true).first
|
366
|
+
assert user, "Expecting User instance to be found"
|
367
|
+
assert user.allowed_fubars.count > 0, 'Expecting allowed fubars to be found'
|
368
|
+
user.allowed_fubars.each do |fubar|
|
369
|
+
assert fubar.enabled?, 'Expecting fubar to be enabled'
|
370
|
+
end
|
371
|
+
end
|
372
|
+
it "should only show enabled fubars with same permission as user" do
|
373
|
+
User.where(:username => 4.times.map{|i|"user_#{i}"}, :active => true).all.each do |user|
|
374
|
+
assert user.active?, 'Expecting active user'
|
375
|
+
assert user.allowed_fubars.count > 0, 'Expecting user to have allowed fubars'
|
376
|
+
user.allowed_fubars.each do |fubar|
|
377
|
+
assert fubar.enabled?, 'Expecting Fubar to be enabled'
|
378
|
+
assert_equal fubar.permissions.first, user.permissions.first
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# TODO: model_custom / user_custom
|
385
|
+
# TODO: more complex stacking
|
386
|
+
end
|
data/spec/setup.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'active_record'
|
5
|
+
if(RUBY_PLATFORM == 'java')
|
6
|
+
require 'jdbc/sqlite3'
|
7
|
+
else
|
8
|
+
require 'sqlite3'
|
9
|
+
end
|
10
|
+
require 'active_restrictors'
|
11
|
+
require 'minitest/autorun'
|
12
|
+
|
13
|
+
ActiveRecord::Base.establish_connection(
|
14
|
+
:adapter => 'sqlite3',
|
15
|
+
:database => ':memory:'
|
16
|
+
)
|
17
|
+
load File.join(File.expand_path(File.dirname(__FILE__)), 'model_definitions.rb')
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_restrictors
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chris Roberts
|
@@ -15,10 +15,24 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-01-
|
18
|
+
date: 2012-01-20 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activerecord
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: "3.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
22
36
|
description: Restrictors for Models
|
23
37
|
email: chrisroberts.code@gmail.com
|
24
38
|
executables: []
|
@@ -29,13 +43,19 @@ extra_rdoc_files:
|
|
29
43
|
- README.rdoc
|
30
44
|
- CHANGELOG.rdoc
|
31
45
|
files:
|
46
|
+
- Gemfile.lock
|
47
|
+
- spec/restrictor_spec.rb
|
48
|
+
- spec/setup.rb
|
49
|
+
- spec/model_definitions.rb
|
32
50
|
- README.rdoc
|
33
|
-
-
|
34
|
-
- active_restrictors.gemspec
|
51
|
+
- Gemfile
|
35
52
|
- lib/active_restrictors/active_restrictor_views.rb
|
36
53
|
- lib/active_restrictors/version.rb
|
37
54
|
- lib/active_restrictors/active_restrictor.rb
|
38
55
|
- lib/active_restrictors.rb
|
56
|
+
- active_restrictors.gemspec
|
57
|
+
- CHANGELOG.rdoc
|
58
|
+
- Rakefile
|
39
59
|
has_rdoc: true
|
40
60
|
homepage: http://bitbucket.org/chrisroberts/active_restrictors
|
41
61
|
licenses: []
|