rails-canhaz 0.0.0 → 0.1.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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ *.sqlite3
4
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "activerecord", :require => "active_record"
4
+ gem "sqlite3"
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Rails-Canhaz
2
+
3
+ This gem is a simple activerecord extention that allows any application using activerecord to manage permissions based roles.
4
+
5
+ ## Installation
6
+
7
+ Standard gem installation :
8
+
9
+ ```
10
+ gem install rails-canhaz
11
+ ```
12
+
13
+ Or in your Gemfile if you use bundler
14
+
15
+ ```ruby
16
+ gem 'rails-canhaz'
17
+ ```
18
+
19
+ You then need to create a single table in order to make this gem to work
20
+
21
+ Here is the schema of this table, if you're using ruby on rails, you should create a migration :
22
+
23
+ ```ruby
24
+ create_table :can_haz_permissions do |t|
25
+ t.integer :csubject_id
26
+ t.string :csubject_type
27
+
28
+ t.integer :cobject_id
29
+ t.string :cobject_type
30
+
31
+ t.string :permission_name
32
+ end
33
+
34
+ add_index :can_haz_permissions, :csubject_id, :name => 'subject_id_ix'
35
+ add_index :can_haz_permissions, :cobject_id, :name => 'object_id_ix'
36
+ ```
37
+
38
+ ## How to use it ?
39
+
40
+ The rails-canhaz gem defines two static functions for ActiveRecord models which allow them to act as a subject or an object.
41
+
42
+ A subject has roles on objects.
43
+
44
+ Here is an example
45
+
46
+ ```ruby
47
+ class User < ActiveRecord::Base
48
+ acts_as_canhaz_subject
49
+ end
50
+
51
+ class Article < ActiveRecord::Base
52
+ acts_as_canhaz_object
53
+ end
54
+ ```
55
+
56
+ Now our models are marked as canhaz subjects and objects, we have access to some handy functions :
57
+
58
+
59
+ ```ruby
60
+ user = User.find(42)
61
+ article = Article.find(1337)
62
+
63
+ user.can?(:read, article) # Can the user read this article? false for now
64
+
65
+ user.can(:read, article) # Ok, so the user can read this article
66
+
67
+ user.can?(:read, article) # Will be true
68
+
69
+ user.objects_with_permission(Article, :read) # Will return all the articles w/ read permissions for this user
70
+
71
+ artice.subjects_with_permission(User, :read) # Will return all the users hat are able to read this article
72
+ ```
73
+
74
+ More coming soon ...
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,27 @@
1
+ require 'active_record'
2
+
3
+ class CanHazPermission < ActiveRecord::Base
4
+
5
+ validates :cobject_id, :uniqueness => {:scope => [:permission_name, :csubject_id]}
6
+
7
+ # Gets the permission row between two objects
8
+ #
9
+ # @param subject [ActiveRecord::Base] The subject
10
+ # @param object [ActiveRecord::Base] The object
11
+ # @param permission [String, Symbol] The permission identifier
12
+ # @return [CanHazPermission, nil] The corresponding permission if found or nil
13
+ def self.find_permission(subject, object, permission)
14
+ raise NotACanHazSubject unless subject.canhaz_subject?
15
+ raise NotACanHazObject unless object.canhaz_object?
16
+
17
+ results = CanHazPermission.where(
18
+ :csubject_id => subject.id,
19
+ :csubject_type => subject.class.to_s,
20
+ :cobject_id => object.id,
21
+ :cobject_type => object.class.to_s,
22
+ :permission_name => permission
23
+ )
24
+ results.first
25
+ end
26
+
27
+ end
@@ -0,0 +1,6 @@
1
+ module CanHaz
2
+ module Exceptions
3
+ class NotACanHazSubject < StandardError; end
4
+ class NotACanHazObject < StandardError; end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ module CanHaz
2
+ module ModelExtensions
3
+ module All
4
+
5
+ # Returns if a model is registered as a canhaz subject
6
+ #
7
+ # @return [Bool] Whether or not the model is a canhaz subject
8
+ def canhaz_subject?
9
+ false
10
+ end
11
+
12
+ # Returns if a model is registered as a canhaz object
13
+ #
14
+ # @return [Bool] Whether or not the model is a canhaz object
15
+ def canhaz_object?
16
+ false
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module CanHaz
2
+ module ModelExtensions
3
+ module Object
4
+
5
+ # Checks if the model is accessible by a given subject and a given permission
6
+ # This is a proxy to subject.can?(permission, subject)
7
+ #
8
+ # @param subject [ActiveRecord::Base] The subject we are testing
9
+ # @param permission [String, Symbol] The permission we want to test the subject on
10
+ # @return [Boolean] True if the subject has the permission on this object, false otherwise
11
+ def accessible_by?(subject, permission)
12
+ subject.can?(permission, self)
13
+ end
14
+
15
+ # Gets the subjects that have the corresponding permission and type on this model
16
+ #
17
+ # @param type [Class] The type of the subjects we're looking for
18
+ # @param permission [String, Symbol] The permission
19
+ def subjects_with_permission(type, permission)
20
+ results = CanHazPermission.where('cobject_id = ? AND cobject_type = ?', self.id, self.class.to_s).where('csubject_type = ?', type.to_s).where('permission_name = ?', permission)
21
+
22
+ ids = results.collect { |r| r.csubject_id }
23
+
24
+ type.where('id IN (?)', ids)
25
+ end
26
+
27
+ def canhaz_object?
28
+ true
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,71 @@
1
+ module CanHaz
2
+ module ModelExtensions
3
+ module Subject
4
+
5
+ # Creates a permission on a given object
6
+ #
7
+ # @param permission [String, Symbol] The identifier of the permission
8
+ # @param object [ActiveRecord::Base] The model on which the permission is effective
9
+ # @return [Bool] True if the role was successfully created, false if it was already present
10
+ def can(permission, object)
11
+ raise Exceptions::NotACanHazObject unless object.canhaz_object?
12
+ CanHazPermission.new({
13
+ :csubject_id => self.id,
14
+ :csubject_type => self.class.to_s,
15
+ :cobject_type => object.class.to_s,
16
+ :cobject_id => object.id,
17
+ :permission_name => permission
18
+ }).save
19
+ end
20
+
21
+ # Checks if the subject has a given permission on a given object
22
+ #
23
+ # @param permission [String, Symbol] The identifier of the permission
24
+ # @param object [ActiveRecord::Base] The model we are testing the permission on
25
+ # @return [Bool] True if the user has the given permission, false otherwise
26
+ def can?(permission, object)
27
+ raise Exceptions::NotACanHazObject unless object.canhaz_object?
28
+ CanHazPermission.find_permission(self, object, permission) != nil
29
+ end
30
+
31
+ # Removes a permission on a given object
32
+ #
33
+ # @param permission [String, Symbol] The identifier of the permission
34
+ # @param object [ActiveRecord::Base] The model on which the permission is effective
35
+ # @return [Bool] True if the role was successfully removed, false if it did not exist
36
+ def cannot(permission, object)
37
+ permission = CanHazPermission.find_permission(self, object, permission)
38
+ return false if permission.nil?
39
+ permission.destroy and return true
40
+ end
41
+
42
+ # Checks if the subject does not have a given permission on a given object
43
+ # Acts as a proxy of !subject.can?(permission, object)
44
+ #
45
+ # @param permission [String, Symbol] The identifier of the permission
46
+ # @param object [ActiveRecord::Base] The model we are testing the permission on
47
+ # @return [Bool] True if the user has not the given permission, false otherwise
48
+ def cannot?(permission, object)
49
+ !self.can?(permission, object)
50
+ end
51
+
52
+ # Gets All objects that match a given type and permission
53
+ #
54
+ # @param type [Class] The type of the objects
55
+ # @param permission [String, Symbol] The name of the permission
56
+ # @return The macthing objects in an array
57
+ def objects_with_permission(type, permission = nil)
58
+ results = CanHazPermission.where('csubject_id = ? AND csubject_type = ?', self.id, self.class.to_s).where('cobject_type = ?', type.to_s).where('permission_name = ?', permission)
59
+
60
+ ids = results.collect { |r| r.cobject_id }
61
+
62
+ type.where('id IN (?)', ids)
63
+ end
64
+
65
+ def canhaz_subject?
66
+ true
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,30 @@
1
+ require 'rails-canhaz/extensions_subject'
2
+ require 'rails-canhaz/extensions_object'
3
+ require 'rails-canhaz/extensions_all'
4
+
5
+ module CanHaz
6
+ module ModelExtensions
7
+ def self.included(base)
8
+ base.send(:extend, ClassMethods)
9
+ base.send(:include, CanHaz::ModelExtensions::All)
10
+ end
11
+ end
12
+
13
+ module ClassMethods
14
+
15
+ ##
16
+ # Marks the current model as a canhaz object for authorizations
17
+ #
18
+ def acts_as_canhaz_object
19
+ include CanHaz::ModelExtensions::Object
20
+ end
21
+
22
+ ##
23
+ # Marks the current model as a canhaz subject for authorizations
24
+ #
25
+ def acts_as_canhaz_subject
26
+ include CanHaz::ModelExtensions::Subject
27
+ end
28
+
29
+ end
30
+ end
data/lib/rails-canhaz.rb CHANGED
@@ -1,5 +1,7 @@
1
- class CanHaz
2
- def self.hi
3
- puts "Hello world, this is WIP :)"
4
- end
1
+ require 'rails-canhaz/exceptions'
2
+ require 'rails-canhaz/model_extensions'
3
+ require 'rails-canhaz/canhaz_permission'
4
+
5
+ if defined? ActiveRecord::Base
6
+ ActiveRecord::Base.send(:include, CanHaz::ModelExtensions)
5
7
  end
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rails-canhaz'
3
+ s.version = '0.1.1'
4
+ s.date = '2012-04-16'
5
+ s.summary = "A simple gem for managing permissions between rails models"
6
+ s.description = "A simple gem for managing permissions between rails models"
7
+ s.authors = ["Adrien Siami (Intrepidd)"]
8
+ s.email = 'adrien@siami.fr'
9
+ s.files = `git ls-files`.split("\n")
10
+
11
+ s.homepage =
12
+ 'http://github.com/Intrepidd/rails-canhaz'
13
+ end
data/test/.gitkeep ADDED
File without changes
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'active_support'
4
+
5
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'test.sqlite3')
6
+
@@ -0,0 +1,5 @@
1
+ require 'active_record'
2
+ require 'rails-canhaz'
3
+
4
+ class FooModel < ActiveRecord::Base
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'active_record'
2
+ require 'rails-canhaz'
3
+
4
+ class ObjectModel < ActiveRecord::Base
5
+
6
+ acts_as_canhaz_object
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'active_record'
2
+ require 'rails-canhaz'
3
+
4
+ class SubjectModel < ActiveRecord::Base
5
+
6
+ acts_as_canhaz_subject
7
+
8
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,33 @@
1
+
2
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'object_models'")
3
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'subject_models'")
4
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'can_haz_permissions'")
5
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'foo_models'")
6
+
7
+ ActiveRecord::Schema.define(:version => 0) do
8
+
9
+ create_table :object_models do |t|
10
+
11
+ end
12
+
13
+ create_table :subject_models do |t|
14
+
15
+ end
16
+
17
+ create_table :can_haz_permissions do |t|
18
+ t.integer :csubject_id
19
+ t.string :csubject_type
20
+
21
+ t.integer :cobject_id
22
+ t.string :cobject_type
23
+
24
+ t.string :permission_name
25
+ end
26
+
27
+ add_index :can_haz_permissions, :csubject_id, :name => 'subject_id_ix'
28
+ add_index :can_haz_permissions, :cobject_id, :name => 'object_id_ix'
29
+
30
+ create_table :foo_models do |t|
31
+ end
32
+
33
+ end
@@ -0,0 +1,155 @@
1
+ require 'init_tests'
2
+ require 'rails-canhaz'
3
+ require 'test/unit'
4
+ require 'models/object_model'
5
+ require 'models/subject_model'
6
+ require 'models/foo_model'
7
+
8
+ load 'schema.rb'
9
+
10
+ class CanHazTest < Test::Unit::TestCase
11
+
12
+ def test_methods
13
+ assert ActiveRecord::Base.respond_to? :acts_as_canhaz_object
14
+ assert ActiveRecord::Base.respond_to? :acts_as_canhaz_subject
15
+
16
+
17
+ foo = FooModel.new
18
+
19
+ assert foo.canhaz_object? == false
20
+ assert foo.canhaz_subject? == false
21
+
22
+ object = ObjectModel.new
23
+
24
+ assert object.canhaz_object?
25
+ assert object.canhaz_subject? == false
26
+
27
+ subject = SubjectModel.new
28
+
29
+ assert subject.canhaz_subject?
30
+ assert subject.canhaz_object? == false
31
+
32
+ end
33
+
34
+ def test_exceptions
35
+ foo = FooModel.new
36
+
37
+ subject = SubjectModel.new
38
+
39
+ object = ObjectModel.new
40
+
41
+ assert_raise CanHaz::Exceptions::NotACanHazObject do
42
+ subject.can(:whatever, foo)
43
+ end
44
+
45
+ assert_nothing_raised RuntimeError do
46
+ subject.can(:whatever, object)
47
+ end
48
+
49
+ assert_raise CanHaz::Exceptions::NotACanHazObject do
50
+ subject.can?(:whatever, foo)
51
+ end
52
+
53
+ assert_nothing_raised RuntimeError do
54
+ subject.can?(:whatever, object)
55
+ end
56
+
57
+ end
58
+
59
+ def test_can
60
+ subject = SubjectModel.new
61
+ subject.save
62
+
63
+ object = ObjectModel.new
64
+ object.save
65
+
66
+ assert subject.can?(:foo, object) == false
67
+ assert subject.can?(:bar, object) == false
68
+
69
+ assert object.accessible_by?(subject, :foo) == false
70
+ assert object.accessible_by?(subject, :bar) == false
71
+
72
+ assert subject.can(:foo, object)
73
+ assert subject.can(:bar, object)
74
+
75
+ assert subject.can(:foo, object) == false
76
+ assert subject.can(:bar, object) == false
77
+
78
+ assert subject.can?(:foo, object)
79
+ assert subject.can?(:bar, object)
80
+
81
+ assert object.accessible_by?(subject, :foo)
82
+ assert object.accessible_by?(subject, :bar)
83
+
84
+ assert subject.objects_with_permission(ObjectModel, :foo).count == 1
85
+ assert subject.objects_with_permission(ObjectModel, :foo).first == object
86
+
87
+ assert subject.objects_with_permission(ObjectModel, :bar).count == 1
88
+ assert subject.objects_with_permission(ObjectModel, :bar).first == object
89
+
90
+ assert subject.objects_with_permission(ObjectModel, :foobar).count == 0
91
+
92
+ end
93
+
94
+ def test_can_cannot
95
+ subject = SubjectModel.new
96
+ subject.save
97
+
98
+ object = ObjectModel.new
99
+ object.save
100
+
101
+ assert subject.can?(:foo, object) == false
102
+ assert subject.cannot(:foo, object) == false
103
+
104
+ subject.can(:foo, object)
105
+ subject.can(:bar, object)
106
+
107
+ assert subject.can?(:foo, object)
108
+ assert subject.can?(:bar, object)
109
+
110
+ assert subject.cannot(:foo, object) == true
111
+
112
+ assert subject.can?(:foo, object) == false
113
+ assert subject.can?(:bar, object) == true
114
+ end
115
+
116
+ def test_subjects_from_object
117
+ object = ObjectModel.new
118
+ object.save
119
+
120
+ s1 = SubjectModel.new
121
+ s2 = SubjectModel.new
122
+ s3 = SubjectModel.new
123
+
124
+ s1.save
125
+ s2.save
126
+ s3.save
127
+
128
+ s1.can(:foo, object)
129
+ s2.can(:bar, object)
130
+ s3.can(:foo, object)
131
+
132
+ foo = object.subjects_with_permission(SubjectModel, :foo)
133
+
134
+ assert foo.include?(s1) == true
135
+ assert foo.include?(s2) == false
136
+ assert foo.include?(s3) == true
137
+
138
+ s3.cannot(:foo, object)
139
+
140
+ foo = object.subjects_with_permission(SubjectModel, :foo)
141
+
142
+ assert foo.include?(s1) == true
143
+ assert foo.include?(s2) == false
144
+ assert foo.include?(s3) == false
145
+
146
+ bar = object.subjects_with_permission(SubjectModel, :bar)
147
+
148
+ assert bar.include?(s1) == false
149
+ assert bar.include?(s2) == true
150
+ assert bar.include?(s3) == false
151
+
152
+ end
153
+
154
+ end
155
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-canhaz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-30 00:00:00.000000000 Z
12
+ date: 2012-04-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A simple gem for managing permissions between rails models
15
15
  email: adrien@siami.fr
@@ -17,8 +17,26 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - .gitignore
21
+ - Gemfile
22
+ - README.md
23
+ - Rakefile
20
24
  - lib/rails-canhaz.rb
21
- homepage: http://rubygems.org/gems/rails-canhaz
25
+ - lib/rails-canhaz/canhaz_permission.rb
26
+ - lib/rails-canhaz/exceptions.rb
27
+ - lib/rails-canhaz/extensions_all.rb
28
+ - lib/rails-canhaz/extensions_object.rb
29
+ - lib/rails-canhaz/extensions_subject.rb
30
+ - lib/rails-canhaz/model_extensions.rb
31
+ - rails-canhaz.gemspec
32
+ - test/.gitkeep
33
+ - test/init_tests.rb
34
+ - test/models/foo_model.rb
35
+ - test/models/object_model.rb
36
+ - test/models/subject_model.rb
37
+ - test/schema.rb
38
+ - test/test_canhaz.rb
39
+ homepage: http://github.com/Intrepidd/rails-canhaz
22
40
  licenses: []
23
41
  post_install_message:
24
42
  rdoc_options: []
@@ -38,8 +56,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
56
  version: '0'
39
57
  requirements: []
40
58
  rubyforge_project:
41
- rubygems_version: 1.8.17
59
+ rubygems_version: 1.8.21
42
60
  signing_key:
43
61
  specification_version: 3
44
62
  summary: A simple gem for managing permissions between rails models
45
63
  test_files: []
64
+ has_rdoc: