id_please 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/id_please.gemspec +5 -3
- data/lib/id_please/assignment_map.rb +40 -12
- data/lib/id_please/model_extensions/for_subject.rb +31 -20
- data/test/assignment_test.rb +38 -0
- data/test/debug.log +222903 -0
- data/test/roles_test.rb +19 -9
- metadata +4 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/id_please.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{id_please}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["James Stuart"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-16}
|
13
13
|
s.description = %q{Access control gem}
|
14
14
|
s.email = %q{tastyhat@jamesstuart.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
"lib/id_please/model_extensions/for_role.rb",
|
36
36
|
"lib/id_please/model_extensions/for_subject.rb",
|
37
37
|
"lib/id_please/model_extensions/for_user.rb",
|
38
|
+
"test/assignment_test.rb",
|
38
39
|
"test/database.yml",
|
39
40
|
"test/debug.log",
|
40
41
|
"test/id_please_test.rb",
|
@@ -49,7 +50,8 @@ Gem::Specification.new do |s|
|
|
49
50
|
s.rubygems_version = %q{1.3.5}
|
50
51
|
s.summary = %q{Access control gem for rails}
|
51
52
|
s.test_files = [
|
52
|
-
"test/
|
53
|
+
"test/assignment_test.rb",
|
54
|
+
"test/id_please_test.rb",
|
53
55
|
"test/roles_test.rb",
|
54
56
|
"test/support/models.rb",
|
55
57
|
"test/support/schema.rb",
|
@@ -25,31 +25,38 @@ module IdPlease
|
|
25
25
|
|
26
26
|
def initialize(*args)
|
27
27
|
options = args.extract_options!
|
28
|
-
options = {:direction => :down, :nested => true}.merge(options)
|
28
|
+
options = {:direction => :down, :nested => true, :members_only => false}.merge(options)
|
29
29
|
@subjects = options[:subjects] # || raise("You must provide a subject")
|
30
30
|
@subjects = [@subjects] unless @subjects.kind_of?(Array)
|
31
31
|
@direction = options[:direction]
|
32
32
|
@assign_class = options[:assignment_class] # || raise("You must provide the assignment class through :assignment_class")
|
33
33
|
@nested = options[:nested]
|
34
34
|
@member_role = options[:member_role] || :member
|
35
|
+
@members_only = options[:members_only]
|
35
36
|
@assignments = []
|
36
37
|
@calculated = false
|
37
38
|
add_all_assignments(@subjects)
|
38
39
|
end
|
39
40
|
|
40
41
|
def add_all_assignments(subjects)
|
41
|
-
|
42
42
|
@calculated = false
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
|
44
|
+
search_proc = lambda { @direction == :down ? @assign_class.role_authorizable_eq(*subjects) : @assign_class.subject_eq(*subjects) }
|
45
|
+
|
46
|
+
search_with_role = lambda { |a| @members_only ? a.role_name_eq(@member_role.to_s) : a}
|
47
|
+
|
48
|
+
assignments = search_with_role.call(search_proc.call).all(:include => [:subject, {:role => :authorizable}])
|
49
|
+
|
50
|
+
@assignments += assignments
|
51
|
+
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
if @nested
|
54
|
+
subjects_to_search = if @direction == :down
|
55
|
+
assignments.select { |a| a.role.name.to_sym == @member_role}.collect(&:subject).select { |s| s._auth_is_group }
|
56
|
+
else
|
57
|
+
assignments.select { |a| a.role.name.to_sym == @member_role}.collect { |a| a.role.authorizable }.select { |s| s.respond_to?(:_auth_is_group) && s._auth_is_group }
|
52
58
|
end
|
59
|
+
add_all_assignments(subjects_to_search) unless subjects_to_search.empty?
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
@@ -100,6 +107,25 @@ module IdPlease
|
|
100
107
|
return result
|
101
108
|
end
|
102
109
|
|
110
|
+
def targets
|
111
|
+
calculate! unless @calculated
|
112
|
+
@targets = @assignment_links.collect(&:target).uniq
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def targets_with_assignments
|
117
|
+
calculate! unless @calculated
|
118
|
+
result = Hash.new { |h,k| h[k] = Hash.new() }
|
119
|
+
@assignment_links.each do |a|
|
120
|
+
result[a.role][a.target] ||= []
|
121
|
+
result[a.role][a.target] << (a.via || a.subject)
|
122
|
+
end
|
123
|
+
|
124
|
+
result.each_key { |name| result[name].each_pair { |target,v| result[name][target] = v.compact.uniq }}
|
125
|
+
return result
|
126
|
+
end
|
127
|
+
|
128
|
+
|
103
129
|
def map
|
104
130
|
return self
|
105
131
|
end
|
@@ -113,14 +139,16 @@ module IdPlease
|
|
113
139
|
|
114
140
|
@assignment_links = []
|
115
141
|
|
116
|
-
@assignments.each do |a|
|
142
|
+
@assignments.select { |a| !@members_only || a.role.name.to_sym == @member_role }.each do |a|
|
117
143
|
al = AssignmentLink.new(:assignment => a)
|
118
144
|
@assignment_links << al
|
119
145
|
end
|
120
146
|
|
121
147
|
@assignment_links.select { |al| al.role != @member_role }.each do |al|
|
148
|
+
|
122
149
|
all_members_of(al.subject).each do |member|
|
123
|
-
|
150
|
+
|
151
|
+
@assignment_links << AssignmentLink.new(:role => al.role, :target => al.target, :subject => member, :via => al.subject)
|
124
152
|
end
|
125
153
|
end
|
126
154
|
|
@@ -28,38 +28,49 @@ module IdPlease
|
|
28
28
|
all_groups.each { |group| self.not_in_group!(group) }
|
29
29
|
end
|
30
30
|
|
31
|
+
|
32
|
+
def groups_with_assignments(*args)
|
33
|
+
options = args.extract_options!.merge(:view => :targets_with_assignments)
|
34
|
+
groups(options)
|
35
|
+
end
|
36
|
+
|
31
37
|
def groups(*args)
|
32
38
|
raise "Groups must be enabled for this model" unless _auth_groups_enabled
|
39
|
+
|
40
|
+
options = {:view => :targets}.merge(args.extract_options!)
|
41
|
+
view = options[:view]
|
42
|
+
valid_views = [:targets, :targets_with_assignments, :map]
|
43
|
+
|
33
44
|
|
34
|
-
|
35
|
-
|
45
|
+
raise "Invalid view argument, must be one of #{valid_views}" unless valid_views.include?(view)
|
46
|
+
|
47
|
+
members_only = if options.has_key?(:members_only)
|
48
|
+
options[:members_only]
|
49
|
+
else
|
50
|
+
view == :targets ? true : false
|
51
|
+
end
|
52
|
+
|
36
53
|
|
37
|
-
|
38
|
-
|
54
|
+
map = IdPlease::AssignmentMap.new(:assignment_class => _auth_assign_class, :direction => :up, :subjects => self, :members_only => members_only, :nested => _auth_nested_groups && options[:nested] != false)
|
55
|
+
|
39
56
|
|
57
|
+
return map.send(view)
|
58
|
+
|
59
|
+
options = args.extract_options!
|
60
|
+
all_groups = direct_parent_groups(self)
|
40
61
|
|
41
62
|
if _auth_nested_groups && options[:nested] != false
|
42
63
|
infinite_loop_counter = 25
|
43
64
|
to_find = all_groups.dup
|
44
65
|
|
45
66
|
until to_find.empty? || (infinite_loop_counter -=1) <= 0
|
46
|
-
|
47
|
-
|
48
|
-
child_groups = direct_parent_groups(parent_group)
|
49
|
-
child_groups.each { |g| group_hash.has_key?(g) ? group_hash[g] << parent_group : group_hash[g] = [parent_group]}
|
50
|
-
all_child_groups += child_groups
|
51
|
-
end
|
52
|
-
all_child_groups.uniq!
|
53
|
-
all_groups += all_child_groups
|
54
|
-
to_find = all_child_groups
|
67
|
+
to_find = direct_parent_groups(*to_find)
|
68
|
+
all_groups += to_find
|
55
69
|
end
|
56
|
-
|
57
|
-
|
58
|
-
case options[:result]
|
59
|
-
when :list
|
70
|
+
|
60
71
|
all_groups.uniq
|
61
|
-
|
62
|
-
|
72
|
+
else
|
73
|
+
all_groups
|
63
74
|
end
|
64
75
|
end
|
65
76
|
|
@@ -133,7 +144,7 @@ module IdPlease
|
|
133
144
|
|
134
145
|
def self_and_groups
|
135
146
|
if _auth_groups_enabled
|
136
|
-
groups << self
|
147
|
+
groups(:members_only => false) << self
|
137
148
|
else
|
138
149
|
[self]
|
139
150
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AssignmentTest < ActiveSupport::TestCase
|
4
|
+
context "given users and groups" do
|
5
|
+
setup do
|
6
|
+
@user_a = User.create!(:name => "Alice")
|
7
|
+
@user_b = User.create!(:name => "Bob")
|
8
|
+
@user_c = User.create!(:name => "Charles")
|
9
|
+
@group_execs = Group.create!(:name => "Executives")
|
10
|
+
@group_company = Group.create!(:name => "Company")
|
11
|
+
@group_division = Group.create!(:name => "Division")
|
12
|
+
|
13
|
+
@user_a.in_group!(@group_execs)
|
14
|
+
@group_execs.has_role!(:owner, @group_division)
|
15
|
+
@group_division.in_group!(@group_company)
|
16
|
+
@group_execs.in_group!(@group_company)
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
should "make an Assignment Map" do
|
21
|
+
map = IdPlease::AssignmentMap.new(:assignment_class => Assignment, :direction => :up, :subjects => @user_a)
|
22
|
+
assert_kind_of IdPlease::AssignmentMap, map
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
should "handle groups, even nested" do
|
29
|
+
assert_same_elements @user_a.groups, [@group_execs, @group_company]
|
30
|
+
assert_same_elements_in_hash @user_a.groups_with_assignments(:members_only => true)[:member], {@group_execs => [@user_a], @group_company => [@group_execs]}
|
31
|
+
assert_same_elements_in_hash @user_a.groups_with_assignments(:members_only => false)[:member], {@group_execs => [@user_a], @group_company => [@group_execs]}
|
32
|
+
|
33
|
+
assert_same_elements_in_hash @user_a.groups_with_assignments(:members_only => true)[:owner], {}
|
34
|
+
assert_same_elements_in_hash @user_a.groups_with_assignments(:members_only => false)[:owner], {@group_division => [@group_execs]}
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|