permissable 0.0.3 → 0.1.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/VERSION +1 -1
- data/lib/permissable/member.rb +33 -76
- data/lib/permissable/permission.rb +5 -14
- data/lib/permissable/resource.rb +1 -12
- data/lib/permissable.rb +55 -38
- data/permissable-0.0.3.gem +0 -0
- data/permissable.gemspec +3 -2
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/permissable/member.rb
CHANGED
@@ -4,94 +4,51 @@ module Permissable
|
|
4
4
|
|
5
5
|
def self.included(base)
|
6
6
|
base.send :include, InstanceMethods
|
7
|
-
|
8
|
-
member_klass.class_eval do
|
9
|
-
has_many :permissions, :as => :member, :conditions => { :member_type => "#{self.to_s}" }
|
10
|
-
end
|
11
|
-
base.send :include, ((base.permissable_by_association) ? AssociatedMethods : MemberMethods)
|
7
|
+
base.send :attr_protected, :member_identifier
|
12
8
|
end
|
13
|
-
|
9
|
+
|
14
10
|
# This module includes methods that should exist on ALL members.
|
15
11
|
module InstanceMethods
|
16
12
|
|
17
|
-
#
|
18
|
-
# Once loaded all of the permission definitions are cached into the @permission_definitions variable.
|
19
|
-
attr_accessor :permission_definitions
|
20
|
-
|
21
|
-
# Can this member perform the requested action?
|
13
|
+
# The can? method returns a boolen value specifying whether or not this member can perform the specific method on resource
|
22
14
|
def can?(method, resource)
|
23
|
-
|
24
|
-
permissions.for_resource(resource).with_permission_to(method).exists?
|
25
|
-
end
|
26
|
-
|
27
|
-
# Set a permission
|
28
|
-
def can!(methods, resource)
|
29
|
-
methods = [methods].flatten.uniq
|
30
|
-
|
31
|
-
members.each do |member|
|
32
|
-
methods.each do |perm|
|
33
|
-
next if resource.permissions.for_member(member).with_permission_to(perm).exists?
|
34
|
-
new_permission = Permission.new({ :permission_type => method.to_s })
|
35
|
-
new_permission.member = m
|
36
|
-
new_permission.resource = resource
|
37
|
-
new_permission.save
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def cannot?(methods, resource)
|
43
|
-
!can?(methods, resource)
|
44
|
-
end
|
45
|
-
|
46
|
-
def cannot!(methods, resources)
|
47
|
-
methods = [methods].flatten.uniq
|
48
|
-
existing = permissions.for_resource(resource).with_permission_to(methods).all.collect{ |perm| perm.id }.uniq
|
49
|
-
Permission.destroy(existing)
|
50
|
-
end
|
51
|
-
|
52
|
-
def permissions_for(resource)
|
53
|
-
permissions.for_resource(resource).all.collect{ |p| p.permission_type.to_sym }.uniq
|
54
|
-
end
|
55
|
-
|
56
|
-
def permissions_for?(resource)
|
57
|
-
!permissions_for(resource).empty?
|
15
|
+
permissions_for(resource, method).exists?
|
58
16
|
end
|
59
17
|
|
60
|
-
|
18
|
+
# Alias to can? to get the inverse.
|
19
|
+
def cannot?(method, resource); !can?(method, resource); end
|
61
20
|
|
62
|
-
def get_const(resource)
|
63
|
-
resource.class.to_s.classify.constantize
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
# This module gets included on member classes that are permissable directly.
|
69
|
-
module MemberMethods
|
70
|
-
alias_attribute :member_id, :id
|
71
|
-
def members; [self]; end
|
72
|
-
end
|
73
|
-
|
74
|
-
# This module gets included on member classes that are permissable with an association.
|
75
|
-
module AssociatedMethods
|
76
|
-
|
77
|
-
attr_reader :permissions
|
78
|
-
attr_reader :member_id
|
79
|
-
|
80
|
-
def permissions
|
81
|
-
return @permissions unless @permissions.nil?
|
82
|
-
@permissions = Permission.where(:member_id => member_id, :member_type => association.to_s)
|
83
|
-
end
|
84
21
|
|
85
|
-
|
86
|
-
|
22
|
+
# This sets the member information for our permission lookup based on the current resource scope.
|
23
|
+
# These attributes correspond to the correct member_id and member_type in our permissions table.
|
24
|
+
def member_identifier(scope)
|
25
|
+
|
26
|
+
@member_identifier ||= {}
|
27
|
+
# The scope should be the classname of a resource we are getting identifiers for
|
28
|
+
scope = scope.to_s.classify
|
29
|
+
|
30
|
+
return @member_identifier[scope] unless @member_identifier[scope].nil?
|
31
|
+
return { :member_id => self.id, :member_type => self.class.to_s } unless permissable_associations.has_key?(scope)
|
32
|
+
|
33
|
+
assoc_key = permissable_associations[scope]
|
34
|
+
assoc = send "#{assoc_key}".to_sym
|
35
|
+
|
36
|
+
@member_identifier[scope] = { :member_id => (assoc.is_a?(Array) ? assoc.collect{ |a| a.id } : assoc.id ), :member_type => assoc_key.to_s.classify }
|
37
|
+
|
87
38
|
end
|
39
|
+
|
40
|
+
# Provide an instance method to our associations
|
41
|
+
def permissable_associations; self.class.permissable_associations; end
|
88
42
|
|
89
|
-
|
90
|
-
@member_id || association.all.collect{ |a| a.attributes['id'] }
|
91
|
-
end
|
43
|
+
private
|
92
44
|
|
93
|
-
|
94
|
-
|
45
|
+
# Looks up permissions for a particular resource.
|
46
|
+
def permissions_for(resource, methods = nil)
|
47
|
+
scope = resource.class.to_s.classify
|
48
|
+
return self.permissions unless permissable_associations.has_key?(scope)
|
49
|
+
relation = Permission.where(member_identifier(scope)).for_resource(resource)
|
50
|
+
relation = relation.with_permission_to(methods) unless methods.nil?
|
51
|
+
relation
|
95
52
|
end
|
96
53
|
|
97
54
|
end
|
@@ -3,28 +3,19 @@ class Permission < ActiveRecord::Base
|
|
3
3
|
belongs_to :resource, :polymorphic => true
|
4
4
|
|
5
5
|
class << self
|
6
|
-
def for_member(member)
|
7
|
-
member = flatten(member)
|
8
|
-
where(:member_id => member[:ids], :member_type => member[:types])
|
9
|
-
end
|
10
6
|
|
11
7
|
def for_resource(resource)
|
12
8
|
resource = flatten(resource)
|
13
|
-
where(
|
14
|
-
end
|
15
|
-
|
16
|
-
def for_member_and_resource(member, resource)
|
17
|
-
for_member(member).for_resource(resource)
|
9
|
+
where(resource)
|
18
10
|
end
|
19
11
|
|
20
|
-
def with_permission_to(
|
21
|
-
|
22
|
-
where(:permission_type => perm)
|
12
|
+
def with_permission_to(methods)
|
13
|
+
where(:permission_type => [methods].flatten.uniq.collect{ |m| m.to_s.downcase })
|
23
14
|
end
|
24
15
|
|
25
16
|
def flatten(obj)
|
26
|
-
return { :
|
27
|
-
{ :
|
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 } }
|
28
19
|
end
|
29
20
|
|
30
21
|
end
|
data/lib/permissable/resource.rb
CHANGED
@@ -3,19 +3,8 @@ module Permissable
|
|
3
3
|
module Resource
|
4
4
|
|
5
5
|
def self.included(base)
|
6
|
-
base.class_eval{ has_many(:permissions, :as => :resource, :conditions => { :resource_type => "#{self.to_s}" }) }
|
7
|
-
base.extend(ClassMethods)
|
8
6
|
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
private
|
12
|
-
def set_permissions!(permission_list)
|
13
|
-
class_inheritable_accessor :permissable_methods
|
14
|
-
write_inheritable_attribute(:permissable_methods, []) if permissable_methods.nil?
|
15
|
-
permissable_methods.concat permission_list.uniq.flatten
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
7
|
+
|
19
8
|
end
|
20
9
|
|
21
10
|
end
|
data/lib/permissable.rb
CHANGED
@@ -3,13 +3,10 @@
|
|
3
3
|
# License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
|
4
4
|
#
|
5
5
|
# Permissable creates the ability to add a permissions system to "resources" based on a "member".
|
6
|
-
# It allows you to define a member using the +
|
6
|
+
# It allows you to define a member using the +has_permissions_for+ method:
|
7
7
|
#
|
8
8
|
# class User < ActiveRecord::Base
|
9
|
-
#
|
10
|
-
# configure.permission_for :read, :posts, :categories
|
11
|
-
# configure.permission_for [:read, :write, :moderate], :comments
|
12
|
-
# end
|
9
|
+
# has_permissions_for [:section, :category, :entry], :to => [:read, :write, :moderate]
|
13
10
|
# end
|
14
11
|
#
|
15
12
|
# Permissable uses a single "permissions" table (and subsuquently a Permission model), with a polymorphic relationship
|
@@ -32,7 +29,7 @@ module Permissable
|
|
32
29
|
class PermissableError < StandardError
|
33
30
|
end
|
34
31
|
|
35
|
-
class PermissionNotDefined < PermissableError
|
32
|
+
class PermissionNotDefined < PermissableError
|
36
33
|
end
|
37
34
|
|
38
35
|
class ResourceNotPermissable < PermissableError
|
@@ -40,45 +37,65 @@ module Permissable
|
|
40
37
|
|
41
38
|
module ClassMethods
|
42
39
|
|
43
|
-
# +
|
44
|
-
# it specifies. It
|
40
|
+
# +has_permissions_for+ gives the class its called on the ability to effect various permission states on the resources
|
41
|
+
# it specifies. It requires two parameters, a resource or array of resources to add permissions to, and an options
|
42
|
+
# hash with instructions of how to handle the permissions.
|
43
|
+
# The options hash consists of the following keys, but only the :to key is required.
|
45
44
|
#
|
46
|
-
# *
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
|
45
|
+
# * +to+: This is a permission or array of permissions allowed. You can use any number of values
|
46
|
+
# and those values can be whatever you want. You must include at least one.
|
47
|
+
#
|
48
|
+
# * +through+: Allows you to scope permissions through one of the member's associations. For example, if your member is
|
49
|
+
# a User, and that user has_many Roles, you could set permissions :through => :roles. When looking up permissions
|
50
|
+
# Permissable will use the association instead of the main member object. This also applies to setting permissions.
|
51
|
+
# NOTE: The :through option uses the same value as your assocation. If the association is a has_many, the value will be
|
52
|
+
# plural. Likewise belongs_to or has_one associations will be singular. The best way to think of this is that the
|
53
|
+
# :through attribute would be exactly the same as the method you would call on your model to find its associations.
|
54
|
+
#
|
55
|
+
def has_permissions_for(resources, options = {})
|
56
|
+
raise Permissable::PermissionNotDefined, "has_permissions_for missing the :to option." unless options.has_key?(:to) and !options[:to].empty?
|
52
57
|
|
53
|
-
write_inheritable_attribute
|
54
|
-
|
58
|
+
write_inheritable_attribute(:permissable_associations, {}) if permissable_associations.nil?
|
59
|
+
resources = [resources].flatten
|
55
60
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
61
|
+
resources.each do |resource|
|
62
|
+
resource = resource.to_s.classify
|
63
|
+
|
64
|
+
# If there is an association on these resources, add those to our associations attribute
|
65
|
+
# so our classes and sub classes will know about it.
|
66
|
+
if options.has_key?(:through)
|
67
|
+
|
68
|
+
permissable_associations[resource] = options[:through]
|
69
|
+
assoc = options[:through].to_s.classify.constantize
|
70
|
+
|
71
|
+
# Our association also creates a has_many association on our permissions table.
|
72
|
+
assoc.class_eval do
|
73
|
+
has_many(:permissions, :as => :member, :conditions => { :member_type => "#{self.to_s}" }) unless respond_to? :permissions
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
# Setup a has_many association of permissions on our resource.
|
79
|
+
resource.constantize.class_eval do
|
80
|
+
include Permissable::Resource
|
81
|
+
has_many(:permissions, :as => :resource, :conditions => { :resource_type => "#{self.to_s}" }) unless respond_to? :permissions
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
# This class becomes a member to resources.
|
60
87
|
include Permissable::Member
|
61
88
|
|
62
|
-
#
|
63
|
-
|
89
|
+
# Members create a has_many association on permissions as a member.
|
90
|
+
has_many(:permissions, :as => :member, :conditions => { :member_type => "#{self.to_s}" }) unless respond_to? :permissions
|
64
91
|
|
65
|
-
end
|
92
|
+
end
|
66
93
|
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# Add each resource to the member class' permissions list.
|
73
|
-
has_permissions_for.concat(resources).flatten.uniq
|
74
|
-
|
75
|
-
resources.uniq.each do |resource|
|
76
|
-
#Include the Resource module to each resource class.
|
77
|
-
resource.to_s.classify.constantize.class_eval{ include Permissable::Resource }
|
78
|
-
resource.to_s.classify.constantize.send :set_permissions!, methods
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
94
|
+
# Each time has_permissions_for is called, different associations may exist.
|
95
|
+
# This provides a way to store and update them all as necessary.
|
96
|
+
def permissable_associations
|
97
|
+
read_inheritable_attribute(:permissable_associations)
|
98
|
+
end
|
82
99
|
|
83
100
|
end
|
84
101
|
end
|
Binary file
|
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.0
|
8
|
+
s.version = "0.1.0"
|
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-07-
|
12
|
+
s.date = %q{2010-07-26}
|
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 = [
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
"lib/permissable/member.rb",
|
29
29
|
"lib/permissable/permission.rb",
|
30
30
|
"lib/permissable/resource.rb",
|
31
|
+
"permissable-0.0.3.gem",
|
31
32
|
"permissable.gemspec",
|
32
33
|
"test/helper.rb",
|
33
34
|
"test/test_permissable.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:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.3
|
10
|
+
version: 0.1.0
|
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-07-
|
18
|
+
date: 2010-07-26 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- lib/permissable/member.rb
|
54
54
|
- lib/permissable/permission.rb
|
55
55
|
- lib/permissable/resource.rb
|
56
|
+
- permissable-0.0.3.gem
|
56
57
|
- permissable.gemspec
|
57
58
|
- test/helper.rb
|
58
59
|
- test/test_permissable.rb
|