active_restrictors 0.1.1 → 0.2.0
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.
- 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: []
|