zuul 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ module Zuul
2
+ module ActiveRecord
3
+ # These are included in roles & permissions objects and assigned roles & permissions objects
4
+ # to provide easy access to the context for that object.
5
+ module ContextAccessors
6
+ def self.included(base)
7
+ base.send :attr_accessible, :context if ::Zuul.should_whitelist?
8
+ end
9
+
10
+ # Return a Zuul::Context object representing the context for the role
11
+ def context
12
+ Zuul::Context.new context_type, context_id
13
+ end
14
+
15
+ # Parse a context into an Zuul::Context and set the type and id
16
+ def context=(context)
17
+ context = Zuul::Context.parse(context)
18
+ self.context_type = context.klass
19
+ self.context_id = context.id
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,14 +3,13 @@ module Zuul
3
3
  module Permission
4
4
  def self.included(base)
5
5
  base.send :extend, ClassMethods
6
- base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
6
+ base.send :include, ContextAccessors
7
7
  base.send :include, InstanceMethods
8
8
  end
9
9
 
10
10
  module ClassMethods
11
11
  def self.extended(base)
12
- base.send :attr_accessible, :context, :context_id, :context_type, :slug if ::Zuul
13
- .should_whitelist?
12
+ base.send :attr_accessible, :context, :context_id, :context_type, :slug if ::Zuul.should_whitelist?
14
13
  add_validations base
15
14
  add_associations base
16
15
  end
@@ -3,13 +3,12 @@ module Zuul
3
3
  module PermissionRole
4
4
  def self.included(base)
5
5
  base.send :extend, ClassMethods
6
- base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
6
+ base.send :include, ContextAccessors
7
7
  end
8
8
 
9
9
  module ClassMethods
10
10
  def self.extended(base)
11
- base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym if ::Zuul
12
- .should_whitelist?
11
+ base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.role_foreign_key.to_sym if ::Zuul.should_whitelist?
13
12
  add_validations base
14
13
  add_associations base
15
14
  end
@@ -3,13 +3,12 @@ module Zuul
3
3
  module PermissionSubject
4
4
  def self.included(base)
5
5
  base.send :extend, ClassMethods
6
- base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
6
+ base.send :include, ContextAccessors
7
7
  end
8
8
 
9
9
  module ClassMethods
10
10
  def self.extended(base)
11
- base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul
12
- .should_whitelist?
11
+ base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.permission_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul.should_whitelist?
13
12
  add_validations base
14
13
  add_associations base
15
14
  end
@@ -3,15 +3,14 @@ module Zuul
3
3
  module Role
4
4
  def self.included(base)
5
5
  base.send :extend, ClassMethods
6
- base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
6
+ base.send :include, ContextAccessors
7
7
  base.send :include, InstanceMethods
8
8
  base.send :include, PermissionMethods if base.auth_scope.config.with_permissions
9
9
  end
10
10
 
11
11
  module ClassMethods
12
12
  def self.extended(base)
13
- base.send :attr_accessible, :context_id, :context_type, :level, :slug if ::Zuul
14
- .should_whitelist?
13
+ base.send :attr_accessible, :context_id, :context_type, :level, :slug if ::Zuul.should_whitelist?
15
14
  add_validations base
16
15
  add_associations base
17
16
  end
@@ -53,9 +52,9 @@ module Zuul
53
52
  auth_scope do
54
53
  context = Zuul::Context.parse(context)
55
54
  target = target_permission(permission, context, force_context)
56
- return false unless verify_target_context(target, context, force_context) && verify_target_context(self, context, false) && permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
55
+ return false unless verify_target_context(target, context, force_context) && verify_target_context(self, context, false)
57
56
 
58
- return permission_role_class.create(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
57
+ return permission_role_class.find_or_create_by(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
59
58
  end
60
59
  end
61
60
 
@@ -70,7 +69,7 @@ module Zuul
70
69
  target = target_permission(permission, context, force_context)
71
70
  return false if target.nil?
72
71
 
73
- assigned_permission = permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
72
+ assigned_permission = permission_role_for(target, context)
74
73
  return false if assigned_permission.nil?
75
74
  return assigned_permission.destroy
76
75
  end
@@ -85,20 +84,18 @@ module Zuul
85
84
  #
86
85
  # The assigned context behaves the same way, in that if the permission is not found
87
86
  # to belong to the role with the specified context, we look up the context chain.
88
- #
89
- # TODO add options to force context, not go up the chain
90
87
  def has_permission?(permission, context=nil, force_context=nil)
91
88
  auth_scope do
92
89
  force_context ||= config.force_context
93
90
  context = Zuul::Context.parse(context)
94
91
  target = target_permission(permission, context, force_context)
95
92
  return false if target.nil?
93
+ return permission_role_for?(target, context) if force_context
96
94
 
97
- return true unless (context.id.nil? && !force_context) || permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
98
- unless force_context
99
- return true unless context.class_name.nil? || permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
100
- return !permission_role_class.where(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
101
- end
95
+ return true if permission_role_for?(target, context)
96
+ return true if context.instance? && permission_role_for?(target, Zuul::Context.new(context.klass))
97
+ return true if !context.global? && permission_role_for?(target, Zuul::Context.new)
98
+ return false
102
99
  end
103
100
  end
104
101
  alias_method :permission?, :has_permission?
@@ -111,9 +108,9 @@ module Zuul
111
108
  force_context ||= config.force_context
112
109
  context = Zuul::Context.parse(context)
113
110
  if force_context
114
- return permission_class.joins(permission_role_plural_key).where(permission_role_plural_key => {role_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id})
111
+ return role_permissions_for(context)
115
112
  else
116
- return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("#{permission_roles_table_name}.#{role_foreign_key} = ? AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL)", id, context.class_name, context.id)
113
+ return role_permissions_within(context)
117
114
  end
118
115
  end
119
116
  end
@@ -122,6 +119,54 @@ module Zuul
122
119
  def permissions_for?(context=nil, force_context=nil)
123
120
  permissions_for(context, force_context).count > 0
124
121
  end
122
+
123
+ # Looks up a single permission_role based on the passed target and context
124
+ def permission_role_for(target, context)
125
+ auth_scope do
126
+ return permission_role_class.find_by(role_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
127
+ end
128
+ end
129
+
130
+ def permission_role_for?(target, context)
131
+ !permission_role_for(target, context).nil?
132
+ end
133
+
134
+ # Looks up all permissions for this role for the passed context
135
+ def role_permissions_for(context)
136
+ auth_scope do
137
+ return permission_class.joins(permission_role_plural_key).where(permission_role_plural_key => {role_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id})
138
+ end
139
+ end
140
+
141
+ def role_permissions_for?(context)
142
+ !role_permissions_for(context).empty?
143
+ end
144
+
145
+ # Looks up all permissions for this role within the passed context (within the context chain)
146
+ def role_permissions_within(context)
147
+ auth_scope do
148
+ return permission_class.joins("
149
+ LEFT JOIN #{permission_roles_table_name}
150
+ ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id"
151
+ ).where("
152
+ #{permission_roles_table_name}.#{role_foreign_key} = ?
153
+ AND (
154
+ #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
155
+ OR #{permission_roles_table_name}.context_type IS NULL
156
+ )
157
+ AND (
158
+ #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?
159
+ OR #{permission_roles_table_name}.context_id IS NULL
160
+ )",
161
+ id,
162
+ context.class_name,
163
+ context.id)
164
+ end
165
+ end
166
+
167
+ def role_permissions_within?(context)
168
+ !role_permissions_within(context).empty?
169
+ end
125
170
  end
126
171
  end
127
172
  end
@@ -3,13 +3,12 @@ module Zuul
3
3
  module RoleSubject
4
4
  def self.included(base)
5
5
  base.send :extend, ClassMethods
6
- base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
6
+ base.send :include, ContextAccessors
7
7
  end
8
8
 
9
9
  module ClassMethods
10
10
  def self.extended(base)
11
- base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul
12
- .should_whitelist?
11
+ base.send :attr_accessible, :context, :context_id, :context_type, base.auth_scope.role_foreign_key.to_sym, base.auth_scope.subject_foreign_key.to_sym if ::Zuul.should_whitelist?
13
12
  add_validations base
14
13
  add_associations base
15
14
  end
@@ -9,10 +9,49 @@ module Zuul
9
9
  @config = config
10
10
  @name = @config.scope
11
11
  define_reflection_methods
12
- super()
13
12
  end
14
13
 
15
14
  # Define dynamic reflection methods that reference the config to be used for subjects, roles, permissions and their associations.
15
+ #
16
+ # With a standard configuration, this defines the following methods:
17
+ #
18
+ # def subject_class : Subject
19
+ # def role_class : Role
20
+ # def permission_class : Permission
21
+ # def role_subject_class : RoleSubject
22
+ # def permission_role_class : PermissionRole
23
+ #
24
+ # def subject_class_name : 'Subject'
25
+ # def role_class_name : 'Role'
26
+ # def permission_class_name : 'Permission'
27
+ # def role_subject_class_name : 'RoleSubject'
28
+ # def permission_role_class_name : 'PermissionRole'
29
+ #
30
+ # def subject_table_name : 'subjects'
31
+ # def role_table_name : 'roles'
32
+ # def permission_table_name : 'permissions'
33
+ # def role_subject_table_name : 'role_subjects'
34
+ # def permission_role_table_name : 'permission_roles'
35
+ #
36
+ # def subject_singular_key : 'subject'
37
+ # def role_singular_key : 'role'
38
+ # def permission_singular_key : 'permission'
39
+ # def role_subject_singular_key : 'role_subject'
40
+ # def permission_role_singular_key : 'permission_role'
41
+ #
42
+ # def subject_plural_key : 'subjects'
43
+ # def role_plural_key : 'roles'
44
+ # def permission_plural_key : 'permissions'
45
+ # def role_subject_plural_key : 'role_subjects'
46
+ # def permission_role_plural_key : 'permission_roles'
47
+ #
48
+ # def subject_foreign_key : 'subject_id'
49
+ # def role_foreign_key : 'role_id'
50
+ # def permission_foreign_key : 'permission_id'
51
+ #
52
+ # All methods are also aliased to pluralized versions, so you can use `subject_class` or `subjects_class`, and
53
+ # when custom class names are used the methods are prefixed with those classes and aliased, so `user_class_name`
54
+ # is aliased to `subject_class_name`
16
55
  def define_reflection_methods
17
56
 
18
57
  # *_class_name, *_class, *_table_name methods for all classes
@@ -54,6 +93,7 @@ module Zuul
54
93
  end
55
94
  alias_method "#{class_type_name.pluralize}_plural_key", "#{class_type_name}_plural_key"
56
95
 
96
+ # These define aliases for custom class names, like user_class and user_table_name aliased to subject_class and subject_table_name
57
97
  unless class_type.to_s.underscore == "#{class_name.to_s.underscore}_class"
58
98
  %w(_class_name _class _table_name _singular_key _plural_key).each do |suffix|
59
99
  alias_method "#{class_name.to_s.underscore.singularize}#{suffix}", "#{class_type_name}#{suffix}"
@@ -28,9 +28,8 @@ module Zuul
28
28
  auth_scope do
29
29
  context = Zuul::Context.parse(context)
30
30
  target = target_role(role, context, force_context)
31
- return false unless verify_target_context(target, context, force_context) && role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
32
-
33
- return role_subject_class.create(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
31
+ return false unless verify_target_context(target, context, force_context)
32
+ return role_subject_class.find_or_create_by(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
34
33
  end
35
34
  end
36
35
 
@@ -43,8 +42,8 @@ module Zuul
43
42
  context = Zuul::Context.parse(context)
44
43
  target = target_role(role, context, force_context)
45
44
  return false if target.nil?
46
-
47
- assigned_role = role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
45
+
46
+ assigned_role = role_subject_for(target, context)
48
47
  return false if assigned_role.nil?
49
48
  return assigned_role.destroy
50
49
  end
@@ -64,11 +63,12 @@ module Zuul
64
63
  context = Zuul::Context.parse(context)
65
64
  target = target_role(role, context, force_context)
66
65
  return false if target.nil?
66
+ return role_subject_for?(target, context) if force_context
67
67
 
68
- return true unless (context.id.nil? && !force_context) || role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
69
- return false if force_context
70
- return true unless context.class_name.nil? || role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
71
- return !role_subject_class.where(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
68
+ return true if role_subject_for?(target, context)
69
+ return true if context.instance? && role_subject_for?(target, Zuul::Context.new(context.klass))
70
+ return true if !context.global? && role_subject_for?(target, Zuul::Context.new)
71
+ return false
72
72
  end
73
73
  end
74
74
  alias_method :role?, :has_role?
@@ -86,12 +86,13 @@ module Zuul
86
86
  context = Zuul::Context.parse(context)
87
87
  target = target_role(role, context, force_context)
88
88
  return false if target.nil?
89
-
90
89
  return true if has_role?(target, context, force_context)
91
-
92
- return true unless context.id.nil? || role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
93
- return true unless context.class_name.nil? || role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => nil).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
94
- return !role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => nil, :context_id => nil).where("#{roles_table_name}.level >= ? AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ? AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?", target.level, target.context_type, target.context_id).first.nil?
90
+ return role_subject_or_higher_for?(target, context) if force_context
91
+
92
+ return true if role_subject_or_higher_for?(target, context)
93
+ return true if context.instance? && role_subject_or_higher_for?(target, Zuul::Context.new(context.klass))
94
+ return true if !context.global? && role_subject_or_higher_for?(target, Zuul::Context.new)
95
+ return false
95
96
  end
96
97
  end
97
98
  alias_method :role_or_higher?, :has_role_or_higher?
@@ -113,19 +114,89 @@ module Zuul
113
114
  force_context ||= config.force_context
114
115
  context = Zuul::Context.parse(context)
115
116
  if force_context
116
- return role_class.joins(role_subject_plural_key).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?", id, context.class_name, context.id)
117
+ return subject_roles_for(context)
117
118
  else
118
- return role_class.joins(role_subject_plural_key).where("#{role_subjects_table_name}.#{subject_foreign_key} = ? AND ((#{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{role_subjects_table_name}.context_type IS NULL) AND (#{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{role_subjects_table_name}.context_id IS NULL))", id, context.class_name, context.id)
119
+ return subject_roles_within(context)
119
120
  end
120
121
  end
121
122
  end
122
-
123
+
123
124
  # Check whether the subject possesses any roles within the specified context.
124
125
  #
125
126
  # This includes any roles found by looking up the context chain.
126
127
  def roles_for?(context=nil, force_context=nil)
127
128
  roles_for(context, force_context).count > 0
128
129
  end
130
+
131
+ # Looks up a single role subject based on the passed target and context
132
+ def role_subject_for(target, context)
133
+ auth_scope do
134
+ return role_subject_class.joins(role_table_name.singularize.to_sym).find_by(subject_foreign_key.to_sym => id, role_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
135
+ end
136
+ end
137
+
138
+ def role_subject_for?(target, context)
139
+ !role_subject_for(target, context).nil?
140
+ end
141
+
142
+ # Looks up a single role subject with a level greather than or equal to the target level based on the passed target and context
143
+ def role_subject_or_higher_for(target, context)
144
+ auth_scope do
145
+ return role_subject_class.joins(role_table_name.singularize.to_sym).where(subject_foreign_key.to_sym => id, :context_type => context.class_name, :context_id => context.id).where("
146
+ #{roles_table_name}.level >= ?
147
+ AND #{roles_table_name}.context_type #{sql_is_or_equal(target.context_type)} ?
148
+ AND #{roles_table_name}.context_id #{sql_is_or_equal(target.context_id)} ?",
149
+ target.level,
150
+ target.context_type,
151
+ target.context_id).limit(1).first
152
+ end
153
+ end
154
+
155
+ def role_subject_or_higher_for?(target, context)
156
+ !role_subject_or_higher_for(target, context).nil?
157
+ end
158
+
159
+ # Looks up all roles for the subject for the passed context
160
+ def subject_roles_for(context)
161
+ auth_scope do
162
+ return role_class.joins(role_subject_plural_key).where("
163
+ #{role_subjects_table_name}.#{subject_foreign_key} = ?
164
+ AND #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
165
+ AND #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?",
166
+ id,
167
+ context.class_name,
168
+ context.id)
169
+ end
170
+ end
171
+
172
+ def subject_roles_for?(context)
173
+ !subject_roles_for(context).empty?
174
+ end
175
+
176
+ # Looks up all roles for the subject within the passed context (within the context chain)
177
+ def subject_roles_within(context)
178
+ auth_scope do
179
+ return role_class.joins(role_subject_plural_key).where("
180
+ #{role_subjects_table_name}.#{subject_foreign_key} = ?
181
+ AND (
182
+ (
183
+ #{role_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
184
+ OR #{role_subjects_table_name}.context_type IS NULL
185
+ )
186
+ AND (
187
+ #{role_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?
188
+ OR #{role_subjects_table_name}.context_id IS NULL
189
+ )
190
+ )",
191
+ id,
192
+ context.class_name,
193
+ context.id)
194
+ end
195
+ end
196
+
197
+ def subject_roles_within?(context)
198
+ !subject_roles_within(context).empty?
199
+ end
129
200
  end
130
201
  end
131
202
 
@@ -146,30 +217,29 @@ module Zuul
146
217
  # Assigns a permission to a subject within the provided context.
147
218
  #
148
219
  # If a Permission object is provided it's used directly, otherwise if a
149
- # permission slug is provided, the permission is looked up in the context
220
+ # permission slug is provided, the permission is looked up in the context
150
221
  # chain by target_permission.
151
222
  def assign_permission(permission, context=nil, force_context=nil)
152
223
  auth_scope do
153
224
  context = Zuul::Context.parse(context)
154
225
  target = target_permission(permission, context, force_context)
155
- return false unless verify_target_context(target, context, force_context) && permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first.nil?
156
-
157
- return permission_subject_class.create(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
226
+ return false unless verify_target_context(target, context, force_context)
227
+ return permission_subject_class.find_or_create_by(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
158
228
  end
159
229
  end
160
230
 
161
231
  # Removes a permission from a subject within the provided context.
162
232
  #
163
233
  # If a Permission object is provided it's used directly, otherwise if a
164
- # permission slug is provided, the permission is looked up in the context
234
+ # permission slug is provided, the permission is looked up in the context
165
235
  # chain by target_permission.
166
236
  def unassign_permission(permission, context=nil, force_context=nil)
167
237
  auth_scope do
168
238
  context = Zuul::Context.parse(context)
169
239
  target = target_permission(permission, context, force_context)
170
240
  return false if target.nil?
171
-
172
- assigned_permission = permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).limit(1).first
241
+
242
+ assigned_permission = permission_subject_for(target, context)
173
243
  return false if assigned_permission.nil?
174
244
  return assigned_permission.destroy
175
245
  end
@@ -179,7 +249,7 @@ module Zuul
179
249
  # Checks whether a subject has a permission within the provided context.
180
250
  #
181
251
  # If a Permission object is provided it's used directly, otherwise if a
182
- # permission slug is provided, the permission is looked up in the context
252
+ # permission slug is provided, the permission is looked up in the context
183
253
  # chain by target_permission.
184
254
  #
185
255
  # The assigned context behaves the same way, in that if the permission is not found
@@ -192,17 +262,12 @@ module Zuul
192
262
  context = Zuul::Context.parse(context)
193
263
  target = target_permission(permission, context, force_context)
194
264
  return false if target.nil?
265
+ return permission_role_or_subject_for?(target, context) if force_context
195
266
 
196
- return true unless (context.id.nil? && !force_context) || permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
197
- unless force_context
198
- return true unless context.class_name.nil? || permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
199
- return true unless permission_subject_class.where(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
200
- end
201
-
202
- return true unless (context.id.nil? && !force_context) || permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id).first.nil?
203
- return false if force_context
204
- return true unless context.class_name.nil? || permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => nil).first.nil?
205
- return !permission_role_class.where(role_foreign_key.to_sym => roles_for(context).map(&:id), permission_foreign_key.to_sym => target.id, :context_type => nil, :context_id => nil).first.nil?
267
+ return true if permission_role_or_subject_for?(target, context)
268
+ return true if context.instance? && permission_role_or_subject_for?(target, Zuul::Context.new(context.klass))
269
+ return true if !context.global? && permission_role_or_subject_for?(target, Zuul::Context.new)
270
+ return false
206
271
  end
207
272
  end
208
273
  alias_method :permission?, :has_permission?
@@ -217,21 +282,130 @@ module Zuul
217
282
  auth_scope do
218
283
  force_context ||= config.force_context
219
284
  context = Zuul::Context.parse(context)
285
+ roles = roles_for(context)
220
286
  if force_context
221
- return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id LEFT JOIN #{permission_subjects_table_name} ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("(#{permission_subjects_table_name}.#{subject_foreign_key} = ? AND #{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?) OR (#{permission_roles_table_name}.#{role_foreign_key} IN (?) AND #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? AND #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?)", id, context.class_name, context.id, roles_for(context).map(&:id), context.class_name, context.id)
287
+ return role_and_subject_permissions_for(context, roles)
222
288
  else
223
- return permission_class.joins("LEFT JOIN #{permission_roles_table_name} ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id LEFT JOIN #{permission_subjects_table_name} ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id").where("(#{permission_subjects_table_name}.#{subject_foreign_key} = ? AND (#{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_subjects_table_name}.context_type IS NULL) AND (#{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_subjects_table_name}.context_id IS NULL)) OR (#{permission_roles_table_name}.#{role_foreign_key} IN (?) AND (#{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ? OR #{permission_roles_table_name}.context_type IS NULL) AND (#{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ? OR #{permission_roles_table_name}.context_id IS NULL))", id, context.class_name, context.id, roles_for(context).map(&:id), context.class_name, context.id)
289
+ return role_and_subject_permissions_within(context, roles)
224
290
  end
225
291
  end
226
292
  end
227
-
293
+
228
294
  # Check whether the subject possesses any permissions within the specified context.
229
295
  #
230
296
  # This includes permissions assigned directly to the subject or any roles possessed by
231
297
  # the subject, as well as all permissions found by looking up the context chain.
232
298
  def permissions_for?(context=nil, force_context=nil)
233
- permissions_for(context, force_context).count > 0
299
+ !permissions_for(context, force_context).empty?
300
+ end
301
+
302
+ # Looks up a permission subject based on the passed target and context
303
+ def permission_subject_for(target, context)
304
+ auth_scope do
305
+ return permission_subject_class.find_by(subject_foreign_key.to_sym => id, permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
306
+ end
307
+ end
308
+
309
+ def permission_subject_for?(target, context)
310
+ !permission_subject_for(target, context).nil?
311
+ end
312
+
313
+ # Looks up a permission role based on the passed target and context
314
+ def permission_role_for(target, context, proles=nil)
315
+ auth_scope do
316
+ proles ||= roles_for(context)
317
+ return permission_role_class.find_by(role_foreign_key.to_sym => proles.map(&:id), permission_foreign_key.to_sym => target.id, :context_type => context.class_name, :context_id => context.id)
318
+ end
319
+ end
320
+
321
+ def permission_role_for?(target, context, proles=nil)
322
+ !permission_role_for(target, context, proles).nil?
323
+ end
324
+
325
+ # Looks up a permission subject or role based on the passed target and context
326
+ def permission_role_or_subject_for(target, context, proles=nil)
327
+ permission_subject_for(target, context) || permission_role_for(target, context, proles)
234
328
  end
329
+
330
+ def permission_role_or_subject_for?(target, context, proles=nil)
331
+ !permission_role_or_subject_for(target, context, proles).nil?
332
+ end
333
+
334
+ def role_and_subject_permissions_for(context, proles=nil)
335
+ auth_scope do
336
+ return permission_class.joins("
337
+ LEFT JOIN #{permission_roles_table_name}
338
+ ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id
339
+ LEFT JOIN #{permission_subjects_table_name}
340
+ ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id"
341
+ ).where("
342
+ (
343
+ #{permission_subjects_table_name}.#{subject_foreign_key} = ?
344
+ AND #{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
345
+ AND #{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?
346
+ )
347
+ OR
348
+ (
349
+ #{permission_roles_table_name}.#{role_foreign_key} IN (?)
350
+ AND #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
351
+ AND #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?
352
+ )",
353
+ id,
354
+ context.class_name,
355
+ context.id,
356
+ (proles || roles_for(context)).map(&:id),
357
+ context.class_name,
358
+ context.id)
359
+ end
360
+ end
361
+
362
+ def role_and_subject_permissions_for?(context, proles=nil)
363
+ !role_and_subject_permissions_for(context, proles).empty?
364
+ end
365
+
366
+ def role_and_subject_permissions_within(context, proles=nil)
367
+ auth_scope do
368
+ return permission_class.joins("
369
+ LEFT JOIN #{permission_roles_table_name}
370
+ ON #{permission_roles_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id
371
+ LEFT JOIN #{permission_subjects_table_name}
372
+ ON #{permission_subjects_table_name}.#{permission_foreign_key} = #{permissions_table_name}.id"
373
+ ).where("
374
+ (
375
+ #{permission_subjects_table_name}.#{subject_foreign_key} = ?
376
+ AND (
377
+ #{permission_subjects_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
378
+ OR #{permission_subjects_table_name}.context_type IS NULL
379
+ )
380
+ AND (
381
+ #{permission_subjects_table_name}.context_id #{sql_is_or_equal(context.id)} ?
382
+ OR #{permission_subjects_table_name}.context_id IS NULL
383
+ )
384
+ )
385
+ OR (
386
+ #{permission_roles_table_name}.#{role_foreign_key} IN (?)
387
+ AND (
388
+ #{permission_roles_table_name}.context_type #{sql_is_or_equal(context.class_name)} ?
389
+ OR #{permission_roles_table_name}.context_type IS NULL
390
+ )
391
+ AND (
392
+ #{permission_roles_table_name}.context_id #{sql_is_or_equal(context.id)} ?
393
+ OR #{permission_roles_table_name}.context_id IS NULL
394
+ )
395
+ )",
396
+ id,
397
+ context.class_name,
398
+ context.id,
399
+ (proles || roles_for(context)).map(&:id),
400
+ context.class_name,
401
+ context.id)
402
+ end
403
+ end
404
+
405
+ def role_and_subject_permissions_within?(context, proles=nil)
406
+ !role_and_subject_permissions_within(context, proles).empty?
407
+ end
408
+
235
409
  end
236
410
  end
237
411
  end