permissable 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.2.2
data/lib/permissable.rb CHANGED
@@ -15,6 +15,7 @@
15
15
  require 'permissable/member'
16
16
  require 'permissable/permission'
17
17
  require 'permissable/resource'
18
+ require 'permissable/permissions_cache'
18
19
 
19
20
  module Permissable
20
21
 
@@ -22,7 +23,13 @@ module Permissable
22
23
 
23
24
  def included(base)
24
25
  base.extend ClassMethods
25
- end
26
+ end
27
+
28
+ # Creates a hash from a resource to be used in a where context.
29
+ def flatten_resource(obj)
30
+ return { :resource_id => obj.id, :resource_type => obj.base_class.to_s } unless obj.is_a?(Array)
31
+ { :resource_id => obj.collect{ |o| o.id }, :resource_type => obj.collect{ |o| o.base_class.to_s } }
32
+ end
26
33
 
27
34
  end
28
35
 
@@ -71,21 +78,20 @@ module Permissable
71
78
 
72
79
  # Our association also creates a has_many association on our permissions table.
73
80
  assoc.class_eval do
74
- has_many(:permissions, :as => :member, :conditions => { :member_type => "#{self.to_s}" }), :dependent => :destroy unless respond_to? :permissions
81
+ has_many(:permissions, :as => :member, :dependent => :destroy) unless respond_to? :permissions
75
82
  include Permissable::Member
76
- class_inheritable_accessor :permission_types
77
- write_inheritable_attribute(:permissable_associations, {})
83
+ class_inheritable_accessor :permissable_types
84
+ self.send :permissable_types=, options[:to]
78
85
  write_inheritable_attribute(:permissable_options, {}) if permissable_options.nil?
79
86
  permissable_options[:allow_permission_with_method] = options[:allow_with] if options.has_key?(:allow_with)
80
- permissable_options[:permission_chain] = options[:chain] if options.has_key?(:chain)
81
- self.send :permission_types=, options[:to]
87
+ permissable_options[:permission_chain] = options[:chain] if options.has_key?(:chain)
82
88
  end
83
89
 
84
90
  end
85
91
 
86
92
  # Setup a has_many association of permissions on our resource.
87
93
  resource.constantize.class_eval do
88
- has_many(:permissions, :as => :resource, :conditions => { :resource_type => "#{self.to_s}" }), :dependent => :destroy unless respond_to? :permissions
94
+ has_many(:permissions, :as => :resource, :dependent => :destroy) unless respond_to? :permissions
89
95
  end
90
96
 
91
97
  resource.constantize.instance_eval{ include Permissable::Resource }
@@ -97,11 +103,13 @@ module Permissable
97
103
 
98
104
  # This class becomes a member to resources.
99
105
  include Permissable::Member
100
- class_inheritable_accessor :permission_types
101
- self.send :permission_types=, options[:to]
106
+ class_inheritable_accessor :permissable_types
107
+ class_inheritable_accessor :permissable_resources
108
+ self.send :permissable_types=, options[:to]
109
+ self.send :permissable_resources=, resources
102
110
 
103
111
  # Members create a has_many association on permissions as a member.
104
- has_many(:permissions, :as => :member, :conditions => { :member_type => "#{self.to_s}" }), :dependent => :destroy unless respond_to? :permissions
112
+ has_many(:permissions, :as => :member, :dependent => :destroy) unless respond_to? :permissions
105
113
 
106
114
  end
107
115
 
@@ -5,22 +5,28 @@ module Permissable
5
5
  def self.included(base)
6
6
  base.send :include, InstanceMethods
7
7
  base.send :attr_protected, :member_identifier
8
- base.send :attr_protected, :permissable_lookups
8
+ base.send :attr_protected, :permissions_cache
9
+ base.send :attr_protected, :association_scopes
9
10
  end
10
11
 
11
12
  # This module includes methods that should exist on ALL members.
12
13
  module InstanceMethods
13
14
 
14
15
  # The can? method returns a boolen value specifying whether or not this member can perform the specific method on resource
15
- def can?(methods, resource)
16
+ def can?(methods, resource, chain = true)
16
17
  unless allow_permission_with_method.nil?
17
18
  if self.respond_to? "#{allow_permission_with_method}"
18
19
  return true if (send "#{allow_permission_with_method}")
19
20
  end
20
21
  end
21
- methods = [methods].flatten.collect{ |m| m.to_sym }
22
- methods = find_methods_from_chain(methods)
23
- permissions_for(resource, methods).exists?
22
+
23
+ if chain
24
+ methods = [methods].flatten.collect{ |m| m.to_sym }
25
+ methods = find_methods_from_chain(methods)
26
+ end
27
+
28
+ permissions_for?(resource, methods)
29
+
24
30
  end
25
31
 
26
32
  # Alias to can? to get the inverse.
@@ -33,7 +39,7 @@ module Permissable
33
39
 
34
40
  # This method should return all of the new permissions that were created, so we build a
35
41
  # response array to return
36
- response = []
42
+ result_response = []
37
43
 
38
44
  [resources].flatten.each do |resource|
39
45
 
@@ -46,19 +52,19 @@ module Permissable
46
52
 
47
53
  [methods].flatten.each do |method|
48
54
  # Permission already exists, continue.
49
- next if can?(method, resource)
55
+ next if can?(method, resource, false)
50
56
 
51
57
  # Create a new permission for each member (once if its self, multiple times if its associated)
52
58
  [identifier[:member_id]].flatten.each do |member_id|
53
59
  perm = Permission.new(:member_id => member_id, :member_type => identifier[:member_type], :permission_type => method.to_s.downcase)
54
60
  perm.resource = resource
55
61
  perm.save
56
- response << perm
62
+ result_response << perm
57
63
  end
58
64
  end
59
65
  end
60
66
 
61
- (response.size == 1) ? response.first : response
67
+ (result_response.size == 1) ? result_response.first : result_response
62
68
 
63
69
  end
64
70
 
@@ -72,20 +78,30 @@ module Permissable
72
78
  return @member_identifier[scope] unless @member_identifier[scope].nil?
73
79
  return { :member_id => self.id, :member_type => self.class.to_s } unless permissable_associations.has_key?(scope)
74
80
 
81
+ @association_scopes ||= {}
75
82
  assoc_key = permissable_associations[scope]
76
- assoc = send "#{assoc_key}".to_sym
83
+ @association_scopes[assoc_key] ||= send("#{assoc_key}".to_sym)
84
+ assoc = @association_scopes[assoc_key]
77
85
 
78
86
  @member_identifier[scope] = { :member_id => (assoc.is_a?(Array) ? assoc.collect{ |a| a.id } : assoc.id ), :member_type => assoc_key.to_s.classify }
79
87
 
80
88
  end
81
89
 
82
90
  # Provide an instance method to our associations
83
- def permissable_associations; self.class.permissable_associations; end
91
+ def permissable_associations; self.class.permissable_associations || {}; end
84
92
  # Find our permission override if available
85
93
  def allow_permission_with_method; self.class.permissable_options[:allow_permission_with_method]; end
86
94
  # See if there is a permissions chain
87
95
  def permission_chain; self.class.permissable_options[:permission_chain] || {}; end
88
96
 
97
+ def permissions_for(resource)
98
+ fetch_permissions_for(resource).all.collect{ |perm| perm.permission_type.to_sym }
99
+ end
100
+
101
+ def lookup_permissions!
102
+ @permissions_cache = PermissionsCache.new(Permission.where(:resource_type => self.class.permissable_resources.collect{ |r| r.to_s.classify }).all)
103
+ end
104
+
89
105
  private
90
106
 
91
107
  def find_methods_from_chain(methods)
@@ -106,12 +122,28 @@ module Permissable
106
122
  end
107
123
 
108
124
  # Looks up permissions for a particular resource.
109
- def permissions_for(resource, methods = nil)
125
+ def fetch_permissions_for(resource, methods = nil)
110
126
  scope = fetch_scope(resource)
111
- return self.permissions.with_permission_to(methods) unless permissable_associations.has_key?(scope)
112
- relation = Permission.where(member_identifier(scope)).for_resource(resource)
127
+
128
+ lookup_with = is_cached? ? @permissions_cache : Permission
129
+ relation = lookup_with.for_member(member_identifier(scope)).for_resource(resource)
113
130
  relation = relation.with_permission_to(methods) unless methods.nil?
114
- relation
131
+ return relation
132
+
133
+ end
134
+
135
+ def fetch_scope(resource)
136
+ return resource if resource.is_a?(String)
137
+ (resource.is_a?(Class)) ? resource.to_s : resource.base_class.to_s.classify
138
+ end
139
+
140
+ # Look to see if we have a permissions cache.
141
+ def is_cached?
142
+ !@permissions_cache.nil?
143
+ end
144
+
145
+ def permissions_for?(resource, methods = nil)
146
+ fetch_permissions_for(resource, methods).exists?
115
147
  end
116
148
 
117
149
  # Returns the member responsible for this resource. This can either be an instance of self, or an instance or
@@ -121,11 +153,6 @@ module Permissable
121
153
  (permissable_associations.has_key?(scope)) ? send("#{permissable_associations[scope]}".to_sym) : self
122
154
  end
123
155
 
124
- def fetch_scope(resource)
125
- return resource if resource.is_a?(String)
126
- (resource.is_a?(Class)) ? resource.to_s : resource.class.to_s.classify
127
- end
128
-
129
156
  end
130
157
 
131
158
  end
@@ -5,17 +5,16 @@ class Permission < ActiveRecord::Base
5
5
  class << self
6
6
 
7
7
  def for_resource(resource)
8
- resource = flatten(resource)
8
+ resource = Permissable.flatten_resource(resource)
9
9
  where(resource)
10
10
  end
11
11
 
12
- def with_permission_to(methods)
13
- where(:permission_type => [methods].flatten.uniq.collect{ |m| m.to_s.downcase })
12
+ def for_member(member)
13
+ where(member)
14
14
  end
15
15
 
16
- def flatten(obj)
17
- return { :resource_id => obj, :resource_type => obj.class.to_s } unless obj.is_a?(Array)
18
- { :resource_id => obj.collect{ |o| o.id }, :resource_type => obj.collect{ |o| o.class.to_s } }
16
+ def with_permission_to(methods)
17
+ where(:permission_type => [methods].flatten.uniq.collect{ |m| m.to_s.downcase })
19
18
  end
20
19
 
21
20
  end
@@ -0,0 +1,68 @@
1
+ module Permissable
2
+
3
+ class PermissionsCache
4
+
5
+ attr_accessor :_permissions
6
+ attr_accessor :_query_results
7
+
8
+ def initialize(permission_list)
9
+ @_permissions = permission_list
10
+ @_query_results = nil
11
+ end
12
+
13
+ def for_member(member)
14
+ arr = create_result_array
15
+ @_query_results = arr.find_all do |perm|
16
+ (member.key?(:member_type) ? true : perm.member_type == member[:member_type]) && [member[:member_id]].flatten.uniq.include?(perm.member_id)
17
+ end
18
+
19
+ return self
20
+
21
+ end
22
+
23
+ def for_resource(resource)
24
+ arr = create_result_array
25
+ resource = Permissable.flatten_resource(resource)
26
+ @_query_results = arr.find_all do |perm|
27
+ [resource[:resource_id]].flatten.include?(perm.resource_id) && [resource[:resource_type]].flatten.include?(perm.resource_type)
28
+ end
29
+
30
+ return self
31
+
32
+ end
33
+
34
+ def with_permission_to(methods)
35
+ arr = create_result_array
36
+ @_query_results = arr.find_all do |perm|
37
+ [methods].flatten.collect{ |m| m.to_s }.include?(perm.permission_type)
38
+ end
39
+
40
+ return self
41
+
42
+ end
43
+
44
+ def all
45
+ results = @_query_results || []
46
+ @_query_results = nil
47
+ results
48
+ end
49
+
50
+ def exists?
51
+ results = @_query_results || []
52
+ @_query_results = nil
53
+ !results.empty?
54
+ end
55
+
56
+ private
57
+
58
+ def create_result_array
59
+ (@_query_results.nil?) ? permissions : @_query_results
60
+ end
61
+
62
+ def permissions
63
+ @_permissions
64
+ end
65
+
66
+ end
67
+
68
+ end
data/permissable.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{permissable}
8
- s.version = "0.2.1"
8
+ s.version = "0.2.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brent Kirby"]
12
- s.date = %q{2010-09-04}
12
+ s.date = %q{2010-09-05}
13
13
  s.description = %q{Permissable lets you set a number of 'permissions' to your database models. By assigning 'members' to 'resources' (models) you can specify various permission states.}
14
14
  s.email = %q{brent@kurbmedia.com}
15
15
  s.extra_rdoc_files = [
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
  "lib/permissable.rb",
28
28
  "lib/permissable/member.rb",
29
29
  "lib/permissable/permission.rb",
30
+ "lib/permissable/permissions_cache.rb",
30
31
  "lib/permissable/resource.rb",
31
32
  "permissable.gemspec",
32
33
  "test/helper.rb",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: permissable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 2
10
+ version: 0.2.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brent Kirby
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-04 00:00:00 -04:00
18
+ date: 2010-09-05 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -52,6 +52,7 @@ files:
52
52
  - lib/permissable.rb
53
53
  - lib/permissable/member.rb
54
54
  - lib/permissable/permission.rb
55
+ - lib/permissable/permissions_cache.rb
55
56
  - lib/permissable/resource.rb
56
57
  - permissable.gemspec
57
58
  - test/helper.rb