cancan-permits 0.3.4 → 0.3.5

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.
@@ -6,7 +6,12 @@ Role specific Permits for use with [CanCan](http://github.com/ryanb/cancan) perm
6
6
 
7
7
  See Changelog.txt (Major updates as per Nov 24. 2010)
8
8
 
9
- Nov 28: Added Generators to create individual Permit and License!
9
+ Nov 28:
10
+ Added Generators to create individual Permit and License!
11
+
12
+ Nov 29:
13
+ Added ability to specify YAML files with configurations for Permits, Licenses and even Permissions for individual users.
14
+ Thanks to 'ticktricktrack' for the request and suggestion. (I hope you can use this and move on from here...)
10
15
 
11
16
  ## Install
12
17
 
@@ -49,6 +54,84 @@ Modify the User model in 'models/user.rb' (optional)
49
54
  end
50
55
  </code>
51
56
 
57
+ ### Load Permissions from yml files
58
+
59
+ *Individual user permissions:*
60
+ - config/user_permissions.yml
61
+
62
+ Each key at the top level is expected to match an email value for an existing user.
63
+
64
+ Example yml config file:
65
+ <code>
66
+ abc@mail.ru:
67
+ can:
68
+ update: [Comment, Fruit, Car, Friendship]
69
+ manage:
70
+ - Article
71
+ owns:
72
+ - User
73
+ mike.shedlock.com:
74
+ can:
75
+ read:
76
+ - all
77
+ cannot:
78
+ update:
79
+ - Post
80
+ </code>
81
+
82
+ Usage in a permit
83
+
84
+ <code>
85
+ class AdminPermit < Permit::Base
86
+ def initialize(ability, options = {})
87
+ super
88
+ end
89
+
90
+ def permit?(user, options = {})
91
+ super
92
+ return if !role_match? user
93
+ can :manage, :all
94
+ load_rules user
95
+ end
96
+ end
97
+ </code>
98
+
99
+
100
+ *License permissions:*
101
+ - config/licenses.yml
102
+
103
+ Each key at the top level is expected to match a license name.
104
+
105
+ Example yml config file:
106
+ <code>
107
+ blogging:
108
+ can:
109
+ manage:
110
+ - Article
111
+ - Post
112
+ admin:
113
+ can:
114
+ manage:
115
+ - all
116
+ cannot:
117
+ manage:
118
+ - User
119
+ </code>
120
+
121
+ Usage in a license
122
+
123
+ <code>
124
+ class UserAdminLicense < License::Base
125
+ def initialize name
126
+ super
127
+ end
128
+
129
+ def enforce!
130
+ can(:manage, User)
131
+ load_rules
132
+ end
133
+ </code>
134
+
52
135
  ### User Roles
53
136
 
54
137
  CanCan permits requires that you have some kind of Role system in place and that User#has_role? uses this Role system.
@@ -94,7 +177,6 @@ Permit example:
94
177
  def permit?(user, options = {})
95
178
  super
96
179
  return if !role_match? user
97
-
98
180
  can :manage, :all
99
181
  end
100
182
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.4
1
+ 0.3.5
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cancan-permits}
8
- s.version = "0.3.4"
8
+ s.version = "0.3.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kristian Mandrup"]
12
- s.date = %q{2010-11-28}
12
+ s.date = %q{2010-11-29}
13
13
  s.description = %q{Role specific Permits for use with CanCan permission system}
14
14
  s.email = %q{kmandrup@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -28,6 +28,9 @@ Gem::Specification.new do |s|
28
28
  "development.sqlite3",
29
29
  "lib/cancan-permits.rb",
30
30
  "lib/cancan-permits/license/base_license.rb",
31
+ "lib/cancan-permits/loader/permission_config.rb",
32
+ "lib/cancan-permits/loader/permissions_loader.rb",
33
+ "lib/cancan-permits/loader/permissions_parser.rb",
31
34
  "lib/cancan-permits/main.rb",
32
35
  "lib/cancan-permits/namespaces.rb",
33
36
  "lib/cancan-permits/permit/base_permit.rb",
@@ -59,6 +62,10 @@ Gem::Specification.new do |s|
59
62
  "spec/active_record/owner_permits_spec.rb",
60
63
  "spec/active_record/permits_spec.rb",
61
64
  "spec/active_record/spec_helper.rb",
65
+ "spec/cancan-permits/license_loader/license_loader_spec.rb",
66
+ "spec/cancan-permits/license_loader/licenses.yml",
67
+ "spec/cancan-permits/user_permissions_loader/user_permissions.yml",
68
+ "spec/cancan-permits/user_permissions_loader/user_permissions_loader.rb",
62
69
  "spec/data_mapper/models/all_models.rb",
63
70
  "spec/data_mapper/owner_permits_spec.rb",
64
71
  "spec/data_mapper/permits_spec.rb",
@@ -111,6 +118,8 @@ Gem::Specification.new do |s|
111
118
  "spec/active_record/owner_permits_spec.rb",
112
119
  "spec/active_record/permits_spec.rb",
113
120
  "spec/active_record/spec_helper.rb",
121
+ "spec/cancan-permits/license_loader/license_loader_spec.rb",
122
+ "spec/cancan-permits/user_permissions_loader/user_permissions_loader.rb",
114
123
  "spec/data_mapper/models/all_models.rb",
115
124
  "spec/data_mapper/owner_permits_spec.rb",
116
125
  "spec/data_mapper/permits_spec.rb",
@@ -1,14 +1,31 @@
1
+ require 'yaml'
2
+
1
3
  module License
2
4
  class Base
3
- attr_reader :permit
5
+ attr_reader :permit, :licenses
4
6
 
5
- def initialize permit
7
+ def initialize permit, licenses_file = nil
6
8
  @permit = permit
9
+ @licenses = ::PermissionsLoader.load_licenses licenses_file
7
10
  end
8
11
 
9
12
  def enforce!
10
13
  raise "enforce! must be implemented by subclass of License::Base"
11
14
  end
15
+
16
+ def load_rules name = nil
17
+ return if !licenses || licenses.empty?
18
+
19
+ name ||= self.class.to_s..gsub(/License$/, "").underscore.to_sym
20
+
21
+ licenses[name].can_statement do |permission_statement|
22
+ instance_eval permission_statement
23
+ end
24
+
25
+ licenses[name].cannot_statement do |permission_statement|
26
+ instance_eval permission_statement
27
+ end
28
+ end
12
29
 
13
30
  def can(action, subject, conditions = nil, &block)
14
31
  permit.can action, subject, conditions, &block
@@ -0,0 +1,41 @@
1
+ class PermissionConfig
2
+ attr_accessor :name, :can, :cannot
3
+
4
+ def initialize name
5
+ @name = name
6
+ end
7
+
8
+ # Should take @can={"manage"=>["all"]}, @cannot={"update"=>["User", "Profile"]}
9
+ # and create string ready to ruby evaluate like:
10
+ # can(:manage, :all)
11
+ # cannot(:update, [User, Profile])
12
+ def can_eval &block
13
+ statements = [:manage, :read, :update, :create, :write].map do |action|
14
+ targets = can[action]
15
+ targets ? "can(:#{action}, #{parse_targets(targets)})" : nil
16
+ end.compact.join("\n")
17
+ yield statements if !statements.empty? && block
18
+ end
19
+
20
+ def can_eval &block
21
+ statements = [:manage, :read, :update, :create, :write].map do |action|
22
+ targets = cannot[action]
23
+ targets ? "cannot(:#{action}, #{parse_targets(targets)})" : nil
24
+ end.compact.join("\n")
25
+ yield statements if !statements.empty? && block
26
+ end
27
+
28
+ def parse_targets targets
29
+ targets.map do |target|
30
+ if target == 'all'
31
+ ':all'
32
+ else
33
+ begin
34
+ "#{target.constantize}"
35
+ rescue
36
+ puts "[permission] target #{target} does not have a class so it was skipped"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ class PermissionsLoader
2
+
3
+ attr_accessor :permissions
4
+
5
+ def initialize file_name
6
+ begin
7
+ if file_name.nil? || !File.file?(file_name)
8
+ # raise ArgumentError, "PermissionsLoader Error: The permissions file #{file_name} could not be found"
9
+ puts "PermissionsLoader Error: The permissions file #{file_name} could not be found"
10
+ return nil
11
+ end
12
+
13
+ yml_content = YAML.load_file(file_name)
14
+ parser = PermissionsParser.new
15
+
16
+ self.permissions ||= {}
17
+ yml_content.each do |key, value|
18
+ parser.parse(key, value) do |permission|
19
+ permissions[permission.name] = permission
20
+ end
21
+ end
22
+ rescue RuntimeError => e
23
+ raise "PermissionsLoader Error: The permissions for the file #{file_name} could not be loaded - cause was #{e}"
24
+ end
25
+ end
26
+
27
+ def self.load_user_permissions name = nil
28
+ name ||= user_permissions_config_file
29
+ PermissionsLoader.new name
30
+ end
31
+
32
+ def self.load_licenses name = nil
33
+ name ||= licenses_config_file
34
+ PermissionsLoader.new name
35
+ end
36
+
37
+ def self.user_permissions_config_file
38
+ # raise '#user_permissions_config_file only works in a Rails app enviroment' if !defined? Rails
39
+ File.join(::Rails.root, 'config', 'user_permissions.yml') if defined? Rails
40
+ end
41
+
42
+ def self.licenses_config_file
43
+ # raise '#licenses_config_file only works in a Rails app enviroment' if !defined? Rails
44
+ File.join(::Rails.root, 'config', 'licenses.yml') if defined? Rails
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ class PermissionsParser
2
+ def initialize
3
+ end
4
+
5
+ def parse(key, obj, &blk)
6
+ license = ::PermissionConfig.new key
7
+ case obj
8
+ when Hash
9
+ parse_permission(obj, license, &blk)
10
+ else
11
+ raise "Each key must have a YAML hash that defines its permission configuration"
12
+ end
13
+ yield license if blk
14
+ end
15
+
16
+ protected
17
+
18
+ def parse_permission(obj, license, &blk)
19
+ # Forget keys because I don't know what to do with them
20
+ obj.each do |key, value|
21
+ raise ArgumentError, "A CanCan license can only have the keys can: and cannot:" if ![:can, :cannot].include?(key.to_sym)
22
+ license.send :"#{key}=", value
23
+ end
24
+ end
25
+ end
@@ -1,4 +1,5 @@
1
1
  require 'cancan-permits/namespaces'
2
2
  require_all File.dirname(__FILE__) + '/permit'
3
3
  require_all File.dirname(__FILE__) + '/permits'
4
- require_all File.dirname(__FILE__) + '/license'
4
+ require_all File.dirname(__FILE__) + '/license'
5
+ require_all File.dirname(__FILE__) + '/loader'
@@ -6,6 +6,8 @@ module Permit
6
6
  attr_reader :ability
7
7
  attr_reader :strategy # this can be used to customize the strategy used by owns to determine ownership, fx to support alternative ORMs
8
8
 
9
+ attr_reader :user_permissions
10
+
9
11
  def licenses *names
10
12
  names.to_strings.each do |name|
11
13
  begin
@@ -22,10 +24,27 @@ module Permit
22
24
  end
23
25
  end
24
26
  end
27
+
28
+ def load_rules user
29
+ return if !user_permissions || user_permissions.empty?
30
+ raise "#load_enforcements expects the user to have an email property: #{user.inspect}" if !user || !user.respond_to?(:email)
31
+
32
+ id = user.email
33
+ return nil if id.strip.empty?
34
+
35
+ user_permissions[id].can_statement do |permission_statement|
36
+ instance_eval permission_statement
37
+ end
38
+
39
+ user_permissions[id].cannot_statement do |permission_statement|
40
+ instance_eval permission_statement
41
+ end
42
+ end
25
43
 
26
44
  def initialize ability, options = {}
27
45
  @ability = ability
28
46
  @strategy = options[:strategy] || Permits::Ability.strategy || :default
47
+ @user_permissions = ::PermissionsLoader.load_user_permissions options[:permissions_file]
29
48
  end
30
49
 
31
50
  def permit?(user, options = {})
@@ -0,0 +1,28 @@
1
+ require 'rspec/core'
2
+ require 'cancan-permits'
3
+
4
+ DIR = File.dirname(__FILE__)
5
+
6
+ describe 'Load License permissions' do
7
+ before :each do
8
+ @permissions_file = File.join(DIR, 'licenses.yml')
9
+ end
10
+
11
+ it "should load a licenses permission file" do
12
+ loader = PermissionsLoader.new @permissions_file
13
+ # puts "loaded permissions #{loader.permissions}"
14
+ loader.permissions.should_not be_empty
15
+ end
16
+
17
+ it "should be able to instantiate a base license with permission file" do
18
+ License::Base.new 'x', @permissions_file
19
+ end
20
+
21
+ it "should be able to instantiate a base permit without permission file" do
22
+ Permit::Base.new 'x'
23
+ end
24
+ end
25
+
26
+
27
+
28
+
@@ -0,0 +1,12 @@
1
+ blogging:
2
+ can:
3
+ manage:
4
+ - Article
5
+ - Post
6
+ admin:
7
+ can:
8
+ manage:
9
+ - all
10
+ cannot:
11
+ manage:
12
+ - User
@@ -0,0 +1,14 @@
1
+ abc@mail.ru:
2
+ can:
3
+ update: [Comment, Fruit, Car, Friendship]
4
+ manage:
5
+ - Article
6
+ owns:
7
+ - User
8
+ mike.shedlock.com:
9
+ can:
10
+ read:
11
+ - all
12
+ cannot:
13
+ update:
14
+ - Post
@@ -0,0 +1,28 @@
1
+ require 'rspec/core'
2
+ require 'cancan-permits'
3
+
4
+ DIR = File.dirname(__FILE__)
5
+
6
+ describe 'User Permissions Loader' do
7
+ before :each do
8
+ @permissions_file = File.join(DIR, 'user_permissions.yml')
9
+ end
10
+
11
+ it "should load a user permissions file" do
12
+ loader = PermissionsLoader.new @permissions_file
13
+ # puts "loaded permissions #{loader.permissions}"
14
+ loader.permissions.should_not be_empty
15
+ end
16
+
17
+ it "should be able to instantiate a base permit with permission file" do
18
+ Permit::Base.new 'x', :permissions_file => @permissions_file
19
+ end
20
+
21
+ it "should be able to instantiate a base permit without permission file" do
22
+ Permit::Base.new 'x'
23
+ end
24
+ end
25
+
26
+
27
+
28
+
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 4
9
- version: 0.3.4
8
+ - 5
9
+ version: 0.3.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Kristian Mandrup
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-28 00:00:00 +01:00
17
+ date: 2010-11-29 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -173,6 +173,9 @@ files:
173
173
  - development.sqlite3
174
174
  - lib/cancan-permits.rb
175
175
  - lib/cancan-permits/license/base_license.rb
176
+ - lib/cancan-permits/loader/permission_config.rb
177
+ - lib/cancan-permits/loader/permissions_loader.rb
178
+ - lib/cancan-permits/loader/permissions_parser.rb
176
179
  - lib/cancan-permits/main.rb
177
180
  - lib/cancan-permits/namespaces.rb
178
181
  - lib/cancan-permits/permit/base_permit.rb
@@ -204,6 +207,10 @@ files:
204
207
  - spec/active_record/owner_permits_spec.rb
205
208
  - spec/active_record/permits_spec.rb
206
209
  - spec/active_record/spec_helper.rb
210
+ - spec/cancan-permits/license_loader/license_loader_spec.rb
211
+ - spec/cancan-permits/license_loader/licenses.yml
212
+ - spec/cancan-permits/user_permissions_loader/user_permissions.yml
213
+ - spec/cancan-permits/user_permissions_loader/user_permissions_loader.rb
207
214
  - spec/data_mapper/models/all_models.rb
208
215
  - spec/data_mapper/owner_permits_spec.rb
209
216
  - spec/data_mapper/permits_spec.rb
@@ -283,6 +290,8 @@ test_files:
283
290
  - spec/active_record/owner_permits_spec.rb
284
291
  - spec/active_record/permits_spec.rb
285
292
  - spec/active_record/spec_helper.rb
293
+ - spec/cancan-permits/license_loader/license_loader_spec.rb
294
+ - spec/cancan-permits/user_permissions_loader/user_permissions_loader.rb
286
295
  - spec/data_mapper/models/all_models.rb
287
296
  - spec/data_mapper/owner_permits_spec.rb
288
297
  - spec/data_mapper/permits_spec.rb