cancan-permits 0.1.4 → 0.2.1

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/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