ktopping_acl9 0.12.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.
@@ -0,0 +1,59 @@
1
+ module Acl9
2
+ module ModelExtensions
3
+ module ForObject
4
+ ##
5
+ # Role check.
6
+ #
7
+ # @return [Boolean] Returns true if +subject+ has a role +role_name+ on this object.
8
+ #
9
+ # @param [Symbol,String] role_name Role name
10
+ # @param [Subject] subject Subject to add role for
11
+ # @see Acl9::ModelExtensions::Subject#has_role?
12
+ def accepts_role?(role_name, subject)
13
+ subject.has_role? role_name, self
14
+ end
15
+
16
+ ##
17
+ # Add role on the object to specified subject.
18
+ #
19
+ # @param [Symbol,String] role_name Role name
20
+ # @param [Subject] subject Subject to add role for
21
+ # @see Acl9::ModelExtensions::Subject#has_role!
22
+ def accepts_role!(role_name, subject)
23
+ subject.has_role! role_name, self
24
+ end
25
+
26
+ ##
27
+ # Free specified subject of a role on this object.
28
+ #
29
+ # @param [Symbol,String] role_name Role name
30
+ # @param [Subject] subject Subject to remove role from
31
+ # @see Acl9::ModelExtensions::Subject#has_no_role!
32
+ def accepts_no_role!(role_name, subject)
33
+ subject.has_no_role! role_name, self
34
+ end
35
+
36
+ ##
37
+ # Are there any roles for the specified +subject+ on this object?
38
+ #
39
+ # @param [Subject] subject Subject to query roles
40
+ # @return [Boolean] Returns true if +subject+ has any roles on this object.
41
+ # @see Acl9::ModelExtensions::Subject#has_roles_for?
42
+ def accepts_roles_by?(subject)
43
+ subject.has_roles_for? self
44
+ end
45
+
46
+ alias :accepts_role_by? :accepts_roles_by?
47
+
48
+ ##
49
+ # Which roles does +subject+ have on this object?
50
+ #
51
+ # @return [Array<Role>] Role instances, associated both with +subject+ and +object+
52
+ # @param [Subject] subject Subject to query roles
53
+ # @see Acl9::ModelExtensions::Subject#roles_for
54
+ def accepted_roles_by(subject)
55
+ subject.roles_for self
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,184 @@
1
+ module Acl9
2
+ module ModelExtensions
3
+ module ForSubject
4
+ ##
5
+ # Role check.
6
+ #
7
+ # There is a global option, +Acl9.config[:protect_global_roles]+, which governs
8
+ # this method behavior.
9
+ #
10
+ # If protect_global_roles is +false+, an object role is automatically counted
11
+ # as global role. E.g.
12
+ #
13
+ # Acl9.config[:protect_global_roles] = false
14
+ # user.has_role!(:manager, @foo)
15
+ # user.has_role?(:manager, @foo) # => true
16
+ # user.has_role?(:manager) # => true
17
+ #
18
+ # In this case manager is anyone who "manages" at least one object.
19
+ #
20
+ # However, if protect_global_roles option set to +true+, you'll need to
21
+ # explicitly grant global role with same name.
22
+ #
23
+ # Acl9.config[:protect_global_roles] = true
24
+ # user.has_role!(:manager, @foo)
25
+ # user.has_role?(:manager) # => false
26
+ # user.has_role!(:manager)
27
+ # user.has_role?(:manager) # => true
28
+ #
29
+ # protect_global_roles option is +false+ by default as for now, but this
30
+ # may change in future!
31
+ #
32
+ # @return [Boolean] Whether +self+ has a role +role_name+ on +object+.
33
+ # @param [Symbol,String] role_name Role name
34
+ # @param [Object] object Object to query a role on
35
+ #
36
+ # @see Acl9::ModelExtensions::Object#accepts_role?
37
+ def has_role?(role_name, object = nil)
38
+ !! if object.nil? && !::Acl9.config[:protect_global_roles]
39
+ self.role_objects.find_by_name(role_name.to_s) ||
40
+ self.role_objects.member?(get_role(role_name, nil))
41
+ else
42
+ role = get_role(role_name, object)
43
+ role && self.role_objects.exists?(role.id)
44
+ end
45
+ end
46
+
47
+ ##
48
+ # Add specified role on +object+ to +self+.
49
+ #
50
+ # @param [Symbol,String] role_name Role name
51
+ # @param [Object] object Object to add a role for
52
+ # @see Acl9::ModelExtensions::Object#accepts_role!
53
+ def has_role!(role_name, object = nil)
54
+ role = get_role(role_name, object)
55
+
56
+ if role.nil?
57
+ role_attrs = case object
58
+ when Class then { :authorizable_type => object.to_s }
59
+ when nil then {}
60
+ else { :authorizable => object }
61
+ end.merge( { :name => role_name.to_s })
62
+
63
+ role = self._auth_role_class.create(role_attrs)
64
+ end
65
+
66
+ self.role_objects << role if role && !self.role_objects.exists?(role.id)
67
+ end
68
+
69
+ ##
70
+ # Free +self+ from a specified role on +object+.
71
+ #
72
+ # @param [Symbol,String] role_name Role name
73
+ # @param [Object] object Object to remove a role on
74
+ # @see Acl9::ModelExtensions::Object#accepts_no_role!
75
+ def has_no_role!(role_name, object = nil)
76
+ delete_role(get_role(role_name, object))
77
+ end
78
+
79
+ ##
80
+ # Are there any roles for +self+ on +object+?
81
+ #
82
+ # @param [Object] object Object to query roles
83
+ # @return [Boolean] Returns true if +self+ has any roles on +object+.
84
+ # @see Acl9::ModelExtensions::Object#accepts_roles_by?
85
+ def has_roles_for?(object)
86
+ !!self.role_objects.detect(&role_selecting_lambda(object))
87
+ end
88
+
89
+ alias :has_role_for? :has_roles_for?
90
+
91
+ ##
92
+ # Which roles does +self+ have on +object+?
93
+ #
94
+ # @return [Array<Role>] Role instances, associated both with +self+ and +object+
95
+ # @param [Object] object Object to query roles
96
+ # @see Acl9::ModelExtensions::Object#accepted_roles_by
97
+ # @example
98
+ # user = User.find(...)
99
+ # product = Product.find(...)
100
+ #
101
+ # user.roles_for(product).map(&:name).sort #=> role names in alphabetical order
102
+ def roles_for(object)
103
+ self.role_objects.select(&role_selecting_lambda(object))
104
+ end
105
+
106
+ ##
107
+ # Unassign any roles on +object+ from +self+.
108
+ #
109
+ # @param [Object,nil] object Object to unassign roles for. +nil+ means unassign global roles.
110
+ def has_no_roles_for!(object = nil)
111
+ roles_for(object).each { |role| delete_role(role) }
112
+ end
113
+
114
+ ##
115
+ # Unassign all roles from +self+.
116
+ def has_no_roles!
117
+ # for some reason simple
118
+ #
119
+ # self.roles.each { |role| delete_role(role) }
120
+ #
121
+ # doesn't work. seems like a bug in ActiveRecord
122
+ self.role_objects.map(&:id).each do |role_id|
123
+ delete_role self._auth_role_class.find(role_id)
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def role_selecting_lambda(object)
130
+ case object
131
+ when Class
132
+ lambda { |role| role.authorizable_type == object.to_s }
133
+ when nil
134
+ lambda { |role| role.authorizable.nil? }
135
+ else
136
+ lambda do |role|
137
+ role.authorizable_type == object.class.base_class.to_s && role.authorizable == object
138
+ end
139
+ end
140
+ end
141
+
142
+ def get_role(role_name, object)
143
+ role_name = role_name.to_s
144
+
145
+ cond = case object
146
+ when Class
147
+ [ 'name = ? and authorizable_type = ? and authorizable_id IS NULL', role_name, object.to_s ]
148
+ when nil
149
+ [ 'name = ? and authorizable_type IS NULL and authorizable_id IS NULL', role_name ]
150
+ else
151
+ [
152
+ 'name = ? and authorizable_type = ? and authorizable_id = ?',
153
+ role_name, object.class.base_class.to_s, object.id
154
+ ]
155
+ end
156
+
157
+ self._auth_role_class.first :conditions => cond
158
+ end
159
+
160
+ def delete_role(role)
161
+ if role
162
+ self.role_objects.delete role
163
+
164
+ role.destroy if role.send(self._auth_subject_class_name.demodulize.tableize).empty?
165
+ end
166
+ end
167
+
168
+ protected
169
+
170
+ def _auth_role_class
171
+ self.class._auth_role_class_name.constantize
172
+ end
173
+
174
+ def _auth_role_assoc
175
+ self.class._auth_role_assoc_name
176
+ end
177
+
178
+ def role_objects
179
+ send(self._auth_role_assoc)
180
+ end
181
+
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,139 @@
1
+ require File.join(File.dirname(__FILE__), 'model_extensions', 'for_subject')
2
+ require File.join(File.dirname(__FILE__), 'model_extensions', 'for_object')
3
+
4
+ module Acl9
5
+ module ModelExtensions #:nodoc:
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # Add #has_role? and other role methods to the class.
12
+ # Makes a class a auth. subject class.
13
+ #
14
+ # @param [Hash] options the options for tuning
15
+ # @option options [String] :role_class_name (Acl9::config[:default_role_class_name])
16
+ # Class name of the role class (e.g. 'AccountRole')
17
+ # @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
18
+ # Join table name (e.g. 'accounts_account_roles')
19
+ # @option options [String] :association_name (Acl9::config[:default_association_name])
20
+ # Association name (e.g. ':roles')
21
+ # @example
22
+ # class User < ActiveRecord::Base
23
+ # acts_as_authorization_subject
24
+ # end
25
+ #
26
+ # user = User.new
27
+ # user.roles #=> returns Role objects, associated with the user
28
+ # user.has_role!(...)
29
+ # user.has_no_role!(...)
30
+ #
31
+ # # other functions from Acl9::ModelExtensions::Subject are made available
32
+ #
33
+ # @see Acl9::ModelExtensions::Subject
34
+ #
35
+ def acts_as_authorization_subject(options = {})
36
+ assoc = options[:association_name] || Acl9::config[:default_association_name]
37
+ role = options[:role_class_name] || Acl9::config[:default_role_class_name]
38
+ join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] ||
39
+ join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(role))
40
+
41
+ has_and_belongs_to_many assoc, :class_name => role, :join_table => join_table
42
+
43
+ cattr_accessor :_auth_role_class_name, :_auth_subject_class_name,
44
+ :_auth_role_assoc_name
45
+
46
+ self._auth_role_class_name = role
47
+ self._auth_subject_class_name = self.to_s
48
+ self._auth_role_assoc_name = assoc
49
+
50
+ include Acl9::ModelExtensions::ForSubject
51
+ end
52
+
53
+ # Add role query and set methods to the class (making it an auth object class).
54
+ #
55
+ # @param [Hash] options the options for tuning
56
+ # @option options [String] :subject_class_name (Acl9::config[:default_subject_class_name])
57
+ # Subject class name (e.g. 'User', or 'Account)
58
+ # @option options [String] :role_class_name (Acl9::config[:default_role_class_name])
59
+ # Role class name (e.g. 'AccountRole')
60
+ # @example
61
+ # class Product < ActiveRecord::Base
62
+ # acts_as_authorization_object
63
+ # end
64
+ #
65
+ # product = Product.new
66
+ # product.accepted_roles #=> returns Role objects, associated with the product
67
+ # product.users #=> returns User objects, associated with the product
68
+ # product.accepts_role!(...)
69
+ # product.accepts_no_role!(...)
70
+ # # other functions from Acl9::ModelExtensions::Object are made available
71
+ #
72
+ # @see Acl9::ModelExtensions::Object
73
+ #
74
+ def acts_as_authorization_object(options = {})
75
+ subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
76
+ subj_table = subject.constantize.table_name
77
+ subj_col = subject.underscore
78
+
79
+ role = options[:role_class_name] || Acl9::config[:default_role_class_name]
80
+ role_table = role.constantize.table_name
81
+
82
+ sql_tables = <<-EOS
83
+ FROM #{subj_table}
84
+ INNER JOIN #{role_table}_#{subj_table} ON #{subj_col}_id = #{subj_table}.id
85
+ INNER JOIN #{role_table} ON #{role_table}.id = #{role.underscore}_id
86
+ EOS
87
+
88
+ sql_where = <<-'EOS'
89
+ WHERE authorizable_type = '#{self.class.base_class.to_s}'
90
+ AND authorizable_id = #{column_for_attribute(self.class.primary_key).text? ? "'#{id}'": id}
91
+ EOS
92
+
93
+ has_many :accepted_roles, :as => :authorizable, :class_name => role, :dependent => :destroy
94
+
95
+ has_many :"#{subj_table}",
96
+ :finder_sql => ("SELECT DISTINCT #{subj_table}.*" + sql_tables + sql_where),
97
+ :counter_sql => ("SELECT COUNT(DISTINCT #{subj_table}.id)" + sql_tables + sql_where),
98
+ :readonly => true
99
+
100
+ include Acl9::ModelExtensions::ForObject
101
+ end
102
+
103
+ # Make a class an auth role class.
104
+ #
105
+ # You'll probably never create or use objects of this class directly.
106
+ # Various auth. subject and object methods will do that for you
107
+ # internally.
108
+ #
109
+ # @param [Hash] options the options for tuning
110
+ # @option options [String] :subject_class_name (Acl9::config[:default_subject_class_name])
111
+ # Subject class name (e.g. 'User', or 'Account)
112
+ # @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
113
+ # Join table name (e.g. 'accounts_account_roles')
114
+ #
115
+ # @example
116
+ # class Role < ActiveRecord::Base
117
+ # acts_as_authorization_role
118
+ # end
119
+ #
120
+ # @see Acl9::ModelExtensions::Subject#has_role!
121
+ # @see Acl9::ModelExtensions::Subject#has_role?
122
+ # @see Acl9::ModelExtensions::Subject#has_no_role!
123
+ # @see Acl9::ModelExtensions::Object#accepts_role!
124
+ # @see Acl9::ModelExtensions::Object#accepts_role?
125
+ # @see Acl9::ModelExtensions::Object#accepts_no_role!
126
+ def acts_as_authorization_role(options = {})
127
+ subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
128
+ join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] ||
129
+ join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(subject))
130
+
131
+ has_and_belongs_to_many subject.demodulize.tableize.to_sym,
132
+ :class_name => subject,
133
+ :join_table => join_table
134
+
135
+ belongs_to :authorizable, :polymorphic => true
136
+ end
137
+ end
138
+ end
139
+ end
data/lib/acl9.rb ADDED
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__), 'acl9', 'config')
2
+
3
+ if defined? ActiveRecord::Base
4
+ require File.join(File.dirname(__FILE__), 'acl9', 'model_extensions')
5
+
6
+ ActiveRecord::Base.send(:include, Acl9::ModelExtensions)
7
+ end
8
+
9
+
10
+ if defined? ActionController::Base
11
+ require File.join(File.dirname(__FILE__), 'acl9', 'controller_extensions')
12
+ require File.join(File.dirname(__FILE__), 'acl9', 'helpers')
13
+
14
+ ActionController::Base.send(:include, Acl9::ControllerExtensions)
15
+ Acl9Helpers = Acl9::Helpers unless defined?(Acl9Helpers)
16
+ end