cancan-permits 0.1.4 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,6 +1,15 @@
1
1
  # CanCan Permits
2
2
 
3
- Role specific Permits for use with [CanCan](http://github.com/ryanb/cancan) permission system.
3
+ Role specific Permits for use with [CanCan](http://github.com/ryanb/cancan) permission system.
4
+
5
+ ## Update Oct 13
6
+
7
+ Now updated to support multiple ownership startegies so that alternative ORMs can be supported. Demonstrates how to use it with Mongoid, including specs to prove it!
8
+ Special thanks to Sam (yoda) for this inspiration and help in this regard :)
9
+
10
+ The generator has also been updated slightly to support this new strategy as of version 0.2.1.
11
+ In general, the new Permits API now uses an options hash to replace the old optional request parameter.
12
+ This design allows for better extensibility in the future if needed.
4
13
 
5
14
  ## Install
6
15
 
@@ -35,11 +44,11 @@ _Note:_ You might consider using the Permits generator in order to generate your
35
44
 
36
45
  <pre>
37
46
  class AdminPermit < Permit::Base
38
- def initialize(ability)
47
+ def initialize(ability, options = {})
39
48
  super
40
49
  end
41
50
 
42
- def permit?(user, request=nil)
51
+ def permit?(user, options = {})
43
52
  super
44
53
  return if !role_match? user
45
54
 
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ begin
11
11
  gem.add_development_dependency 'code-spec', "~> 0.2.5"
12
12
  gem.add_development_dependency 'rails-app-spec', "~> 0.2.14"
13
13
 
14
- gem.add_dependency 'cancan', "~> 1.3.2"
14
+ gem.add_dependency 'cancan', "~> 1.4.0"
15
15
  gem.add_dependency 'require_all', "~> 1.2.0"
16
16
  gem.add_dependency 'sugar-high', "~> 0.2.10"
17
17
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{cancan-permits}
8
- s.version = "0.1.4"
8
+ s.version = "0.2.1"
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-10-07}
12
+ s.date = %q{2010-10-13}
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 = [
@@ -48,6 +48,10 @@ Gem::Specification.new do |s|
48
48
  "spec/cancan-permits/permits/owner_permits_spec.rb",
49
49
  "spec/cancan-permits/permits/permits_spec.rb",
50
50
  "spec/generators/permit_generator_spec.rb",
51
+ "spec/mongoid/models/all_models.rb",
52
+ "spec/mongoid/owner_permits_spec.rb",
53
+ "spec/mongoid/permits_spec.rb",
54
+ "spec/mongoid/spec_helper.rb",
51
55
  "spec/spec_helper.rb"
52
56
  ]
53
57
  s.homepage = %q{http://github.com/kristianmandrup/cancan-permits}
@@ -63,6 +67,10 @@ Gem::Specification.new do |s|
63
67
  "spec/cancan-permits/permits/owner_permits_spec.rb",
64
68
  "spec/cancan-permits/permits/permits_spec.rb",
65
69
  "spec/generators/permit_generator_spec.rb",
70
+ "spec/mongoid/models/all_models.rb",
71
+ "spec/mongoid/owner_permits_spec.rb",
72
+ "spec/mongoid/permits_spec.rb",
73
+ "spec/mongoid/spec_helper.rb",
66
74
  "spec/spec_helper.rb"
67
75
  ]
68
76
 
@@ -74,14 +82,14 @@ Gem::Specification.new do |s|
74
82
  s.add_development_dependency(%q<rspec>, ["~> 2.0.0.beta.22"])
75
83
  s.add_development_dependency(%q<code-spec>, ["~> 0.2.5"])
76
84
  s.add_development_dependency(%q<rails-app-spec>, ["~> 0.2.14"])
77
- s.add_runtime_dependency(%q<cancan>, ["~> 1.3.2"])
85
+ s.add_runtime_dependency(%q<cancan>, ["~> 1.4.0"])
78
86
  s.add_runtime_dependency(%q<require_all>, ["~> 1.2.0"])
79
87
  s.add_runtime_dependency(%q<sugar-high>, ["~> 0.2.10"])
80
88
  else
81
89
  s.add_dependency(%q<rspec>, ["~> 2.0.0.beta.22"])
82
90
  s.add_dependency(%q<code-spec>, ["~> 0.2.5"])
83
91
  s.add_dependency(%q<rails-app-spec>, ["~> 0.2.14"])
84
- s.add_dependency(%q<cancan>, ["~> 1.3.2"])
92
+ s.add_dependency(%q<cancan>, ["~> 1.4.0"])
85
93
  s.add_dependency(%q<require_all>, ["~> 1.2.0"])
86
94
  s.add_dependency(%q<sugar-high>, ["~> 0.2.10"])
87
95
  end
@@ -89,7 +97,7 @@ Gem::Specification.new do |s|
89
97
  s.add_dependency(%q<rspec>, ["~> 2.0.0.beta.22"])
90
98
  s.add_dependency(%q<code-spec>, ["~> 0.2.5"])
91
99
  s.add_dependency(%q<rails-app-spec>, ["~> 0.2.14"])
92
- s.add_dependency(%q<cancan>, ["~> 1.3.2"])
100
+ s.add_dependency(%q<cancan>, ["~> 1.4.0"])
93
101
  s.add_dependency(%q<require_all>, ["~> 1.2.0"])
94
102
  s.add_dependency(%q<sugar-high>, ["~> 0.2.10"])
95
103
  end
@@ -1,6 +1,7 @@
1
1
  module Permit
2
2
  class Base
3
3
  attr_reader :ability
4
+ attr_reader :strategy # this can be used to customize the strategy used by owns to determine ownership, fx to support alternative ORMs
4
5
 
5
6
  def licenses *names
6
7
  names.to_strings.each do |name|
@@ -14,11 +15,12 @@ module Permit
14
15
  end
15
16
  end
16
17
 
17
- def initialize(ability)
18
- @ability = ability
18
+ def initialize ability, options = {}
19
+ @ability = ability
20
+ @strategy = options[:strategy] || :default
19
21
  end
20
22
 
21
- def permit?(user, request=nil)
23
+ def permit?(user, options = {})
22
24
  false
23
25
  end
24
26
 
@@ -30,13 +32,41 @@ module Permit
30
32
  can_definitions << CanCan::CanDefinition.new(false, action, subject, conditions, block)
31
33
  end
32
34
 
33
- def owns(user, clazz, ownership_relation = :user_id, user_id_attribute = :id)
34
- begin
35
+ def owns(user, clazz, ownership_relation = :user_id, user_id_attribute = :id, strategy_used = nil)
36
+ begin
37
+ strategy_used = strategy_used || self.strategy
35
38
  user_id = user.send :"#{user_id_attribute}"
36
39
  rescue
37
40
  raise ArgumentError, "ERROR (owns) - The user of class #{user.class} does not respond to ##{user_id_attribute}"
41
+ end
42
+ # puts "can #{clazz} manage ownership: #{ownership_relation.inspect} => #{user_id.inspect} ???"
43
+ # puts "Using strategy: #{strategy_used}"
44
+ begin
45
+ case strategy_used
46
+ when :mongoid
47
+ # puts "Ownership with mongoid for class: #{clazz}"
48
+ # can :manage, clazz, ownership_relation => user_id
49
+ can :manage, clazz do |obj|
50
+ # puts "obj: #{obj.inspect}"
51
+ # puts "ownership relation: #{ownership_relation}"
52
+ # rel = obj.send ownership_relation
53
+ #
54
+ # puts "related obj: #{rel.inspect}"
55
+ # puts "user_id: #{user_id_attribute.inspect}"
56
+ # puts "user.user_id: #{user.send(user_id_attribute).inspect}"
57
+ # puts user.send(user_id_attribute).to_s
58
+ #
59
+ obj.send(ownership_relation) == user.send(user_id_attribute).to_s
60
+ end
61
+ when :default
62
+ # puts "Basic CanCan ownership"
63
+ can :manage, clazz, ownership_relation => user_id
64
+ else
65
+ raise "Trying to use unknown ownership strategy: #{strategy}"
66
+ end
67
+ rescue Exception => e
68
+ puts e.inspect
38
69
  end
39
- can :manage, clazz, ownership_relation => user_id
40
70
  end
41
71
 
42
72
  protected
@@ -4,34 +4,42 @@ module Permits
4
4
 
5
5
  # set up each Permit instance to share this same Ability
6
6
  # so that the can and cannot operations work on the same permission collection!
7
- def self.permits ability
7
+ def self.permits ability, options = {}
8
8
  special_permits = []
9
- special_permits << [:system, :any].map{|role| make_permit(role, ability)}
9
+ special_permits << [:system, :any].map{|role| make_permit(role, ability, options)}
10
+ # puts "Available roles: #{Permits::Roles.available}"
10
11
  role_permits = Permits::Roles.available.inject([]) do |permits, role|
11
- permit = make_permit(role, ability)
12
+ permit = make_permit(role, ability, options)
13
+ # puts "made permit: #{permit}"
12
14
  permits << permit if permit
13
15
  end
16
+ # puts "role_permits: #{role_permits.inspect}"
14
17
  (special_permits + role_permits).flatten.compact
15
18
  end
16
19
 
17
- def initialize(user, request=nil)
20
+ def initialize user, options = {}
18
21
  # put ability logic here!
19
22
  user ||= Guest.new
20
-
21
- Permits::Ability.permits(self).each do |permit|
23
+
24
+ all_permits = Permits::Ability.permits(self, options)
25
+ # puts "Trying permits: #{all_permits.inspect}"
26
+ all_permits.each do |permit|
22
27
  # get role name of permit
23
28
  permit_role = permit.class.demodulize.gsub(/Permit$/, '').underscore.to_sym
24
-
29
+
30
+ # puts "Permit role: #{permit_role.inspect}"
25
31
  if permit_role == :system
26
32
  # always execute system permit
27
- result = role_permit.permit?(user, request)
33
+ result = permit.permit?(user, options)
28
34
  break if result == :break
29
35
  else
30
36
  # only execute the permit if the user has the role of the permit or is for any role
37
+ # puts "does user have_role? #{user.has_role?(permit_role)}, #{user.inspect}"
31
38
  if user.has_role?(permit_role) || permit_role == :any
32
39
  # puts "user: #{user} of #{permit_role} has permit?"
33
- permit.permit?(user, request)
34
- # else
40
+ # puts "permit: #{permit.inspect}"
41
+ permit.permit?(user, options)
42
+ # else
35
43
  # puts "Permit #{permit} not used for role #{permit_role}"
36
44
  end
37
45
  end
@@ -40,11 +48,12 @@ module Permits
40
48
 
41
49
  protected
42
50
 
43
- def self.make_permit role, ability
51
+ def self.make_permit role, ability, options = {}
44
52
  begin
45
53
  clazz_name = "#{role.to_s.camelize}Permit"
54
+ # puts "Attempting to load #{clazz_name} permition class"
46
55
  permit_clazz = clazz_name.constantize
47
- permit_clazz.new(ability) if permit_clazz && permit_clazz.kind_of?(Class)
56
+ permit_clazz.new(ability, options) if permit_clazz && permit_clazz.kind_of?(Class)
48
57
  rescue
49
58
  # puts "permit class not found: #{clazz_name}"
50
59
  nil
@@ -1,9 +1,10 @@
1
1
  module Permits::Roles
2
2
  def self.available
3
3
  if Module.const_defined? :User
4
- User.roles if User.respond_to? :roles
4
+ [:guest, :admin]
5
+ #User.defined_roles if User.respond_to? :defined_roles
5
6
  else
6
7
  [:guest, :admin]
7
8
  end
8
9
  end
9
- end
10
+ end
@@ -1,9 +1,9 @@
1
1
  class <%= permit_name.to_s.camelize %>Permit < Permit::Base
2
- def initialize(ability)
2
+ def initialize(ability, options = {})
3
3
  super
4
4
  end
5
5
 
6
- def permit?(user, request=nil)
6
+ def permit?(user, options = {})
7
7
  super
8
8
  <%= permit_logic %>
9
9
  licenses :user_admin, :blogging
@@ -1,9 +1,9 @@
1
1
  class AdminPermit < Permit::Base
2
- def initialize(ability)
2
+ def initialize(ability, options = {})
3
3
  super
4
4
  end
5
5
 
6
- def permit?(user, request=nil)
6
+ def permit?(user, options = {})
7
7
  super
8
8
  return if !role_match? user
9
9
 
@@ -1,9 +1,9 @@
1
1
  class EditorPermit < Permit::Base
2
- def initialize(ability)
2
+ def initialize(ability, options = {})
3
3
  super
4
4
  end
5
5
 
6
- def permit?(user, request=nil)
6
+ def permit?(user, options = {})
7
7
  super
8
8
  return if !role_match? user
9
9
 
@@ -1,18 +1,18 @@
1
1
  class GuestPermit < Permit::Base
2
- def initialize(ability)
2
+ def initialize(ability, options = {})
3
3
  super
4
4
  end
5
5
 
6
- def permit?(user, request=nil)
6
+ def permit?(user, options = {})
7
7
  super
8
8
  return if !role_match? user
9
9
 
10
10
  can :read, [Comment, Post]
11
- can [:update, :destroy], [Comment]
12
11
  can :create, Article
13
12
 
14
- licenses :user_admin, :blogging
15
- # owns(user, Comment)
13
+ # licenses :user_admin, :blogging
14
+
15
+ owns(user, Comment)
16
16
 
17
17
  # a user can manage comments he/she created
18
18
  # can :manage, Comment do |comment|
@@ -0,0 +1,17 @@
1
+ class Comment
2
+ include Mongoid::Document
3
+
4
+ field :user_id, :type => String
5
+ end
6
+
7
+ class Post
8
+ include Mongoid::Document
9
+
10
+ field :writer, :type => String
11
+ end
12
+
13
+ class Article
14
+ include Mongoid::Document
15
+
16
+ field :author, :type => String
17
+ end
@@ -0,0 +1,73 @@
1
+ require 'mongoid/spec_helper'
2
+
3
+ describe Permits::Ability do
4
+ context "Editor user" do
5
+ context "using default :user_id relation - foreign key to User.id" do
6
+ before :each do
7
+ @editor = User.create(:name => "Kristian", :role => "editor")
8
+ @other_guy = User.create(:name => "Random dude", :role => "admin")
9
+
10
+ @ability = Permits::Ability.new(@editor, :strategy => :mongoid)
11
+
12
+ @own_comment = Comment.create(:user_id => @editor.id)
13
+ @other_comment = Comment.create(:user_id => @other_guy.id)
14
+ # @post = Post.create(:writer => @editor.id)
15
+ # @article = Article.create(:author => @editor.id)
16
+ end
17
+
18
+ it "should be able to :read Comment he owns" do
19
+ @ability.should be_able_to(:read, Comment)
20
+ @ability.should be_able_to(:read, @own_comment)
21
+ end
22
+
23
+ it "should be able to :update Comment he owns" do
24
+ @ability.should be_able_to(:update, @own_comment)
25
+ end
26
+
27
+ it "should NOT be able to :update Comment he does NOT own" do
28
+ @ability.should_not be_able_to(:update, @other_comment)
29
+ end
30
+
31
+ it "should be able to :delete Comment he owns" do
32
+ @ability.should be_able_to(:delete, @own_comment)
33
+ end
34
+
35
+ it "should NOT be able to :update Comment he does NOT own" do
36
+ @ability.should_not be_able_to(:delete, @other_comment)
37
+ end
38
+ end
39
+
40
+ context "using custom :writer relation - foreign key to User.id" do
41
+ before :each do
42
+ @editor = User.create(:name => "Kristian", :role => "editor")
43
+ @other_guy = User.create(:name => "Random dude", :role => "admin")
44
+
45
+ @ability = Permits::Ability.new(@editor, :strategy => :mongoid)
46
+
47
+ @own_post = Post.create(:writer => @editor.id)
48
+ @other_post = Post.create(:writer => @other_guy.id)
49
+ end
50
+
51
+ it "should be able to :read Post he owns" do
52
+ @ability.should be_able_to(:read, Post)
53
+ @ability.should be_able_to(:read, @own_post)
54
+ end
55
+
56
+ it "should be able to :update Post he owns" do
57
+ @ability.should be_able_to(:update, @own_post)
58
+ end
59
+
60
+ it "should NOT be able to :update Post he does NOT own" do
61
+ @ability.should_not be_able_to(:update, @other_post)
62
+ end
63
+
64
+ it "should be able to :delete Post he owns" do
65
+ @ability.should be_able_to(:delete, @own_post)
66
+ end
67
+
68
+ it "should NOT be able to :update Post he does NOT own" do
69
+ @ability.should_not be_able_to(:delete, @other_post)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,83 @@
1
+ require 'mongoid/spec_helper'
2
+
3
+ # class Comment
4
+ # attr_accessor :owner
5
+ # end
6
+ #
7
+ # class Post
8
+ # attr_accessor :writer
9
+ # end
10
+ #
11
+ # class Article
12
+ # attr_accessor :author
13
+ # end
14
+
15
+ describe Permits::Ability do
16
+ context "Guest user" do
17
+ before :each do
18
+ @guest = User.create(:name => "Kristian", :role => "guest")
19
+
20
+ @ability = Permits::Ability.new(@guest)
21
+
22
+ @comment = Comment.create(:user_id => @guest.id)
23
+
24
+ @post = Post.create(:writer => @guest.id)
25
+
26
+ @article = Article.create(:author => @guest.id)
27
+ end
28
+
29
+ # can :read, [Comment, Post]
30
+ # can [:update, :destroy], [Comment]
31
+ # can :create, Article
32
+
33
+ it "should be able to :read Comment and Post but NOT Article" do
34
+ @ability.can?(:read, Comment).should be_true
35
+ @ability.can?(:read, @comment).should be_true
36
+
37
+ @ability.can?(:read, Post).should be_true
38
+ @ability.can?(:read, @post).should be_true
39
+
40
+ @ability.can?(:read, Article).should be_false
41
+ @ability.can?(:read, @article).should be_false
42
+ end
43
+
44
+ it "should be not able to :update only Comment" do
45
+ @ability.can?(:update, Comment).should be_true
46
+ @ability.can?(:update, @comment).should be_true
47
+
48
+ @ability.can?(:update, Post).should be_false
49
+ @ability.can?(:update, @post).should be_false
50
+ end
51
+
52
+ end
53
+
54
+ context "Admin user" do
55
+ before do
56
+ @admin = User.create(:role => 'admin')
57
+ @ability = Permits::Ability.new(@admin)
58
+ end
59
+ #
60
+ # # can :manage, :all
61
+ #
62
+ it "should be able to :read anything" do
63
+ @ability.can?(:read, Comment).should be_true
64
+ @ability.can?(:read, Post).should be_true
65
+ end
66
+
67
+ it "should be not able to :update everything" do
68
+ @ability.can?(:update, Comment).should be_true
69
+ @ability.can?(:update, Post).should be_true
70
+ end
71
+
72
+ it "should be not able to :create everything" do
73
+ @ability.can?(:create, Comment).should be_true
74
+ @ability.can?(:create, Post).should be_true
75
+ end
76
+
77
+ it "should be not able to :update everything" do
78
+ @ability.can?(:destroy, Comment).should be_true
79
+ @ability.can?(:destroy, Post).should be_true
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,61 @@
1
+ require 'rspec/core'
2
+ require 'mongoid'
3
+ require 'cancan/matchers'
4
+ require 'cancan-permits'
5
+ require 'cancan-permits/rspec'
6
+
7
+ require_all File.dirname(__FILE__) + '/../cancan-permits/fixtures/permits'
8
+ require_all File.dirname(__FILE__) + '/models/all_models'
9
+
10
+ RSpec.configure do |config|
11
+ config.mock_with :mocha
12
+ end
13
+
14
+ module Permits::Roles
15
+ def self.available
16
+ User.roles
17
+ end
18
+ end
19
+
20
+ class User
21
+ include Mongoid::Document
22
+
23
+ field :role, :type => String
24
+ field :name, :type => String
25
+
26
+ def self.roles
27
+ [:guest, :admin, :editor]
28
+ end
29
+
30
+ def has_role? role
31
+ self.role.to_sym == role.to_sym
32
+ end
33
+ end
34
+
35
+
36
+ Mongoid.configure.master = Mongo::Connection.new.db('cancan_permits')
37
+
38
+ module Database
39
+ def self.teardown
40
+ Mongoid.database.collections.each do |coll|
41
+ coll.remove
42
+ end
43
+ end
44
+ end
45
+
46
+ Mongoid.database.collections.each do |coll|
47
+ coll.remove
48
+ end
49
+
50
+ RSpec.configure do |config|
51
+ config.mock_with :mocha
52
+ config.before do
53
+ Mongoid.database.collections.each do |coll|
54
+ coll.remove
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+
61
+
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 2
7
8
  - 1
8
- - 4
9
- version: 0.1.4
9
+ version: 0.2.1
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-10-07 00:00:00 +02:00
17
+ date: 2010-10-13 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -74,9 +74,9 @@ dependencies:
74
74
  - !ruby/object:Gem::Version
75
75
  segments:
76
76
  - 1
77
- - 3
78
- - 2
79
- version: 1.3.2
77
+ - 4
78
+ - 0
79
+ version: 1.4.0
80
80
  type: :runtime
81
81
  version_requirements: *id004
82
82
  - !ruby/object:Gem::Dependency
@@ -150,6 +150,10 @@ files:
150
150
  - spec/cancan-permits/permits/owner_permits_spec.rb
151
151
  - spec/cancan-permits/permits/permits_spec.rb
152
152
  - spec/generators/permit_generator_spec.rb
153
+ - spec/mongoid/models/all_models.rb
154
+ - spec/mongoid/owner_permits_spec.rb
155
+ - spec/mongoid/permits_spec.rb
156
+ - spec/mongoid/spec_helper.rb
153
157
  - spec/spec_helper.rb
154
158
  has_rdoc: true
155
159
  homepage: http://github.com/kristianmandrup/cancan-permits
@@ -191,4 +195,8 @@ test_files:
191
195
  - spec/cancan-permits/permits/owner_permits_spec.rb
192
196
  - spec/cancan-permits/permits/permits_spec.rb
193
197
  - spec/generators/permit_generator_spec.rb
198
+ - spec/mongoid/models/all_models.rb
199
+ - spec/mongoid/owner_permits_spec.rb
200
+ - spec/mongoid/permits_spec.rb
201
+ - spec/mongoid/spec_helper.rb
194
202
  - spec/spec_helper.rb